Skip to content

Running a node in your program

Adrien Béraud edited this page Nov 27, 2022 · 9 revisions

A DHT node can be implemented in C++ as an instance of the dht::Dht class standalone, integrated into your program's main loop, or by using the helper class dht::DhtRunner (recommended).

Running a node with dht::DhtRunner

The class dht::DhtRunner provides thread-safe access to the running DHT instance and also manages network sockets.

DhtRunner runs an instance of dht::SecureDht so that cryptographic operations are made available. An identity (RSA key pair) can be optionally provided to sign/encrypt values (see DhtRunner::run).

dht::DhtRunner node;

// Launch a dht node on a new thread, using a
// generated RSA key pair, and listen on port 4222.
node.run(4222, dht::crypto::generateIdentity(), true);

// use the node...

// stop the node
node.join();

// node.run() can be called again

The run method is defined as:

void run(in_port_t port, const crypto::Identity identity, bool threaded = true, StatusCallback status_cb = nullptr);
  • port is the UDP port to bind.
  • identity is the RSA keypair to use for the crypto layer. A new key pair can be generated with dht::crypto::generateIdentity().
  • threaded defines if a new thread will be launched to run the DHT. If true, no further action is required to have a working DHT. If false (default), DhtRunner::loop() has to be called regularly.
  • status_cb is a status callback informing about the connection state of the DHT (connecting, connected..) for both IPv4 and IPv6.

Calling run while the instance is already running has no effect.

Joining an existing network

On a local network, the simplest way to initiate or join a network is to use Peer Discovery. This will use IP multicast to find and add DHT peers.

A node can join an existing OpenDHT network through any connected node. The recommended method to join a network is to use one of:

void bootstrap(const char* host, const char* service);
void bootstrap(const std::vector<std::pair<sockaddr_storage, socklen_t>>& nodes);
void bootstrap(const std::vector<Dht::NodeExport>& nodes);

The first two will ping specified IP addresses. The first version will resolve a string representation to an actual IP address, the second method takes raw sockaddr structures.

The third method is recommended when joining a known network. It will add previously known nodes to the routing table and only try to contact them if necessary. It takes a list of the Dht::NodeExport structure, obtained during previous runs using exportNodes().

Dht::NodeExport is msgpack-serializable so that the result of exportNodes() can be easily serialized/unserialized as in this example:

dht::DhtRunner node;

// Export nodes to binary file
std::ofstream myfile("dhtNodeExport.bin", std::ios::binary);
msgpack::pack(myfile, node.exportNodes());

// Import nodes from binary file
msgpack::unpacker pac;
{
    // Read whole file
    std::ifstream myfile("dhtNodeExport.bin", std::ios::binary|std::ios::ate);
    auto size = myfile.tellg();
    myfile.seekg (0, std::ios::beg);
    pac.reserve_buffer(size);
    myfile.read (pac.buffer(), size);
    pac.buffer_consumed(size);
}
// Import nodes
msgpack::object_handle oh;
while (pac.next(oh)) {
    auto imported_nodes = oh.get().as<std::vector<dht::NodeExport>>();
    std::cout << "Importing : " << imported_nodes.size() << " nodes" << std::endl;
    node.bootstrap(imported_nodes);
}