| 291 | } |
| 292 | |
| 293 | Session::Reply Session::SendRequestAndGetReply(const Sock& sock, |
| 294 | const std::string& request, |
| 295 | bool check_result_ok) const |
| 296 | { |
| 297 | sock.SendComplete(request + "\n", MAX_WAIT_FOR_IO, *m_interrupt); |
| 298 | |
| 299 | Reply reply; |
| 300 | |
| 301 | // Don't log the full "SESSION CREATE ..." because it contains our private key. |
| 302 | reply.request = request.starts_with("SESSION CREATE") ? "SESSION CREATE ..." : request; |
| 303 | |
| 304 | // It could take a few minutes for the I2P router to reply as it is querying the I2P network |
| 305 | // (when doing name lookup, for example). Notice: `RecvUntilTerminator()` is checking |
| 306 | // `m_interrupt` more often, so we would not be stuck here for long if `m_interrupt` is |
| 307 | // signaled. |
| 308 | static constexpr auto recv_timeout = 3min; |
| 309 | |
| 310 | reply.full = sock.RecvUntilTerminator('\n', recv_timeout, *m_interrupt, MAX_MSG_SIZE); |
| 311 | |
| 312 | for (const auto& kv : Split(reply.full, ' ')) { |
| 313 | const auto pos{std::ranges::find(kv, '=')}; |
| 314 | if (pos != kv.end()) { |
| 315 | reply.keys.emplace(std::string{kv.begin(), pos}, std::string{pos + 1, kv.end()}); |
| 316 | } else { |
| 317 | reply.keys.emplace(std::string{kv.begin(), kv.end()}, std::nullopt); |
| 318 | } |
| 319 | } |
| 320 | |
| 321 | if (check_result_ok && reply.Get("RESULT") != "OK") { |
| 322 | throw std::runtime_error( |
| 323 | strprintf("Reply to \"%s\": had a RESULT not equal to OK.", reply.request)); |
| 324 | } |
| 325 | |
| 326 | return reply; |
| 327 | } |
| 328 | |
| 329 | std::unique_ptr<Sock> Session::Hello() const |
| 330 | { |
nothing calls this directly
no test coverage detected