Skip to content
Snippets Groups Projects
Commit 125f5b34 authored by Amna Snene's avatar Amna Snene
Browse files

doc: add an example to illustrate the usage of the dhtnet API for both server-side and client-side.

Change-Id: I57c29dcf0a0fc54dcd299edd9db1a6d2b363bcf4
parent c1dc8a77
Branches
Tags
No related merge requests found
...@@ -28,6 +28,7 @@ option(BUILD_DEPENDENCIES "Build dependencies" ON) ...@@ -28,6 +28,7 @@ option(BUILD_DEPENDENCIES "Build dependencies" ON)
option(DNC_SYSTEMD_UNIT_FILE_LOCATION "Where to install systemd unit file") option(DNC_SYSTEMD_UNIT_FILE_LOCATION "Where to install systemd unit file")
option(DNC_SYSTEMD "Enable dnc systemd integration" ON) option(DNC_SYSTEMD "Enable dnc systemd integration" ON)
option(CODE_COVERAGE "Enable coverage reporting" OFF) option(CODE_COVERAGE "Enable coverage reporting" OFF)
option(BUILD_EXAMPLE "Build example" ON)
# Check if testing is enabled # Check if testing is enabled
if(BUILD_TESTING) if(BUILD_TESTING)
...@@ -427,3 +428,16 @@ if (BUILD_TESTING AND NOT MSVC) ...@@ -427,3 +428,16 @@ if (BUILD_TESTING AND NOT MSVC)
#add_test(NAME tests_stringutils COMMAND tests_stringutils) #add_test(NAME tests_stringutils COMMAND tests_stringutils)
endif() endif()
if (BUILD_EXAMPLES AND NOT MSVC)
add_executable(server
example/server.cpp)
target_link_libraries(server PRIVATE dhtnet)
target_include_directories(server PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/example)
install(TARGETS server RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
add_executable(client
example/client.cpp)
target_link_libraries(client PRIVATE dhtnet)
target_include_directories(client PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/example)
install(TARGETS client RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
\ No newline at end of file
# DHTNet - Lightweight Peer-to-Peer Communication Library # DHTNet - Lightweight Peer-to-Peer Communication Library
![DHTNet Logo](your-logo.png) ![DHTNet Logo]()
DHTNet is a C++17 library designed to serve as a network overlay that provides an IP network abstraction. Its main objective is to establish secure peer-to-peer connections using public-key authentication. DHTNet is a C++17 library designed to serve as a network overlay that provides an IP network abstraction. Its main objective is to establish secure peer-to-peer connections using public-key authentication.
...@@ -31,58 +31,9 @@ Get started with DHTNet by building and installing the library: ...@@ -31,58 +31,9 @@ Get started with DHTNet by building and installing the library:
- [Build and Install Instructions](BUILD.md) - [Build and Install Instructions](BUILD.md)
## Usage Example ## Usage Example
In the example repository, there is a client-server application where the client connects to the server and sends a "hello" message.
```cpp You can build the example using the project's [Build and Install Instructions](BUILD.md) with `-BUILS_EXAMPLE=ON`.
#include "connectionmanager.h" ![Demo](example/client-server_dhtnet.png)
#include <opendht/log.h>
#include <opendht/utils.h>
#include <opendht/thread_pool.h>
#include <fmt/core.h>
int main() {
// Create identities for CA (Certificate Authority), client, and server
auto ca = dht::crypto::generateIdentity("ca");
auto id_client = dht::crypto::generateIdentity("client", ca);
auto id_server = dht::crypto::generateIdentity("server", ca);
// Create client and server ConnectionManager instances
auto client = std::make_shared<ConnectionManager>(id_client);
auto server = std::make_shared<ConnectionManager>(id_server);
// Launch dht nodes
client->onDhtConnected(id_client.first->getPublicKey());
server->onDhtConnected(id_server.first->getPublicKey());
// Connect the client to the server's device via a channel named "channelName"
client->connectDevice(id_server.second->getId(), "channelName", [&](std::shared_ptr<dhtnet::ChannelSocket> socket,
const dht::InfoHash&) {
if (socket) {
// Send a message (example: "Hello") to the server
std::error_code ec;
std::string data = "hello";
socket->write(data.data(), data.size(), ec);
}
});
// Define a callback function for when the server's connection is ready
server->onConnectionReady([&](const DeviceId& device, const std::string& name, std::shared_ptr<ChannelSocket> socket) {
if (socket) {
// Server: Connection succeeded
fmt::print("Server: Connection succeeded\n");
// Set a callback for receiving messages
socket->setOnRecv([&](const uint8_t* data, size_t size) {
fmt::print("Message received: {}\n", std::string_view(data, data + size)); // Print received message
});
} else {
// Server: Connection failed
fmt::print("Server: Connection failed\n");
}
});
return 0;
}
```
## Dependencies ## Dependencies
......
example/client-server_dhtnet.png

1.51 MiB

#include "certstore.h"
#include "connectionmanager.h"
#include "fileutils.h"
#include <opendht/crypto.h>
#include <string>
#include <vector>
namespace dhtnet {
void
client(dht::crypto::Identity id_client, dht::InfoHash id_server)
{
fmt::print("Start client\n");
fmt::print("Client identity: {}\n", id_client.second->getId());
// Create client ConnectionManager instance
auto client = std::make_shared<ConnectionManager>(id_client);
// Launch dht node
client->onDhtConnected(id_client.first->getPublicKey());
// Connect the client to the server's device via a channel named "channelName"
client->connectDevice(id_server,
"channelName",
[&](std::shared_ptr<ChannelSocket> socket, const dht::InfoHash&) {
fmt::print("Client: Sending request\n");
if (socket) {
// Send a message (example: "Hello") to the server
std::error_code ec;
std::string msg = "hello";
fmt::print("Client: Sending message: {}\n", msg);
std::vector<unsigned char> data(msg.begin(), msg.end());
socket->write(data.data(), data.size(), ec);
// For continuous data transmission, refer to the readFromPipe
// function in tools/common.cpp
if (ec) {
fmt::print("Client: Error writing to socket: {}\n",
ec.message());
} else {
fmt::print("Client: Message sent\n");
}
} else {
fmt::print("Client: Connection failed\n");
return;
}
});
// keep the client running
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
} // namespace dhtnet
int
main(int argc, char** argv)
{
// Set the log level to 0 to avoids pj logs
pj_log_set_level(0);
// This is the root certificate that will be used to sign other certificates
auto ca = dht::crypto::generateIdentity("ca_client");
auto id_client = dht::crypto::generateIdentity("client", ca);
auto id_server = dht::InfoHash(argv[1]);
dhtnet::client(id_client, id_server);
return 0;
}
\ No newline at end of file
#include "connectionmanager.h"
#include "fileutils.h"
#include <opendht/log.h>
#include <opendht/crypto.h>
#include <fcntl.h>
#include <unistd.h>
#include <string>
#include <string_view>
namespace dhtnet {
void
server(dht::crypto::Identity id_server)
{
fmt::print("Server identity: {}\n", id_server.second->getId());
// Create an instance of ConnectionManager for the server
auto server = std::make_shared<ConnectionManager>(id_server);
fmt::print("Start server\n");
// Start the DHT node for the server
server->onDhtConnected(id_server.first->getPublicKey());
// Handle ICE connection requests from devices
// This callback is triggered when a device requests an ICE connection.
// The callback should decide whether to accept or decline the request.
server->onICERequest([id_server](const DeviceId& device) {
// Optional: Add logic to validate the device's certificate
// Example: Check if the device's certificate is signed by a trusted authority
// In this example, all devices are allowed to connect
fmt::print("Server: ICE request received from {}\n", device.toString());
return true;
});
// Handle requests for establishing a communication channel
// The callback checks if the channel should be opened based on the name or device's certificate.
server->onChannelRequest(
[&](const std::shared_ptr<dht::crypto::Certificate>& cert, const std::string& name) {
// Optional: Add logic to validate the channel name or certificate
// Example: Allow the connection if the channel name is "channelName"
fmt::print("Server: Channel request received from {}\n", cert->getLongId());
return name == "channelName";
});
// Define a callback when the connection is established
server->onConnectionReady([&](const DeviceId& device,
const std::string& name,
std::shared_ptr<ChannelSocket> socket) {
if (socket) {
fmt::print("Server: Connection succeeded\n");
// Set up a callback to handle incoming messages on this connection
socket->setOnRecv([socket](const uint8_t* data, size_t size) {
fmt::print("Server: Received message: {}\n", std::string((const char*) data, size));
return size;
});
} else {
// The connection failed
fmt::print("Server: Connection failed\n");
}
});
// Keep the server running indefinitely
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
} // namespace dhtnet
int
main()
{
// Set the log level to 0 to avoids pj logs
pj_log_set_level(0);
// This is the root certificate that will be used to sign other certificates
auto ca = dht::crypto::generateIdentity("ca");
auto id_server = dht::crypto::generateIdentity("server", ca);
dhtnet::server(id_server);
return 0;
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment