LCOV - code coverage report
Current view: top level - src - PacketSort.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 2 164 1.2 %
Date: 2010-12-13 Functions: 2 30 6.7 %
Branches: 2 138 1.4 %

           Branch data     Line data    Source code
       1                 :            : // $Id: PacketSort.cc 3228 2006-06-08 02:12:03Z vern $
       2                 :            : 
       3                 :            : #include "IP.h"
       4                 :            : #include "PacketSort.h"
       5                 :            : 
       6                 :            : const bool DEBUG_packetsort = false;
       7                 :            : 
       8                 :            : PacketSortElement::PacketSortElement(PktSrc* arg_src,
       9                 :            :                         double arg_timestamp, const struct pcap_pkthdr* arg_hdr,
      10                 :          0 :                         const u_char* arg_pkt, int arg_hdr_size)
      11                 :            :         {
      12                 :          0 :         src = arg_src;
      13                 :          0 :         timestamp = arg_timestamp;
      14                 :          0 :         hdr = *arg_hdr;
      15                 :          0 :         hdr_size = arg_hdr_size;
      16                 :            : 
      17                 :          0 :         pkt = new u_char[hdr.caplen];
      18                 :          0 :         memcpy(pkt, arg_pkt, hdr.caplen);
      19                 :            : 
      20                 :          0 :         is_tcp = 0;
      21                 :          0 :         ip_hdr = 0;
      22                 :          0 :         key = 0;
      23                 :            : 
      24                 :            :         // Now check if it is a "parsable" TCP packet.
      25                 :          0 :         uint32 caplen = hdr.caplen;
      26                 :            :         uint32 tcp_offset;
      27                 :            : 
      28   [ #  #  #  # ]:          0 :         if ( caplen >= sizeof(struct ip) + hdr_size )
      29                 :            :                 {
      30                 :          0 :                 const struct ip* ip = (const struct ip*) (pkt + hdr_size);
      31 [ #  # ][ #  # ]:          0 :                 if ( ip->ip_v == 4 )
      32                 :          0 :                         ip_hdr = new IP_Hdr(ip);
      33                 :            :                 else
      34                 :          0 :                         ip_hdr = new IP_Hdr((const struct ip6_hdr*) ip);
      35                 :            : 
      36 [ #  # ][ #  # ]:          0 :                 if ( ip_hdr->NextProto() == IPPROTO_TCP &&
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      37                 :            :                       // Note: can't sort fragmented packets
      38                 :            :                      (ip_hdr->FragField() & 0x3fff) == 0 )
      39                 :            :                         {
      40                 :          0 :                         tcp_offset = hdr_size + ip_hdr->HdrLen();
      41   [ #  #  #  # ]:          0 :                         if ( caplen >= tcp_offset + sizeof(struct tcphdr) )
      42                 :            :                                 {
      43                 :            :                                 const struct tcphdr* tp = (const struct tcphdr*)
      44                 :          0 :                                                         (pkt + tcp_offset);
      45                 :            : 
      46                 :          0 :                                 id.src_addr = ip_hdr->SrcAddr();
      47                 :          0 :                                 id.dst_addr = ip_hdr->DstAddr();
      48                 :          0 :                                 id.src_port = tp->th_sport;
      49                 :          0 :                                 id.dst_port = tp->th_dport;
      50                 :          0 :                                 id.is_one_way = 0;
      51                 :            : 
      52                 :            :                                 endp = addr_port_canon_lt(id.src_addr,
      53                 :            :                                                           id.src_port,
      54                 :            :                                                           id.dst_addr,
      55                 :          0 :                                                           id.dst_port) ? 0 : 1;
      56                 :            : 
      57                 :          0 :                                 seq[endp] = ntohl(tp->th_seq);
      58                 :            : 
      59   [ #  #  #  # ]:          0 :                                 if ( tp->th_flags & TH_ACK )
      60                 :          0 :                                         seq[1-endp] = ntohl(tp->th_ack);
      61                 :            :                                 else
      62                 :          0 :                                         seq[1-endp] = 0;
      63                 :            : 
      64                 :          0 :                                 tcp_flags = tp->th_flags;
      65                 :            : 
      66                 :            :                                 // DEBUG_MSG("%.6f: %u, %u\n", timestamp, seq[0], seq[1]);
      67                 :            : 
      68                 :          0 :                                 payload_length = ip_hdr->PayloadLen() - tp->th_off * 4;
      69                 :            : 
      70                 :          0 :                                 key = id.BuildConnKey();
      71                 :            : 
      72                 :          0 :                                 is_tcp = 1;
      73                 :            :                                 }
      74                 :            :                         }
      75                 :            :                 }
      76                 :            : 
      77                 :            :         if ( DEBUG_packetsort && ! is_tcp )
      78                 :            :                 DEBUG_MSG("%.6f non-TCP packet\n", timestamp);
      79                 :          0 :         }
      80                 :            : 
      81                 :          0 : PacketSortElement::~PacketSortElement()
      82                 :            :         {
      83 [ #  # ][ #  # ]:          0 :         delete [] pkt;
      84 [ #  # ][ #  # ]:          0 :         delete ip_hdr;
      85 [ #  # ][ #  # ]:          0 :         delete key;
      86                 :          0 :         }
      87                 :            : 
      88                 :          0 : int PacketSortPQ::Timestamp_Cmp(PacketSortElement* a, PacketSortElement* b)
      89                 :            :         {
      90                 :          0 :         double d = a->timestamp - b->timestamp;
      91                 :            : 
      92         [ #  # ]:          0 :         if ( d > 0 ) return 1;
      93         [ #  # ]:          0 :         else if ( d < 0 ) return -1;
      94                 :          0 :         else return 0;
      95                 :            :         }
      96                 :            : 
      97                 :          0 : int PacketSortPQ::UpdatePQ(PacketSortElement* prev_e, PacketSortElement* new_e)
      98                 :            :         {
      99                 :          0 :         int index = prev_e->pq_index[pq_level];
     100                 :            : 
     101                 :          0 :         new_e->pq_index[pq_level] = index;
     102                 :          0 :         pq[index] = new_e;
     103                 :            : 
     104         [ #  # ]:          0 :         if ( Cmp(prev_e, new_e) > 0 )
     105                 :          0 :                 return FixUp(new_e, index);
     106                 :            :         else
     107                 :            :                 {
     108                 :          0 :                 FixDown(new_e, index);
     109                 :          0 :                 return index == 0;
     110                 :            :                 }
     111                 :            :         }
     112                 :            : 
     113                 :          0 : int PacketSortPQ::AddToPQ(PacketSortElement* new_e)
     114                 :            :         {
     115                 :          0 :         int index = pq.size();
     116                 :            : 
     117                 :          0 :         new_e->pq_index[pq_level] = index;
     118                 :          0 :         pq.push_back(new_e);
     119                 :            : 
     120                 :          0 :         return FixUp(new_e, index);
     121                 :            :         }
     122                 :            : 
     123                 :          0 : int PacketSortPQ::RemoveFromPQ(PacketSortElement* prev_e)
     124                 :            :         {
     125         [ #  # ]:          0 :         if ( pq.size() > 1 )
     126                 :            :                 {
     127                 :          0 :                 PacketSortElement* new_e = pq[pq.size() - 1];
     128                 :          0 :                 pq.pop_back();
     129                 :          0 :                 return UpdatePQ(prev_e, new_e);         
     130                 :            :                 }
     131                 :            :         else
     132                 :            :                 {
     133                 :          0 :                 pq.pop_back();
     134                 :          0 :                 return 1;
     135                 :            :                 }
     136                 :            :         }
     137                 :            : 
     138                 :          0 : void PacketSortPQ::Assign(int k, PacketSortElement* e)
     139                 :            :         {
     140                 :          0 :         pq[k] = e;
     141                 :          0 :         e->pq_index[pq_level] = k;
     142                 :          0 :         }
     143                 :            : 
     144                 :          0 : PacketSortConnPQ::~PacketSortConnPQ()
     145                 :            :         {
     146                 :            :         // Delete elements only in ConnPQ (not in GlobalPQ) to avoid
     147                 :            :         // double delete.
     148 [ #  # ][ #  # ]:          0 :         for ( int i = 0; i < (int) pq.size(); ++i )
                 [ #  # ]
     149                 :            :                 {
     150 [ #  # ][ #  # ]:          0 :                 delete pq[i];
                 [ #  # ]
     151                 :          0 :                 pq[i] = 0;
     152                 :            :                 }
     153 [ #  # ][ #  # ]:          0 :         }
                 [ #  # ]
     154                 :            : 
     155                 :          0 : int PacketSortConnPQ::Cmp(PacketSortElement* a, PacketSortElement* b)
     156                 :            :         {
     157                 :            :         // Note: here we do not distinguish between packets without
     158                 :            :         // an ACK and packets with seq/ack of 0. The later will sorted
     159                 :            :         // only by their timestamps.
     160                 :            : 
     161 [ #  # ][ #  # ]:          0 :         if ( a->seq[0] && b->seq[0] && a->seq[0] != b->seq[0] )
                 [ #  # ]
     162         [ #  # ]:          0 :                 return (a->seq[0] > b->seq[0]) ? 1 : -1;
     163                 :            : 
     164 [ #  # ][ #  # ]:          0 :         else if ( a->seq[1] && b->seq[1] && a->seq[1] != b->seq[1] )
                 [ #  # ]
     165         [ #  # ]:          0 :                 return (a->seq[1] > b->seq[1]) ? 1 : -1;
     166                 :            : 
     167                 :            :         else
     168                 :          0 :                 return Timestamp_Cmp(a, b);
     169                 :            :         }
     170                 :            : 
     171                 :          0 : int PacketSortPQ::FixUp(PacketSortElement* e, int k)
     172                 :            :         {
     173         [ #  # ]:          0 :         if ( k == 0 )
     174                 :            :                 {
     175                 :          0 :                 Assign(0, e);
     176                 :          0 :                 return 1;
     177                 :            :                 }
     178                 :            : 
     179                 :          0 :         int parent = (k-1) / 2;
     180         [ #  # ]:          0 :         if ( Cmp(pq[parent], e) > 0 )
     181                 :            :                 {
     182                 :          0 :                 Assign(k, pq[parent]);
     183                 :          0 :                 return FixUp(e, parent);
     184                 :            :                 }
     185                 :            :         else
     186                 :            :                 {
     187                 :          0 :                 Assign(k, e);
     188                 :          0 :                 return 0;
     189                 :            :                 }
     190                 :            :         }
     191                 :            : 
     192                 :          0 : void PacketSortPQ::FixDown(PacketSortElement* e, int k)
     193                 :            :         {
     194                 :          0 :         uint32 kid = k * 2 + 1;
     195                 :            : 
     196         [ #  # ]:          0 :         if ( kid >= pq.size() )
     197                 :            :                 {
     198                 :          0 :                 Assign(k, e);
     199                 :          0 :                 return;
     200                 :            :                 }
     201                 :            : 
     202 [ #  # ][ #  # ]:          0 :         if ( kid + 1 < pq.size() && Cmp(pq[kid], pq[kid+1]) > 0 )
                 [ #  # ]
     203                 :          0 :                 ++kid;
     204                 :            : 
     205         [ #  # ]:          0 :         if ( Cmp(e, pq[kid]) > 0 )
     206                 :            :                 {
     207                 :          0 :                 Assign(k, pq[kid]);
     208                 :          0 :                 FixDown(e, kid);
     209                 :            :                 }
     210                 :            :         else
     211                 :          0 :                 Assign(k, e);
     212                 :            :         }
     213                 :            : 
     214                 :            : 
     215                 :          0 : int PacketSortConnPQ::Add(PacketSortElement* e)
     216                 :            :         {
     217                 :            : #if 0
     218                 :            :         int endp = e->endp;
     219                 :            :         uint32 end_seq = e->seq[endp] + e->payload_length;
     220                 :            : 
     221                 :            :         int p = 1 - endp;
     222                 :            :         if ( (e->tcp_flags & TH_RST) && ! (e->tcp_flags & TH_ACK) )
     223                 :            :                 {
     224                 :            :                 DEBUG_MSG("%.6f %c: %u -> %u\n",
     225                 :            :                           e->TimeStamp(), (p == endp) ? 'S' : 'A',
     226                 :            :                           e->seq[p], next_seq[p]);
     227                 :            :                 e->seq[p] = next_seq[p];
     228                 :            :                 }
     229                 :            : 
     230                 :            :         if ( end_seq > next_seq[endp] )
     231                 :            :                 next_seq[endp] = end_seq;
     232                 :            : #endif
     233                 :            : 
     234                 :          0 :         return AddToPQ(e);
     235                 :            :         }
     236                 :            : 
     237                 :          0 : void PacketSortConnPQ::UpdateDeliveredSeq(int endp, int seq, int len, int ack)
     238                 :            :         {
     239 [ #  # ][ #  # ]:          0 :         if ( delivered_seq[endp] == 0 || delivered_seq[endp] == seq )
     240                 :          0 :                 delivered_seq[endp] = seq + len;
     241         [ #  # ]:          0 :         if ( ack > delivered_seq[1 - endp] )
     242                 :          0 :                 delivered_seq[endp] = ack;
     243                 :          0 :         }
     244                 :            : 
     245                 :          0 : bool PacketSortConnPQ::IsContentGapSafe(PacketSortElement* e)
     246                 :            :         {
     247                 :          0 :         int ack = e->seq[1 - e->endp];
     248                 :          0 :         return ack <= delivered_seq[1 - e->endp];
     249                 :            :         }
     250                 :            : 
     251                 :          0 : int PacketSortConnPQ::Remove(PacketSortElement* e)
     252                 :            :         {
     253                 :          0 :         int ret = RemoveFromPQ(e);
     254                 :            :         UpdateDeliveredSeq(e->endp, e->seq[e->endp], e->payload_length,
     255                 :          0 :                                 e->seq[1 - e->endp]);
     256                 :          0 :         return ret;
     257                 :            :         }
     258                 :            : 
     259                 :          0 : static void DeleteConnPQ(void* p)
     260                 :            :         {
     261         [ #  # ]:          0 :         delete (PacketSortConnPQ*) p;
     262                 :          0 :         }
     263                 :            : 
     264                 :          0 : PacketSortGlobalPQ::PacketSortGlobalPQ()
     265                 :            :         {
     266                 :          0 :         pq_level = GLOBAL_PQ;
     267                 :          0 :         conn_pq_table.SetDeleteFunc(DeleteConnPQ);
     268                 :          0 :         }
     269                 :            : 
     270                 :          0 : PacketSortGlobalPQ::~PacketSortGlobalPQ()
     271                 :            :         {
     272                 :            :         // Destruction of PacketSortConnPQ will delete all conn_pq's.
     273 [ #  # ][ #  # ]:          0 :         }
                 [ #  # ]
     274                 :            : 
     275                 :          0 : int PacketSortGlobalPQ::Add(PacketSortElement* e)
     276                 :            :         {
     277         [ #  # ]:          0 :         if ( e->is_tcp )
     278                 :            :                 {
     279                 :            :                 // TCP packets are sorted by sequence numbers
     280                 :          0 :                 PacketSortConnPQ* conn_pq = FindConnPQ(e);
     281                 :          0 :                 PacketSortElement* prev_min = conn_pq->Min();
     282                 :            : 
     283         [ #  # ]:          0 :                 if ( conn_pq->Add(e) )
     284                 :            :                         {
     285         [ #  # ]:          0 :                         ASSERT(conn_pq->Min() != prev_min);
     286                 :            : 
     287         [ #  # ]:          0 :                         if ( prev_min )
     288                 :          0 :                                 return UpdatePQ(prev_min, e);
     289                 :            :                         else
     290                 :          0 :                                 return AddToPQ(e);
     291                 :            :                         }
     292                 :            : 
     293                 :            :                 else
     294                 :            :                         {
     295         [ #  # ]:          0 :                         ASSERT(conn_pq->Min() == prev_min);
     296                 :          0 :                         return 0;
     297                 :            :                         }
     298                 :            :                 }
     299                 :            :         else
     300                 :          0 :                 return AddToPQ(e);
     301                 :            :         }
     302                 :            : 
     303                 :          0 : PacketSortElement* PacketSortGlobalPQ::RemoveMin(double timestamp)
     304                 :            :         {
     305                 :          0 :         PacketSortElement* e = Min();
     306                 :            : 
     307         [ #  # ]:          0 :         if ( ! e )
     308                 :          0 :                 return 0;
     309                 :            : 
     310         [ #  # ]:          0 :         if ( e->is_tcp )
     311                 :            :                 {
     312                 :          0 :                 PacketSortConnPQ* conn_pq = FindConnPQ(e);
     313                 :            : 
     314                 :            : #if 0
     315                 :            :                 // Note: the content gap safety check does not work
     316                 :            :                 // because we remove the state for a connection once
     317                 :            :                 // it has no packet in the priority queue.
     318                 :            : 
     319                 :            :                 // Do not deliver e if it arrives later than timestamp,
     320                 :            :                 // and is not content-gap-safe.
     321                 :            :                 if ( e->timestamp > timestamp &&
     322                 :            :                      ! conn_pq->IsContentGapSafe(e) )
     323                 :            :                         return 0;
     324                 :            : #else
     325         [ #  # ]:          0 :                 if ( e->timestamp > timestamp )
     326                 :          0 :                         return 0;
     327                 :            : #endif
     328                 :            : 
     329                 :          0 :                 conn_pq->Remove(e);
     330                 :          0 :                 PacketSortElement* new_e = conn_pq->Min();
     331                 :            : 
     332         [ #  # ]:          0 :                 if ( new_e )
     333                 :          0 :                         UpdatePQ(e, new_e);
     334                 :            :                 else
     335                 :            :                         {
     336                 :          0 :                         RemoveFromPQ(e);
     337                 :          0 :                         conn_pq_table.Remove(e->key);
     338         [ #  # ]:          0 :                         delete conn_pq;
     339                 :            :                         }
     340                 :            :                 }
     341                 :            :         else
     342                 :          0 :                 RemoveFromPQ(e);
     343                 :            : 
     344                 :          0 :         return e;
     345                 :            :         }
     346                 :            : 
     347                 :          0 : PacketSortConnPQ* PacketSortGlobalPQ::FindConnPQ(PacketSortElement* e)
     348                 :            :         {
     349         [ #  # ]:          0 :         if ( ! e->is_tcp )
     350                 :          0 :                 internal_error("cannot find a connection for an invalid id");
     351                 :            :         
     352                 :          0 :         PacketSortConnPQ* pq = (PacketSortConnPQ*) conn_pq_table.Lookup(e->key);
     353         [ #  # ]:          0 :         if ( ! pq )
     354                 :            :                 {
     355                 :          0 :                 pq = new PacketSortConnPQ();
     356                 :          0 :                 conn_pq_table.Insert(e->key, pq);
     357                 :            :                 }
     358                 :            : 
     359                 :          0 :         return pq;
     360 [ +  - ][ +  - ]:          6 :         }

Generated by: LCOV version 1.8