diff --git a/src/trianglesrpc.cpp b/src/trianglesrpc.cpp index c69e74f..07b3fba 100644 --- a/src/trianglesrpc.cpp +++ b/src/trianglesrpc.cpp @@ -548,10 +548,17 @@ int ReadHTTP(std::basic_istream& stream, map& mapHeadersRe bool HTTPAuthorized(map& mapHeaders) { string strAuth = mapHeaders["authorization"]; - if (strAuth.substr(0,6) != "Basic ") + if (strAuth.size() < 6 || strAuth.substr(0,6) != "Basic ") return false; string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64); - string strUserPass = DecodeBase64(strUserPass64); + if (strUserPass64.empty()) + return false; + string strUserPass; + try { + strUserPass = DecodeBase64(strUserPass64); + } catch (const std::exception&) { + return false; + } return TimingResistantEqual(strUserPass, strRPCUserColonPass); } @@ -788,44 +795,61 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptoris_open()) - RPCListen(acceptor, context, fUseSSL); + try { + // Immediately start accepting new connections, except when we're cancelled or our socket is closed. + if (error != asio::error::operation_aborted + && acceptor->is_open()) + RPCListen(acceptor, context, fUseSSL); - AcceptedConnectionImpl* tcp_conn = dynamic_cast< AcceptedConnectionImpl* >(conn); + AcceptedConnectionImpl* tcp_conn = dynamic_cast< AcceptedConnectionImpl* >(conn); - if (error) - { - if (error != asio::error::operation_aborted) - printf("RPC accept error from %s: %s (%d)\n", - tcp_conn ? tcp_conn->peer.address().to_string().c_str() : "unknown peer", - error.message().c_str(), - error.value()); + if (error) + { + if (error != asio::error::operation_aborted) + printf("RPC accept error from %s: %s (%d)\n", + tcp_conn ? tcp_conn->peer.address().to_string().c_str() : "unknown peer", + error.message().c_str(), + error.value()); + delete conn; + vnThreadsRunning[THREAD_RPCLISTENER]--; + return; + } + + // Restrict callers by IP. It is important to + // do this before starting client thread, to filter out + // certain DoS and misbehaving clients. + else if (tcp_conn + && !ClientAllowed(tcp_conn->peer.address())) + { + // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake. + try { + if (!fUseSSL) + conn->stream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush; + } catch (const std::exception& e) { + printf("RPC error sending 403 to %s: %s\n", + tcp_conn->peer.address().to_string().c_str(), e.what()); + } + delete conn; + vnThreadsRunning[THREAD_RPCLISTENER]--; + return; + } + + // start HTTP client thread + else if (!NewThread(ThreadRPCServer3, conn)) { + printf("Failed to create RPC server client thread\n"); + delete conn; + } + + vnThreadsRunning[THREAD_RPCLISTENER]--; + } catch (std::exception& e) { + PrintException(&e, "RPCAcceptHandler()"); delete conn; vnThreadsRunning[THREAD_RPCLISTENER]--; - return; - } - - // Restrict callers by IP. It is important to - // do this before starting client thread, to filter out - // certain DoS and misbehaving clients. - else if (tcp_conn - && !ClientAllowed(tcp_conn->peer.address())) - { - // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake. - if (!fUseSSL) - conn->stream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush; + } catch (...) { + PrintException(NULL, "RPCAcceptHandler()"); delete conn; + vnThreadsRunning[THREAD_RPCLISTENER]--; } - - // start HTTP client thread - else if (!NewThread(ThreadRPCServer3, conn)) { - printf("Failed to create RPC server client thread\n"); - delete conn; - } - - vnThreadsRunning[THREAD_RPCLISTENER]--; } void ThreadRPCServer2(void* parg) @@ -1133,6 +1157,7 @@ void ThreadRPCServer3(void* parg) AcceptedConnection *conn = (AcceptedConnection *) parg; bool fRun = true; + try { while (true) { if (fShutdown || !fRun) @@ -1252,6 +1277,13 @@ void ThreadRPCServer3(void* parg) } } + } // end try + catch (std::exception& e) { + PrintException(&e, "ThreadRPCServer3()"); + } catch (...) { + PrintException(NULL, "ThreadRPCServer3()"); + } + delete conn; { LOCK(cs_THREAD_RPCHANDLER);