#include #include "nghttp3/nghttp3.h" #include #include #include #include #include #include #include #include #include #include #include #include #include static void error_log(const char *fmt, ...) { time_t t = time(nullptr); char time_buf[100]; strftime(time_buf, sizeof time_buf, "%D %T", gmtime(&t)); std::va_list args1; va_start(args1, fmt); std::va_list args2; va_copy(args2, args1); std::vector buf(1 + std::vsnprintf(nullptr, 0, fmt, args1)); va_end(args1); std::vsnprintf(buf.data(), buf.size(), fmt, args2); va_end(args2); std::printf("%s [error]: %s\n", time_buf, buf.data()); } int create_socket(int port) { int soc_fd = socket(AF_INET, SOCK_DGRAM, 0); if (soc_fd < 0) { error_log("Socket creation failed"); exit(9); } int reuse = 1; if (setsockopt(soc_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) { error_log("Setting SOL_SOCKET, SO_REUSEADDR for socket failed"); close(soc_fd); exit(9); } sockaddr_in addr = {}; addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("0.0.0.0"); addr.sin_port = htons(port); if (bind(soc_fd, reinterpret_cast(&addr), sizeof(addr)) < 0) { error_log("Socket bind failed"); close(soc_fd); exit(9); } if (int flags; (flags = fcntl(soc_fd, F_GETFL, 0)) < 0 || fcntl(soc_fd, F_SETFL, flags | O_NONBLOCK) < 0) { error_log("Error making socket non-blocking"); exit(9); } return soc_fd; } static unsigned char alpn_protos[256]; static size_t alpn_protos_len; #if OPENSSL_VERSION_NUMBER >= 0x10002000L int alpn_select_proto_cb(SSL* ssl, const unsigned char** out, unsigned char* outlen, const unsigned char* in, unsigned int inlen, void* arg) { // Placeholder for nghttp3 protocol selection logic // This needs to be replaced with actual nghttp3 function call (void)ssl; (void)arg; // Example protocol selection logic for (unsigned int i = 0; i + 1 < inlen; i += in[i] + 1) { if (memcmp(&in[i + 1], "h3", in[i]) == 0) { *out = &in[i + 1]; *outlen = in[i]; return SSL_TLSEXT_ERR_OK; } } return SSL_TLSEXT_ERR_NOACK; } #endif SSL_CTX* create_ssl_ctx(const char* key_file, const char* cert_file) { SSL_CTX* ssl_ctx; ssl_ctx = SSL_CTX_new(TLS_server_method()); if (!ssl_ctx) { error_log("Could not create SSL/TLS context: %s", ERR_error_string(ERR_get_error(), nullptr)); return nullptr; } // Set SSL context options SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); // Load private key and certificate if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) { error_log("Could not read private key file %s", key_file); SSL_CTX_free(ssl_ctx); return nullptr; } if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) { error_log("Could not read certificate file %s", cert_file); SSL_CTX_free(ssl_ctx); return nullptr; } // Set ALPN protocols for HTTP/3 const char* http3_alpn_protos = "\x2h3"; // "\x2" is the length of "h3" alpn_protos_len = strlen(http3_alpn_protos); memcpy(alpn_protos, http3_alpn_protos, alpn_protos_len); #if OPENSSL_VERSION_NUMBER >= 0x10002000L SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, nullptr); #endif return ssl_ctx; } void acceptcb(evconnlistener* listener, int fd, sockaddr* addr, int addrlen, void* arg) { auto server_dt = static_cast*>(arg); } int main() { nghttp3_conn *conn; int rv; nghttp3_callbacks callbacks; nghttp3_settings settings; /* Initialize callbacks and settings */ memset(&callbacks, 0, sizeof(callbacks)); nghttp3_settings_default(&settings); /* Create a new nghttp3_conn object for the server */ rv = nghttp3_conn_server_new(&conn, &callbacks, &settings, NULL, NULL); if (rv != 0) { /* Handle error */ } /* Use conn for HTTP/3 operations */ /* When done, free the nghttp3_conn object */ nghttp3_conn_del(conn); SSL_CTX* ssl_ctx = create_ssl_ctx("/Users/kirillzhukov/Downloads/server.key", "/Users/kirillzhukov/Downloads/server.pem"); event_base *evbase; int soc_fd = create_socket(8080); // Initialize libevent evbase = event_base_new(); // Set up the listening socket (non-blocking, etc.) std::pair server_dt = {ssl_ctx, evbase}; // Create an event for the listen socket evconnlistener* listener = evconnlistener_new(evbase, acceptcb, &server_dt, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 50, soc_fd); // Enter the libevent loop event_base_dispatch(evbase); // Clean up event_base_free(evbase); return 0; }