/// <summary> /// Asynchronously starts the server that will run until <paramref name="cancellationToken" /> is cancelled /// </summary> /// <param name="cancellationToken">Cancellation token</param> /// <returns><see cref="Task" /></returns> public virtual async Task StartAsync(CancellationToken cancellationToken) { var tcpListener = this.CreateTcpListener(); this.Config.ConfigureTcpListenerCallback?.Invoke(tcpListener); try { tcpListener.Start(); } catch (Exception ex) { var tcpServerErrorEventArgs = new TcpServerErrorEventArgs(new ErrorData(ex)); this.OnServerErrorOccured(tcpServerErrorEventArgs); return; } try { await Task.WhenAll( this.ListenAsync(tcpListener, cancellationToken), Task.Run(() => this.OnServerStarted(new TcpServerStartedEventArgs(new TcpServerStartedData(this.Config.IPAddress, this.Config.Port))))) .ConfigureAwait(false); } catch (Exception ex) { var tcpServerErrorEventArgs = new TcpServerErrorEventArgs(new ErrorData(ex)); this.OnServerErrorOccured(tcpServerErrorEventArgs); } finally { try { tcpListener.Stop(); } catch (Exception ex) { var tcpServerErrorEventArgs = new TcpServerErrorEventArgs(new ErrorData(ex)); this.OnServerErrorOccured(tcpServerErrorEventArgs); } this.OnServerStopped(new TcpServerStoppedEventArgs(new TcpServerStoppedData(this.Config.IPAddress, this.Config.Port))); } }
protected virtual void OnServerErrorOccured(TcpServerErrorEventArgs e) { this.ServerErrorOccured?.Invoke(this, e); }
// exploiting "async void" simplifies everything protected virtual async void HandleNewTcpClientAsync(TcpClient tcpClient, CancellationToken token) { using (tcpClient) using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(token)) { var sendQueue = this.CreateSendQueueActionBlock(linkedCts.Token); RemoteTcpPeer remoteTcpPeer; SslStream sslStream = null; try { if (this.Config.UseSsl && this.Config.X509Certificate != null) { sslStream = this.CreateSslStream(tcpClient); await this.AuthenticateSslStream(tcpClient, sslStream, linkedCts.Token) .ConfigureAwait(false); remoteTcpPeer = this.CreateRemoteTcpPeer(tcpClient, sslStream, sendQueue, linkedCts); } else { remoteTcpPeer = this.CreateRemoteTcpPeer(tcpClient, sendQueue, linkedCts); } } catch (AuthenticationException ex) { var serverErrorEventArgs = new TcpServerErrorEventArgs(new ErrorData(ex)); this.OnServerErrorOccured(serverErrorEventArgs); sendQueue.Complete(); sslStream?.Dispose(); return; } catch (Exception) { sendQueue.Complete(); return; } using (remoteTcpPeer) { var connectionEstablishedEventArgs = new ConnectionEstablishedEventArgs(new ConnectionEstablishedData(remoteTcpPeer)); this.OnConnectionEstablished(connectionEstablishedEventArgs); try { await this.HandleRemotePeerAsync(remoteTcpPeer, linkedCts.Token).ConfigureAwait(false); } catch (Exception ex) { var unhandledErrorEventArgs = new UnhandledErrorEventArgs(new ErrorData(ex)); this.OnUnhandledError(unhandledErrorEventArgs); } finally { sendQueue.Complete(); sslStream?.Dispose(); } } } }