Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 1 | #include "../common.h" |
| 2 | |
| 3 | #include "connectionmanager.h" |
| 4 | #include "multiplexed_socket.h" |
| 5 | #include "certstore.h" |
| 6 | |
| 7 | #include <opendht/log.h> |
| 8 | #include <opendht/utils.h> |
| 9 | #include <opendht/thread_pool.h> |
| 10 | |
| 11 | #include <asio/executor_work_guard.hpp> |
| 12 | #include <asio/io_context.hpp> |
| 13 | |
| 14 | namespace dhtnet { |
| 15 | using namespace std::literals::chrono_literals; |
| 16 | using clock = std::chrono::high_resolution_clock; |
| 17 | using time_point = clock::time_point; |
| 18 | using duration = clock::duration; |
| 19 | |
| 20 | struct ConnectionHandler |
| 21 | { |
| 22 | dht::crypto::Identity id; |
| 23 | std::shared_ptr<Logger> logger; |
| 24 | std::shared_ptr<tls::CertificateStore> certStore; |
| 25 | std::shared_ptr<dht::DhtRunner> dht; |
| 26 | std::shared_ptr<ConnectionManager> connectionManager; |
| 27 | std::shared_ptr<asio::io_context> ioContext; |
| 28 | std::shared_ptr<std::thread> ioContextRunner; |
| 29 | }; |
| 30 | |
| 31 | std::unique_ptr<ConnectionHandler> |
| 32 | setupHandler(const std::string& name, |
| 33 | std::shared_ptr<asio::io_context> ioContext, |
| 34 | std::shared_ptr<std::thread> ioContextRunner, |
Adrien Béraud | cd8fea9 | 2023-09-20 14:16:36 -0400 | [diff] [blame] | 35 | std::shared_ptr<IceTransportFactory> factory, |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 36 | std::shared_ptr<Logger> logger) |
| 37 | { |
| 38 | auto h = std::make_unique<ConnectionHandler>(); |
| 39 | auto ca = dht::crypto::generateIdentity("ca"); |
| 40 | h->id = dht::crypto::generateIdentity(name, ca); |
| 41 | h->logger = logger; |
| 42 | h->certStore = std::make_shared<tls::CertificateStore>(name, h->logger); |
| 43 | h->ioContext = std::make_shared<asio::io_context>(); |
| 44 | h->ioContext = ioContext; |
| 45 | h->ioContextRunner = ioContextRunner; |
| 46 | |
| 47 | dht::DhtRunner::Config dhtConfig; |
| 48 | dhtConfig.dht_config.id = h->id; |
| 49 | dhtConfig.threaded = true; |
| 50 | |
| 51 | dht::DhtRunner::Context dhtContext; |
| 52 | dhtContext.certificateStore = [c = h->certStore](const dht::InfoHash& pk_id) { |
| 53 | std::vector<std::shared_ptr<dht::crypto::Certificate>> ret; |
| 54 | if (auto cert = c->getCertificate(pk_id.toString())) |
| 55 | ret.emplace_back(std::move(cert)); |
| 56 | return ret; |
| 57 | }; |
| 58 | // dhtContext.logger = h->logger; |
| 59 | |
| 60 | h->dht = std::make_shared<dht::DhtRunner>(); |
| 61 | h->dht->run(dhtConfig, std::move(dhtContext)); |
Adrien Béraud | f8b33b2 | 2023-11-05 12:29:13 -0500 | [diff] [blame] | 62 | h->dht->bootstrap("127.0.0.1:36432"); |
| 63 | //h->dht->bootstrap("bootstrap.jami.net"); |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 64 | |
| 65 | auto config = std::make_shared<ConnectionManager::Config>(); |
| 66 | config->dht = h->dht; |
| 67 | config->id = h->id; |
| 68 | config->ioContext = h->ioContext; |
Adrien Béraud | cd8fea9 | 2023-09-20 14:16:36 -0400 | [diff] [blame] | 69 | config->factory = factory; |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 70 | config->logger = logger; |
Adrien Béraud | cd8fea9 | 2023-09-20 14:16:36 -0400 | [diff] [blame] | 71 | config->certStore = h->certStore; |
Adrien Béraud | 9deadef | 2024-02-18 14:53:07 -0500 | [diff] [blame] | 72 | config->cachePath = std::filesystem::current_path() / "temp"; |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 73 | |
| 74 | h->connectionManager = std::make_shared<ConnectionManager>(config); |
| 75 | h->connectionManager->onICERequest([](const DeviceId&) { return true; }); |
Amna | b31c374 | 2023-08-28 13:58:31 -0400 | [diff] [blame] | 76 | return h; |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 77 | } |
| 78 | |
| 79 | struct BenchResult { |
| 80 | duration connection; |
| 81 | duration send; |
| 82 | bool success; |
| 83 | }; |
| 84 | |
| 85 | BenchResult |
| 86 | runBench(std::shared_ptr<asio::io_context> ioContext, |
| 87 | std::shared_ptr<std::thread> ioContextRunner, |
Adrien Béraud | cd8fea9 | 2023-09-20 14:16:36 -0400 | [diff] [blame] | 88 | std::shared_ptr<IceTransportFactory>& factory, |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 89 | std::shared_ptr<Logger> logger) |
| 90 | { |
| 91 | BenchResult ret; |
| 92 | std::mutex mtx; |
| 93 | std::unique_lock<std::mutex> lock {mtx}; |
| 94 | std::condition_variable serverConVar; |
| 95 | |
Adrien Béraud | f8b33b2 | 2023-11-05 12:29:13 -0500 | [diff] [blame] | 96 | auto boostrap_node = std::make_shared<dht::DhtRunner>(); |
| 97 | boostrap_node->run(36432); |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 98 | |
Amna | b31c374 | 2023-08-28 13:58:31 -0400 | [diff] [blame] | 99 | fmt::print("Generating identities…\n"); |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 100 | auto server = setupHandler("server", ioContext, ioContextRunner, factory, logger); |
| 101 | auto client = setupHandler("client", ioContext, ioContextRunner, factory, logger); |
| 102 | |
| 103 | client->connectionManager->onDhtConnected(client->id.first->getPublicKey()); |
| 104 | server->connectionManager->onDhtConnected(server->id.first->getPublicKey()); |
| 105 | |
| 106 | server->connectionManager->onChannelRequest( |
| 107 | [](const std::shared_ptr<dht::crypto::Certificate>&, |
| 108 | const std::string& name) { |
| 109 | return name == "channelName"; |
| 110 | }); |
| 111 | server->connectionManager->onConnectionReady([&](const DeviceId& device, const std::string& name, std::shared_ptr<ChannelSocket> socket) { |
| 112 | if (socket) { |
Amna | b31c374 | 2023-08-28 13:58:31 -0400 | [diff] [blame] | 113 | fmt::print("Server: Connection succeeded\n"); |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 114 | socket->setOnRecv([s=socket.get()](const uint8_t* data, size_t size) { |
| 115 | std::error_code ec; |
| 116 | return s->write(data, size, ec); |
| 117 | }); |
| 118 | } else { |
Amna | b31c374 | 2023-08-28 13:58:31 -0400 | [diff] [blame] | 119 | fmt::print("Server: Connection failed\n"); |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 120 | } |
| 121 | }); |
| 122 | |
| 123 | std::condition_variable cv; |
| 124 | bool completed = false; |
| 125 | size_t rx = 0; |
| 126 | constexpr size_t TX_SIZE = 64 * 1024; |
| 127 | constexpr size_t TX_NUM = 1024; |
| 128 | constexpr size_t TX_GOAL = TX_SIZE * TX_NUM; |
| 129 | time_point start_connect, start_send; |
| 130 | |
Adrien Béraud | f8b33b2 | 2023-11-05 12:29:13 -0500 | [diff] [blame] | 131 | std::this_thread::sleep_for(3s); |
Adrien Beraud | abdbe20 | 2023-08-30 12:35:42 -0400 | [diff] [blame] | 132 | fmt::print("Connecting…\n"); |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 133 | start_connect = clock::now(); |
| 134 | client->connectionManager->connectDevice(server->id.second, "channelName", [&](std::shared_ptr<ChannelSocket> socket, const DeviceId&) { |
| 135 | if (socket) { |
| 136 | socket->setOnRecv([&](const uint8_t* data, size_t size) { |
| 137 | rx += size; |
| 138 | if (rx == TX_GOAL) { |
| 139 | auto end = clock::now(); |
| 140 | ret.send = end - start_send; |
Amna | b31c374 | 2023-08-28 13:58:31 -0400 | [diff] [blame] | 141 | fmt::print("Streamed {} bytes back and forth in {} ({} kBps)\n", rx, dht::print_duration(ret.send), (unsigned)(rx / (1000 * std::chrono::duration<double>(ret.send).count()))); |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 142 | cv.notify_one(); |
| 143 | } |
| 144 | return size; |
| 145 | }); |
| 146 | ret.connection = clock::now() - start_connect; |
Amna | b31c374 | 2023-08-28 13:58:31 -0400 | [diff] [blame] | 147 | fmt::print("Connected in {}\n", dht::print_duration(ret.connection)); |
Adrien Béraud | f8b33b2 | 2023-11-05 12:29:13 -0500 | [diff] [blame] | 148 | std::vector<uint8_t> data(TX_SIZE, (uint8_t)'y'); |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 149 | std::error_code ec; |
| 150 | start_send = clock::now(); |
| 151 | for (unsigned i = 0; i < TX_NUM; ++i) { |
| 152 | socket->write(data.data(), data.size(), ec); |
| 153 | if (ec) |
Amna | b31c374 | 2023-08-28 13:58:31 -0400 | [diff] [blame] | 154 | fmt::print("error: {}\n", ec.message()); |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 155 | } |
| 156 | } else { |
| 157 | completed = true; |
| 158 | } |
| 159 | }); |
| 160 | ret.success = cv.wait_for(lock, 60s, [&] { return completed or rx == TX_GOAL; }); |
| 161 | std::this_thread::sleep_for(500ms); |
| 162 | return ret; |
| 163 | } |
| 164 | |
| 165 | |
| 166 | void |
| 167 | bench() |
| 168 | { |
| 169 | |
| 170 | std::shared_ptr<Logger> logger;// = dht::log::getStdLogger(); |
Adrien Béraud | cd8fea9 | 2023-09-20 14:16:36 -0400 | [diff] [blame] | 171 | auto factory = std::make_shared<IceTransportFactory>(logger); |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 172 | auto ioContext = std::make_shared<asio::io_context>(); |
| 173 | auto ioContextRunner = std::make_shared<std::thread>([context = ioContext]() { |
| 174 | try { |
| 175 | auto work = asio::make_work_guard(*context); |
| 176 | context->run(); |
| 177 | } catch (const std::exception& ex) { |
Amna | b31c374 | 2023-08-28 13:58:31 -0400 | [diff] [blame] | 178 | fmt::print(stderr, "Exception: {}\n", ex.what()); |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 179 | } |
| 180 | }); |
Amna | b31c374 | 2023-08-28 13:58:31 -0400 | [diff] [blame] | 181 | |
| 182 | BenchResult total = {0s, 0s, false}; |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 183 | unsigned total_success = 0; |
| 184 | constexpr unsigned ITERATIONS = 20; |
| 185 | for (unsigned i = 0; i < ITERATIONS; ++i) { |
Amna | b31c374 | 2023-08-28 13:58:31 -0400 | [diff] [blame] | 186 | fmt::print("Iteration {}\n", i); |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 187 | auto res = runBench(ioContext, ioContextRunner, factory, logger); |
| 188 | if (res.success) { |
| 189 | total.connection += res.connection; |
| 190 | total.send += res.send; |
| 191 | total_success++; |
| 192 | } |
| 193 | } |
Amna | b31c374 | 2023-08-28 13:58:31 -0400 | [diff] [blame] | 194 | fmt::print("Average connection time: {}\n", dht::print_duration(total.connection / total_success)); |
| 195 | fmt::print("Average send time: {}\n", dht::print_duration(total.send / total_success)); |
| 196 | fmt::print("Total success: {}\n", total_success); |
| 197 | |
Adrien Béraud | 6c6a962 | 2023-08-27 12:49:31 -0400 | [diff] [blame] | 198 | std::this_thread::sleep_for(500ms); |
| 199 | ioContext->stop(); |
| 200 | ioContextRunner->join(); |
| 201 | } |
| 202 | |
| 203 | } |
| 204 | |
| 205 | static void |
| 206 | setSipLogLevel() |
| 207 | { |
| 208 | int level = 0; |
| 209 | if (char* envvar = getenv("SIPLOGLEVEL")) { |
| 210 | // From 0 (min) to 6 (max) |
| 211 | level = std::clamp(std::stoi(envvar), 0, 6); |
| 212 | } |
| 213 | |
| 214 | pj_log_set_level(level); |
| 215 | pj_log_set_log_func([](int level, const char* data, int /*len*/) { |
| 216 | }); |
| 217 | } |
| 218 | |
| 219 | int |
| 220 | main(int argc, char** argv) |
| 221 | { |
| 222 | setSipLogLevel(); |
| 223 | dhtnet::bench(); |
| 224 | return 0; |
| 225 | } |