| 247 | } |
| 248 | |
| 249 | Session::Reply Session::SendRequestAndGetReply(const Sock& sock, |
| 250 | const std::string& request, |
| 251 | bool check_result_ok) const |
| 252 | { |
| 253 | sock.SendComplete(request + "\n", MAX_WAIT_FOR_IO, *m_interrupt); |
| 254 | |
| 255 | Reply reply; |
| 256 | |
| 257 | // Don't log the full "SESSION CREATE ..." because it contains our private key. |
| 258 | reply.request = request.substr(0, 14) == "SESSION CREATE" ? "SESSION CREATE ..." : request; |
| 259 | |
| 260 | // It could take a few minutes for the I2P router to reply as it is querying the I2P network |
| 261 | // (when doing name lookup, for example). Notice: `RecvUntilTerminator()` is checking |
| 262 | // `m_interrupt` more often, so we would not be stuck here for long if `m_interrupt` is |
| 263 | // signaled. |
| 264 | static constexpr auto recv_timeout = 3min; |
| 265 | |
| 266 | reply.full = sock.RecvUntilTerminator('\n', recv_timeout, *m_interrupt, MAX_MSG_SIZE); |
| 267 | |
| 268 | for (const auto& kv : spanparsing::Split(reply.full, ' ')) { |
| 269 | const auto& pos = std::find(kv.begin(), kv.end(), '='); |
| 270 | if (pos != kv.end()) { |
| 271 | reply.keys.emplace(std::string{kv.begin(), pos}, std::string{pos + 1, kv.end()}); |
| 272 | } else { |
| 273 | reply.keys.emplace(std::string{kv.begin(), kv.end()}, std::nullopt); |
| 274 | } |
| 275 | } |
| 276 | |
| 277 | if (check_result_ok && reply.Get("RESULT") != "OK") { |
| 278 | throw std::runtime_error( |
| 279 | strprintf("Unexpected reply to \"%s\": \"%s\"", request, reply.full)); |
| 280 | } |
| 281 | |
| 282 | return reply; |
| 283 | } |
| 284 | |
| 285 | std::unique_ptr<Sock> Session::Hello() const |
| 286 | { |
nothing calls this directly
no test coverage detected