aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/i2p.cpp59
-rw-r--r--src/i2p.h19
-rw-r--r--src/test/i2p_tests.cpp2
3 files changed, 64 insertions, 16 deletions
diff --git a/src/i2p.cpp b/src/i2p.cpp
index c45bcc15d2..9aa1ad0f47 100644
--- a/src/i2p.cpp
+++ b/src/i2p.cpp
@@ -12,11 +12,11 @@
#include <netaddress.h>
#include <netbase.h>
#include <random.h>
-#include <util/strencodings.h>
#include <tinyformat.h>
#include <util/readwritefile.h>
#include <util/sock.h>
#include <util/spanparsing.h>
+#include <util/strencodings.h>
#include <util/system.h>
#include <chrono>
@@ -115,8 +115,19 @@ namespace sam {
Session::Session(const fs::path& private_key_file,
const CService& control_host,
CThreadInterrupt* interrupt)
- : m_private_key_file(private_key_file), m_control_host(control_host), m_interrupt(interrupt),
- m_control_sock(std::make_unique<Sock>(INVALID_SOCKET))
+ : m_private_key_file{private_key_file},
+ m_control_host{control_host},
+ m_interrupt{interrupt},
+ m_control_sock{std::make_unique<Sock>(INVALID_SOCKET)},
+ m_transient{false}
+{
+}
+
+Session::Session(const CService& control_host, CThreadInterrupt* interrupt)
+ : m_control_host{control_host},
+ m_interrupt{interrupt},
+ m_control_sock{std::make_unique<Sock>(INVALID_SOCKET)},
+ m_transient{true}
{
}
@@ -355,29 +366,47 @@ void Session::CreateIfNotCreatedAlready()
return;
}
- Log("Creating SAM session with %s", m_control_host.ToString());
+ const auto session_type = m_transient ? "transient" : "persistent";
+ const auto session_id = GetRandHash().GetHex().substr(0, 10); // full is overkill, too verbose in the logs
+
+ Log("Creating %s SAM session %s with %s", session_type, session_id, m_control_host.ToString());
auto sock = Hello();
- const auto& [read_ok, data] = ReadBinaryFile(m_private_key_file);
- if (read_ok) {
- m_private_key.assign(data.begin(), data.end());
+ if (m_transient) {
+ // The destination (private key) is generated upon session creation and returned
+ // in the reply in DESTINATION=.
+ const Reply& reply = SendRequestAndGetReply(
+ *sock,
+ strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT", session_id));
+
+ m_private_key = DecodeI2PBase64(reply.Get("DESTINATION"));
} else {
- GenerateAndSavePrivateKey(*sock);
- }
+ // Read our persistent destination (private key) from disk or generate
+ // one and save it to disk. Then use it when creating the session.
+ const auto& [read_ok, data] = ReadBinaryFile(m_private_key_file);
+ if (read_ok) {
+ m_private_key.assign(data.begin(), data.end());
+ } else {
+ GenerateAndSavePrivateKey(*sock);
+ }
- const std::string& session_id = GetRandHash().GetHex().substr(0, 10); // full is an overkill, too verbose in the logs
- const std::string& private_key_b64 = SwapBase64(EncodeBase64(m_private_key));
+ const std::string& private_key_b64 = SwapBase64(EncodeBase64(m_private_key));
- SendRequestAndGetReply(*sock, strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=%s",
- session_id, private_key_b64));
+ SendRequestAndGetReply(*sock,
+ strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=%s",
+ session_id,
+ private_key_b64));
+ }
m_my_addr = CService(DestBinToAddr(MyDestination()), I2P_SAM31_PORT);
m_session_id = session_id;
m_control_sock = std::move(sock);
- LogPrintfCategory(BCLog::I2P, "SAM session created: session id=%s, my address=%s\n",
- m_session_id, m_my_addr.ToString());
+ Log("%s SAM session %s created, my address=%s",
+ Capitalize(session_type),
+ m_session_id,
+ m_my_addr.ToString());
}
std::unique_ptr<Sock> Session::StreamAccept()
diff --git a/src/i2p.h b/src/i2p.h
index eb0a10103d..ebbcb437da 100644
--- a/src/i2p.h
+++ b/src/i2p.h
@@ -71,6 +71,19 @@ public:
CThreadInterrupt* interrupt);
/**
+ * Construct a transient session which will generate its own I2P private key
+ * rather than read the one from disk (it will not be saved on disk either and
+ * will be lost once this object is destroyed). This will not initiate any IO,
+ * the session will be lazily created later when first used.
+ * @param[in] control_host Location of the SAM proxy.
+ * @param[in,out] interrupt If this is signaled then all operations are canceled as soon as
+ * possible and executing methods throw an exception. Notice: only a pointer to the
+ * `CThreadInterrupt` object is saved, so it must not be destroyed earlier than this
+ * `Session` object.
+ */
+ Session(const CService& control_host, CThreadInterrupt* interrupt);
+
+ /**
* Destroy the session, closing the internally used sockets. The sockets that have been
* returned by `Accept()` or `Connect()` will not be closed, but they will be closed by
* the SAM proxy because the session is destroyed. So they will return an error next time
@@ -262,6 +275,12 @@ private:
* SAM session id.
*/
std::string m_session_id GUARDED_BY(m_mutex);
+
+ /**
+ * Whether this is a transient session (the I2P private key will not be
+ * read or written to disk).
+ */
+ const bool m_transient;
};
} // namespace sam
diff --git a/src/test/i2p_tests.cpp b/src/test/i2p_tests.cpp
index bd9ba4b8f7..80684ac205 100644
--- a/src/test/i2p_tests.cpp
+++ b/src/test/i2p_tests.cpp
@@ -30,7 +30,7 @@ BOOST_AUTO_TEST_CASE(unlimited_recv)
i2p::sam::Session session(gArgs.GetDataDirNet() / "test_i2p_private_key", CService{}, &interrupt);
{
- ASSERT_DEBUG_LOG("Creating SAM session");
+ ASSERT_DEBUG_LOG("Creating persistent SAM session");
ASSERT_DEBUG_LOG("too many bytes without a terminator");
i2p::Connection conn;