using System.Net; using System.Net.Quic; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using DTLib.Logging; namespace Meum.Server; public class Server { private readonly ServerConfig _config; private readonly X509Certificate _certificate; private readonly ILogger _logger; private QuicListener? _listener; private int _lastConnectionId; public Server(ServerConfig config, ILogger logger, X509Certificate? certificate = null) { _config = config; _logger = logger; _certificate = certificate ?? X509Certificate2.CreateFromPemFile(config.certificate_path, config.key_path); } public async ValueTask ListenAsync() { var serverConnectionOptions = new QuicServerConnectionOptions { DefaultStreamErrorCode = Constants.DefaultStreamErrorCode, DefaultCloseErrorCode = Constants.DefaultCloseErrorCode, ServerAuthenticationOptions = new SslServerAuthenticationOptions { ApplicationProtocols = Constants.ApplicationProtocols, ServerCertificate = _certificate, ClientCertificateRequired = false } }; var listenerOptions = new QuicListenerOptions { ListenEndPoint = new IPEndPoint(IPAddress.Parse(_config.listener_ip), _config.listener_port), ApplicationProtocols = Constants.ApplicationProtocols, ConnectionOptionsCallback = (_, _, _) => ValueTask.FromResult(serverConnectionOptions) }; _listener = await QuicListener.ListenAsync(listenerOptions); } public async Task AcceptConnectionAsync(CancellationToken ct = default) { if (_listener == null) throw new Exception("Server is not listening"); ct.ThrowIfCancellationRequested(); var quicConnection = await _listener.AcceptConnectionAsync(ct); var timeOutCts = CancellationTokenSource.CreateLinkedTokenSource(ct); timeOutCts.CancelAfter(Constants.ConnectionTimeout); var clientConnection = await ClientConnection.OpenAsync( _lastConnectionId, quicConnection, _logger, timeOutCts.Token); Interlocked.Increment(ref _lastConnectionId); return clientConnection; } }