 |
Bitcoin Core
22.99.0
P2P Digital Currency
|
Go to the documentation of this file.
40 to.resize(from.size());
41 for (
size_t i = 0; i < from.size(); ++i) {
71 const std::string& std_b64 =
SwapBase64(i2p_b64);
75 throw std::runtime_error(
strprintf(
"Cannot decode Base64: \"%s\"", i2p_b64));
89 hasher.
Write(dest.data(), dest.size());
94 const std::string addr_str =
EncodeBase32(hash,
false) +
".b32.i2p";
96 throw std::runtime_error(
strprintf(
"Cannot parse I2P address: \"%s\"", addr_str));
119 : m_private_key_file(private_key_file), m_control_host(control_host), m_interrupt(interrupt),
138 }
catch (
const std::runtime_error& e) {
139 Log(
"Error listening: %s", e.what());
151 throw std::runtime_error(
"wait on socket failed");
159 const std::string& peer_dest =
166 }
catch (
const std::runtime_error& e) {
167 Log(
"Error accepting: %s", e.what());
184 std::string session_id;
185 std::unique_ptr<Sock> sock;
192 session_id = m_session_id;
197 const Reply& lookup_reply =
200 const std::string& dest = lookup_reply.
Get(
"VALUE");
203 *sock,
strprintf(
"STREAM CONNECT ID=%s DESTINATION=%s SILENT=false", session_id, dest),
206 const std::string& result = connect_reply.
Get(
"RESULT");
208 if (result ==
"OK") {
209 conn.
sock = std::move(sock);
213 if (result ==
"INVALID_ID") {
216 throw std::runtime_error(
"Invalid session id");
219 if (result ==
"CANT_REACH_PEER" || result ==
"TIMEOUT") {
223 throw std::runtime_error(
strprintf(
"\"%s\"", connect_reply.
full));
224 }
catch (
const std::runtime_error& e) {
225 Log(
"Error connecting to %s: %s", to.
ToString(), e.what());
235 const auto& pos =
keys.find(key);
236 if (pos ==
keys.end() || !pos->second.has_value()) {
237 throw std::runtime_error(
240 return pos->second.value();
243 template <
typename... Args>
250 const std::string& request,
251 bool check_result_ok)
const
258 reply.
request = request.substr(0, 14) ==
"SESSION CREATE" ?
"SESSION CREATE ..." : request;
264 static constexpr
auto recv_timeout = 3min;
269 const auto& pos = std::find(kv.begin(), kv.end(),
'=');
270 if (pos != kv.end()) {
271 reply.
keys.emplace(std::string{kv.begin(), pos}, std::string{pos + 1, kv.end()});
273 reply.
keys.emplace(std::string{kv.begin(), kv.end()}, std::nullopt);
277 if (check_result_ok && reply.
Get(
"RESULT") !=
"OK") {
278 throw std::runtime_error(
279 strprintf(
"Unexpected reply to \"%s\": \"%s\"", request, reply.
full));
290 throw std::runtime_error(
"Cannot create socket");
307 if (!m_control_sock->IsConnected(errmsg)) {
308 Log(
"Control socket error: %s", errmsg);
329 std::string(m_private_key.begin(), m_private_key.end()))) {
330 throw std::runtime_error(
340 static constexpr
size_t DEST_LEN_BASE = 387;
341 static constexpr
size_t CERT_LEN_POS = 385;
344 memcpy(&cert_len, &m_private_key.at(CERT_LEN_POS),
sizeof(cert_len));
347 const size_t dest_len = DEST_LEN_BASE + cert_len;
349 return Binary{m_private_key.begin(), m_private_key.begin() + dest_len};
355 if (m_control_sock->IsConnected(errmsg)) {
365 m_private_key.assign(data.begin(), data.end());
374 session_id, private_key_b64));
377 m_session_id = session_id;
378 m_control_sock = std::move(sock);
380 LogPrintf(
"I2P: SAM session created: session id=%s, my address=%s\n", m_session_id,
381 m_my_addr.ToString());
389 *sock,
strprintf(
"STREAM ACCEPT ID=%s SILENT=false", m_session_id),
false);
391 const std::string& result = reply.
Get(
"RESULT");
393 if (result ==
"OK") {
397 if (result ==
"INVALID_ID") {
408 if (m_session_id.empty()) {
409 Log(
"Destroying incomplete session");
411 Log(
"Destroying session %s", m_session_id);
414 m_control_sock->Reset();
415 m_session_id.clear();
static std::string SwapBase64(const std::string &from)
Swap Standard Base64 <-> I2P Base64.
std::unordered_map< std::string, std::optional< std::string > > keys
A map of keywords from the parsed reply.
A combination of a network address (CNetAddr) and a (TCP) port.
static constexpr uint16_t I2P_SAM31_PORT
SAM 3.1 and earlier do not support specifying ports and force the port to 0.
const fs::path m_private_key_file
The name of the file where this peer's private key is stored (in binary).
CSHA256 & Write(const unsigned char *data, size_t len)
void Disconnect() EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
Destroy the session, closing the internally used sockets.
Session(const fs::path &private_key_file, const CService &control_host, CThreadInterrupt *interrupt)
Construct a session.
A reply from the SAM proxy.
CService peer
The peer's I2P address.
std::unique_ptr< Sock > Hello() const EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
Open a new connection to the SAM proxy.
std::vector< Span< const char > > Split(const Span< const char > &sp, char sep)
Split a string on every instance of sep, returning a vector.
void GenerateAndSavePrivateKey(const Sock &sock) EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
Generate a new destination with the SAM proxy, set m_private_key to it and save it on disk to m_priva...
static auto quoted(const std::string &s)
bool ConnectSocketDirectly(const CService &addrConnect, const Sock &sock, int nTimeout, bool manual_connection)
Try to connect to the specified service on the specified socket.
virtual void SendComplete(const std::string &data, std::chrono::milliseconds timeout, CThreadInterrupt &interrupt) const
Send the given data, retrying on transient errors.
std::function< std::unique_ptr< Sock >const CService &)> CreateSock
Socket factory.
static std::string PathToString(const path &path)
Convert path object to a byte string.
std::string full
Full, unparsed reply.
std::string EncodeBase64(Span< const unsigned char > input)
bool WriteBinaryFile(const fs::path &filename, const std::string &data)
Write contents of std::string to a file.
const CService m_control_host
The host and port of the SAM control service.
bool Listen(Connection &conn)
Start listening for an incoming connection.
std::string ToStringIP() const
RAII helper class that manages a socket.
std::pair< bool, std::string > ReadBinaryFile(const fs::path &filename, size_t maxsize=std::numeric_limits< size_t >::max())
Read full contents of a file and return them in a std::string.
virtual std::string RecvUntilTerminator(uint8_t terminator, std::chrono::milliseconds timeout, CThreadInterrupt &interrupt, size_t max_data) const
Read from socket until a terminator character is encountered.
Reply SendRequestAndGetReply(const Sock &sock, const std::string &request, bool check_result_ok=true) const
Send request and get a reply from the SAM proxy.
static Binary DecodeI2PBase64(const std::string &i2p_b64)
Decode an I2P-style Base64 string.
std::vector< uint8_t > Binary
Binary data.
std::string ToString() const
void CreateIfNotCreatedAlready() EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
Create the session if not already created.
bool SetSpecial(const std::string &addr)
Parse a Tor or I2P address and set this object to it.
Mutex m_mutex
Mutex protecting the members that can be concurrently accessed.
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
CThreadInterrupt *const m_interrupt
Cease network activity when this is signaled.
Binary MyDestination() const EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
Derive own destination from m_private_key.
std::vector< unsigned char > DecodeBase64(const char *p, bool *pf_invalid)
static CNetAddr DestBinToAddr(const Binary &dest)
Derive the .b32.i2p address of an I2P destination (binary).
uint16_t be16toh(uint16_t big_endian_16bits)
uint256 GetRandHash() noexcept
std::string request
Request, used for detailed error reporting.
std::string Get(const std::string &key) const
Get the value of a given key.
std::string GetHex() const
bool Connect(const CService &to, Connection &conn, bool &proxy_error)
Connect to an I2P peer.
void Finalize(unsigned char hash[OUTPUT_SIZE])
#define LogPrint(category,...)
std::unique_ptr< Sock > StreamAccept() EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
Open a new connection to the SAM proxy and issue "STREAM ACCEPT" request using the existing session i...
std::string EncodeBase32(Span< const unsigned char > input, bool pad)
Base32 encode.
static const size_t OUTPUT_SIZE
void Log(const std::string &fmt, const Args &... args) const
Log a message in the BCLog::I2P category.
void DestGenerate(const Sock &sock) EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
Generate a new destination with the SAM proxy and set m_private_key to it.
static constexpr size_t MAX_MSG_SIZE
The maximum size of an incoming message from the I2P SAM proxy (in bytes).
An established connection with another peer.
A hasher class for SHA-256.
static constexpr auto MAX_WAIT_FOR_IO
Maximum time to wait for I/O readiness.
CService me
Our I2P address.
static CNetAddr DestB64ToAddr(const std::string &dest)
Derive the .b32.i2p address of an I2P destination (I2P-style Base64).
void CheckControlSock()
Check the control socket for errors and possibly disconnect.
static constexpr Event RECV
If passed to Wait(), then it will wait for readiness to read from the socket.
bool Accept(Connection &conn)
Wait for and accept a new incoming connection.
std::unique_ptr< Sock > sock
Connected socket.
~Session()
Destroy the session, closing the internally used sockets.