Labs 3 & 4 implementation

This commit is contained in:
Andrew Golovashevich 2025-11-08 19:55:29 +03:00
parent ca1cedae85
commit 65b6aedf86
19 changed files with 378 additions and 294 deletions

View File

@ -26,7 +26,7 @@ add_subdirectory(modules/streams)
add_subdirectory(modules/sockets)
add_subdirectory(modules/asyncio)
add_subdirectory(programs/lab4)
add_subdirectory(programs/lab34)
add_executable(main main.cpp)
target_link_libraries(main PRIVATE exceptions threads sockets streams)

View File

@ -44,7 +44,7 @@ namespace LdH {
template<class prefix_printer_t, class routine_t>
requires std::invocable<routine_t> && std::same_as<std::invoke_result_t<routine_t>, void>
&& std::invocable<prefix_printer_t> && std::same_as<std::invoke_result_t<prefix_printer_t>, void>
void run_catching(prefix_printer_t const &prefix_printer, routine_t const &routine) {
void run_catching(prefix_printer_t const &prefix_printer, routine_t &routine) {
try {
routine();
} catch (LdH::Exception const &e) {

View File

@ -25,9 +25,9 @@ namespace LdH::Sockets::Berkeley {
requires(typename ctx_t::socket_t s, typename ctx_t::address_t e) { { s.connect(e) } -> std::same_as<void>; } &&
requires(typename ctx_t::socket_t s, typename ctx_t::address_t e) { { s.bind(e) } -> std::same_as<void>; } &&
requires(typename ctx_t::socket_t s) { { s.close() } -> std::same_as<void>; } &&
requires(typename ctx_t::socket_t s, std::size_t c, char const *d) { { s.send_stream(c, d) } -> std::same_as<void>; } &&
requires(typename ctx_t::socket_t s, std::size_t c, char *d) { { s.recv_stream(c, d) } -> std::same_as<void>; } &&
requires(typename ctx_t::socket_t s, std::size_t c, char *d) { { s.recv_datagram(c, d) } -> std::same_as<typename ctx_t::address_t>; } &&
requires(typename ctx_t::socket_t s, std::size_t *c, char const *d, bool r) { { s.send_stream(c, d, r) } -> std::same_as<bool>; } &&
requires(typename ctx_t::socket_t s, std::size_t *c, char *d, bool r) { { s.recv_stream(c, d, r) } -> std::same_as<bool>; } &&
requires(typename ctx_t::socket_t s, std::size_t *c, char *d) { { s.recv_datagram(c, d) } -> std::same_as<typename ctx_t::address_t>; } &&
requires(typename ctx_t::socket_t s, typename ctx_t::address_t e, std::size_t c, char const *d) { { s.send_datagram(e, c, d) } -> std::same_as<void>; } &&
requires(typename ctx_t::socket_t s, typename ctx_t::address_t *a) { { s.accept(a) } -> std::same_as<typename ctx_t::socket_t>; };
}

View File

@ -190,7 +190,7 @@ namespace LdH::Sockets::Berkeley {
ServerDatagramSocket &operator=(ServerDatagramSocket &&other) noexcept = default;
public:
Address<ctx_t> recvOneTruncating(std::size_t size, char *data) {
Address<ctx_t> recvOneTruncating(std::size_t *size, char *data) {
this->_start_usage();
auto addr = this->_value.recv_datagram(size, data);
this->_finish_usage();
@ -199,7 +199,7 @@ namespace LdH::Sockets::Berkeley {
void sendOne(Address<ctx_t> destination, std::size_t size, char const *data) {
this->_start_usage();
this->_value.send_datagram(destination, size, data);
this->_value.send_datagram(_addr_internals<ctx_t>::unwrap(destination), size, data);
this->_finish_usage();
}
@ -238,15 +238,15 @@ namespace LdH::Sockets::Berkeley {
ClientDatagramSocket &operator=(ClientDatagramSocket &&other) noexcept = default;
public:
void recvOneTruncating(std::size_t size, char *data) override {
void recvOneTruncating(std::size_t *size, char *data) override {
this->_start_usage();
this->_value.recv_stream(size, data);
this->_value.recv_stream(size, data, false);
this->_finish_usage();
}
void sendOne(std::size_t size, char const *data) override {
this->_start_usage();
this->_value.send_stream(size, data);
this->_value.send_stream(&size, data, false);
this->_finish_usage();
}

View File

@ -208,16 +208,18 @@ namespace LdH::Sockets::Berkeley {
StreamSocket &operator=(StreamSocket &&other) noexcept = default;
void read(std::size_t size, char *data) override {
bool read(std::size_t *size, char *data) override {
this->_start_reading("Socket already read by another thread");
this->_value.recv_stream(size, data);
bool closed = this->_value.recv_stream(size, data, true);
this->_finish_reading();
return closed;
}
void write(std::size_t size, char const *data) override {
bool write(std::size_t *size, char const *data) override {
this->_start_writing("Socket already written by another thread");
this->_value.send_stream(size, data);
bool closed = this->_value.send_stream(size, data, true);
this->_finish_writing();
return closed;
}
void close() override {
@ -261,7 +263,9 @@ namespace LdH::Sockets::Berkeley {
typename ctx_t::socket_t raw = this->_value.accept(&addr_raw);
this->_finish_reading();
*addr = std::move(_addr_internals<ctx_t>::wrap(addr_raw));
if (addr != nullptr)
*addr = std::move(_addr_internals<ctx_t>::wrap(addr_raw));
return _socket_internals<StreamSocket<ctx_t> >::wrap(std::move(raw));
}

View File

@ -135,7 +135,8 @@ namespace LdH::Sockets {
}
socket_t accept(address_t *addr) {
SOCKET sock = ::accept(this->_value, reinterpret_cast<sockaddr *>(&(addr->_value)), nullptr);
int addrlen = sizeof(sockaddr_storage);
SOCKET sock = ::accept(this->_value, reinterpret_cast<sockaddr *>(&(addr->_value)), &addrlen);
if (sock == INVALID_SOCKET) {
LdH::throwFromWindowsErrCode(WSAGetLastError());
}
@ -149,27 +150,41 @@ namespace LdH::Sockets {
}
void send_stream(std::size_t size, char const *data) {
bool send_stream(std::size_t *size, char const *data, bool repeat) {
size_t expected_size = *size;
*size = 0;
while (true) {
std::size_t sent_count = ::send(this->_value, data, size, 0);
std::size_t sent_count = ::send(this->_value, data, expected_size, 0);
if (sent_count == SOCKET_ERROR) {
LdH::throwFromWindowsErrCode(WSAGetLastError());
}
data += sent_count;
size -= sent_count;
if (size <= 0) return;
expected_size -= sent_count;
*size += sent_count;
if (expected_size <= 0) return false;
if (!repeat) return false;
}
}
void recv_stream(std::size_t size, char *data) {
bool recv_stream(std::size_t *size, char *data, bool repeat) {
size_t expected_size = *size;
*size = 0;
while (true) {
std::size_t sent_count = ::recv(this->_value, data, size, 0);
if (sent_count == SOCKET_ERROR) {
LdH::throwFromWindowsErrCode(WSAGetLastError());
std::size_t read_count = ::recv(this->_value, data, expected_size, 0);
switch (read_count) {
case SOCKET_ERROR:
LdH::throwFromWindowsErrCode(WSAGetLastError());
case 0:
return true;
default:
break;
}
data += sent_count;
size -= sent_count;
if (size <= 0) return;
data += read_count;
expected_size -= read_count;
*size += read_count;
if (expected_size <= 0) return false;
if (!repeat) return false;
}
}
@ -180,13 +195,14 @@ namespace LdH::Sockets {
}
}
address_t recv_datagram(std::size_t size, char *data) {
address_t recv_datagram(std::size_t *size, char *data) {
address_t out;
int out_size = sizeof(out);
int sent_count = ::recvfrom(this->_value, data, size, 0, reinterpret_cast<sockaddr *>(&out), &out_size);
int sent_count = ::recvfrom(this->_value, data, *size, 0, reinterpret_cast<sockaddr *>(&out), &out_size);
if (sent_count == SOCKET_ERROR) {
LdH::throwFromWindowsErrCode(WSAGetLastError());
}
*size = sent_count;
return out;
}
};

View File

@ -5,7 +5,7 @@ import std;
namespace LdH::Streams {
export class OutputStream {
public:
virtual void write(std::size_t, char const *) = 0;
virtual bool write(std::size_t *, char const *) = 0;
virtual void close() = 0;
@ -14,7 +14,7 @@ namespace LdH::Streams {
export class InputStream {
public:
virtual void read(std::size_t, char *) = 0;
virtual bool read(std::size_t *, char *) = 0;
virtual void close() = 0;
@ -33,7 +33,7 @@ namespace LdH::Streams {
export class InputMessanger {
public:
virtual void recvOneTruncating(std::size_t, char *) = 0;
virtual void recvOneTruncating(std::size_t *, char *) = 0;
virtual void close() = 0;

View File

@ -0,0 +1,17 @@
add_library(lab34_ping_ OBJECT src/_ping.cpp src/variant.hpp)
target_link_libraries(lab34_ping_ PRIVATE sockets exceptions)
add_executable(lab34_ping_tcp src/ping_tcp.cpp)
target_link_libraries(lab34_ping_tcp PRIVATE lab34_ping_)
add_executable(lab34_ping_udp src/ping_udp.cpp)
target_link_libraries(lab34_ping_udp PRIVATE lab34_ping_)
add_library(lab34_pong_ OBJECT ./src/pong.cpp src/variant.hpp)
target_link_libraries(lab34_pong_ PRIVATE sockets exceptions)
add_executable(lab34_pong_tcp src/pong_tcp.cpp)
target_link_libraries(lab34_pong_tcp PRIVATE lab34_pong_)
add_executable(lab34_pong_udp src/pong_udp.cpp)
target_link_libraries(lab34_pong_udp PRIVATE lab34_pong_)

View File

@ -0,0 +1,104 @@
import std;
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
import ru.landgrafhomyak.BGTU.networks_1.sockets;
#include "variant.hpp"
namespace
{
template <Protocol>
class PingVariant
{
};
template <>
class PingVariant<Protocol::TCP>
{
using socket_t = LdH::Sockets::StreamSocket;
static socket_t connect(LdH::Sockets::Address& addr)
{
return LdH::Sockets::connect_tcp(addr);
}
};
}
template <Protocol PING_TYPE>
int ping_main(int argc, char const* const* argv)
{
int ret_v;
bool was_error = true;
LdH::run_catching_main([&]
{
if (argc != 3 && argc != 4)
{
std::cout << "Wrong CLI arguments count: " << (argc - 1) << "\n";
std::cout << "Usage: " << argv[0] << " {dst_addr} {payload}" << std::endl;
std::cout << "Usage: " << argv[0] << " {dst_addr} {port/service} {payload}" << std::endl;
ret_v = 1, was_error = false;
return;
}
std::size_t payload_size = std::strlen(argv[(argc == 3 ? 2 : 3)]);
if (payload_size > 255)
{
std::cout << "Payloand too long: " << payload_size << "\n";
std::cout << "Maximum payload size is 255" << std::endl;
ret_v = 1, was_error = false;
return;
}
char payload[256];
payload[0] = static_cast<unsigned char>(payload_size);
std::memcpy(payload + 1, argv[(argc == 3 ? 2 : 3)], payload_size);
payload_size++;
LdH::Sockets::init_sockets();
auto dst = LdH::Sockets::Address::parse(argv[1], (argc == 3 ? nullptr : argv[2]));
if constexpr (PING_TYPE == Protocol::TCP)
{
auto sock = LdH::Sockets::connect_tcp(dst);
sock.write(&payload_size, payload);
std::cout << "Sent " << payload_size << " bytes\nReceiving:\n\n";
std::cout.flush();
while (true)
{
char buff[1024];
std::size_t buff_size = sizeof(buff);
bool is_closed = sock.read(&buff_size, buff);
std::cout << std::string{buff, buff_size};
if (is_closed) break;
}
sock.close();
ret_v = 0, was_error = false;
}
else if constexpr (PING_TYPE == Protocol::UDP)
{
auto sock = LdH::Sockets::connect_udp(dst);
sock.sendOne(payload_size, payload);
std::cout << "Sent " << payload_size << " bytes\nReceiving:\n\n";
std::cout.flush();
char buff[65536];
std::size_t buff_size = sizeof(buff);
sock.recvOneTruncating(&buff_size, buff);
std::cout << std::string{buff, buff_size};
sock.close();
ret_v = 0, was_error = false;
}
LdH::Sockets::deinit_sockets();
});
if (was_error)
return 3;
return ret_v;
}

View File

@ -0,0 +1,5 @@
#include "variant.hpp"
int main(int argc, char const *const*argv) {
return ping_main<Protocol::TCP>(argc, argv);
}

View File

@ -0,0 +1,5 @@
#include "variant.hpp"
int main(int argc, char const *const*argv) {
return ping_main<Protocol::UDP>(argc, argv);
}

160
programs/lab34/src/pong.cpp Normal file
View File

@ -0,0 +1,160 @@
import std;
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
import ru.landgrafhomyak.BGTU.networks_1.sockets;
#include "variant.hpp"
namespace
{
class ByteCounter
{
private:
std::size_t bytes[std::numeric_limits<char>::max() - std::numeric_limits<char>::min() + 1];
public:
ByteCounter() : bytes{}
{
for (auto& e : this->bytes)
{
e = 0;
}
}
std::size_t& operator[](char c)
{
return this->bytes[c - std::numeric_limits<char>::min()];
}
void apply(char const* payload, std::size_t count)
{
for (std::size_t i = 0; i < count; i++)
this->operator[](payload[i])++;
}
void print(std::ostream& out)
{
for (char c = std::numeric_limits<char>::min(); c < std::numeric_limits<char>::max(); c++)
{
if (this->operator[](c) != 0)
{
out << static_cast<int>(c) << ": " << this->operator[](c) << " times\n";
}
}
if (this->operator[](std::numeric_limits<char>::max()) != 0)
{
out << static_cast<int>(std::numeric_limits<char>::max()) << ": " << this->operator[](
std::numeric_limits<char>::max()) << " times\n";
}
}
};
void do_tcp(LdH::Sockets::Address& listen_addr)
{
auto server = LdH::Sockets::listen_tcp(listen_addr, 10);
while (true)
{
LdH::Sockets::Address addr;
auto sock = server.wait_for_connection(&addr);
std::cout << "Connection from " << addr.to_string() << std::endl;
std::size_t read_count;
bool closed;
char payload_size;
read_count = 1;
closed = sock.read(&read_count, &payload_size);
if (closed)
{
sock.close();
continue;
}
char payload[255];
read_count = static_cast<unsigned char>(payload_size);
closed = sock.read(&read_count, payload);
if (closed)
{
sock.close();
continue;
}
ByteCounter counter;
counter.apply(payload, read_count);
std::stringstream resp_builder;
resp_builder << "Bytes summary:\n";
counter.print(resp_builder);
auto resp = resp_builder.str();
read_count = resp.length();
sock.write(&read_count, resp.c_str());
sock.close();
}
}
void do_udp(LdH::Sockets::Address& listen_addr)
{
auto server = LdH::Sockets::listen_udp(listen_addr);
while (true)
{
char payload[65536];
std::size_t read_count = 65536;
LdH::Sockets::Address addr = server.recvOneTruncating(&read_count, payload);
std::cout << "Connection from " << addr.to_string() << std::endl;
ByteCounter counter;
counter.apply(payload, read_count);
std::stringstream resp_builder;
resp_builder << "Bytes summary:\n";
counter.print(resp_builder);
auto resp = resp_builder.str();
read_count = resp.length();
server.sendOne(addr, read_count, resp.c_str());
}
server.close();
}
}
template <Protocol PROTOCOL>
int pong_main(int argc, char const* const* argv)
{
int ret_v;
bool was_error = true;
LdH::run_catching_main([&]
{
if (argc != 2 && argc != 3)
{
std::cout << "Wrong CLI arguments count: " << (argc - 1) << "\n";
std::cout << "Usage: " << argv[0] << " {listen_addr}" << std::endl;
std::cout << "Usage: " << argv[0] << " {listen_addr} {port/service}" << std::endl;
ret_v = 1, was_error = false;
return;
}
LdH::Sockets::init_sockets();
auto addr = LdH::Sockets::Address::parse(argv[1], (argc == 2 ? nullptr : argv[2]));
if constexpr (PROTOCOL == Protocol::TCP)
{
do_tcp(addr);
}
else if constexpr (PROTOCOL == Protocol::UDP)
{
do_udp(addr);
}
LdH::Sockets::deinit_sockets();
});
if (was_error)
return 3;
return ret_v;
}

View File

@ -0,0 +1,5 @@
#include "variant.hpp"
int main(int argc, char const *const*argv) {
return pong_main<Protocol::TCP>(argc, argv);
}

View File

@ -0,0 +1,5 @@
#include "variant.hpp"
int main(int argc, char const *const*argv) {
return pong_main<Protocol::UDP>(argc, argv);
}

View File

@ -0,0 +1,25 @@
#pragma once
enum class Protocol {
TCP,
UDP,
};
template<Protocol>
extern int ping_main(int argc, char const* const* argv);
template
int ping_main<Protocol::TCP>(int, char const* const*);
template
int ping_main<Protocol::UDP>(int, char const* const*);
template<Protocol>
extern int pong_main(int argc, char const* const* argv);
template
int pong_main<Protocol::TCP>(int, char const* const*);
template
int pong_main<Protocol::UDP>(int, char const* const*);

View File

@ -1,5 +0,0 @@
add_executable(lab4_ping ./src/ping.cpp)
add_executable(lab4_pong ./src/pong.cpp)
target_link_libraries(lab4_ping PRIVATE wsock32 ws2_32 exceptions asyncio)
target_link_libraries(lab4_pong PRIVATE wsock32 ws2_32 exceptions asyncio)

View File

@ -1,80 +0,0 @@
#include <Winsock2.h>
#include <Windows.h>
#include <iostream>
#include <LdH/exception.hpp>
#include <LdH/asyncio.hpp>
static void ping() {
SOCKET sock = WSASocketW(
AF_INET,
SOCK_DGRAM,
0,
nullptr,
0,
/*WSA_FLAG_OVERLAPPED | */WSA_FLAG_NO_HANDLE_INHERIT
);
if (sock == INVALID_SOCKET)
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
sockaddr selfaddr;
INT selfaddrlen = sizeof(sockaddr);
if (SOCKET_ERROR == WSAStringToAddressW((wchar_t *) L"127.0.0.1:8082", AF_INET, nullptr, &selfaddr, &selfaddrlen))
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
while (true) {
char buffer[1024] = "hello world";
WSABUF buffers_meta[1] = {{1024, buffer}};
sockaddr addr;
INT addrlen = sizeof(sockaddr);
DWORD flags = 0;/* MSG_PARTIAL*/
DWORD transferred_count;
auto res = WSASendTo(
sock,
buffers_meta, 1,
&transferred_count,
/* MSG_PARTIAL*/ 0,
&selfaddr, selfaddrlen,
nullptr, nullptr
);
if (res == SOCKET_ERROR) {
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
}
res = WSARecvFrom(
sock,
buffers_meta, 1,
&transferred_count,
&flags,
&addr, &addrlen,
nullptr, nullptr
);
if (res == SOCKET_ERROR) {
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
}
std::cout << buffer << std::endl;
}
}
int main() {
try {
WSADATA wsaData;
auto wsa_init_res = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (wsa_init_res != ERROR_SUCCESS)
LdH::Exception::throwFromWindowsErrCode(wsa_init_res);
ping();
WSACleanup();
} catch (LdH::Exception &e) {
e.printStackTrace();
}
}

View File

@ -1,83 +0,0 @@
#include <Winsock2.h>
#include <Windows.h>
#include <iostream>
#include <LdH/exception.hpp>
#include <LdH/asyncio.hpp>
static void connections_listener() {
SOCKET sock = WSASocketW(
AF_INET,
SOCK_DGRAM,
0,
nullptr,
0,
/*WSA_FLAG_OVERLAPPED | */WSA_FLAG_NO_HANDLE_INHERIT
);
if (sock == INVALID_SOCKET)
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
sockaddr selfaddr;
INT selfaddrlen = sizeof(sockaddr);
if (SOCKET_ERROR == WSAStringToAddressW((wchar_t *) L"127.0.0.1:8082", AF_INET, nullptr, &selfaddr, &selfaddrlen))
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
if (SOCKET_ERROR == bind(sock, &selfaddr, selfaddrlen))
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
while (true) {
char buffer[1024];
WSABUF buffers_meta[1] = {{1024, buffer}};
sockaddr addr;
INT addrlen = sizeof(sockaddr);
DWORD flags = 0;/* MSG_PARTIAL*/
DWORD transferred_count;
auto res = WSARecvFrom(
sock,
buffers_meta, 1,
&transferred_count,
&flags,
&addr, &addrlen,
nullptr, nullptr
);
if (res == SOCKET_ERROR) {
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
}
buffers_meta[0].len = transferred_count;
std::cout << buffer << std::endl;
res = WSASendTo(
sock,
buffers_meta, 1,
&transferred_count,
/* MSG_PARTIAL*/ 0,
&addr, sizeof(sockaddr),
nullptr, nullptr
);
if (res == SOCKET_ERROR) {
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
}
}
}
int main() {
try {
WSADATA wsaData;
auto wsa_init_res = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (wsa_init_res != ERROR_SUCCESS)
LdH::Exception::throwFromWindowsErrCode(wsa_init_res);
connections_listener();
WSACleanup();
} catch (LdH::Exception &e) {
e.printStackTrace();
}
}

View File

@ -1,94 +0,0 @@
#include <Winsock2.h>
#include <Windows.h>
#include <LdH/exception.hpp>
#include <LdH/asyncio.hpp>
struct request_t {
char buffer[1024];
WSABUF buffers_meta[1] = {{1024, buffer}};
sockaddr addr;
SOCKET socket;
};
static void connections_listener(void *) {
SOCKET server = WSASocketW(
AF_INET,
SOCK_DGRAM,
0,
nullptr,
0,
WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT
);
if (server == INVALID_SOCKET)
LdH::Exception::throwFromWindowsErrCode(WSAGetLastError());
while (true) {
auto req = new request_t{};
req->socket = server;
LdH::Asyncio::WindowsOverlappedEventloop::overlappedCall(
[&](LPOVERLAPPED o, LPOVERLAPPED_COMPLETION_ROUTINE ocr) -> DWORD {
DWORD recived_count;
auto res = WSARecvFrom(
server,
req->buffers_meta, 1,
&recived_count,
/* MSG_PARTIAL*/ nullptr,
&req->addr, nullptr,
o, reinterpret_cast<LPWSAOVERLAPPED_COMPLETION_ROUTINE>(ocr)
);
if (res == SOCKET_ERROR) {
auto err = WSAGetLastError();
if (err == WSA_IO_PENDING)
return 0;
LdH::Exception::throwFromWindowsErrCode(err);
}
return recived_count;
}
);
}
}
static void answer(request_t *data) {
LdH::Asyncio::WindowsOverlappedEventloop::overlappedCall(
[&](LPOVERLAPPED o, LPOVERLAPPED_COMPLETION_ROUTINE ocr) -> DWORD {
DWORD recived_count;
auto res = WSASendTo(
data->socket,
data->buffers_meta, 1,
&recived_count,
/* MSG_PARTIAL*/ 0,
&data->addr, sizeof(sockaddr),
o, reinterpret_cast<LPWSAOVERLAPPED_COMPLETION_ROUTINE>(ocr)
);
if (res == SOCKET_ERROR) {
auto err = WSAGetLastError();
if (err == WSA_IO_PENDING)
return 0;
LdH::Exception::throwFromWindowsErrCode(err);
}
return recived_count;
}
);
}
int main() {
try {
WSADATA wsaData;
auto wsa_init_res = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (wsa_init_res != ERROR_SUCCESS)
LdH::Exception::throwFromWindowsErrCode(wsa_init_res);
LdH::Asyncio::WindowsOverlappedEventloop eventloop{};
eventloop.addTask<void>(&connections_listener, nullptr);
eventloop.runUntilHasTasksAndNotInterrupted();
WSACleanup();
} catch (LdH::Exception &e) {
e.printStackTrace();
}
}