Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2020-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#ifndef BITCOIN_I2P_H6#define BITCOIN_I2P_H8#include <compat/compat.h>9#include <netaddress.h>10#include <netbase.h>11#include <sync.h>12#include <util/fs.h>13#include <util/sock.h>14#include <util/threadinterrupt.h>16#include <memory>17#include <optional>18#include <string>19#include <unordered_map>20#include <vector>22namespace i2p {24/**25* Binary data.26*/27using Binary = std::vector<uint8_t>;29/**30* An established connection with another peer.31*/32struct Connection {33/** Connected socket. */34std::unique_ptr<Sock> sock;36/** Our I2P address. */37CService me;39/** The peer's I2P address. */40CService peer;41};43namespace sam {45/**46* The maximum size of an incoming message from the I2P SAM proxy (in bytes).47* Used to avoid a runaway proxy from sending us an "unlimited" amount of data without a terminator.48* The longest known message is ~1400 bytes, so this is high enough not to be triggered during49* normal operation, yet low enough to avoid a malicious proxy from filling our memory.50*/51inline constexpr size_t MAX_MSG_SIZE{65'536};53/**54* I2P SAM session.55*/56class Session57{58public:59/**60* Construct a session. This will not initiate any IO, the session will be lazily created61* later when first used.62* @param[in] private_key_file Path to a private key file. If the file does not exist then the63* private key will be generated and saved into the file.64* @param[in] control_host Location of the SAM proxy.65* @param[in,out] interrupt If this is signaled then all operations are canceled as soon as66* possible and executing methods throw an exception.67*/68Session(const fs::path& private_key_file,69const Proxy& control_host,70std::shared_ptr<CThreadInterrupt> interrupt);72/**73* Construct a transient session which will generate its own I2P private key74* rather than read the one from disk (it will not be saved on disk either and75* will be lost once this object is destroyed). This will not initiate any IO,76* the session will be lazily created later when first used.77* @param[in] control_host Location of the SAM proxy.78* @param[in,out] interrupt If this is signaled then all operations are canceled as soon as79* possible and executing methods throw an exception.80*/81Session(const Proxy& control_host, std::shared_ptr<CThreadInterrupt> interrupt);83/**84* Destroy the session, closing the internally used sockets. The sockets that have been85* returned by `Accept()` or `Connect()` will not be closed, but they will be closed by86* the SAM proxy because the session is destroyed. So they will return an error next time87* we try to read or write to them.88*/89~Session();91/**92* Start listening for an incoming connection.93* @param[out] conn Upon successful completion the `sock` and `me` members will be set94* to the listening socket and address.95* @return true on success96*/97bool Listen(Connection& conn) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);99/**100* Wait for and accept a new incoming connection.101* @param[in,out] conn The `sock` member is used for waiting and accepting. Upon successful102* completion the `peer` member will be set to the address of the incoming peer.103* @return true on success104*/105bool Accept(Connection& conn) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);107/**108* Connect to an I2P peer.109* @param[in] to Peer to connect to.110* @param[out] conn Established connection. Only set if `true` is returned.111* @param[out] proxy_error If an error occurs due to proxy or general network failure, then112* this is set to `true`. If an error occurs due to unreachable peer (likely peer is down), then113* it is set to `false`. Only set if `false` is returned.114* @return true on success115*/116bool Connect(const CService& to, Connection& conn, bool& proxy_error) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);118private:119/**120* A reply from the SAM proxy.121*/122struct Reply {123/**124* Full, unparsed reply.125*/126std::string full;128/**129* Request, used for detailed error reporting.130*/131std::string request;133/**134* A map of keywords from the parsed reply.135* For example, if the reply is "A=X B C=YZ", then the map will be136* keys["A"] == "X"137* keys["B"] == (empty std::optional)138* keys["C"] == "YZ"139*/140std::unordered_map<std::string, std::optional<std::string>> keys;142/**143* Get the value of a given key.144* For example if the reply is "A=X B" then:145* Value("A") -> "X"146* Value("B") -> throws147* Value("C") -> throws148* @param[in] key Key whose value to retrieve149* @returns the key's value150* @throws std::runtime_error if the key is not present or if it has no value151*/152std::string Get(const std::string& key) const;153};155/**156* Send request and get a reply from the SAM proxy.157* @param[in] sock A socket that is connected to the SAM proxy.158* @param[in] request Raw request to send, a newline terminator is appended to it.159* @param[in] check_result_ok If true then after receiving the reply a check is made160* whether it contains "RESULT=OK" and an exception is thrown if it does not.161* @throws std::runtime_error if an error occurs162*/163Reply SendRequestAndGetReply(const Sock& sock,164const std::string& request,165bool check_result_ok = true) const;167/**168* Open a new connection to the SAM proxy.169* @return a connected socket170* @throws std::runtime_error if an error occurs171*/172std::unique_ptr<Sock> Hello() const EXCLUSIVE_LOCKS_REQUIRED(m_mutex);174/**175* Check the control socket for errors and possibly disconnect.176*/177void CheckControlSock() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);179/**180* Generate a new destination with the SAM proxy and set `m_private_key` to it.181* @param[in] sock Socket to use for talking to the SAM proxy.182* @throws std::runtime_error if an error occurs183*/184void DestGenerate(const Sock& sock) EXCLUSIVE_LOCKS_REQUIRED(m_mutex);186/**187* Generate a new destination with the SAM proxy, set `m_private_key` to it and save188* it on disk to `m_private_key_file`.189* @param[in] sock Socket to use for talking to the SAM proxy.190* @throws std::runtime_error if an error occurs191*/192void GenerateAndSavePrivateKey(const Sock& sock) EXCLUSIVE_LOCKS_REQUIRED(m_mutex);194/**195* Derive own destination from `m_private_key`.196* @see https://i2p.net/en/docs/specs/common-structures/#destination197* @return an I2P destination198*/199Binary MyDestination() const EXCLUSIVE_LOCKS_REQUIRED(m_mutex);201/**202* Create the session if not already created. Reads the private key file and connects to the203* SAM proxy.204* @throws std::runtime_error if an error occurs205*/206void CreateIfNotCreatedAlready() EXCLUSIVE_LOCKS_REQUIRED(m_mutex);208/**209* Open a new connection to the SAM proxy and issue "STREAM ACCEPT" request using the existing210* session id.211* @return the idle socket that is waiting for a peer to connect to us212* @throws std::runtime_error if an error occurs213*/214std::unique_ptr<Sock> StreamAccept() EXCLUSIVE_LOCKS_REQUIRED(m_mutex);216/**217* Destroy the session, closing the internally used sockets.218*/219void Disconnect() EXCLUSIVE_LOCKS_REQUIRED(m_mutex);221/**222* The name of the file where this peer's private key is stored (in binary).223*/224const fs::path m_private_key_file;226/**227* The SAM control service proxy.228*/229const Proxy m_control_host;231/**232* Cease network activity when this is signaled.233*/234const std::shared_ptr<CThreadInterrupt> m_interrupt;236/**237* Mutex protecting the members that can be concurrently accessed.238*/239mutable Mutex m_mutex;241/**242* The private key of this peer.243* @see The reply to the "DEST GENERATE" command in https://i2p.net/en/docs/api/samv3244*/245Binary m_private_key GUARDED_BY(m_mutex);247/**248* SAM control socket.249* Used to connect to the I2P SAM service and create a session250* ("SESSION CREATE"). With the established session id we later open
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.