172 lines
5.3 KiB
C++
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;
|
|
}
|