#pragma once #include #include #include #include #include // Platform-specific socket includes and helpers #ifdef _WIN32 #include #include #pragma comment(lib, "ws2_32.lib") using socket_t = SOCKET; #define CLOSE_SOCKET closesocket #define SOCKLEN_T int #define IS_INVALID_SOCKET(s) ((s) == INVALID_SOCKET) #define GET_LAST_ERROR() WSAGetLastError() #else #include #include #include #include #include #include using socket_t = int; #define CLOSE_SOCKET close #define SOCKLEN_T socklen_t #define IS_INVALID_SOCKET(s) ((s) < 0) #define GET_LAST_ERROR() errno #endif namespace Artifact { namespace { struct Ngtcp2CidEqual { bool operator()(const ngtcp2_cid& a, const ngtcp2_cid& b) const noexcept { return a.datalen == b.datalen && std::memcmp(a.data, b.data, a.datalen) == 0; } }; struct Ngtcp2CidHash { size_t operator()(const ngtcp2_cid& cid) const noexcept { size_t h = cid.datalen; for (uint8_t i = 0; i < cid.datalen; ++i) { h = (h * 31) ^ cid.data[i]; // or better hash as above } return h; } }; } class Connection { public: ngtcp2_settings settings; ngtcp2_transport_params transportParams; ngtcp2_callbacks callbacks; ngtcp2_cid dcid, scid; gnutls_session_t session; ngtcp2_conn * conn; Connection(); void readPacket(ngtcp2_pkt_info * info, void * packet); }; class ClientConnection: public Connection { public: ClientConnection(std::string host, std::string port); }; class ServerConnection: public Connection { public: ngtcp2_path path; ServerConnection(ngtcp2_path path); }; class ServerListener { socket_t socketDescriptor; std::unordered_map, Ngtcp2CidHash, Ngtcp2CidEqual> connections; ngtcp2_addr localAddr; struct ev_loop * loop; ev_io watcher; public: ServerListener(std::string port); static void onReadable(struct ev_loop *, ev_io * watcher, int); void run(); }; }