0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-02 09:46:52 -05:00

i2p: use pointers to Sock to accommodate mocking

Change the types of `i2p::Connection::sock` and
`i2p::sam::Session::m_control_sock` from `Sock` to
`std::unique_ptr<Sock>`.

Using pointers would allow us to sneak `FuzzedSock` instead of `Sock`
and have the methods of the former called.

After this change a test only needs to replace `CreateSock()` with
a function that returns `FuzzedSock`.
This commit is contained in:
Vasil Dimov 2021-03-04 14:31:49 +01:00
parent 82d360b5a8
commit 9947e44de0
No known key found for this signature in database
GPG key ID: 54DF06F64B55CBBF
3 changed files with 30 additions and 26 deletions

View file

@ -20,6 +20,7 @@
#include <util/system.h>
#include <chrono>
#include <memory>
#include <stdexcept>
#include <string>
@ -115,7 +116,8 @@ 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_private_key_file(private_key_file), m_control_host(control_host), m_interrupt(interrupt),
m_control_sock(std::make_unique<Sock>(INVALID_SOCKET))
{
}
@ -145,7 +147,7 @@ bool Session::Accept(Connection& conn)
try {
while (!*m_interrupt) {
Sock::Event occurred;
conn.sock.Wait(MAX_WAIT_FOR_IO, Sock::RECV, &occurred);
conn.sock->Wait(MAX_WAIT_FOR_IO, Sock::RECV, &occurred);
if ((occurred & Sock::RECV) == 0) {
// Timeout, no incoming connections within MAX_WAIT_FOR_IO.
@ -153,7 +155,7 @@ bool Session::Accept(Connection& conn)
}
const std::string& peer_dest =
conn.sock.RecvUntilTerminator('\n', MAX_WAIT_FOR_IO, *m_interrupt, MAX_MSG_SIZE);
conn.sock->RecvUntilTerminator('\n', MAX_WAIT_FOR_IO, *m_interrupt, MAX_MSG_SIZE);
conn.peer = CService(DestB64ToAddr(peer_dest), Params().GetDefaultPort());
@ -171,7 +173,7 @@ bool Session::Connect(const CService& to, Connection& conn, bool& proxy_error)
proxy_error = true;
std::string session_id;
Sock sock;
std::unique_ptr<Sock> sock;
conn.peer = to;
try {
@ -184,12 +186,12 @@ bool Session::Connect(const CService& to, Connection& conn, bool& proxy_error)
}
const Reply& lookup_reply =
SendRequestAndGetReply(sock, strprintf("NAMING LOOKUP NAME=%s", to.ToStringIP()));
SendRequestAndGetReply(*sock, strprintf("NAMING LOOKUP NAME=%s", to.ToStringIP()));
const std::string& dest = lookup_reply.Get("VALUE");
const Reply& connect_reply = SendRequestAndGetReply(
sock, strprintf("STREAM CONNECT ID=%s DESTINATION=%s SILENT=false", session_id, dest),
*sock, strprintf("STREAM CONNECT ID=%s DESTINATION=%s SILENT=false", session_id, dest),
false);
const std::string& result = connect_reply.Get("RESULT");
@ -271,7 +273,7 @@ Session::Reply Session::SendRequestAndGetReply(const Sock& sock,
return reply;
}
Sock Session::Hello() const
std::unique_ptr<Sock> Session::Hello() const
{
auto sock = CreateSock(m_control_host);
@ -285,7 +287,7 @@ Sock Session::Hello() const
SendRequestAndGetReply(*sock, "HELLO VERSION MIN=3.1 MAX=3.1");
return std::move(*sock);
return sock;
}
void Session::CheckControlSock()
@ -293,7 +295,7 @@ void Session::CheckControlSock()
LOCK(m_mutex);
std::string errmsg;
if (!m_control_sock.IsConnected(errmsg)) {
if (!m_control_sock->IsConnected(errmsg)) {
Log("Control socket error: %s", errmsg);
Disconnect();
}
@ -341,26 +343,26 @@ Binary Session::MyDestination() const
void Session::CreateIfNotCreatedAlready()
{
std::string errmsg;
if (m_control_sock.IsConnected(errmsg)) {
if (m_control_sock->IsConnected(errmsg)) {
return;
}
Log("Creating SAM session with %s", m_control_host.ToString());
Sock sock = Hello();
auto sock = Hello();
const auto& [read_ok, data] = ReadBinaryFile(m_private_key_file);
if (read_ok) {
m_private_key.assign(data.begin(), data.end());
} else {
GenerateAndSavePrivateKey(sock);
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));
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()), Params().GetDefaultPort());
m_session_id = session_id;
@ -370,12 +372,12 @@ void Session::CreateIfNotCreatedAlready()
m_my_addr.ToString());
}
Sock Session::StreamAccept()
std::unique_ptr<Sock> Session::StreamAccept()
{
Sock sock = Hello();
auto sock = Hello();
const Reply& reply = SendRequestAndGetReply(
sock, strprintf("STREAM ACCEPT ID=%s SILENT=false", m_session_id), false);
*sock, strprintf("STREAM ACCEPT ID=%s SILENT=false", m_session_id), false);
const std::string& result = reply.Get("RESULT");
@ -393,14 +395,14 @@ Sock Session::StreamAccept()
void Session::Disconnect()
{
if (m_control_sock.Get() != INVALID_SOCKET) {
if (m_control_sock->Get() != INVALID_SOCKET) {
if (m_session_id.empty()) {
Log("Destroying incomplete session");
} else {
Log("Destroying session %s", m_session_id);
}
}
m_control_sock.Reset();
m_control_sock->Reset();
m_session_id.clear();
}
} // namespace sam

