/// <inheritdoc /> protected override Task StopInternalAsync() { // Simple lock here to guard start and stop phase TcpListener?lastListener = null; TcpClient? lastSendSocket = null; lock (_startStopLock) { if (!_isRunning) { throw new InvalidOperationException($"Unable to stop {nameof(TcpPassiveByteStreamHandler)} for port {this.ListeningPort}: This object is stopped already!"); } _isRunning = false; _runningLoopCounter++; if (_runningLoopCounter > RUNNING_LOOP_COUNTER_MAX) { _runningLoopCounter = 1; } lastListener = _currentListener; lastSendSocket = _currentSendSocket; _currentListener = null; _currentSendSocket = null; } // Dispose previous sockets TcpAsyncUtil.SafeStop(ref lastListener); TcpAsyncUtil.SafeDispose(ref lastSendSocket); this.Log(LoggingMessageType.Info, "TCP communication stopped"); return(Task.CompletedTask); }
/// <inheritdoc /> protected override Task StopInternalAsync() { // Simple lock here to guard start and stop phase UdpClient?lastSendSocket = null; lock (_startStopLock) { if (!_isRunning) { throw new InvalidOperationException( $"Unable to stop {nameof(TcpActiveByteStreamHandler)} for host {this.RemoteHost} and port {this.RemotePort}: This object is stopped already!"); } _isRunning = false; _connState = ConnectionState.Stopped; _runningLoopCounter++; if (_runningLoopCounter > RUNNING_LOOP_COUNTER_MAX) { _runningLoopCounter = 1; } lastSendSocket = _udpClient; _udpClient = null; } // Dispose previous sockets TcpAsyncUtil.SafeDispose(ref lastSendSocket); this.Log(LoggingMessageType.Info, "UDP communication stopped"); return(Task.CompletedTask); }
private async void RunConnectionMainLoop(int loopId) { this.Log(LoggingMessageType.Info, "TcpCommunicator started in passive mode"); // Start main loop TcpClient?lastClient = null; CancellationTokenSource?lastCancelTokenSource = null; TcpListener? tcpListener = null; var reconnectErrorCount = 0; while (loopId == _runningLoopCounter) { if (tcpListener == null) { this.ActualListeningPort = this.ListeningPort; try { if (this.IsLoggerSet) { this.Log( LoggingMessageType.Info, StringBuffer.Format("Creating TcpListener socket for port {0}...", this.ListeningPort)); } tcpListener = new TcpListener(this.ListeningIPAddress, this.ListeningPort); tcpListener.Start(); this.ActualListeningPort = (ushort)((IPEndPoint)tcpListener.LocalEndpoint).Port; reconnectErrorCount = 0; _currentListener = tcpListener; if (this.IsLoggerSet) { this.Log( LoggingMessageType.Info, StringBuffer.Format("TcpListener created for port {0}", this.ActualListeningPort)); } } catch (Exception ex) { if (this.IsLoggerSet) { this.Log( LoggingMessageType.Error, StringBuffer.Format("Error while creating TcpListener for port {0}: {1}", this.ActualListeningPort, ex.Message), exception: ex); } _currentListener = null; TcpAsyncUtil.SafeStop(ref tcpListener); TcpAsyncUtil.SafeDispose(ref _currentSendSocket); await this.WaitByReconnectWaitTimeAsync(reconnectErrorCount) .ConfigureAwait(false); reconnectErrorCount++; } if (tcpListener == null) { continue; } } // Wait for incoming connection TcpClient? actTcpClient = null; IPEndPoint?actPartnerEndPoint = null; IPEndPoint?actLocalEndPoint = null; try { if (this.IsLoggerSet) { this.Log( LoggingMessageType.Info, StringBuffer.Format("Listening for incoming connections on port {0}...", this.ActualListeningPort)); } actTcpClient = await tcpListener.AcceptTcpClientAsync() .ConfigureAwait(false); actLocalEndPoint = (IPEndPoint)actTcpClient.Client.LocalEndPoint !; actPartnerEndPoint = (IPEndPoint)actTcpClient.Client.RemoteEndPoint !; if (this.IsLoggerSet) { this.Log( LoggingMessageType.Info, StringBuffer.Format( "Got new connection on listening port {0}. Connection established between {1} and {2}", this.ActualListeningPort, actLocalEndPoint.ToString(), actPartnerEndPoint.ToString())); } } catch (ObjectDisposedException) { // Stop may be called in the meanwhile if (!_isRunning) { continue; } if (loopId != _runningLoopCounter) { continue; } } catch (Exception ex) { if (this.IsLoggerSet) { this.Log( LoggingMessageType.Error, StringBuffer.Format("Error while listening for incoming connections on port {0}: {1}", this.ActualListeningPort, ex.Message), exception: ex); } TcpAsyncUtil.SafeStop(ref tcpListener); TcpAsyncUtil.SafeDispose(ref _currentSendSocket); await this.WaitByReconnectWaitTimeAsync(reconnectErrorCount) .ConfigureAwait(false); reconnectErrorCount++; } if (tcpListener == null) { continue; } if (actTcpClient == null) { continue; } // New connection request coming in... close the previous one if (lastClient != null) { lastCancelTokenSource !.Cancel(); lastCancelTokenSource = null; lastClient = null; } // Register new client _currentSendSocket = actTcpClient; lastClient = actTcpClient; lastCancelTokenSource = new CancellationTokenSource(); // Run receive loop for this client (we don't have to await this because we a listening for a new connection request) #pragma warning disable 4014 this.RunReceiveLoopAsync( lastClient, lastClient.Client, actLocalEndPoint !, actPartnerEndPoint !, lastCancelTokenSource.Token); #pragma warning restore 4014 } if (tcpListener != null) { TcpAsyncUtil.SafeStop(ref tcpListener); } }
/// <summary> /// Internal method which reacts on incoming bytes on the currently active socket connection. /// Only one of this connection is active at one time. /// </summary> protected async Task RunReceiveLoopAsync(IDisposable parentDisposable, Socket socket, IPEndPoint localEndPoint, IPEndPoint partnerEndPoint, CancellationToken cancelToken) { parentDisposable.MustNotBeNull(nameof(parentDisposable)); socket.MustNotBeNull(nameof(socket)); localEndPoint.MustNotBeNull(nameof(localEndPoint)); partnerEndPoint.MustNotBeNull(nameof(partnerEndPoint)); _lastSuccessfulConnectTimestampUtc = DateTime.UtcNow; var localEndPointStr = localEndPoint.ToString(); var partnerEndPointStr = partnerEndPoint.ToString(); var newConnection = true; if (this.IsLoggerSet) { this.Log( LoggingMessageType.Info, StringBuffer.Format("Starting receive loop for connection {0} to {1}", localEndPointStr, partnerEndPointStr)); } var receiveBuffer = new byte[this.ReceiveBufferSize]; while (!cancelToken.IsCancellationRequested) { int lastReceiveResult; try { // Read next bytes #if NETSTANDARD2_0 var receiveTask = socket.ReceiveAsync(new ArraySegment <byte>(receiveBuffer), SocketFlags.None); if (receiveTask.IsCompleted) { lastReceiveResult = receiveTask.Result; } else if (this.ReceiveTimeout == TimeSpan.Zero) { lastReceiveResult = await receiveTask .ConfigureAwait(false); } else { var timeoutTask = Task.Delay(this.ReceiveTimeout); await Task.WhenAny(receiveTask, timeoutTask) .ConfigureAwait(false); if (receiveTask.IsCompleted) { lastReceiveResult = receiveTask.Result; } else { _ = receiveTask.ContinueWith(s_dummyReceiveContinuation); if (this.IsLoggerSet) { this.Log( LoggingMessageType.Error, StringBuffer.Format( "Timeout while receiving from {0}!", partnerEndPointStr)); } break; } } #else var receiveTaskStruct = socket.ReceiveAsync(new Memory <byte>(receiveBuffer), SocketFlags.None); if (receiveTaskStruct.IsCompleted) { lastReceiveResult = receiveTaskStruct.Result; } else if (this.ReceiveTimeout == TimeSpan.Zero) { lastReceiveResult = await receiveTaskStruct .ConfigureAwait(false); } else { var receiveTask = receiveTaskStruct.AsTask(); var timeoutTask = Task.Delay(this.ReceiveTimeout); await Task.WhenAny(receiveTask, timeoutTask) .ConfigureAwait(false); if (receiveTask.IsCompleted) { lastReceiveResult = receiveTask.Result; } else { _ = receiveTask.ContinueWith(s_dummyReceiveContinuation); if (this.IsLoggerSet) { this.Log( LoggingMessageType.Error, StringBuffer.Format( "Timeout while receiving from {0}!", partnerEndPointStr)); } break; } } #endif // Reset receive result if we where canceled already if (lastReceiveResult == 0) { this.Log(LoggingMessageType.Info, "Connection closed by remote partner"); } else if (cancelToken.IsCancellationRequested) { this.Log(LoggingMessageType.Info, "Connection canceled by local program"); lastReceiveResult = 0; } else { _lastSuccessfulReceiveTimestampUtc = DateTime.UtcNow; } } catch (ObjectDisposedException) { break; } catch (SocketException socketException) { if (this.IsLoggerSet) { this.Log( LoggingMessageType.Error, StringBuffer.Format( "Error while receiving bytes from {0}: (Code: {1}) {2}", partnerEndPointStr, socketException.SocketErrorCode.ToString(), socketException.Message), exception: socketException); } break; } catch (Exception ex) { if (this.IsLoggerSet) { this.Log( LoggingMessageType.Error, StringBuffer.Format( "Error while receiving bytes from {0}: {1}", partnerEndPointStr, ex.Message), exception: ex); } break; } if (lastReceiveResult <= 0) { break; } this.ProcessReceivedBytes(newConnection, receiveBuffer, lastReceiveResult); newConnection = false; } // Ensure that the socket is closed after ending this method TcpAsyncUtil.SafeDispose(parentDisposable); }
private async void RunConnectionMainLoop(int loopId) { this.Log(LoggingMessageType.Info, "TcpCommunicator started in active mode"); var reconnectErrorCount = 0; var remoteAddressStr = this.RemoteHost; while (loopId == _runningLoopCounter) { TcpClient?newClient = null; try { _connState = ConnectionState.Connecting; if (this.IsLoggerSet) { this.Log( LoggingMessageType.Info, StringBuffer.Format("Connecting to host {0} on port {1}", remoteAddressStr, this.RemotePort)); } newClient = new TcpClient(); if (!ReferenceEquals(this.RemoteIPAddress, IPAddress.None)) { await newClient.ConnectAsync(this.RemoteIPAddress, this.RemotePort); } else { await newClient.ConnectAsync(this.RemoteHost, this.RemotePort); } _currentClient = newClient; reconnectErrorCount = 0; _connState = ConnectionState.Connected; if (this.IsLoggerSet) { this.Log( LoggingMessageType.Info, StringBuffer.Format("Successfully connected to host {0} on port {1}", remoteAddressStr, this.RemotePort)); } } catch (Exception ex) { TcpAsyncUtil.SafeDispose(ref newClient); _currentClient = null; if (this.IsLoggerSet) { this.Log( LoggingMessageType.Error, StringBuffer.Format("Error while connecting to host {0} on port {1}: {2}", remoteAddressStr, this.RemotePort, ex.Message), exception: ex); } _connState = ConnectionState.Connecting; await this.WaitByReconnectWaitTimeAsync(reconnectErrorCount) .ConfigureAwait(false); reconnectErrorCount++; } if (_currentClient == null) { continue; } // Normal receive loop handling try { await this.RunReceiveLoopAsync( _currentClient, _currentClient.Client, (IPEndPoint)_currentClient.Client.LocalEndPoint !, (IPEndPoint)_currentClient.Client.RemoteEndPoint !, CancellationToken.None); } catch (Exception ex) { if (this.IsLoggerSet) { this.Log( LoggingMessageType.Error, StringBuffer.Format( "Error while running receive loop for host {0} on port {1}: {2}", remoteAddressStr, this.RemotePort, ex.Message), exception: ex); } } // Client gets already disposed in receive loop _currentClient = null; } }