/// <summary> /// returns true if the TcpStreamMonitor timed out /// </summary> /// <returns> /// A <see cref="System.Boolean"/> /// </returns> public bool CheckForTimeout() { TimeSpan ts = DateTime.Now - last_continuous_packet_received; if (ts.TotalSeconds > timeout.TotalSeconds) { // Monitor has timed out, notify the user of the monitor via the callback lock (this) { condition = TcpStreamGenerator.CallbackCondition.ConnectionTimeout; } return(true); } return(false); }
/// <summary> /// Create a TcpStreamGenerator given a flow /// </summary> /// <param name="f"> /// A <see cref="TcpFlow"/> /// </param> /// <param name="timeout"> /// A <see cref="TimeSpan"/> /// </param> /// <param name="sizeLimitInBytes"> /// A <see cref="System.Nullable<System.Int64>"/> /// </param> public TcpStreamGenerator(TcpFlow f, TimeSpan timeout, long?sizeLimitInBytes) { this.flow = f; this.flow.OnPacketReceived += HandleFlowOnPacketReceived; this.timeout = timeout; this.sizeLimitInBytes = sizeLimitInBytes; packets = new LinkedList <PacketDotNet.TcpPacket>(); tcpStream = new TcpStream(); condition = TcpStreamGenerator.CallbackCondition.NextInSequence; waiting_for_start_seq = true; LastContinuousSequence = 0; last_overall_seq = 0; // use now as our last packet received time to avoid // timing this monitor out immediately last_continuous_packet_received = DateTime.Now; }
//FIXME: we don't handle rolling sequence numbers properly in here // so after 4GB of packets we will have issues private void InternalAddPacket(PacketDotNet.TcpPacket newPacket) { #if PERFORMANCE_CRITICAL_LOGGING log.Debug(""); #endif UInt32 new_packet_seq = newPacket.SequenceNumber; // if we haven't set the value of start_seq we should do so now if (waiting_for_start_seq) { #if PERFORMANCE_CRITICAL_LOGGING log.Debug("waiting_for_start_seq"); #endif // NOTE: we always use the sequence value because we won't have a new packet // added unless it matches the direction we are monitoring, see tcp_stream_manager::handle() start_seq = new_packet_seq; waiting_for_start_seq = false; LastContinuousSequence = last_overall_seq = new_packet_seq; } // Adjust sequence number against the start sequence number #if PERFORMANCE_CRITICAL_LOGGING log.DebugFormat("new_packet.ip.tcp.get_seq() is {0}, start_seq is {1}", newPacket.SequenceNumber, start_seq); #endif UInt32 new_packet_size = (UInt32)newPacket.PayloadData.Length; #if PERFORMANCE_CRITICAL_LOGGING log.DebugFormat("new_packet_seq: {0}, new_packet_size: {1}," + " lastContinuousSequence: {2}, last_overall_seq: {3}", new_packet_seq, new_packet_size, LastContinuousSequence, last_overall_seq); #endif // if the packet came before the last continuous sequence // number we've already seen the packet if (new_packet_seq < LastContinuousSequence) { log.DebugFormat("new_packet_seq({0}) < lastContinuousSequence({1}), rejecting packet", new_packet_seq, LastContinuousSequence); return; } // Verify that the packet within our allowed sequence range if (SizeLimit.HasValue) { if ((new_packet_seq - start_seq) > SizeLimit) { log.DebugFormat("OutOfRange, new_packet_seq({0}) > SizeLimit({1}), deleting packet", new_packet_seq, SizeLimit); condition = CallbackCondition.OutOfRange; return; } } bool packet_added = false; LinkedListNode <PacketDotNet.TcpPacket> pNode; // try to place this packet in our pending packets list if (packets.Count != 0) { pNode = packets.Last; do { if (pNode == null) { break; } var p = pNode.Value; UInt32 current_packet_seq = (UInt32)p.SequenceNumber; UInt32 current_packet_size = (UInt32)p.PayloadData.Length; #if PERFORMANCE_CRITICAL_LOGGING log.DebugFormat("current_packet_seq: {0}, current_packet_size: {1}", current_packet_seq, current_packet_size); #endif // Does this packet belong after, but not *immediately* after current? if (new_packet_seq > (current_packet_seq + current_packet_size)) { #if PERFORMANCE_CRITICAL_LOGGING log.Debug("OutOfSequence, adding packet"); #endif // Sanity check passed, insert into vector condition = CallbackCondition.OutOfSequence; if (last_overall_seq < (new_packet_seq + new_packet_size)) { last_overall_seq = new_packet_seq + new_packet_size; } packets.AddAfter(pNode, newPacket); return; // adding an out-of-sequence packet won't put any other // packets back in sequence, so we are done } // Does this packet fit exactly in sequence after current? if (new_packet_seq == (current_packet_seq + current_packet_size)) { #if PERFORMANCE_CRITICAL_LOGGING log.Debug("packet fits into sequence, adding it"); #endif // Verify highest sequence number if ((new_packet_seq + new_packet_size) > last_overall_seq) { last_overall_seq = new_packet_seq + new_packet_size; } packets.AddAfter(pNode, newPacket); packet_added = true; break; } // if the sequence numbers match there is a packet overlap if (new_packet_seq == current_packet_seq) { if (new_packet_size == current_packet_size) { #if PERFORMANCE_CRITICAL_LOGGING log.Debug("DuplicateDropped"); #endif condition = CallbackCondition.DuplicateDropped; // Duplicate packet, drop it return; } else { #if PERFORMANCE_CRITICAL_LOGGING log.Debug("StreamError, packet would overlap previous packet and is different size"); #endif condition = CallbackCondition.StreamError; // Error: Packet would overlap return; } } // move to the previous node pNode = pNode.Previous; } while(packets.Count != 0); } // Packet did not fall between the existing packets or after all of them, // so it should belong before them all. if (!packet_added) { #if PERFORMANCE_CRITICAL_LOGGING log.Debug("!packet_added, packet did not fall between existing packets or after them, adding packet at front"); #endif packets.AddFirst(newPacket); packet_added = true; } // // process our pending packets list // pull all sequential packets out of the packets list and // push them into the TcpStream // // retrieve the last packet // if there is no last packet then break out of the do {} while() pNode = packets.First; do { if (pNode == null) { #if PERFORMANCE_CRITICAL_LOGGING log.Debug("pNode == null"); #endif break; } var p = pNode.Value; var seq = p.SequenceNumber; var size = (UInt32)p.PayloadData.Length; // if the size is zero and this is a syn packet then // we need to adjust the size to be 1 according to the tcp protocol if (newPacket.Synchronize) { size = 1; LastContinuousSequence = seq; log.DebugFormat("syn packet, lastContinousSequence updated to {0}", LastContinuousSequence); } #if PERFORMANCE_CRITICAL_LOGGING log.DebugFormat("seq: {0}, size: {1}", seq, size); #endif if (seq == LastContinuousSequence) { if (SizeLimit.HasValue) { // is this packet beyond our range? if ((seq - start_seq) >= SizeLimit + 1) { log.Debug("dropping beyond range packet"); // just drop this packet and loop packets.Remove(pNode); pNode = pNode.Next; continue; // skip back around to the top of the do {} while() } } condition = CallbackCondition.NextInSequence; last_continuous_packet_received = DateTime.Now; // store the packet and remove the node from the packets linked list #if PERFORMANCE_CRITICAL_LOGGING log.Debug("AppendPacket() to tcpStream"); #endif tcpStream.AppendPacket(p); packets.Remove(pNode); // is this packet the next in line? if so update our // last continuous sequence value if (seq == LastContinuousSequence) { LastContinuousSequence += size; } // is the last continuous sequence after the current value? // if our last overall sequence is behind, update it as well if (last_overall_seq < LastContinuousSequence) { last_overall_seq = LastContinuousSequence; } } else { #if PERFORMANCE_CRITICAL_LOGGING log.DebugFormat("seq {0} != LastContinuousSequence() {1}", seq, LastContinuousSequence); #endif break; } pNode = pNode.Next; } while(packets.Count != 0); }