public IpV4Packet Defrag( IpV4Packet ipPacket ) { var result = ipPacket; var header = ipPacket.Header; if (header.IsFragmented) { var ufid = ipPacket.Header.UniqueFragmentId; var agent = CreateOrGetAgent(ufid); result = agent.Consume(ipPacket); if (result != null) { agentMap_.Remove(ufid); } } return(result); }
public IpV4Packet Consume( IpV4Packet packet ) { IpV4Packet mergedPacket = null; if (packet == null) { throw new ArgumentNullException("packet"); } var header = packet.Header; var isNotFragmented = false; var offsetInterval = default(IntervalInt32); switch (header.FragmentFlags) { case 0x00: if (header.FragmentOffset > 0) { if (lastFragmentHeader_ != null) { throw new Exception("Duplicated last fragment!"); } lastFragmentHeader_ = packet.Header; offsetInterval = new IntervalInt32(header.FragmentOffset, holeList_.Range.Maximum); } else { isNotFragmented = true; } break; case 0x01: if (header.FragmentOffset == 0) { if (firstFragmentHeader_ != null) { throw new Exception("Duplicated first fragment!"); } else { firstFragmentHeader_ = packet.Header; } } if ((header.PayloadLength & ((1 << 3) - 1)) != 0) { throw new FormatException("The length of non-final fragments must be multiple of 8."); } offsetInterval = new IntervalInt32(header.FragmentOffset, (header.PayloadLength > 0 ? header.PayloadLength - 1 : 0)); break; case 0x02: isNotFragmented = true; break; default: throw new FormatException("The fragment flag has an invalid value."); } if (isNotFragmented) { mergedPacket = packet; Reset(); } else { try { holeList_.Fill(offsetInterval); payloadMap_.Add(header.FragmentOffset, packet.Payload); if (holeList_.HasNoMoreHoles) { if (lastFragmentHeader_ == null || firstFragmentHeader_ == null) { throw new FormatException(""); } var mergedPayloadLength = lastFragmentHeader_.FragmentOffset + lastFragmentHeader_.PayloadLength; var mergedPayloadBuffer = new ByteBuffer(lastFragmentHeader_.FragmentOffset + lastFragmentHeader_.PayloadLength); foreach (var pair in payloadMap_) { mergedPayloadBuffer.Enqueue(pair.Value); } if (mergedPayloadBuffer.Count != mergedPayloadLength) { throw new FormatException(""); } mergedPacket = new IpV4Packet(header, mergedPayloadBuffer.Dequeue()); Reset(); } } catch (Exception e) { Reset(); throw e; } } return(mergedPacket); }