- The i2p accept code is in
ThreadI2PAcceptIncoming
, instead of inThreadSocketHandler
like the non-i2p accept code. - When accepting non-i2p connections, a connection is accepted in
AcceptConnection
and if there are more thanmaxInbound
outstanding connections, one is marked for disconnect. The next iteration of the loop inThreadSocketHandler
will callDisconnectNodes
and remove it. - Since the i2p code resides in its own thread, it’s possible for i2p connections to stack up past 125 (I was able to hit 190 outstanding connections when running a local script to connect to my bitcoind i2p address). I think the higher numbered fd’s could cause a slight slowdown in
select
. - How many connections it can go past 125 is a race between
DisconnectNodes
andThreadI2PAcceptIncoming
.
0diff --git a/src/test/i2p_tests.cpp b/src/test/i2p_tests.cpp
1index b2e1ae43b..f1f0b2a60 100644
2--- a/src/test/i2p_tests.cpp
3+++ b/src/test/i2p_tests.cpp
4@@ -10,14 +10,52 @@
5 #include <test/util/net.h>
6 #include <test/util/setup_common.h>
7 #include <util/threadinterrupt.h>
8+#include <netbase.h>
9+#include <protocol.h>
10+
11+#include <chrono>
12+#include <thread>
13
14 #include <boost/test/unit_test.hpp>
15
16 #include <memory>
17 #include <string>
18+#include <stdio.h>
19
20 BOOST_FIXTURE_TEST_SUITE(i2p_tests, BasicTestingSetup)
21
22+BOOST_AUTO_TEST_CASE(spam)
23+{
24+ CThreadInterrupt interrupt;
25+
26+ in_addr ipv4Addr;
27+ ipv4Addr.s_addr = inet_addr("127.0.0.1");
28+
29+ Proxy p = Proxy(CService(ipv4Addr, 7656), false);
30+
31+ auto i2p_transient_session = std::make_unique<i2p::sam::Session>(p.proxy, &interrupt);
32+
33+ const char* pszDest = "tfshhokzifn2g46dc6dxwrwwxwbeo4l5eeepequ52kpvrflm3foq.b32.i2p";
34+
35+ const std::vector<CService> resolved{Lookup(pszDest, 0, false, 256)};
36+
37+ CAddress addrConnect = CAddress(resolved[0], NODE_NONE);
38+
39+ std::vector<std::unique_ptr<Sock>> v;
40+ v.reserve(1000);
41+
42+ for (int i = 0; i < 1000; i++) {
43+ i2p::Connection conn;
44+ bool proxy_error;
45+ auto connected = i2p_transient_session->Connect(addrConnect, conn, proxy_error);
46+ if (connected) {
47+ v.push_back(std::move(conn.sock));
48+ }
49+ }
50+
51+ std::this_thread::sleep_for(std::chrono::milliseconds(50000));
52+}
53+
54 BOOST_AUTO_TEST_CASE(unlimited_recv)
55 {
56 const auto prev_log_level{LogInstance().LogLevel()};
I then called it from a script:
0#!/bin/bash
1#
2for i in {1..10}
3do
4 ./src/test/test_bitcoin --log_level=all --run_test=i2p_tests/spam &
5done
When testing this, I also ran into a reproducible error when simultaneously using bitcoin-cli
:
0error: timeout on transient error: Could not connect to the server 127.0.0.1:18443 (error code 1 - "EOF reached")
1
2Make sure the bitcoind server is running and that you are connecting to the correct RPC port.
Wireshark showed that a TCP port was reused which led to a RST being sent back to bitcoin-cli. It happened when the i2p sam bridge ran out of memory, but as far as I can tell the rpc server should be totally unaffected by that. This error message also appeared in bitcoind’s logs at the same time:
2023-06-09T15:02:58Z connect() to 127.0.0.1:7656 failed: Can't assign requested address (49)