16
16
#include < memory>
17
17
#include < string>
18
18
19
- BOOST_FIXTURE_TEST_SUITE (i2p_tests, BasicTestingSetup)
19
+ // / Save the log level and the value of CreateSock and restore them when the test ends.
20
+ class EnvTestingSetup : public BasicTestingSetup
21
+ {
22
+ public:
23
+ explicit EnvTestingSetup (const ChainType chainType = ChainType::MAIN,
24
+ const std::vector<const char *>& extra_args = {})
25
+ : BasicTestingSetup{chainType, extra_args},
26
+ m_prev_log_level{LogInstance ().LogLevel ()},
27
+ m_create_sock_orig{CreateSock}
28
+ {
29
+ LogInstance ().SetLogLevel (BCLog::Level::Trace);
30
+ }
31
+
32
+ ~EnvTestingSetup ()
33
+ {
34
+ CreateSock = m_create_sock_orig;
35
+ LogInstance ().SetLogLevel (m_prev_log_level);
36
+ }
37
+
38
+ private:
39
+ const BCLog::Level m_prev_log_level;
40
+ const std::function<std::unique_ptr<Sock>(const CService&)> m_create_sock_orig;
41
+ };
42
+
43
+ BOOST_FIXTURE_TEST_SUITE (i2p_tests, EnvTestingSetup)
20
44
21
45
BOOST_AUTO_TEST_CASE(unlimited_recv)
22
46
{
23
- const auto prev_log_level{LogInstance ().LogLevel ()};
24
- LogInstance ().SetLogLevel (BCLog::Level::Trace);
25
- auto CreateSockOrig = CreateSock;
26
-
27
47
// Mock CreateSock() to create MockSock.
28
48
CreateSock = [](const CService&) {
29
49
return std::make_unique<StaticContentsSock>(std::string (i2p::sam::MAX_MSG_SIZE + 1 , ' a' ));
@@ -40,9 +60,69 @@ BOOST_AUTO_TEST_CASE(unlimited_recv)
40
60
bool proxy_error;
41
61
BOOST_REQUIRE (!session.Connect (CService{}, conn, proxy_error));
42
62
}
63
+ }
64
+
65
+ BOOST_AUTO_TEST_CASE (listen_ok_accept_fail)
66
+ {
67
+ size_t num_sockets{0 };
68
+ CreateSock = [&num_sockets](const CService&) {
69
+ // clang-format off
70
+ ++num_sockets;
71
+ // First socket is the control socket for creating the session.
72
+ if (num_sockets == 1 ) {
73
+ return std::make_unique<StaticContentsSock>(
74
+ // reply to HELLO
75
+ " HELLO REPLY RESULT=OK VERSION=3.1\n "
76
+ // reply to DEST GENERATE
77
+ "DEST REPLY PUB=WnGOLXRBqHQhdVjFlWqRxJwz9hxx~2~wGc2Vplta1KhacY4tdEGodCF1WMWVapHEnDP2HHH~b~AZzZWmW1rUqFpxji10Qah0IXVYxZVqkcScM~Yccf9v8BnNlaZbWtSoWnGOLXRBqHQhdVjFlWqRxJwz9hxx~2~wGc2Vplta1KhacY4tdEGodCF1WMWVapHEnDP2HHH~b~AZzZWmW1rUqFpxji10Qah0IXVYxZVqkcScM~Yccf9v8BnNlaZbWtSoWnGOLXRBqHQhdVjFlWqRxJwz9hxx~2~wGc2Vplta1KhacY4tdEGodCF1WMWVapHEnDP2HHH~b~AZzZWmW1rUqFpxji10Qah0IXVYxZVqkcScM~Yccf9v8BnNlaZbWtSoWnGOLXRBqHQhdVjFlWqRxJwz9hxx~2~wGc2Vplta1KhacY4tdEGodCF1WMWVapHEnDP2HHH~b~AZzZWmW1rUqLE4SD-yjT48UNI7qiTUfIPiDitCoiTTz2cr4QGfw89rBQAEAAcAAA== PRIV=WnGOLXRBqHQhdVjFlWqRxJwz9hxx~2~wGc2Vplta1KhacY4tdEGodCF1WMWVapHEnDP2HHH~b~AZzZWmW1rUqFpxji10Qah0IXVYxZVqkcScM~Yccf9v8BnNlaZbWtSoWnGOLXRBqHQhdVjFlWqRxJwz9hxx~2~wGc2Vplta1KhacY4tdEGodCF1WMWVapHEnDP2HHH~b~AZzZWmW1rUqFpxji10Qah0IXVYxZVqkcScM~Yccf9v8BnNlaZbWtSoWnGOLXRBqHQhdVjFlWqRxJwz9hxx~2~wGc2Vplta1KhacY4tdEGodCF1WMWVapHEnDP2HHH~b~AZzZWmW1rUqFpxji10Qah0IXVYxZVqkcScM~Yccf9v8BnNlaZbWtSoWnGOLXRBqHQhdVjFlWqRxJwz9hxx~2~wGc2Vplta1KhacY4tdEGodCF1WMWVapHEnDP2HHH~b~AZzZWmW1rUqLE4SD-yjT48UNI7qiTUfIPiDitCoiTTz2cr4QGfw89rBQAEAAcAAOvuCIKTyv5f~1QgGq7XQl-IqBULTB5WzB3gw5yGPtd1p0AeoADrq1ccZggLPQ4ZLUsGK-HVw373rcTfvxrcuwenqVjiN4tbbYLWtP7xXGWj6fM6HyORhU63GphrjEePpMUHDHXd3o7pWGM-ieVVQSK~1MzF9P93pQWI3Do52EeNAayz4HbpPjNhVBzG1hUEFwznfPmUZBPuaOR4-uBm1NEWEuONlNOCctE4-U0Ukh94z-Qb55U5vXjR5G4apmBblr68t6Wm1TKlzpgFHzSqLryh3stWqrOKY1H0z9eZ2z1EkHFOpD5LyF6nf51e-lV7HLMl44TYzoEHK8RRVodtLcW9lacVdBpv~tOzlZERIiDziZODPETENZMz5oy9DQ7UUw==\n"
78
+ // reply to SESSION CREATE
79
+ " SESSION STATUS RESULT=OK\n "
80
+ // dummy to avoid reporting EOF on the socket
81
+ " a"
82
+ );
83
+ }
84
+ // Subsequent sockets are for recreating the session or for listening and accepting incoming connections.
85
+ if (num_sockets % 2 == 0 ) {
86
+ // Replies to Listen() and Accept()
87
+ return std::make_unique<StaticContentsSock>(
88
+ // reply to HELLO
89
+ " HELLO REPLY RESULT=OK VERSION=3.1\n "
90
+ // reply to STREAM ACCEPT
91
+ " STREAM STATUS RESULT=OK\n "
92
+ // continued reply to STREAM ACCEPT, violating the protocol described at
93
+ // https://geti2p.net/en/docs/api/samv3#Accept%20Response
94
+ // should be base64, something like
95
+ // "IchV608baDoXbqzQKSqFDmTXPVgoDbPAhZJvNRXXxi4hyFXrTxtoOhdurNApKoUOZNc9WCgNs8CFkm81FdfGLiHIVetPG2g6F26s0CkqhQ5k1z1YKA2zwIWSbzUV18YuIchV608baDoXbqzQKSqFDmTXPVgoDbPAhZJvNRXXxi4hyFXrTxtoOhdurNApKoUOZNc9WCgNs8CFkm81FdfGLiHIVetPG2g6F26s0CkqhQ5k1z1YKA2zwIWSbzUV18YuIchV608baDoXbqzQKSqFDmTXPVgoDbPAhZJvNRXXxi4hyFXrTxtoOhdurNApKoUOZNc9WCgNs8CFkm81FdfGLiHIVetPG2g6F26s0CkqhQ5k1z1YKA2zwIWSbzUV18YuIchV608baDoXbqzQKSqFDmTXPVgoDbPAhZJvNRXXxi4hyFXrTxtoOhdurNApKoUOZNc9WCgNs8CFkm81FdfGLlSreVaCuCS5sdb-8ToWULWP7kt~lRPDeUNxQMq3cRSBBQAEAAcAAA==\n"
96
+ " STREAM STATUS RESULT=I2P_ERROR MESSAGE=\" Session was closed\"\n "
97
+ );
98
+ } else {
99
+ // Another control socket, but without creating a destination (it is cached in the session).
100
+ return std::make_unique<StaticContentsSock>(
101
+ // reply to HELLO
102
+ " HELLO REPLY RESULT=OK VERSION=3.1\n "
103
+ // reply to SESSION CREATE
104
+ " SESSION STATUS RESULT=OK\n "
105
+ // dummy to avoid reporting EOF on the socket
106
+ " a"
107
+ );
108
+ }
109
+ // clang-format on
110
+ };
43
111
44
- CreateSock = CreateSockOrig;
45
- LogInstance ().SetLogLevel (prev_log_level);
112
+ CThreadInterrupt interrupt;
113
+ i2p::sam::Session session (gArgs .GetDataDirNet () / " test_i2p_private_key" ,
114
+ CService{in6_addr (IN6ADDR_LOOPBACK_INIT), /* port=*/ 7656 },
115
+ &interrupt);
116
+
117
+ i2p::Connection conn;
118
+ for (size_t i = 0 ; i < 5 ; ++i) {
119
+ ASSERT_DEBUG_LOG (" Creating persistent SAM session" );
120
+ ASSERT_DEBUG_LOG (" Persistent SAM session" /* ... created */ );
121
+ ASSERT_DEBUG_LOG (" Error accepting" );
122
+ ASSERT_DEBUG_LOG (" Destroying SAM session" );
123
+ BOOST_REQUIRE (session.Listen (conn));
124
+ BOOST_REQUIRE (!session.Accept (conn));
125
+ }
46
126
}
47
127
48
128
BOOST_AUTO_TEST_SUITE_END ()
0 commit comments