private static void AnalyzePacket_Tcp(PacketDotNet.TcpPacket packet, PacketAnalyzeParam param) { param.Protocol = "TCP"; param.SourcePort = packet.SourcePort; param.DestinationPort = packet.DestinationPort; param.PayloadFrame = packet.PayloadData; }
public Connection(PacketDotNet.TcpPacket packet) { srcIp = (packet.ParentPacket as PacketDotNet.IPv4Packet).SourceAddress.ToString(); dstIp = (packet.ParentPacket as PacketDotNet.IPv4Packet).DestinationAddress.ToString(); srcPort = (ushort)packet.SourcePort; dstPort = (ushort)packet.DestinationPort; }
/* here we search through all the frag we have collected to see if * one fits */ bool check_fragments(int index, PacketDotNet.TcpPacket tcpPacket) { TcpFrag prev = null; TcpFrag current; current = frags[index]; while (current != null) { if (current.seq == seq[index]) { /* this fragment fits the stream */ if (current.data != null) { write_packet_data(index, current.data, tcpPacket); } seq[index] += current.len; if (prev != null) { prev.next = current.next; } else { frags[index] = current.next; } current.data = null; current = null; return(true); } prev = current; current = current.next; } return(false); }
public void AddTcpPacket(PacketDotNet.TcpPacket packet) { Next_sequence_number = packet.SequenceNumber + packet.PayloadData.Length; Tcp_packets.Add(new TcpPacketWrapper() { Packet = packet, Counter = counter++ }); Packets_added = true; }
static void HandleOnPacketReceived(PosixTimeval timeval, PacketDotNet.TcpPacket tcp, TcpConnection connection, TcpFlow flow) { lock (DictionaryLock) { if (!TcpPackets.ContainsKey(flow)) { TcpPackets[flow] = new List <Entry>(); } var entry = new Entry(timeval, tcp); TcpPackets[flow].Add(entry); } }
internal void reConstruction(PacketDotNet.TcpPacket tcpPacket) { if (tcpPacket.PayloadData == null || tcpPacket.PayloadData.Length == 0) { return; } reassemble_tcp( tcpPacket.SequenceNumber, //Номер пакета tcpPacket.PayloadData.Length, //Длина данных (byte[])tcpPacket.PayloadData.Clone(), //Копия данных пакета, т.к. я уверен могут быть проблемы tcpPacket.SourcePort, tcpPacket.DestinationPort //Номера портов, т.к. мне нужен реконструктор а не снифер ); }
public Message(SharpPcap.RawCapture packet) { PacketDotNet.TcpPacket tcpPacket = (PacketDotNet.TcpPacket)PacketDotNet.Packet.ParsePacket(packet.LinkLayerType, packet.Data).PayloadPacket.PayloadPacket; this.packets = new List <PacketDotNet.TcpPacket>(); this.packets.Add(tcpPacket); this.Ack = tcpPacket.AcknowledgmentNumber; this.RawData = packet.Data; this.PayloadData = tcpPacket.PayloadData; this.Length = tcpPacket.PayloadData.Length; this.Timestamp = packet.Timeval.Date; this.Complete = this.Length != 1460; }
/// <summary> /// Writes the payload data to the file /// </summary> /// <param name="index"></param> /// <param name="data"></param> private void write_packet_data(int index, byte[] i_data, PacketDotNet.TcpPacket tcpPacket) { // Add packet to packets list. this.packets.Add(tcpPacket); // ignore empty packets. if (i_data.Length == 0) { return; } data = Combine(this.data, i_data); bytes_written[index] += (uint)i_data.Length; EmptyStream = false; }
public void HandlePacket(PacketDotNet.TcpPacket tcpPacket) { var ipPacket = (PacketDotNet.IPPacket)tcpPacket.ParentPacket; var session = new TcpSession() { SourceIp = ipPacket.SourceAddress.ToString(), SourcePort = tcpPacket.SourcePort, DestinationIp = ipPacket.DestinationAddress.ToString(), DestinationPort = tcpPacket.DestinationPort }; if (!_sessions.ContainsKey(session)) { TcpRecon recon = new TcpRecon(); _sessions.Add(session, recon); } _sessions[session].ReassemblePacket(tcpPacket); // If the tcp packet contains FIN or ACK flags we can determine that the session // is terminated by means that no more data is about to be sent. if (IsLiveCapture) { if (tcpPacket.Flags == 17 || tcpPacket.Flags == 1) { session.Data = _sessions[session].Data; foreach (var currentTcpPacket in _sessions[session].packets) { var currentIpPacket = (PacketDotNet.IPPacket)currentTcpPacket.ParentPacket; session.Packets.Add(new TcpPacket() { SourceIp = currentIpPacket.SourceAddress.ToString(), SourcePort = currentTcpPacket.SourcePort, DestinationIp = currentIpPacket.DestinationAddress.ToString(), DestinationPort = currentTcpPacket.DestinationPort, Data = currentTcpPacket.PayloadData }); } completedSessions.Add(session); _sessions.Remove(session); } } }
public void HandlePacket(PacketDotNet.TcpPacket tcpPacket) { var session = new TcpSession() { SourceIp = ((PacketDotNet.IPPacket)tcpPacket.ParentPacket).SourceAddress.ToString(), SourcePort = tcpPacket.SourcePort, DestinationIp = ((PacketDotNet.IPPacket)tcpPacket.ParentPacket).DestinationAddress.ToString(), DestinationPort = tcpPacket.DestinationPort }; if (!_sessions.ContainsKey(session)) { TcpRecon recon = new TcpRecon(); _sessions.Add(session, recon); } _sessions[session].ReassemblePacket(tcpPacket); }
public void AddPacket(SharpPcap.RawCapture packet) { PacketDotNet.TcpPacket tcpPacket = (PacketDotNet.TcpPacket)PacketDotNet.Packet.ParsePacket(packet.LinkLayerType, packet.Data).PayloadPacket.PayloadPacket; if (tcpPacket.AcknowledgmentNumber == this.Ack) { packets.Add(tcpPacket); this.Complete = tcpPacket.PayloadData.Length != 1460; byte[] raw = new byte[tcpPacket.PayloadData.Length + this.PayloadData.Length]; Array.Copy(this.PayloadData, raw, this.PayloadData.Length); Array.Copy(tcpPacket.PayloadData, 0, raw, this.PayloadData.Length, tcpPacket.PayloadData.Length); this.PayloadData = raw; this.Length = this.PayloadData.Length; } }
public uint[] AddPacket(PacketDotNet.TcpPacket packet, string srcIp) { delay.Restart(); uint[] rel = new uint[2]; if (seq2Start == 0) { seq2Start = packet.SequenceNumber; } if (ip1 == srcIp) { packetsOut.Add(packet); rel[0] = packet.SequenceNumber - seq1Start; rel[1] = packet.AcknowledgmentNumber - seq2Start; } else { packetsIn.Add(packet); rel[0] = packet.SequenceNumber - seq2Start; rel[1] = packet.AcknowledgmentNumber - seq1Start; } return(rel); }
/// <summary> /// The main function of the class receives a tcp packet and reconstructs the stream /// </summary> /// <param name="tcpPacket"></param> public void ReassemblePacket(PacketDotNet.TcpPacket tcpPacket) { // if the paylod length is zero bail out ulong length = (ulong)(tcpPacket.Bytes.Length - tcpPacket.Header.Length); if (length == 0) { return; } reassemble_tcp( (ulong)tcpPacket.SequenceNumber, length, tcpPacket.PayloadData, (ulong)tcpPacket.PayloadData.Length, tcpPacket.Syn, IpAddressToLong(((PacketDotNet.IpPacket)tcpPacket.ParentPacket).SourceAddress.ToString()), IpAddressToLong(((PacketDotNet.IpPacket)tcpPacket.ParentPacket).DestinationAddress.ToString()), (uint)tcpPacket.SourcePort, (uint)tcpPacket.DestinationPort, tcpPacket); }
//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); }
/// <summary> /// Reconstructs the tcp session /// </summary> /// <param name="sequence">Sequence number of the tcp packet</param> /// <param name="length">The size of the original packet data</param> /// <param name="data">The captured data</param> /// <param name="data_length">The length of the captured data</param> /// <param name="synflag"></param> /// <param name="net_src">The source ip address</param> /// <param name="net_dst">The destination ip address</param> /// <param name="srcport">The source port</param> /// <param name="dstport">The destination port</param> private void reassemble_tcp(ulong sequence, ulong length, byte[] data, ulong data_length, bool synflag, long net_src, long net_dst, uint srcport, uint dstport, PacketDotNet.TcpPacket tcpPacket) { long srcx, dstx; int src_index, j; bool first = false; ulong newseq; TcpFrag tmp_frag; src_index = -1; /* Now check if the packet is for this connection. */ srcx = net_src; dstx = net_dst; // Check to see if we have seen this source IP and port before. // Note: We have to check both source IP and port, the connection // might be between two different ports on the same machine. for (j = 0; j < 2; j++) { if (src_addr[j] == srcx && src_port[j] == srcport) { src_index = j; } } // We didn't find it if src_index == -1. if (src_index < 0) { // Assign it to a src_index and get going. for (j = 0; j < 2; j++) { if (src_port[j] == 0) { src_addr[j] = srcx; src_port[j] = srcport; src_index = j; first = true; break; } } } if (src_index < 0) { throw new Exception("ERROR in reassemble_tcp: Too many addresses!"); } if (data_length < length) { incomplete_tcp_stream = true; } /* now that we have filed away the srcs, lets get the sequence number stuff * figured out */ if (first) { /* this is the first time we have seen this src's sequence number */ seq[src_index] = sequence + length; if (synflag) { seq[src_index]++; } /* write out the packet data */ write_packet_data(src_index, data, tcpPacket); return; } /* if we are here, we have already seen this src, let's * try and figure out if this packet is in the right place */ if (sequence < seq[src_index]) { /* this sequence number seems dated, but * check the end to make sure it has no more * info than we have already seen */ newseq = sequence + length; if (newseq > seq[src_index]) { ulong new_len; /* this one has more than we have seen. let's get the * payload that we have not seen. */ new_len = seq[src_index] - sequence; if (data_length <= new_len) { data = null; data_length = 0; incomplete_tcp_stream = true; } else { data_length -= new_len; byte[] tmpData = new byte[data_length]; for (ulong i = 0; i < data_length; i++) { tmpData[i] = data[i + new_len]; } data = tmpData; } sequence = seq[src_index]; length = newseq - seq[src_index]; /* this will now appear to be right on time :) */ } } if (sequence == seq[src_index]) { /* right on time */ seq[src_index] += length; if (synflag) { seq[src_index]++; } if (data != null) { write_packet_data(src_index, data, tcpPacket); } /* done with the packet, see if it caused a fragment to fit */ while (check_fragments(src_index, tcpPacket)) { ; } } else { /* out of order packet */ if (data_length > 0 && sequence > seq[src_index]) { tmp_frag = new TcpFrag(); tmp_frag.data = data; tmp_frag.seq = sequence; tmp_frag.len = length; tmp_frag.data_len = data_length; if (frags[src_index] != null) { tmp_frag.next = frags[src_index]; } else { tmp_frag.next = null; } frags[src_index] = tmp_frag; } } }
private void ui_populate_packet_view() { // There's a race condition here, but imo not worth changing the architecture to fix yet. if (cFileUtilities.get_size(_backend_file) == _backend_size) { return; } _backend_size = cFileUtilities.get_size(_backend_file); ICaptureDevice pcap_device = null; bool has_temp_file_open = false; string temp_file = ""; _packet_bytes.Clear(); try { temp_file = cFileUtilities.get_temp_copy(_backend_file); has_temp_file_open = true; pcap_device = new SharpPcap.LibPcap.CaptureFileReaderDevice(temp_file); pcap_device.Open(); RawCapture capture; int current_packet = 0; while ((capture = pcap_device.GetNextPacket()) != null) { var eth_packet = PacketDotNet.Packet.ParsePacket(capture.LinkLayerType, capture.Data); PacketDotNet.IPPacket ip_packet = eth_packet.Extract <PacketDotNet.IPPacket>(); if (_stream_type == "tcp") { PacketDotNet.TcpPacket tcp_packet = eth_packet.Extract <PacketDotNet.TcpPacket>(); _packet_bytes.Add(tcp_packet.PayloadData.ToList()); object packet_view_item = new { PacketNumber = current_packet.ToString(), Source = ip_packet.SourceAddress.ToString() + ":" + tcp_packet.SourcePort.ToString(), Destination = ip_packet.DestinationAddress.ToString() + ":" + tcp_packet.DestinationPort.ToString(), PayloadLength = tcp_packet.PayloadData.Length.ToString(), }; if (packet_stream_view.Items.Contains(packet_view_item) == false) { packet_stream_view.Items.Add(packet_view_item); } } else { PacketDotNet.UdpPacket udp_packet = eth_packet.Extract <PacketDotNet.UdpPacket>(); _packet_bytes.Add(udp_packet.PayloadData.ToList()); object packet_view_item = new { PacketNumber = current_packet.ToString(), Source = ip_packet.SourceAddress.ToString() + ":" + udp_packet.SourcePort.ToString(), Destination = ip_packet.DestinationAddress.ToString() + ":" + udp_packet.DestinationPort.ToString(), PayloadLength = udp_packet.PayloadData.Length.ToString(), }; if (packet_stream_view.Items.Contains(packet_view_item) == false) { packet_stream_view.Items.Add(packet_view_item); } } current_packet++; } } catch (Exception e) { if (has_temp_file_open == true) { cFileUtilities.remove_temp_copy(temp_file); has_temp_file_open = false; } MessageBox.Show("Error: " + e.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } if (pcap_device != null) { pcap_device.Close(); } if (has_temp_file_open == true) { cFileUtilities.remove_temp_copy(temp_file); has_temp_file_open = false; } }
static void HandleOnFlowClosed(PosixTimeval timeval, PacketDotNet.TcpPacket tcp, TcpConnection connection, TcpFlow flow) { // unhook the received handler flow.OnPacketReceived -= HandleOnPacketReceived; }
private void device_OnPacketArrival(object sender, CaptureEventArgs e) { var time = e.Packet.Timeval.Date; var len = e.Packet.Data.Length; var pack = PacketDotNet.Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data); if (pack is PacketDotNet.EthernetPacket) { PacketDotNet.EthernetPacket ethPack = pack as PacketDotNet.EthernetPacket; if (ethPack.PayloadPacket is PacketDotNet.IPv4Packet) { PacketDotNet.IPv4Packet ipPack = ethPack.PayloadPacket as PacketDotNet.IPv4Packet; //TCP if (ipPack.PayloadPacket is PacketDotNet.TcpPacket) { PacketDotNet.TcpPacket tcpPack = ipPack.PayloadPacket as PacketDotNet.TcpPacket; if ((ipPack.DestinationAddress.ToString().Equals("172.25.25.50") && tcpPack.DestinationPort == 8001) || (ipPack.SourceAddress.ToString().Equals("172.25.25.50") && tcpPack.SourcePort == 8001)) { //Console.WriteLine("TCP:{0}:{1}-{2}:{3}",ipPack.SourceAddress, tcpPack.SourcePort,ipPack.DestinationAddress,tcpPack.DestinationPort); if (tcpPack.PayloadData != null && tcpPack.PayloadData.Length > 0) { Console.WriteLine("读取数据:{0}", System.Text.Encoding.UTF8.GetString(tcpPack.PayloadData)); } } } //UDP else if (ipPack.PayloadPacket is PacketDotNet.UdpPacket) { PacketDotNet.UdpPacket udp = ipPack.PayloadPacket as PacketDotNet.UdpPacket; if (ipPack.DestinationAddress.ToString().Equals("172.25.25.69") && udp.DestinationPort == 5060) { if (udp.PayloadData != null && udp.PayloadData.Length > 0) { Console.WriteLine("读取数据:{0}", System.Text.Encoding.UTF8.GetString(udp.PayloadData)); } } //if (ipPack.DestinationAddress.ToString().Equals("172.25.25.69") && udp.DestinationPort == 18038) if (ipPack.DestinationAddress.ToString().Equals("172.25.25.66") && udp.DestinationPort == 18132) { if (udp.PayloadData != null && udp.PayloadData.Length > 100) { RtpPacket rtpPacket = new RtpPacket(udp.PayloadData); RtpHeader rtpHeader = new RtpHeader(udp.PayloadData); int packetRate = RTPPayloadTypes.GetSamplingFrequency((RTPPayloadTypesEnum)Enum.ToObject(typeof(RTPPayloadTypesEnum), rtpHeader.PayloadType)); //8000 int minSec = ((int)rtpHeader.Timestamp - _preTimestamp - _prePacketLength) / (packetRate / 1000); _preTimestamp = (int)rtpHeader.Timestamp; _prePacketLength = rtpPacket.Payload.Length; //写文件 string fileName = "F:\\" + "testRtp9" + ".wav"; PCMU m_PCMU = new PCMU(); //语音包 using (System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, System.IO.FileShare.None)) { byte[] temp = null; //空白语音 byte[] dec = null; //payload荷载数据 byte[] data = null; //完整数据 //空白 if (minSec > 0) { //temp = new byte[16 * minSec]; //dec = m_PCMU.Decode_pcm8(rtpPacket.Payload, 0, rtpPacket.Payload.Length); //data = new byte[temp.Length + dec.Length]; //Array.Copy(temp, 0, data, 0, temp.Length); //Array.Copy(dec, 0, data, temp.Length, dec.Length); temp = new byte[8 * minSec]; for (int i = 0; i < temp.Length; i++) { temp[i] = 0xFE; } dec = rtpPacket.Payload; data = new byte[temp.Length + dec.Length]; Array.Copy(temp, 0, data, 0, temp.Length); Array.Copy(dec, 0, data, temp.Length, dec.Length); data = m_PCMU.Decode_ulaw_pcm8(data, 0, data.Length); } else { data = m_PCMU.Decode_ulaw_pcm8(rtpPacket.Payload, 0, rtpPacket.Payload.Length); } fs.Position = fs.Length; fs.Write(data, 0, data.Length); } } } } } } }
static void HandleCOnConnectionClosed(PosixTimeval timeval, TcpConnection connection, PacketDotNet.TcpPacket tcp, TcpConnection.CloseType closeType) { connection.OnConnectionClosed -= HandleCOnConnectionClosed; OpenConnections.Remove(connection); }