public TcpConnection(Ethernet ethHeader, IPv4 ipHeader, Network.Header.Tcp tcpHeader, TTransmitter packetTransmitter, PipeScheduler readScheduler, PipeScheduler writeScheduler, MemoryPool <byte> memoryPool, IConnectionDispatcher connectionDispatcher) { _packetTransmitter = packetTransmitter; _connectionDispatcher = connectionDispatcher; _remoteAddress = ipHeader.SourceAddress; _localAddress = ipHeader.DestinationAddress; _outboundEthernetHeader = new Ethernet() { Destination = ethHeader.Source, Ethertype = EtherType.IPv4, Source = ethHeader.Destination }; var pseudo = new TcpV4PseudoHeader() { Destination = _remoteAddress, Source = _localAddress, ProtocolNumber = Internet.Ip.ProtocolNumber.Tcp, Reserved = 0 }; _pseudoPartialSum = Checksum.PartialCalculate(ref Unsafe.As <TcpV4PseudoHeader, byte>(ref pseudo), Unsafe.SizeOf <TcpV4PseudoHeader>()); LocalAddress = new System.Net.IPAddress(_localAddress.Address); RemoteAddress = new System.Net.IPAddress(_remoteAddress.Address); RemotePort = tcpHeader.SourcePort; LocalPort = tcpHeader.DestinationPort; OutputReaderScheduler = readScheduler ?? throw new ArgumentNullException(nameof(readScheduler)); InputWriterScheduler = writeScheduler ?? throw new ArgumentNullException(nameof(writeScheduler)); MemoryPool = memoryPool ?? throw new ArgumentNullException(nameof(memoryPool)); ConnectionClosed = _closedToken.Token; }
public void ProcessPacket(TcpHeaderWithOptions header, ReadOnlySpan <byte> data) { // If there is backpressure just drop the packet if (!_flushTask.IsCompleted) { return; } _echoTimestamp = header.TimeStamp; switch (_state) { case TcpConnectionState.Listen: _maxSegmentSize = header.MaximumSegmentSize <= 50 || header.MaximumSegmentSize > 1460 ? 1460 : header.MaximumSegmentSize; _sendSequenceNumber = GetRandomSequenceStart(); _receiveSequenceNumber = header.Header.SequenceNumber; // We know we checked for syn in the upper layer so we can ignore that for now _partialTcpHeader = Network.Header.Tcp.Create((ushort)LocalPort, (ushort)RemotePort); WriteSyncAckPacket(); _state = TcpConnectionState.Syn_Rcvd; break; case TcpConnectionState.Syn_Rcvd: if (header.Header.SYN) { //Console.WriteLine("Another Syn made"); return; } _connectionDispatcher.OnConnection(this); var ignore = TransmitLoop(); _state = TcpConnectionState.Established; break; case TcpConnectionState.Established: if (header.Header.FIN) { _receiveSequenceNumber++; _state = TcpConnectionState.Fin_Wait_1; return; } if (header.Header.RST) { //Console.WriteLine("Got RST Should shut down!"); return; } // First lets update our acked squence number; _sendAckSequenceNumber = header.Header.AcknowledgmentNumber; if (_receiveSequenceNumber != header.Header.SequenceNumber) { // We are just going to drop this and wait for a resend return; } unchecked { _receiveSequenceNumber += (uint)data.Length; } var output = Input.GetMemory(data.Length); data.CopyTo(output.Span); Input.Advance(data.Length); // need to do something with the task and make sure we don't overlap the writes var task = Input.FlushAsync(); if (!task.IsCompleted) { _flushTask = task.AsTask(); } PendingAck = true; _totalBytesWritten += data.Length; break; case TcpConnectionState.Fin_Wait_1: case TcpConnectionState.Fin_Wait_2: break; default: throw new NotImplementedException($"Unknown tcp state?? {_state}"); } }
public TcpConnection(Ethernet ethHeader, IPv4 ipHeader, Network.Header.Tcp tcpHeader, TTransmitter packetTransmitter, IConnectionDispatcher connectionDispatcher) : this(ethHeader, ipHeader, tcpHeader, packetTransmitter, PipeScheduler.ThreadPool, PipeScheduler.ThreadPool, MemoryPool <byte> .Shared, connectionDispatcher) { }