private void ProcessRequest(DateTime utcNow, PlcRequestContext requestContext) { if (requestContext.Deadline?.ToUniversalTime() < utcNow) { this.logger.LogDebug( "Request deadline exceeded, deadline={0:u}, now1={1:u}, now2={2:u}", requestContext.Deadline, utcNow, DateTime.UtcNow); requestContext.TaskCompletionSource.SetException(new RpcException( new Status(StatusCode.DeadlineExceeded, string.Empty))); return; } int sequenceNumber = Interlocked.Increment(ref this.sequenceNumberGenerator); requestContext.RequestFrame.FrameHeader.SequenceNumber = (uint)sequenceNumber; if (!this.requestContextReceivingDictionary.TryAdd(sequenceNumber, requestContext)) { throw new InvalidOperationException(); // Should not happen. } if (this.logger.IsEnabled(LogLevel.Debug)) { using var stream = new MemoryStream(); requestContext.RequestFrame.WriteTo(stream); this.logger.LogDebug( "Sending {0} to {1}{2}{3}", sequenceNumber, this.RemoteEndPoint, Environment.NewLine, HexUtils.Dump(stream.ToArray())); this.OnDebugSending?.Invoke(this, stream.ToArray()); stream.Seek(0, SeekOrigin.Begin); stream.CopyTo(this.tcpClient.GetStream()); } else { requestContext.RequestFrame.WriteTo(this.tcpClient.GetStream()); } }
private void ReceivingBackgroundTaskEntryPoint() { CancellationToken closingCancellationToken = this.closingCancellationTokenSource.Token; using var reader = new BinaryReader(this.tcpClient.GetStream(), Encoding.ASCII, true); try { while (!closingCancellationToken.IsCancellationRequested) { byte[] headerBytes = reader.ReadBytes(20); if (headerBytes.Length != 20) { throw new IOException("Failed to read frame header"); } var header = PlcFrameHeader.Parse(headerBytes); if (header.ContentOffset != 20) { throw new InvalidDataException("Content offset is not 20"); } byte[] bodyBytes = reader.ReadBytes(header.ContentLength); if (bodyBytes.Length != header.ContentLength) { throw new IOException("Failed to read frame body"); } if (this.logger.IsEnabled(LogLevel.Debug)) { byte[] buffer = new byte[headerBytes.Length + bodyBytes.Length]; Buffer.BlockCopy(headerBytes, 0, buffer, 0, headerBytes.Length); Buffer.BlockCopy(bodyBytes, 0, buffer, headerBytes.Length, bodyBytes.Length); this.logger.LogDebug( "Received {0} from {1}{2}{3}", header.SequenceNumber, this.RemoteEndPoint, Environment.NewLine, HexUtils.Dump(buffer)); this.OnDebugReceiving?.Invoke(this, buffer); } if (this.requestContextReceivingDictionary.TryRemove( (int)header.SequenceNumber, out PlcRequestContext requestContext)) { if (header.Crc32cChecksum != 0 && header.Crc32cChecksum != Crc32C.Crc32CAlgorithm.Compute(bodyBytes)) { this.logger.LogWarning( "Received frame crc32c checksum mismatch from {0}", this.RemoteEndPoint); requestContext.TaskCompletionSource.TrySetException(new RpcException( new Status(StatusCode.Internal, "Data transfer error, checksum mismatch."))); } else { requestContext.TaskCompletionSource.TrySetResult(new PlcFrame { FrameHeader = header, FrameBody = ByteString.CopyFrom(bodyBytes), }); } } else { this.logger.LogWarning("Received unknown sequence number from {0}", this.RemoteEndPoint); } } } catch (IOException e) { this.logger.LogError(e, "Failed to receiving from {0}", this.RemoteEndPoint); this.Close().ConfigureAwait(false).GetAwaiter().GetResult(); } catch (InvalidDataException e) { this.logger.LogError(e, "Received invalid data from {0}", this.RemoteEndPoint); this.Close().ConfigureAwait(false).GetAwaiter().GetResult(); } }