2024-01-10 17:20:50 +03:00

172 lines
5.3 KiB
C++

#include <iostream>
#include "nghttp3/nghttp3.h"
#include <event.h>
#include <event2/bufferevent.h>
#include <event2/event.h>
#include <event2/bufferevent_ssl.h>
#include <event2/listener.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/conf.h>
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<char> 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<sockaddr *>(&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<std::pair<SSL_CTX*, event_base*>*>(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;
}