public BasicTcpPacket getPacket(byte[] bytes) { BasicTcpPacket packet; switch (bytes[BasicTcpPacket.PKT_POS_TYPE]) { case BasicTcpPacket.PKT_TYPE_DISCONNECT: packet = new StandardDisconnectPacket(); break; case BasicTcpPacket.PKT_TYPE_DISCONNECT_ACK: packet = new StandardDisconnectAckPacket(); break; case BasicTcpPacket.PKT_TYPE_DISCONNECT_RS: packet = new StandardDisconnectRsPacket(); break; case BasicTcpPacket.PKT_TYPE_CONNECT_RS_ACK: packet = new StandardConnectRsAckPacket(); break; case BasicTcpPacket.PKT_TYPE_CONNECT_NAME_RS: packet = new StandardNamedConnectRsPacket(); break; case BasicTcpPacket.PKT_TYPE_CONNECT_NAME_RQ: packet = new StandardNamedConnectRqPacket(); break; case BasicTcpPacket.PKT_TYPE_DATA: packet = new StandardTcpDataPacket(); break; case BasicTcpPacket.PKT_TYPE_ACK: packet = new StandardAckPacket(); break; case BasicTcpPacket.PKT_TYPE_NOP: packet = new StandardTcpNopPacket(); break; default: throw new UnknownPacketException("Failed to determine packet type"); } packet.ProcessPacket(bytes); return packet; }
public override void SendData(byte[] data, int length, int timeout) { BlockIfNotEstablished(timeout); long waitTime = timeout * 10000; lock (_sendingLock) { _sequenceOut++; StandardTcpDataPacket packet = new StandardTcpDataPacket(_sequenceOut); byte[] packetData = new byte[length]; Array.Copy(data,packetData,length); packet.Data = packetData; packet.ConnectionId = ConnectionId; #if(DEBUG) Logger.Debug("Sending packet " + packet.ToString()); #endif long startTime = DateTime.Now.Ticks; _ackEvent.Reset(); do { if (!Established) { #if(DEBUG) Logger.Debug("Connection is down, aborting data send"); #endif throw new ConnectionException("Cannot send data, connection is down"); } Transport.SendData(packet); if (packet.ResendCount > 0) { PacketCountTransmitDataResend++; } else { PacketCountTransmitDataFirst++; } if (DateTime.Now.Ticks - startTime > waitTime) { #if(DEBUG) Logger.Debug("Data timeout : " + (DateTime.Now.Ticks - startTime)); #endif _sequenceOut--; throw new TimeoutException("Timeout occured while sending data to " + Transport.TransportManager.RemoteIp); } #if(DEBUG) Logger.Debug("Waiting for ack from " + Transport.TransportManager.RemoteIp + " for packet " + _sequenceOut); #endif packet.ResendCount++; } while (!_ackEvent.WaitOne(AckWaitInterval + (AckWaitInterval * packet.ResendCount))); long stopTime = DateTime.Now.Ticks; int ackTrip = (int)((stopTime - startTime) / 10000); if (ackTrip > AckWaitInterval && (ackTrip - AckWaitInterval) > 20) { // ackTrip was more than 50ms longer than our interval, we need to adjust up AckWaitInterval = ((ackTrip - AckWaitInterval) / 2) + AckWaitInterval; #if(DEBUG) Logger.Debug("Adjusted ack wait interval UP to " + AckWaitInterval + ", trip was " + ackTrip); #endif } else if (ackTrip < AckWaitInterval && (AckWaitInterval - ackTrip) > 20) { // ackTrip was more than 50ms shorter than our internal, we need to adjust down AckWaitInterval = AckWaitInterval - ((AckWaitInterval - ackTrip) / 2); #if(DEBUG) Logger.Debug("Adjusted ack wait interval DOWN to " + AckWaitInterval + ", trip was " + ackTrip); #endif } } }
private void ProcessDataPacket(StandardTcpDataPacket packet) { try { TcpConnectionHolder conn = _tcpConnections.GetRemoteConnection(packet.ConnectionId); // If the connect response ack packet was lost, its possible that this connection is not open, we need to open it now if (!conn.Connection.Established) { Logger.Debug("Outgoing Connection [" + conn.Connection.ConnectionId + "] received data, means our connect rs ack was lost, auto opening"); conn.Connection.Open(); } // Lock receiving while we process this packet (we will still be able to send) // Now TcpConnection doesn't have to be threadsafe, but each connection // can process data independently at full speed. lock (conn.ReceiveLock) { // now process the dataPacket; conn.Connection.ProcessDataPacket(packet); } } catch (ConnectionException e) { Logger.Error("Dropping data packet [" + packet + "], failed to get a connection : " + e.Message); } }
public void DataSender() { try { // if we still have stuff to send or we are still open while ( (_sendBuffer.Count > 0 || (!Closing && !Closed)) // we are closing and flushing, or not closing && (!_isDisconnecting && !Disconnected) ) { long waitStart = Environment.TickCount; lock (_ackWaitingLock) { // wait until there is space in the window. ( we can't send stuff to far into the future ) while (!SpaceInWindow() && !Disconnected && !_isDisconnecting) { Stats.NoSpaceInWindow++; #if DEBUG Logger.Debug("Pausing send, no space left in window"); #endif // timeout waiting for space in the window if (!Monitor.Wait(_ackWaitingLock, _currentTimeout)) { throw new TimeoutException("Timeout occured while waiting for space in the window to " + Transport.TransportManager.RemoteIp); } #if DEBUG Logger.Debug("AckWaitLock release, probably space in window now"); #endif } } byte[] payload = null; if (!Disconnected && !_isDisconnecting) { // ok now there is space in the window, we will need to send some data and add it to the window. payload = _sendBuffer.Get(TcpChunkSize); } if (!Disconnected && !_isDisconnecting) { if (payload != null && payload.Length > 0) { #if DEBUG Logger.Debug("Got " + payload.Length + " bytes from the sendBuffer, " + _sendBuffer.Count + " left in buffer"); #endif StandardTcpDataPacket packet = new StandardTcpDataPacket { Data = payload, ConnectionId = ConnectionId, Sequence = _nextDataSeqOut }; // make sure there is nothing in the next window space if (_sendWindow[_sendWindowNextFree] != null) throw new ConnectionException( "Cannot insert packet into window, there is something already there! [" + _sendWindow[_sendWindowNextFree].Sequence + "]"); // actually send the packet Transport.SendData(packet); // calculate some stats Stats.AvgSendWaitTime = (Stats.AvgSendWaitTime * Stats.DataPacketSendCount + (Environment.TickCount - waitStart)) / (Stats.DataPacketSendCount + 1); Stats.DataPacketSendCount++; // timestamp the packet so we know when it was sent, this will help us when it comes to retrying packets packet.Timestamp = Environment.TickCount; // put it in the next free space in the window and update the free space, expected next data seq etc. _sendWindow[_sendWindowNextFree] = packet; _sendWindowNextFree = (byte)((_sendWindowNextFree + 1) % WindowSize); _nextDataSeqOut++; lock (_retryTimer) { // if we are not currently pending for a retry of an earlier packet, start the timer now. if (!_retryTimer.Enabled) { _retryTimer.Interval = _retryInterval; _retryTimer.Start(); #if DEBUG Logger.Debug("Setup retry time for " + packet.Sequence + " to " + _retryInterval + "ms"); #endif } } #if DEBUG Logger.Debug("Sent packet " + packet.Sequence + ", nextDataSeqOut=" + _nextDataSeqOut + ", sendWindowNextFree=" + _sendWindowNextFree + ", oldestUnackedPacket=" + _oldestUnackedPacket); #endif } } else { Logger.Debug("Not sending packet, remote side is disconnecting or disconnected."); } } Logger.Debug("Data sender has completed, buffer=" + _sendBuffer.Count + ", Closing=" + Closing + ", Closed=" + Closed + ", Disconnecting=" + _isDisconnecting + ", Disconnected=" + Disconnected); } catch (Exception e) { Logger.Error("DataSender caught Exception while running buffer : " + e.Message, e); Close(); } OnDataSenderComplete(EventArgs.Empty); }