 |
Bitcoin Core
21.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());
157 const std::string& peer_dest =
164 }
catch (
const std::runtime_error& e) {
165 Log(
"Error accepting: %s", e.what());
175 std::string session_id;
176 std::unique_ptr<Sock> sock;
183 session_id = m_session_id;
188 const Reply& lookup_reply =
191 const std::string& dest = lookup_reply.
Get(
"VALUE");
194 *sock,
strprintf(
"STREAM CONNECT ID=%s DESTINATION=%s SILENT=false", session_id, dest),
197 const std::string& result = connect_reply.
Get(
"RESULT");
199 if (result ==
"OK") {
200 conn.
sock = std::move(sock);
204 if (result ==
"INVALID_ID") {
207 throw std::runtime_error(
"Invalid session id");
210 if (result ==
"CANT_REACH_PEER" || result ==
"TIMEOUT") {
214 throw std::runtime_error(
strprintf(
"\"%s\"", connect_reply.
full));
215 }
catch (
const std::runtime_error& e) {
216 Log(
"Error connecting to %s: %s", to.
ToString(), e.what());
226 const auto& pos =
keys.find(key);
227 if (pos ==
keys.end() || !pos->second.has_value()) {
228 throw std::runtime_error(
231 return pos->second.value();
234 template <
typename... Args>
241 const std::string& request,
242 bool check_result_ok)
const
249 reply.
request = request.substr(0, 14) ==
"SESSION CREATE" ?
"SESSION CREATE ..." : request;
255 static constexpr
auto recv_timeout = 3min;
260 const auto& pos = std::find(kv.begin(), kv.end(),
'=');
261 if (pos != kv.end()) {
262 reply.
keys.emplace(std::string{kv.begin(), pos}, std::string{pos + 1, kv.end()});
264 reply.
keys.emplace(std::string{kv.begin(), kv.end()}, std::nullopt);
268 if (check_result_ok && reply.
Get(
"RESULT") !=
"OK") {
269 throw std::runtime_error(
270 strprintf(
"Unexpected reply to \"%s\": \"%s\"", request, reply.
full));
281 throw std::runtime_error(
"Cannot create socket");
298 if (!m_control_sock->IsConnected(errmsg)) {
299 Log(
"Control socket error: %s", errmsg);
320 std::string(m_private_key.begin(), m_private_key.end()))) {
321 throw std::runtime_error(
331 static constexpr
size_t DEST_LEN_BASE = 387;
332 static constexpr
size_t CERT_LEN_POS = 385;
335 memcpy(&cert_len, &m_private_key.at(CERT_LEN_POS),
sizeof(cert_len));
338 const size_t dest_len = DEST_LEN_BASE + cert_len;
340 return Binary{m_private_key.begin(), m_private_key.begin() + dest_len};
346 if (m_control_sock->IsConnected(errmsg)) {
356 m_private_key.assign(data.begin(), data.end());
365 session_id, private_key_b64));
368 m_session_id = session_id;
369 m_control_sock = std::move(sock);
371 LogPrintf(
"I2P: SAM session created: session id=%s, my address=%s\n", m_session_id,
372 m_my_addr.ToString());
380 *sock,
strprintf(
"STREAM ACCEPT ID=%s SILENT=false", m_session_id),
false);
382 const std::string& result = reply.
Get(
"RESULT");
384 if (result ==
"OK") {
388 if (result ==
"INVALID_ID") {
399 if (m_session_id.empty()) {
400 Log(
"Destroying incomplete session");
402 Log(
"Destroying session %s", m_session_id);
405 m_control_sock->Reset();
406 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.
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...
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.
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.
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.
const CChainParams & Params()
Return the currently selected parameters.
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.