@@ -46,6 +46,8 @@ extern Value importprivkey(const Array& params, bool fHelp);
46
46
47
47
const Object emptyobj;
48
48
49
+ void ThreadRPCServer3 (void * parg);
50
+
49
51
Object JSONRPCError (int code, const string& message)
50
52
{
51
53
Object error;
@@ -2021,7 +2023,7 @@ Value getwork(const Array& params, bool fHelp)
2021
2023
throw JSONRPCError (-10 , " Bitcoin is downloading blocks..." );
2022
2024
2023
2025
typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
2024
- static mapNewBlock_t mapNewBlock;
2026
+ static mapNewBlock_t mapNewBlock; // FIXME: thread safety
2025
2027
static vector<CBlock*> vNewBlock;
2026
2028
static CReserveKey reservekey (pwalletMain);
2027
2029
@@ -2573,20 +2575,34 @@ class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
2573
2575
SSLStream& stream;
2574
2576
};
2575
2577
2578
+ class AcceptedConnection
2579
+ {
2580
+ public:
2581
+ SSLStream sslStream;
2582
+ SSLIOStreamDevice d;
2583
+ iostreams::stream<SSLIOStreamDevice> stream;
2584
+
2585
+ ip::tcp::endpoint peer;
2586
+
2587
+ AcceptedConnection (asio::io_service &io_service, ssl::context &context,
2588
+ bool fUseSSL ) : sslStream(io_service, context), d(sslStream, fUseSSL ),
2589
+ stream (d) { ; }
2590
+ };
2591
+
2576
2592
void ThreadRPCServer (void * parg)
2577
2593
{
2578
2594
IMPLEMENT_RANDOMIZE_STACK (ThreadRPCServer (parg));
2579
2595
try
2580
2596
{
2581
- vnThreadsRunning[THREAD_RPCSERVER ]++;
2597
+ vnThreadsRunning[THREAD_RPCLISTENER ]++;
2582
2598
ThreadRPCServer2 (parg);
2583
- vnThreadsRunning[THREAD_RPCSERVER ]--;
2599
+ vnThreadsRunning[THREAD_RPCLISTENER ]--;
2584
2600
}
2585
2601
catch (std::exception& e) {
2586
- vnThreadsRunning[THREAD_RPCSERVER ]--;
2602
+ vnThreadsRunning[THREAD_RPCLISTENER ]--;
2587
2603
PrintException (&e, " ThreadRPCServer()" );
2588
2604
} catch (...) {
2589
- vnThreadsRunning[THREAD_RPCSERVER ]--;
2605
+ vnThreadsRunning[THREAD_RPCLISTENER ]--;
2590
2606
PrintException (NULL , " ThreadRPCServer()" );
2591
2607
}
2592
2608
printf (" ThreadRPCServer exiting\n " );
@@ -2664,54 +2680,67 @@ void ThreadRPCServer2(void* parg)
2664
2680
loop
2665
2681
{
2666
2682
// Accept connection
2667
- SSLStream sslStream (io_service, context);
2668
- SSLIOStreamDevice d (sslStream, fUseSSL );
2669
- iostreams::stream<SSLIOStreamDevice> stream (d);
2670
-
2671
- ip::tcp::endpoint peer;
2672
- vnThreadsRunning[THREAD_RPCSERVER]--;
2673
- acceptor.accept (sslStream.lowest_layer (), peer);
2674
- vnThreadsRunning[4 ]++;
2683
+ AcceptedConnection *conn =
2684
+ new AcceptedConnection (io_service, context, fUseSSL );
2685
+
2686
+ vnThreadsRunning[THREAD_RPCLISTENER]--;
2687
+ acceptor.accept (conn->sslStream .lowest_layer (), conn->peer );
2688
+ vnThreadsRunning[THREAD_RPCLISTENER]++;
2689
+
2675
2690
if (fShutdown )
2691
+ {
2692
+ delete conn;
2676
2693
return ;
2694
+ }
2677
2695
2678
- // Restrict callers by IP
2679
- if (!ClientAllowed (peer.address ().to_string ()))
2696
+ // Restrict callers by IP. It is important to
2697
+ // do this before starting client thread, to filter out
2698
+ // certain DoS and misbehaving clients.
2699
+ if (!ClientAllowed (conn->peer .address ().to_string ()))
2680
2700
{
2681
2701
// Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
2682
2702
if (!fUseSSL )
2683
- stream << HTTPReply (403 , " " ) << std::flush;
2684
- continue ;
2703
+ conn-> stream << HTTPReply (403 , " " ) << std::flush;
2704
+ delete conn ;
2685
2705
}
2686
2706
2707
+ // start HTTP client thread
2708
+ else if (!CreateThread (ThreadRPCServer3, conn)) {
2709
+ printf (" Failed to create RPC server client thread\n " );
2710
+ delete conn;
2711
+ }
2712
+ }
2713
+ }
2714
+
2715
+ void ThreadRPCServer3 (void * parg)
2716
+ {
2717
+ IMPLEMENT_RANDOMIZE_STACK (ThreadRPCServer3 (parg));
2718
+ vnThreadsRunning[THREAD_RPCHANDLER]++;
2719
+ AcceptedConnection *conn = (AcceptedConnection *) parg;
2720
+
2721
+ do {
2687
2722
map<string, string> mapHeaders;
2688
2723
string strRequest;
2689
2724
2690
- boost::thread api_caller (ReadHTTP, boost::ref (stream), boost::ref (mapHeaders), boost::ref (strRequest));
2691
- if (!api_caller.timed_join (boost::posix_time::seconds (GetArg (" -rpctimeout" , 30 ))))
2692
- { // Timed out:
2693
- acceptor.cancel ();
2694
- printf (" ThreadRPCServer ReadHTTP timeout\n " );
2695
- continue ;
2696
- }
2725
+ ReadHTTP (conn->stream , mapHeaders, strRequest);
2697
2726
2698
2727
// Check authorization
2699
2728
if (mapHeaders.count (" authorization" ) == 0 )
2700
2729
{
2701
- stream << HTTPReply (401 , " " ) << std::flush;
2702
- continue ;
2730
+ conn-> stream << HTTPReply (401 , " " ) << std::flush;
2731
+ break ;
2703
2732
}
2704
2733
if (!HTTPAuthorized (mapHeaders))
2705
2734
{
2706
- printf (" ThreadRPCServer incorrect password attempt from %s\n " ,peer.address ().to_string ().c_str ());
2735
+ printf (" ThreadRPCServer incorrect password attempt from %s\n " , conn-> peer .address ().to_string ().c_str ());
2707
2736
/* Deter brute-forcing short passwords.
2708
2737
If this results in a DOS the user really
2709
2738
shouldn't have their RPC port exposed.*/
2710
2739
if (mapArgs[" -rpcpassword" ].size () < 20 )
2711
2740
Sleep (250 );
2712
2741
2713
- stream << HTTPReply (401 , " " ) << std::flush;
2714
- continue ;
2742
+ conn-> stream << HTTPReply (401 , " " ) << std::flush;
2743
+ break ;
2715
2744
}
2716
2745
2717
2746
Value id = Value::null;
@@ -2750,17 +2779,22 @@ void ThreadRPCServer2(void* parg)
2750
2779
2751
2780
// Send reply
2752
2781
string strReply = JSONRPCReply (result, Value::null, id);
2753
- stream << HTTPReply (200 , strReply) << std::flush;
2782
+ conn-> stream << HTTPReply (200 , strReply) << std::flush;
2754
2783
}
2755
2784
catch (Object& objError)
2756
2785
{
2757
- ErrorReply (stream, objError, id);
2786
+ ErrorReply (conn->stream , objError, id);
2787
+ break ;
2758
2788
}
2759
2789
catch (std::exception& e)
2760
2790
{
2761
- ErrorReply (stream, JSONRPCError (-32700 , e.what ()), id);
2791
+ ErrorReply (conn->stream , JSONRPCError (-32700 , e.what ()), id);
2792
+ break ;
2762
2793
}
2763
2794
}
2795
+ while (0 );
2796
+ delete conn;
2797
+ vnThreadsRunning[THREAD_RPCHANDLER]--;
2764
2798
}
2765
2799
2766
2800
json_spirit::Value CRPCTable::execute (const std::string &strMethod, const json_spirit::Array ¶ms) const
0 commit comments