Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1251} catch (...) {1252// Don't try to read any more data for this request1253req.SetState(HTTPRequest::State::Error);1254// Clear the memory allocated to this client, caller must disconnect1255m_recv_buffer.clear();1256throw;1257}1259// Remove the bytes read out of the buffer.1260m_recv_buffer.erase(1261m_recv_buffer.begin(),1262m_recv_buffer.begin() + reader.Consumed());1263}1265bool HTTPRemoteClient::MaybeSendBytesFromBuffer()1266{1267// Send as much data from this client's buffer as we can1268LOCK(m_send_mutex);1269if (!m_send_buffer.empty()) {1270// Socket flags (See kernel docs for send(2) and tcp(7) for more details).1271// MSG_NOSIGNAL: If the remote end of the connection is closed,1272// fail with EPIPE (an error) as opposed to triggering1273// SIGPIPE which terminates the process.1274// MSG_DONTWAIT: Makes the send operation non-blocking regardless of socket blocking mode.1275// MSG_MORE: We do not set this flag here because http responses are usually1276// small and we want the kernel to send them right away. Setting MSG_MORE1277// would "cork" the socket to prevent sending out partial frames.1278int flags{MSG_NOSIGNAL | MSG_DONTWAIT};1280// Try to send bytes through socket1281ssize_t bytes_sent;1282{1283LOCK(m_sock_mutex);1284bytes_sent = m_sock->Send(m_send_buffer.data(),1285m_send_buffer.size(),1286flags);1287}1289if (bytes_sent < 0) {1290// Something went wrong1291const int err{WSAGetLastError()};1292if (!IOErrorIsPermanent(err)) {1293// The error can be safely ignored, try the send again on the next I/O loop.1294m_send_ready = true;1295m_connection_busy = true;1296return true;1297} else {1298// Unrecoverable error, log and disconnect client.1299LogDebug(1300BCLog::HTTP,1301"Error sending HTTP response data to client %s (id=%llu): %s",1302m_origin,1303m_id,1304NetworkErrorString(err));1305m_send_ready = false;1306m_disconnect = true;1308// Do not attempt to read from this client.1309return false;1310}1311}1313// Successful send, remove sent bytes from our local buffer.1314Assume(static_cast<size_t>(bytes_sent) <= m_send_buffer.size());1315m_send_buffer.erase(m_send_buffer.begin(),1316m_send_buffer.begin() + bytes_sent);1318LogDebug(1319BCLog::HTTP,1320"Sent %d bytes to client %s (id=%llu)",1321bytes_sent,1322m_origin,1323m_id);1325// This check is inside the if(!empty) block meaning "there was data but now its gone".1326// We wouldn't want to change the flags if MaybeSendBytesFromBuffer() was called1327// on an already-empty m_send_buffer because the connection might have just been opened.1328if (m_send_buffer.empty()) {1329m_send_ready = false;1330m_connection_busy = false;1332// Our work is done here1333if (!m_keep_alive) {1334m_disconnect = true;1335// Do not attempt to read from this client.1336return false;1337}1338} else {1339// The send buffer isn't flushed yet, try to push more on the next loop.1340m_send_ready = true;1341m_connection_busy = true;1342}1344// Finally, reset idle timeout1345m_idle_since = Now<SteadySeconds>();1346}1348return true;1349}1351bool InitHTTPServer()1352{1353// Create HTTPServer1354g_http_server = std::make_unique<HTTPServer>(MaybeDispatchRequestToWorker);1356if (!g_http_server->InitHTTPAllowList()) {1357return false;1358}1360g_http_server->SetServerTimeout(std::chrono::seconds(gArgs.GetIntArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT)));1361g_http_server->SetMaxConnections(std::max(gArgs.GetArg<int>("-rpcmaxconnections", DEFAULT_MAX_HTTP_CONNECTIONS), 1));1363// Bind HTTP server to specified addresses1364std::vector<std::pair<std::string, uint16_t>> endpoints{GetBindAddresses()};1365bool bind_success{false};1366for (const auto& [address_string, port] : endpoints) {1367LogInfo("Binding RPC on address %s port %i", address_string, port);1368const std::optional<CService> addr{Lookup(address_string, port, false)};1369if (addr) {1370if (addr->IsBindAny()) {1371LogWarning("The RPC server is not safe to expose to untrusted networks such as the public internet");1372}1373auto result{g_http_server->BindAndStartListening(addr.value())};1374if (!result) {1375LogWarning("Binding RPC on address %s failed: %s", addr->ToStringAddrPort(), result.error());1376} else {1377bind_success = true;1378}1379} else {1380LogWarning("Could not bind RPC on address %s port %i: Address lookup failed.", address_string, port);1381}1382}1384if (!bind_success) {1385LogError("Unable to bind any endpoint for RPC server");1386return false;1387}1389LogDebug(BCLog::HTTP, "Initialized HTTP server");1391g_max_queue_depth = std::max(gArgs.GetArg<int>("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1);1392LogDebug(BCLog::HTTP, "set work queue of depth %d\n", g_max_queue_depth);1394return true;1395}1397void StartHTTPServer()1398{1399auto rpcThreads{std::max(gArgs.GetArg<int>("-rpcthreads", DEFAULT_HTTP_THREADS), 1)};1400LogInfo("Starting HTTP server with %d worker threads", rpcThreads);1401g_threadpool_http.Start(rpcThreads);1402g_http_server->StartSocketsThreads();1403}1405void InterruptHTTPServer()1406{1407LogDebug(BCLog::HTTP, "Interrupting HTTP server");1408if (g_http_server) {1409// Reject all new requests1410g_http_server->SetRequestHandler(RejectRequest);1411}1413// Interrupt pool after disabling requests1414g_threadpool_http.Interrupt();1415}1417void StopHTTPServer()1418{1419LogDebug(BCLog::HTTP, "Stopping HTTP server");1421LogDebug(BCLog::HTTP, "Waiting for HTTP worker threads to exit\n");1422g_threadpool_http.Stop();1424if (g_http_server) {1425// Must precede DisconnectAllClients(): a connection accepted after1426// GetConnectionsCount() returns 0 would survive into the destructor.1427g_http_server->StopAccepting();1428// Disconnect clients as their remaining responses are flushed1429g_http_server->DisconnectAllClients();1430// Wait 30 seconds for all disconnections1431LogDebug(BCLog::HTTP, "Waiting for HTTP clients to disconnect gracefully");1432const auto deadline{NodeClock::now() + 30s};1433while (g_http_server->GetConnectionsCount() != 0) {1434if (NodeClock::now() > deadline) {1435LogWarning("Timeout waiting for HTTP clients to disconnect gracefully, continuing shutdown");1436break;1437}1438std::this_thread::sleep_for(50ms);1439}1440// Break HTTPServer I/O loop: stop accepting connections, sending and receiving data1441g_http_server->InterruptNet();1442// Wait for HTTPServer I/O thread to exit1443g_http_server->JoinSocketsThreads();1444// Force-remove any clients that survived the graceful wait1445g_http_server->ClearConnectedClients();1446// Close all listening sockets1447g_http_server->StopListening();1448}1449LogDebug(BCLog::HTTP, "Stopped HTTP server");1450}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.