Page MenuHomePhabricator

i2p.h
No OneTemporary

// Copyright (c) 2020-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_I2P_H
#define BITCOIN_I2P_H
#include <compat.h>
#include <fs.h>
#include <netaddress.h>
#include <sync.h>
#include <threadinterrupt.h>
#include <util/sock.h>
#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
namespace i2p {
/**
* Binary data.
*/
using Binary = std::vector<uint8_t>;
/**
* An established connection with another peer.
*/
struct Connection {
/** Connected socket. */
std::unique_ptr<Sock> sock;
/** Our I2P address. */
CService me;
/** The peer's I2P address. */
CService peer;
};
namespace sam {
/**
* The maximum size of an incoming message from the I2P SAM proxy (in
* bytes). Used to avoid a runaway proxy from sending us an "unlimited"
* amount of data without a terminator. The longest known message is ~1400
* bytes, so this is high enough not to be triggered during normal
* operation, yet low enough to avoid a malicious proxy from filling our
* memory.
*/
static constexpr size_t MAX_MSG_SIZE{65536};
/**
* I2P SAM session.
*/
class Session {
public:
/**
* Construct a session. This will not initiate any IO, the session will
* be lazily created later when first used.
* @param[in] private_key_file Path to a private key file. If the file
* does not exist then the private key will be generated and saved into
* the file.
* @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 fs::path &private_key_file, 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 we try to read
* or write to them.
*/
~Session();
/**
* Start listening for an incoming connection.
* @param[out] conn Upon successful completion the `sock` and `me`
* members will be set to the listening socket and address.
* @return true on success
*/
bool Listen(Connection &conn);
/**
* Wait for and accept a new incoming connection.
* @param[in,out] conn The `sock` member is used for waiting and
* accepting. Upon successful completion the `peer` member will be set
* to the address of the incoming peer.
* @return true on success
*/
bool Accept(Connection &conn);
/**
* Connect to an I2P peer.
* @param[in] to Peer to connect to.
* @param[out] conn Established connection. Only set if `true` is
* returned.
* @param[out] proxy_error If an error occurs due to proxy or general
* network failure, then this is set to `true`. If an error occurs due
* to unreachable peer (likely peer is down), then it is set to `false`.
* Only set if `false` is returned.
* @return true on success
*/
bool Connect(const CService &to, Connection &conn, bool &proxy_error);
private:
/**
* A reply from the SAM proxy.
*/
struct Reply {
/**
* Full, unparsed reply.
*/
std::string full;
/**
* Request, used for detailed error reporting.
*/
std::string request;
/**
* A map of keywords from the parsed reply.
* For example, if the reply is "A=X B C=YZ", then the map will be
* keys["A"] == "X"
* keys["B"] == (empty std::optional)
* keys["C"] == "YZ"
*/
std::unordered_map<std::string, std::optional<std::string>> keys;
/**
* Get the value of a given key.
* For example if the reply is "A=X B" then:
* Value("A") -> "X"
* Value("B") -> throws
* Value("C") -> throws
* @param[in] key Key whose value to retrieve
* @returns the key's value
* @throws std::runtime_error if the key is not present or if it has
* no value
*/
std::string Get(const std::string &key) const;
};
/**
* Log a message in the `BCLog::I2P` category.
* @param[in] fmt printf(3)-like format string.
* @param[in] args printf(3)-like arguments that correspond to `fmt`.
*/
template <typename... Args>
void Log(const std::string &fmt, const Args &...args) const;
/**
* Send request and get a reply from the SAM proxy.
* @param[in] sock A socket that is connected to the SAM proxy.
* @param[in] request Raw request to send, a newline terminator is
* appended to it.
* @param[in] check_result_ok If true then after receiving the reply a
* check is made whether it contains "RESULT=OK" and an exception is
* thrown if it does not.
* @throws std::runtime_error if an error occurs
*/
Reply SendRequestAndGetReply(const Sock &sock,
const std::string &request,
bool check_result_ok = true) const;
/**
* Open a new connection to the SAM proxy.
* @return a connected socket
* @throws std::runtime_error if an error occurs
*/
std::unique_ptr<Sock> Hello() const EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
/**
* Check the control socket for errors and possibly disconnect.
*/
void CheckControlSock();
/**
* Generate a new destination with the SAM proxy and set `m_private_key`
* to it.
* @param[in] sock Socket to use for talking to the SAM proxy.
* @throws std::runtime_error if an error occurs
*/
void DestGenerate(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_private_key_file`.
* @param[in] sock Socket to use for talking to the SAM proxy.
* @throws std::runtime_error if an error occurs
*/
void GenerateAndSavePrivateKey(const Sock &sock)
EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
/**
* Derive own destination from `m_private_key`.
* @see https://geti2p.net/spec/common-structures#destination
* @return an I2P destination
*/
Binary MyDestination() const EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
/**
* Create the session if not already created. Reads the private key file
* and connects to the SAM proxy.
* @throws std::runtime_error if an error occurs
*/
void CreateIfNotCreatedAlready() EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
/**
* Open a new connection to the SAM proxy and issue "STREAM ACCEPT"
* request using the existing session id.
* @return the idle socket that is waiting for a peer to connect to us
* @throws std::runtime_error if an error occurs
*/
std::unique_ptr<Sock> StreamAccept() EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
/**
* Destroy the session, closing the internally used sockets.
*/
void Disconnect() EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
/**
* The name of the file where this peer's private key is stored (in
* binary).
*/
const fs::path m_private_key_file;
/**
* The host and port of the SAM control service.
*/
const CService m_control_host;
/**
* Cease network activity when this is signaled.
*/
CThreadInterrupt *const m_interrupt;
/**
* Mutex protecting the members that can be concurrently accessed.
*/
mutable Mutex m_mutex;
/**
* The private key of this peer.
* @see The reply to the "DEST GENERATE" command in
* https://geti2p.net/en/docs/api/samv3
*/
Binary m_private_key GUARDED_BY(m_mutex);
/**
* SAM control socket.
* Used to connect to the I2P SAM service and create a session
* ("SESSION CREATE"). With the established session id we later open
* other connections to the SAM service to accept incoming I2P
* connections and make outgoing ones.
* See https://geti2p.net/en/docs/api/samv3
*/
std::unique_ptr<Sock> m_control_sock GUARDED_BY(m_mutex);
/**
* Our .b32.i2p address.
* Derived from `m_private_key`.
*/
CService m_my_addr GUARDED_BY(m_mutex);
/**
* SAM session id.
*/
std::string m_session_id GUARDED_BY(m_mutex);
};
} // namespace sam
} // namespace i2p
#endif // BITCOIN_I2P_H

File Metadata

Mime Type
text/x-c++
Expires
Sat, Nov 23, 10:01 (1 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4514311
Default Alt Text
i2p.h (9 KB)

Event Timeline