View file

@ -12,6 +12,7 @@
#include <threadinterrupt.h>
#include <util/sock.h>
#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
@ -29,7 +30,7 @@ using Binary = std::vector<uint8_t>;
*/
struct Connection {
/** Connected socket. */
Sock sock;
std::unique_ptr<Sock> sock;
/** Our I2P address. */
CService me;
@ -166,7 +167,7 @@ private:
* @return a connected socket
* @throws std::runtime_error if an error occurs
*/
Sock Hello() const EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
std::unique_ptr<Sock> Hello() const EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
/**
* Check the control socket for errors and possibly disconnect.
@ -204,10 +205,11 @@ private:
/**
* 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.
* session id.
* @return the idle socket that is waiting for a peer to connect to us
* @throws std::runtime_error if an error occurs
*/
Sock StreamAccept() EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
std::unique_ptr<Sock> StreamAccept() EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
/**
* Destroy the session, closing the internally used sockets.
@ -248,7 +250,7 @@ private:
* connections and make outgoing ones.
* See https://geti2p.net/en/docs/api/samv3
*/
Sock m_control_sock GUARDED_BY(m_mutex);
std::unique_ptr<Sock> m_control_sock GUARDED_BY(m_mutex);
/**
* Our .b32.i2p address.

View file

@ -432,7 +432,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
i2p::Connection conn;
if (m_i2p_sam_session->Connect(addrConnect, conn, proxyConnectionFailed)) {
connected = true;
sock = std::make_unique<Sock>(std::move(conn.sock));
sock = std::move(conn.sock);
addr_bind = CAddress{conn.me, NODE_NONE};
}
} else if (GetProxy(addrConnect.GetNetwork(), proxy)) {
@ -2221,7 +2221,7 @@ void CConnman::ThreadI2PAcceptIncoming()
continue;
}
CreateNodeFromAcceptedSocket(conn.sock.Release(), NetPermissionFlags::PF_NONE,
CreateNodeFromAcceptedSocket(conn.sock->Release(), NetPermissionFlags::PF_NONE,
CAddress{conn.me, NODE_NONE}, CAddress{conn.peer, NODE_NONE});
}
}