148 lines
5.1 KiB
C++
148 lines
5.1 KiB
C++
#include <string>
|
|
#include <thread>
|
|
|
|
#include <ngtcp2/ngtcp2_crypto.h>
|
|
#include <ngtcp2/ngtcp2_crypto_gnutls.h>
|
|
#include <gnutls/crypto.h>
|
|
#include <cista.h>
|
|
|
|
#include "Connection.h"
|
|
|
|
namespace Artifact {
|
|
|
|
Connection::Connection() {
|
|
ngtcp2_settings_default(&settings);
|
|
ngtcp2_transport_params_default(&transportParams);
|
|
transportParams.initial_max_streams_bidi = 1;
|
|
transportParams.initial_max_data = 65535;
|
|
transportParams.initial_max_stream_data_bidi_local = 65535;
|
|
|
|
callbacks.encrypt = ngtcp2_crypto_encrypt_cb;
|
|
callbacks.decrypt = ngtcp2_crypto_decrypt_cb;
|
|
callbacks.hp_mask = ngtcp2_crypto_hp_mask_cb;
|
|
callbacks.update_key = ngtcp2_crypto_update_key_cb;
|
|
callbacks.delete_crypto_aead_ctx = ngtcp2_crypto_delete_crypto_aead_ctx_cb;
|
|
callbacks.delete_crypto_cipher_ctx = ngtcp2_crypto_delete_crypto_cipher_ctx_cb;
|
|
callbacks.get_path_challenge_data = ngtcp2_crypto_get_path_challenge_data_cb;
|
|
callbacks.rand = [](auto dest, auto len, auto ctx) {
|
|
gnutls_rnd(GNUTLS_RND_RANDOM, dest, len);
|
|
};
|
|
callbacks.get_new_connection_id = [](auto conn, auto cid, auto token, auto cidlen, auto userdata) {
|
|
gnutls_rnd(GNUTLS_RND_RANDOM, cid, cidlen);
|
|
gnutls_rnd(GNUTLS_RND_RANDOM, token, NGTCP2_STATELESS_RESET_TOKENLEN);
|
|
return 0;
|
|
};
|
|
callbacks.version_negotiation = ngtcp2_crypto_version_negotiation_cb;
|
|
|
|
gnutls_rnd(GNUTLS_RND_RANDOM, dcid.data, dcid.datalen);
|
|
gnutls_rnd(GNUTLS_RND_RANDOM, scid.data, scid.datalen);
|
|
}
|
|
|
|
void readPacket(ngtcp2_pkt_info * info, void * packet) {
|
|
|
|
}
|
|
|
|
ClientConnection::ClientConnection(std::string host, std::string port) {
|
|
struct addrinfo hints;
|
|
struct addrinfo * local = nullptr;
|
|
struct addrinfo * remote = nullptr;
|
|
getaddrinfo("::", "", &hints, &local);
|
|
getaddrinfo(host.c_str(), port.c_str(), &hints, &remote);
|
|
ngtcp2_path path = {
|
|
.local = {
|
|
.addr = local->ai_addr,
|
|
.addrlen = local->ai_addrlen
|
|
},
|
|
.remote = {
|
|
.addr = remote->ai_addr,
|
|
.addrlen = remote->ai_addrlen
|
|
}
|
|
};
|
|
|
|
if (gnutls_init(&session, GNUTLS_CLIENT) != GNUTLS_E_SUCCESS) {
|
|
throw std::runtime_error("Failed to initialize gnutls.");
|
|
}
|
|
gnutls_set_default_priority(session);
|
|
|
|
ngtcp2_conn_client_new(&conn, &dcid, &scid, &path, NGTCP2_PROTO_VER_V1, &callbacks, &settings, &transportParams, nullptr, this);
|
|
ngtcp2_conn_set_tls_native_handle(conn, session);
|
|
}
|
|
|
|
ServerConnection::ServerConnection(ngtcp2_path path) : path(path) {
|
|
if (gnutls_init(&session, GNUTLS_CLIENT) != GNUTLS_E_SUCCESS) {
|
|
throw std::runtime_error("Failed to initialize gnutls.");
|
|
}
|
|
gnutls_set_default_priority(session);
|
|
|
|
ngtcp2_conn_server_new(&conn, &dcid, &scid, &path, NGTCP2_PROTO_VER_V1, &callbacks, &settings, &transportParams, nullptr, this);
|
|
ngtcp2_conn_set_tls_native_handle(conn, session);
|
|
}
|
|
|
|
ServerListener::ServerListener(std::string port) {
|
|
struct addrinfo hints;
|
|
struct addrinfo * local = nullptr;
|
|
getaddrinfo("::", "", &hints, &local);
|
|
|
|
socketDescriptor = socket(local->ai_family, local->ai_socktype, local->ai_protocol);
|
|
|
|
int on = 1;
|
|
setsockopt(socketDescriptor, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&on), sizeof(int));
|
|
|
|
if (local->ai_family == AF_INET6) {
|
|
int off = 0;
|
|
setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char *>(&off), sizeof(int));
|
|
}
|
|
|
|
if (bind(socketDescriptor, local->ai_addr, local->ai_addrlen)) {
|
|
// Save our actual local address for later use.
|
|
getsockname(socketDescriptor, reinterpret_cast<sockaddr *>(&localAddr.addr), &localAddr.addrlen);
|
|
}
|
|
}
|
|
|
|
void ServerListener::onReadable(struct ev_loop *, ev_io * watcher, int) {
|
|
auto self = static_cast<ServerListener *>(watcher->data);
|
|
|
|
uint8_t buf[2048];
|
|
ngtcp2_addr remote;
|
|
auto len = recvfrom(self->socketDescriptor, buf, sizeof(buf), 0, remote.addr, &remote.addrlen);
|
|
|
|
ngtcp2_pkt_info pi{};
|
|
ngtcp2_pkt_hd hd{};
|
|
ngtcp2_pkt_decode_hd_long(&hd, buf, len);
|
|
|
|
auto it = self->connections.find(hd.dcid);
|
|
if (it != self->connections.end()) {
|
|
ServerConnection * conn = it->second.get();
|
|
|
|
ngtcp2_conn_read_pkt(conn->conn, &conn->path, &pi, buf, len, std::chrono::steady_clock::now().time_since_epoch().count());
|
|
|
|
conn->readPacket(&pi, buf);
|
|
return;
|
|
}
|
|
|
|
if (hd.flags & NGTCP2_PKT_FLAG_LONG_FORM && hd.type == NGTCP2_PKT_INITIAL) {
|
|
ngtcp2_pkt_hd accept_hd{};
|
|
if (ngtcp2_accept(&accept_hd, buf, static_cast<size_t>(len)) != 0) {
|
|
return;
|
|
}
|
|
|
|
auto new_conn = std::make_unique<ServerConnection>(ngtcp2_path {
|
|
.local = self->localAddr,
|
|
.remote = remote
|
|
});
|
|
|
|
self->connections[accept_hd.dcid] = std::move(new_conn);
|
|
}
|
|
}
|
|
|
|
void ServerListener::run() {
|
|
std::thread([this]() {
|
|
loop = ev_loop_new(EVFLAG_AUTO);
|
|
ev_io_init(&watcher, onReadable, socketDescriptor, EV_READ);
|
|
watcher.data = this;
|
|
ev_io_start(loop, &watcher);
|
|
ev_run(loop, 0);
|
|
}).detach();
|
|
}
|
|
|
|
}
|