LCOV - code coverage report
Current view: top level - src - TCP_Reassembler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 133 250 53.2 %
Date: 2010-12-13 Functions: 15 28 53.6 %
Branches: 127 276 46.0 %

           Branch data     Line data    Source code
       1                 :            : // $Id: TCP_Reassembler.cc,v 1.1.2.8 2006/05/31 01:52:02 sommer Exp $
       2                 :            : 
       3                 :            : #include "Analyzer.h"
       4                 :            : #include "TCP_Reassembler.h"
       5                 :            : #include "TCP.h"
       6                 :            : #include "TCP_Endpoint.h"
       7                 :            : #include "TCP_Rewriter.h"
       8                 :            : 
       9                 :            : // Only needed for gap_report events.
      10                 :            : #include "Event.h"
      11                 :            : 
      12                 :            : const bool DEBUG_tcp_contents = false;
      13                 :            : const bool DEBUG_tcp_connection_close = false;
      14                 :            : const bool DEBUG_tcp_match_undelivered = false;
      15                 :            : 
      16                 :            : static double last_gap_report = 0.0;
      17                 :            : static uint32 last_ack_events = 0;
      18                 :            : static uint32 last_ack_bytes = 0;
      19                 :            : static uint32 last_gap_events = 0;
      20                 :            : static uint32 last_gap_bytes = 0;
      21                 :            : 
      22                 :            : TCP_Reassembler::TCP_Reassembler(Analyzer* arg_dst_analyzer,
      23                 :            :                                 TCP_Analyzer* arg_tcp_analyzer,
      24                 :            :                                 TCP_Reassembler::Type arg_type,
      25                 :       1876 :                                 bool arg_is_orig, TCP_Endpoint* arg_endp)
      26                 :       1876 : : Reassembler(1, arg_endp->dst_addr, REASSEM_TCP)
      27                 :            :         {
      28                 :       1876 :         dst_analyzer = arg_dst_analyzer;
      29                 :       1876 :         tcp_analyzer = arg_tcp_analyzer;
      30                 :       1876 :         type = arg_type;
      31                 :       1876 :         is_orig = arg_is_orig;
      32                 :       1876 :         endp = arg_endp;
      33                 :       1876 :         had_gap = false;
      34                 :       1876 :         record_contents_file = 0;
      35                 :       1876 :         deliver_tcp_contents = 0;
      36                 :       1876 :         skip_deliveries = 0;
      37                 :       1876 :         did_EOF = 0;
      38                 :       1876 :         seq_to_skip = 0;
      39                 :       1876 :         in_delivery = false;
      40                 :            : 
      41   [ -  +  #  # ]:       1876 :         if ( tcp_contents )
      42                 :            :                 {
      43                 :            :                 // Val dst_port_val(ntohs(Conn()->RespPort()), TYPE_PORT);
      44                 :            :                 PortVal dst_port_val(ntohs(tcp_analyzer->Conn()->RespPort()),
      45                 :          0 :                                         TRANSPORT_TCP);
      46                 :            :                 TableVal* ports = IsOrig() ?
      47                 :            :                         tcp_content_delivery_ports_orig :
      48 [ #  # ][ #  # ]:          0 :                         tcp_content_delivery_ports_resp;
      49                 :          0 :                 Val* result = ports->Lookup(&dst_port_val);
      50                 :            : 
      51   [ #  #  #  # ]:          0 :                 if ( (IsOrig() && tcp_content_deliver_all_orig) ||
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
           [ #  #  #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      52                 :            :                      (! IsOrig() && tcp_content_deliver_all_resp) ||
      53                 :            :                      (result && result->AsBool()) )
      54                 :          0 :                         deliver_tcp_contents = 1;
      55                 :            :                 }
      56                 :       1876 :         }
      57                 :            : 
      58                 :       1876 : TCP_Reassembler::~TCP_Reassembler()
      59                 :            :         {
      60                 :       1876 :         Unref(record_contents_file);
      61 [ +  - ][ #  # ]:       1876 :         }
                 [ #  # ]
      62                 :            : 
      63                 :       1876 : void TCP_Reassembler::Done()
      64                 :            :         {
      65                 :       1876 :         MatchUndelivered(-1);
      66                 :            : 
      67         [ -  + ]:       1876 :         if ( record_contents_file )
      68                 :            :                 { // Record any undelivered data.
      69 [ #  # ][ #  # ]:          0 :                 if ( blocks &&
                 [ #  # ]
      70                 :            :                      seq_delta(last_reassem_seq, last_block->upper) < 0 )
      71                 :            :                         RecordToSeq(last_reassem_seq, last_block->upper,
      72                 :          0 :                                         record_contents_file);
      73                 :            : 
      74                 :          0 :                 record_contents_file->Close();
      75                 :            :                 }
      76                 :       1876 :         }
      77                 :            : 
      78                 :            : void TCP_Reassembler::SizeBufferedData(int& waiting_on_hole,
      79                 :          0 :                                         int& waiting_on_ack) const
      80                 :            :         {
      81                 :          0 :         waiting_on_hole = waiting_on_ack = 0;
      82         [ #  # ]:          0 :         for ( DataBlock* b = blocks; b; b = b->next )
      83                 :            :                 {
      84         [ #  # ]:          0 :                 if ( seq_delta(b->seq, last_reassem_seq) <= 0 )
      85                 :            :                         // We must have delivered this block, but
      86                 :            :                         // haven't yet trimmed it.
      87                 :          0 :                         waiting_on_ack += b->Size();
      88                 :            :                 else
      89                 :          0 :                         waiting_on_hole += b->Size();
      90                 :            :                 }
      91                 :          0 :         }
      92                 :            : 
      93                 :          0 : void TCP_Reassembler::SetContentsFile(BroFile* f)
      94                 :            :         {
      95         [ #  # ]:          0 :         if ( ! f->IsOpen() )
      96                 :            :                 {
      97                 :          0 :                 run_time("no such file \"%s\"", f->Name());
      98                 :          0 :                 return;
      99                 :            :                 }
     100                 :            : 
     101         [ #  # ]:          0 :         if ( record_contents_file )
     102                 :            :                 // We were already recording, no need to catch up.
     103                 :          0 :                 Unref(record_contents_file);
     104                 :            :         else
     105                 :            :                 {
     106         [ #  # ]:          0 :                 if ( blocks )
     107                 :          0 :                         RecordToSeq(blocks->seq, last_reassem_seq, f);
     108                 :            :                 }
     109                 :            : 
     110                 :            :         // Don't want rotation on these files.
     111                 :          0 :         f->SetRotateInterval(0);
     112                 :            : 
     113                 :          0 :         Ref(f);
     114                 :          0 :         record_contents_file = f;
     115                 :            :         }
     116                 :            : 
     117                 :            : 
     118                 :        867 : void TCP_Reassembler::Undelivered(int up_to_seq)
     119                 :            :         {
     120                 :        867 :         TCP_Endpoint* endpoint = endp;
     121                 :        867 :         TCP_Endpoint* peer = endpoint->peer;
     122                 :            : 
     123 [ +  + ][ +  - ]:        867 :         if ( up_to_seq <= 2 && tcp_analyzer->IsPartial() )
                 [ +  + ]
     124                 :            :                 // Since it was a partial connection, we faked up its
     125                 :            :                 // initial sequence numbers as though we'd seen a SYN.
     126                 :            :                 // We've now received the first ack and are getting a
     127                 :            :                 // complaint that either that data is missing (if
     128                 :            :                 // up_to_seq is 1), or one octet beyond it is missing
     129                 :            :                 // (if up_to_seq is 2).  The latter can occur when the
     130                 :            :                 // first packet we saw instantiating the partial connection
     131                 :            :                 // was a keep-alive.  So, in either case, just ignore it.
     132                 :         32 :                 return;
     133                 :            : 
     134                 :            : #if 0
     135                 :            :         if ( endpoint->FIN_cnt > 0 )
     136                 :            :                 {
     137                 :            :                 // Make sure we're not worrying about undelivered
     138                 :            :                 // FIN control octets!
     139                 :            :                 int FIN_seq = endpoint->FIN_seq - endpoint->start_seq;
     140                 :            :                 if ( seq_delta(up_to_seq, FIN_seq) >= 0 )
     141                 :            :                         up_to_seq = FIN_seq - 1;
     142                 :            :                 }
     143                 :            : #endif
     144                 :            : 
     145                 :            :         if ( DEBUG_tcp_contents )
     146                 :            :                 {
     147                 :            :                 DEBUG_MSG("%.6f Undelivered: up_to_seq=%d, last_reassm=%d, "
     148                 :            :                           "endp: FIN_cnt=%d, RST_cnt=%d, "
     149                 :            :                           "peer: FIN_cnt=%d, RST_cnt=%d\n",
     150                 :            :                           network_time, up_to_seq, last_reassem_seq,
     151                 :            :                           endpoint->FIN_cnt, endpoint->RST_cnt,
     152                 :            :                           peer->FIN_cnt, peer->RST_cnt);
     153                 :            :                 }
     154                 :            : 
     155         [ -  + ]:        835 :         if ( seq_delta(up_to_seq, last_reassem_seq) <= 0 )
     156                 :          0 :                 return;
     157                 :            : 
     158 [ +  + ][ +  - ]:        835 :         if ( last_reassem_seq == 1 &&
         [ +  - ][ +  + ]
                 [ -  + ]
     159                 :            :              (endpoint->FIN_cnt > 0 || endpoint->RST_cnt > 0 ||
     160                 :            :               peer->FIN_cnt > 0 || peer->RST_cnt > 0) )
     161                 :            :                 {
     162                 :            :                 // We could be running on a SYN/FIN/RST-filtered trace - don't
     163                 :            :                 // complain about data missing at the end of the connection.
     164                 :            :                 //
     165                 :            :                 // ### However, note that the preceding test is not a precise
     166                 :            :                 // one for filtered traces, and may fail, for example, when
     167                 :            :                 // the SYN packet carries data.
     168                 :            :                 //
     169                 :            :                 // Note, this check will confuse the EOF checker (and cause a
     170                 :            :                 // missing FIN in the rewritten trace) when the content gap
     171                 :            :                 // in the middle is discovered only after the FIN packet.
     172                 :            : 
     173                 :            :                 // Skip the undelivered part without reporting to the endpoint.
     174                 :          6 :                 skip_deliveries = 1;
     175                 :            :                 }
     176                 :            :         else
     177                 :            :                 {
     178                 :            :                 if ( DEBUG_tcp_contents )
     179                 :            :                         {
     180                 :            :                         DEBUG_MSG("%.6f Undelivered: seq=%d, len=%d, "
     181                 :            :                                           "skip_deliveries=%d\n",
     182                 :            :                                           network_time, last_reassem_seq,
     183                 :            :                                           seq_delta(up_to_seq, last_reassem_seq),
     184                 :            :                                           skip_deliveries);
     185                 :            :                         }
     186                 :            : 
     187         [ +  + ]:        829 :                 if ( ! skip_deliveries )
     188                 :            :                         {
     189                 :            :                         // This can happen because we're processing a trace
     190                 :            :                         // that's been filtered.  For example, if it's just
     191                 :            :                         // SYN/FIN data, then there can be data in the FIN
     192                 :            :                         // packet, but it's undelievered because it's out of
     193                 :            :                         // sequence.
     194                 :            : 
     195                 :        567 :                         int seq = last_reassem_seq;
     196                 :        567 :                         int len = seq_delta(up_to_seq, last_reassem_seq);
     197                 :            : 
     198                 :            :                         // Only report on content gaps for connections that
     199                 :            :                         // are in a cleanly established state.  In other
     200                 :            :                         // states, these can arise falsely due to things
     201                 :            :                         // like sequence number mismatches in RSTs, or
     202                 :            :                         // unseen previous packets in partial connections.
     203                 :            :                         // The one opportunity we lose here is on clean FIN
     204                 :            :                         // handshakes, but Oh Well.
     205                 :            : 
     206   [ +  -  +  + ]:        567 :                         if ( content_gap &&
         [ +  + ][ +  + ]
     207                 :            :                              endpoint->state == TCP_ENDPOINT_ESTABLISHED &&
     208                 :            :                              peer->state == TCP_ENDPOINT_ESTABLISHED )
     209                 :            :                                 {
     210                 :        204 :                                 val_list* vl = new val_list;
     211                 :        204 :                                 vl->append(dst_analyzer->BuildConnVal());
     212                 :        204 :                                 vl->append(new Val(is_orig, TYPE_BOOL));
     213                 :        204 :                                 vl->append(new Val(seq, TYPE_COUNT));
     214                 :        204 :                                 vl->append(new Val(len, TYPE_COUNT));
     215                 :            : 
     216                 :        204 :                                 dst_analyzer->ConnectionEvent(content_gap, vl);
     217                 :            :                                 }
     218                 :            : 
     219                 :            :                         TCP_Rewriter* r = (TCP_Rewriter*)
     220                 :        567 :                                 dst_analyzer->Conn()->TraceRewriter();
     221         [ -  + ]:        567 :                         if ( r )
     222                 :          0 :                                 r->ContentGap(is_orig, len);
     223                 :            : 
     224         [ -  + ]:        567 :                         if ( type == Direct )
     225                 :            :                                 dst_analyzer->NextUndelivered(last_reassem_seq,
     226                 :          0 :                                                                 len, is_orig);
     227                 :            :                         else
     228                 :            :                                 {
     229                 :            :                                 dst_analyzer->ForwardUndelivered(last_reassem_seq,
     230                 :        567 :                                                                 len, is_orig);
     231                 :            :                                 }
     232                 :            :                         }
     233                 :            : 
     234                 :        829 :                 had_gap = true;
     235                 :            :                 }
     236                 :            : 
     237                 :            :         // We should record and match undelivered even if we are skipping
     238                 :            :         // content gaps between SYN and FIN, because FIN may carry some data.
     239                 :            :         //
     240         [ -  + ]:        835 :         if ( record_contents_file )
     241                 :          0 :                 RecordToSeq(last_reassem_seq, up_to_seq, record_contents_file);
     242                 :            : 
     243         [ +  - ]:        835 :         if ( tcp_match_undelivered )
     244                 :        835 :                 MatchUndelivered(up_to_seq);
     245                 :            : 
     246                 :            :         // But we need to re-adjust last_reassem_seq in either case.
     247                 :        867 :         last_reassem_seq = up_to_seq;   // we've done our best ...
     248                 :            :         }
     249                 :            : 
     250                 :       2711 : void TCP_Reassembler::MatchUndelivered(int up_to_seq)
     251                 :            :         {
     252 [ +  + ][ +  - ]:       2711 :         if ( ! blocks || ! rule_matcher )
     253                 :       2711 :                 return;
     254                 :            : 
     255         [ #  # ]:          0 :         ASSERT(last_block);
     256         [ #  # ]:          0 :         if ( up_to_seq == -1 )
     257                 :          0 :                 up_to_seq = last_block->upper;
     258                 :            : 
     259                 :            :         // ### Note: the original code did not check whether blocks have
     260                 :            :         // already been delivered, but not ACK'ed, and therefore still
     261                 :            :         // must be kept in the reassember.
     262                 :            : 
     263                 :            :         // We are to match any undelivered data, from last_reassem_seq to
     264                 :            :         // min(last_block->upper, up_to_seq).
     265                 :            :         // Is there such data?
     266 [ #  # ][ #  # ]:          0 :         if ( seq_delta(up_to_seq, last_reassem_seq) <= 0 ||
                 [ #  # ]
     267                 :            :              seq_delta(last_block->upper, last_reassem_seq) <= 0 )
     268                 :       2711 :                 return;
     269                 :            : 
     270                 :            :         // Skip blocks that are already delivered (but not ACK'ed).
     271                 :            :         // Question: shall we instead keep a pointer to the first undelivered
     272                 :            :         // block?
     273                 :            :         DataBlock* b;
     274 [ #  # ][ #  # ]:          0 :         for ( b = blocks; b && seq_delta(b->upper, last_reassem_seq) <= 0;
                 [ #  # ]
     275                 :            :               b = b->next )
     276                 :            :               tcp_analyzer->Conn()->Match(Rule::PAYLOAD, b->block, b->Size(),
     277                 :          0 :                                                 false, false, is_orig, false);
     278                 :            : 
     279         [ #  # ]:          0 :         ASSERT(b);
     280                 :            :         }
     281                 :            : 
     282                 :          0 : void TCP_Reassembler::RecordToSeq(int start_seq, int stop_seq, BroFile* f)
     283                 :            :         {
     284                 :          0 :         DataBlock* b = blocks;
     285                 :            :         // Skip over blocks up to the start seq.
     286 [ #  # ][ #  # ]:          0 :         while ( b && seq_delta(b->upper, start_seq) <= 0 )
                 [ #  # ]
     287                 :          0 :                 b = b->next;
     288                 :            : 
     289         [ #  # ]:          0 :         if ( ! b )
     290                 :          0 :                 return;
     291                 :            : 
     292                 :          0 :         int last_seq = start_seq;
     293 [ #  # ][ #  # ]:          0 :         while ( b && seq_delta(b->upper, stop_seq) <= 0 )
                 [ #  # ]
     294                 :            :                 {
     295         [ #  # ]:          0 :                 if ( seq_delta(b->seq, last_seq) > 0 )
     296                 :          0 :                         RecordGap(last_seq, b->seq, f);
     297                 :            : 
     298                 :          0 :                 RecordBlock(b, f);
     299                 :          0 :                 last_seq = b->upper;
     300                 :          0 :                 b = b->next;
     301                 :            :                 }
     302                 :            : 
     303         [ #  # ]:          0 :         if ( b )
     304                 :            :                 // Check for final gap.
     305         [ #  # ]:          0 :                 if ( seq_delta(last_seq, stop_seq) < 0 )
     306                 :          0 :                         RecordGap(last_seq, stop_seq, f);
     307                 :            :         }
     308                 :            : 
     309                 :          0 : void TCP_Reassembler::RecordBlock(DataBlock* b, BroFile* f)
     310                 :            :         {
     311                 :          0 :         unsigned int len = b->Size();
     312         [ #  # ]:          0 :         if ( ! f->Write((const char*) b->block, len) )
     313                 :            :                 // ### this should really generate an event
     314                 :          0 :                 internal_error("contents write failed");
     315                 :          0 :         }
     316                 :            : 
     317                 :          0 : void TCP_Reassembler::RecordGap(int start_seq, int upper_seq, BroFile* f)
     318                 :            :         {
     319         [ #  # ]:          0 :         if ( ! f->Write(fmt("\n<<gap %d>>\n", seq_delta(upper_seq, start_seq))) )
     320                 :            :                 // ### this should really generate an event
     321                 :          0 :                 internal_error("contents gap write failed");
     322                 :          0 :         }
     323                 :            : 
     324                 :       8418 : void TCP_Reassembler::BlockInserted(DataBlock* start_block)
     325                 :            :         {
     326 [ +  + ][ +  + ]:       8418 :         if ( seq_delta(start_block->seq, last_reassem_seq) > 0 ||
                 [ +  + ]
     327                 :            :              seq_delta(start_block->upper, last_reassem_seq) <= 0 )
     328                 :        791 :                 return;
     329                 :            : 
     330                 :            :         // We've filled a leading hole.  Deliver as much as possible.
     331                 :            :         // Note that the new block may include both some old stuff
     332                 :            :         // and some new stuff.  AddAndCheck() will have split the
     333                 :            :         // new stuff off into its own block(s), but in the following
     334                 :            :         // loop we have to take care not to deliver already-delivered
     335                 :            :         // data.
     336 [ +  + ][ +  + ]:      15589 :         for ( DataBlock* b = start_block;
                 [ +  + ]
     337                 :            :               b && seq_delta(b->seq, last_reassem_seq) <= 0; b = b->next )
     338                 :            :                 {
     339         [ +  - ]:       7962 :                 if ( b->seq == last_reassem_seq )
     340                 :            :                         { // New stuff.
     341                 :       7962 :                         int len = b->Size();
     342                 :       7962 :                         int seq = last_reassem_seq;
     343                 :            : 
     344                 :       7962 :                         last_reassem_seq += len;
     345                 :            : 
     346         [ -  + ]:       7962 :                         if ( record_contents_file )
     347                 :          0 :                                 RecordBlock(b, record_contents_file);
     348                 :            : 
     349                 :       7962 :                         DeliverBlock(seq, len, b->block);
     350                 :            :                         }
     351                 :            :                 }
     352                 :            : 
     353                 :       7627 :         TCP_Endpoint* e = endp;
     354                 :            : 
     355         [ -  + ]:       7627 :         if ( ! e->peer->HasContents() )
     356                 :            :                 // Our endpoint's peer doesn't do reassembly and so
     357                 :            :                 // (presumably) isn't processing acks.  So don't hold
     358                 :            :                 // the now-delivered data.
     359                 :          0 :                 TrimToSeq(last_reassem_seq);
     360                 :            : 
     361 [ +  + ][ +  - ]:       7627 :         else if ( e->NoDataAcked() && tcp_max_initial_window &&
         [ +  + ][ +  + ]
     362                 :            :                   e->Size() > tcp_max_initial_window )
     363                 :            :                 // We've sent quite a bit of data, yet none of it has
     364                 :            :                 // been acked.  Presume that we're not seeing the peer's
     365                 :            :                 // acks (perhaps due to filtering or split routing) and
     366                 :            :                 // don't hang onto the data further, as we may wind up
     367                 :            :                 // carrying it all the way until this connection ends.
     368                 :       8418 :                 TrimToSeq(last_reassem_seq);
     369                 :            : 
     370                 :            :         // Note: don't make an EOF check here, because then we'd miss it
     371                 :            :         // for FIN packets that don't carry any payload (and thus
     372                 :            :         // endpoint->DataSent is not called).  Instead, do the check in
     373                 :            :         // TCP_Connection::NextPacket.
     374                 :            :         }
     375                 :            : 
     376                 :        235 : void TCP_Reassembler::Overlap(const u_char* b1, const u_char* b2, int n)
     377                 :            :         {
     378                 :            :         if ( DEBUG_tcp_contents )
     379                 :            :                 DEBUG_MSG("%.6f TCP contents overlap: %d\n", network_time,  n);
     380                 :            : 
     381 [ +  - ][ -  + ]:        235 :         if ( rexmit_inconsistency &&
         [ #  # ][ #  # ]
                 [ -  + ]
     382                 :            :              memcmp((const void*) b1, (const void*) b2, n) &&
     383                 :            :              // The following weeds out keep-alives for which that's all
     384                 :            :              // we've ever seen for the connection.
     385                 :            :              (n > 1 || endp->peer->HasDoneSomething()) )
     386                 :            :                 {
     387                 :          0 :                 BroString* b1_s = new BroString((const u_char*) b1, n, 0);
     388                 :          0 :                 BroString* b2_s = new BroString((const u_char*) b2, n, 0);
     389                 :            :                 tcp_analyzer->Event(rexmit_inconsistency,
     390                 :          0 :                                         new StringVal(b1_s), new StringVal(b2_s));
     391                 :            :                 }
     392                 :        235 :         }
     393                 :            : 
     394                 :          3 : IMPLEMENT_SERIAL(TCP_Reassembler, SER_TCP_REASSEMBLER);
     395                 :            : 
     396                 :          0 : bool TCP_Reassembler::DoSerialize(SerialInfo* info) const
     397                 :            :         {
     398                 :          0 :         internal_error("TCP_Reassembler::DoSerialize not implemented");
     399                 :            :         }
     400                 :            : 
     401                 :          0 : bool TCP_Reassembler::DoUnserialize(UnserialInfo* info)
     402                 :            :         {
     403                 :          0 :         internal_error("TCP_Reassembler::DoUnserialize not implemented");
     404                 :            :         }
     405                 :            : 
     406                 :       7962 : void TCP_Reassembler::Deliver(int seq, int len, const u_char* data)
     407                 :            :         {
     408         [ -  + ]:       7962 :         if ( type == Direct )
     409                 :          0 :                 dst_analyzer->NextStream(len, data, is_orig);
     410                 :            :         else
     411                 :       7962 :                 dst_analyzer->ForwardStream(len, data, is_orig);
     412                 :       7962 :         }
     413                 :            : 
     414                 :            : int TCP_Reassembler::DataSent(double t, int seq, int len,
     415                 :       9174 :                                 const u_char* data, bool replaying)
     416                 :            :         {
     417                 :       9174 :         int ack = seq_delta(endp->AckSeq(), endp->StartSeq());
     418                 :       9174 :         int upper_seq = seq + len;
     419                 :            : 
     420                 :            :         if ( DEBUG_tcp_contents )
     421                 :            :                 {
     422                 :            :                 DEBUG_MSG("%.6f DataSent: seq=%d upper=%d ack=%d\n",
     423                 :            :                           network_time, seq, upper_seq, ack);
     424                 :            :                 }
     425                 :            : 
     426         [ +  + ]:       9174 :         if ( skip_deliveries )
     427                 :        622 :                 return 0;
     428                 :            : 
     429 [ +  + ][ -  + ]:       8552 :         if ( seq_delta(seq, ack) < 0 && ! replaying )
                 [ -  + ]
     430                 :            :                 {
     431         [ #  # ]:          0 :                 if ( seq_delta(upper_seq, ack) <= 0 )
     432                 :            :                         // We've already delivered this and it's been acked.
     433                 :          0 :                         return 0;
     434                 :            : 
     435                 :            :                 // We've seen an ack for part of this packet, but not the
     436                 :            :                 // whole thing.  This can happen when, for example, a previous
     437                 :            :                 // packet held [a, a+b) and this packet holds [a, a+c) for c>b
     438                 :            :                 // (which some TCP's will do when retransmitting).  Trim the
     439                 :            :                 // packet to just the unacked data.
     440                 :          0 :                 int amount_acked = seq_delta(ack, seq);
     441                 :          0 :                 seq += amount_acked;
     442                 :          0 :                 data += amount_acked;
     443                 :          0 :                 len -= amount_acked;
     444                 :            :                 }
     445                 :            : 
     446                 :       8552 :         NewBlock(t, seq, len, data);
     447                 :            : 
     448   [ +  +  +  - ]:       8552 :         if ( Endpoint()->NoDataAcked() && tcp_max_above_hole_without_any_acks &&
         [ +  + ][ +  + ]
     449                 :            :              NumUndeliveredBytes() > tcp_max_above_hole_without_any_acks )
     450                 :            :                 {
     451                 :         12 :                 tcp_analyzer->Weird("above_hole_data_without_any_acks");
     452                 :         12 :                 ClearBlocks();
     453                 :         12 :                 skip_deliveries = 1;
     454                 :            :                 }
     455                 :            : 
     456 [ +  - ][ -  + ]:       8552 :         if ( tcp_excessive_data_without_further_acks &&
                 [ -  + ]
     457                 :            :              NumUndeliveredBytes() > tcp_excessive_data_without_further_acks )
     458                 :            :                 {
     459                 :          0 :                 tcp_analyzer->Weird("excessive_data_without_further_acks");
     460                 :          0 :                 ClearBlocks();
     461                 :          0 :                 skip_deliveries = 1;
     462                 :            :                 }
     463                 :            : 
     464                 :       9174 :         return 1;
     465                 :            :         }
     466                 :            : 
     467                 :            : 
     468                 :      17321 : void TCP_Reassembler::AckReceived(int seq)
     469                 :            :         {
     470 [ +  + ][ +  + ]:      17321 :         if ( endp->FIN_cnt > 0 && seq_delta(seq, endp->FIN_seq) >= 0 )
                 [ +  + ]
     471                 :            :                 // TrimToSeq: FIN_seq - 1
     472                 :       1137 :                 seq = endp->FIN_seq - 1;
     473                 :            : 
     474                 :      17321 :         int bytes_covered = seq_delta(seq, trim_seq);
     475                 :            : 
     476         [ +  + ]:      17321 :         if ( bytes_covered <= 0 )
     477                 :            :                 // Zero, or negative in sequence-space terms.  Nothing to do.
     478                 :      11651 :                 return;
     479                 :            : 
     480                 :            :         bool test_active =
     481                 :            :              ! skip_deliveries && ! tcp_analyzer->Skipping() &&
     482                 :            :              endp->state == TCP_ENDPOINT_ESTABLISHED &&
     483 [ +  + ][ +  - ]:       5670 :              endp->peer->state == TCP_ENDPOINT_ESTABLISHED;
         [ +  + ][ +  + ]
     484                 :            : 
     485                 :       5670 :         int num_missing = TrimToSeq(seq);
     486                 :            : 
     487         [ +  + ]:       5670 :         if ( test_active )
     488                 :            :                 {
     489                 :       2766 :                 ++tot_ack_events;
     490                 :       2766 :                 tot_ack_bytes += bytes_covered;
     491                 :            : 
     492         [ +  + ]:       2766 :                 if ( num_missing > 0 )
     493                 :            :                         {
     494                 :        206 :                         ++tot_gap_events;
     495                 :        206 :                         tot_gap_bytes += num_missing;
     496                 :        206 :                         tcp_analyzer->Event(ack_above_hole);
     497                 :            :                         }
     498                 :            : 
     499                 :       2766 :                 double dt = network_time - last_gap_report;
     500                 :            : 
     501 [ -  + ][ #  # ]:       2766 :                 if ( gap_report && gap_report_freq > 0.0 &&
         [ #  # ][ -  + ]
     502                 :            :                      dt >= gap_report_freq )
     503                 :            :                         {
     504                 :          0 :                         int devents = tot_ack_events - last_ack_events;
     505                 :          0 :                         int dbytes = tot_ack_bytes - last_ack_bytes;
     506                 :          0 :                         int dgaps = tot_gap_events - last_gap_events;
     507                 :          0 :                         int dgap_bytes = tot_gap_bytes - last_gap_bytes;
     508                 :            : 
     509                 :          0 :                         RecordVal* r = new RecordVal(gap_info);
     510                 :          0 :                         r->Assign(0, new Val(devents, TYPE_COUNT));
     511                 :          0 :                         r->Assign(1, new Val(dbytes, TYPE_COUNT));
     512                 :          0 :                         r->Assign(2, new Val(dgaps, TYPE_COUNT));
     513                 :          0 :                         r->Assign(3, new Val(dgap_bytes, TYPE_COUNT));
     514                 :            : 
     515                 :          0 :                         val_list* vl = new val_list;
     516                 :          0 :                         vl->append(new IntervalVal(dt, Seconds));
     517                 :          0 :                         vl->append(r);
     518                 :            : 
     519                 :          0 :                         mgr.QueueEvent(gap_report, vl);
     520                 :            : 
     521                 :          0 :                         last_gap_report = network_time;
     522                 :          0 :                         last_ack_events = tot_ack_events;
     523                 :          0 :                         last_ack_bytes = tot_ack_bytes;
     524                 :          0 :                         last_gap_events = tot_gap_events;
     525                 :          0 :                         last_gap_bytes = tot_gap_bytes;
     526                 :            :                         }
     527                 :            :                 }
     528                 :            : 
     529                 :            :         // Check EOF here because t_reassem->LastReassemSeq() may have
     530                 :            :         // changed after calling TrimToSeq().
     531                 :      17321 :         CheckEOF();
     532                 :            :         }
     533                 :            : 
     534                 :      23646 : void TCP_Reassembler::CheckEOF()
     535                 :            :         {
     536                 :            :         // It is important that the check on whether we have pending data here
     537                 :            :         // is consistent with the check in TCP_Connection::ConnnectionClosed().
     538                 :            :         //
     539                 :            :         // If we choose to call EndpointEOF here because, for example, we
     540                 :            :         // are already skipping deliveries, ConnnectionClosed() might decide
     541                 :            :         // that there is still DataPending, because it does not check
     542                 :            :         // SkipDeliveries(), and the connection will not be closed until
     543                 :            :         // timeout, since the did_EOF flag makes sure that EndpointEOF will
     544                 :            :         // be called only once.
     545                 :            :         //
     546                 :            :         // Now both places call TCP_Reassembler::DataPending(), which checks
     547                 :            :         // whether we are skipping deliveries.
     548                 :            : 
     549 [ +  + ][ +  + ]:      23646 :         if ( ! did_EOF &&
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
     550                 :            :              (endp->FIN_cnt > 0 || endp->state == TCP_ENDPOINT_CLOSED ||
     551                 :            :                                    endp->state == TCP_ENDPOINT_RESET) &&
     552                 :            :              ! DataPending() )
     553                 :            :                 {
     554                 :            :                 // We've now delivered all of the data.
     555                 :            :                 if ( DEBUG_tcp_connection_close )
     556                 :            :                         {
     557                 :            :                         DEBUG_MSG("%.6f EOF for %d\n",
     558                 :            :                                   network_time, endp->IsOrig());
     559                 :            :                         }
     560                 :            : 
     561                 :       1010 :                 did_EOF = 1;
     562                 :       1010 :                 tcp_analyzer->EndpointEOF(this);
     563                 :            :                 }
     564                 :      23646 :         }
     565                 :            : 
     566                 :            : // DeliverBlock is basically a relay to function Deliver. But unlike
     567                 :            : // Deliver, DeliverBlock is not virtual, and this allows us to insert
     568                 :            : // operations that apply to all connections using TCP_Contents.
     569                 :            : 
     570                 :       7962 : void TCP_Reassembler::DeliverBlock(int seq, int len, const u_char* data)
     571                 :            :         {
     572         [ -  + ]:       7962 :         if ( seq_delta(seq + len, seq_to_skip) <= 0 )
     573                 :          0 :                 return;
     574                 :            : 
     575         [ -  + ]:       7962 :         if ( seq_delta(seq, seq_to_skip) < 0 )
     576                 :            :                 {
     577                 :          0 :                 int to_skip = seq_delta(seq_to_skip, seq);
     578                 :          0 :                 len -= to_skip;
     579                 :          0 :                 data += to_skip;
     580                 :          0 :                 seq = seq_to_skip;
     581                 :            :                 }
     582                 :            : 
     583         [ -  + ]:       7962 :         if ( deliver_tcp_contents )
     584                 :            :                 {
     585                 :          0 :                 val_list* vl = new val_list();
     586                 :          0 :                 vl->append(tcp_analyzer->BuildConnVal());
     587                 :          0 :                 vl->append(new Val(IsOrig(), TYPE_BOOL));
     588                 :          0 :                 vl->append(new Val(seq, TYPE_COUNT));
     589                 :          0 :                 vl->append(new StringVal(len, (const char*) data));
     590                 :            : 
     591                 :          0 :                 tcp_analyzer->ConnectionEvent(tcp_contents, vl);
     592                 :            :                 }
     593                 :            : 
     594                 :            :         // Q. Can we say this because it is already checked in DataSent()?
     595                 :            :         // ASSERT(!Conn()->Skipping() && !SkipDeliveries());
     596                 :            :         //
     597                 :            :         // A. No, because TrimToSeq() can deliver some blocks after
     598                 :            :         // skipping the undelivered.
     599                 :            : 
     600         [ -  + ]:       7962 :         if ( skip_deliveries )
     601                 :          0 :                 return;
     602                 :            : 
     603                 :       7962 :         in_delivery = true;
     604                 :       7962 :         Deliver(seq, len, data);
     605                 :       7962 :         in_delivery = false;
     606                 :            : 
     607         [ -  + ]:       7962 :         if ( seq_delta(seq + len, seq_to_skip) < 0 )
     608                 :       7962 :                 SkipToSeq(seq_to_skip);
     609                 :            :         }
     610                 :            : 
     611                 :          0 : void TCP_Reassembler::SkipToSeq(int seq)
     612                 :            :         {
     613         [ #  # ]:          0 :         if ( seq_delta(seq, seq_to_skip) > 0 )
     614                 :            :                 {
     615                 :          0 :                 seq_to_skip = seq;
     616         [ #  # ]:          0 :                 if ( ! in_delivery )
     617                 :          0 :                         TrimToSeq(seq);
     618                 :            :                 }
     619                 :          0 :         }
     620                 :            : 
     621                 :       2288 : int TCP_Reassembler::DataPending() const
     622                 :            :         {
     623                 :            :         // If we are skipping deliveries, the reassembler will not get called
     624                 :            :         // in DataSent(), and DataSeq() will not be updated.
     625         [ +  + ]:       2288 :         if ( skip_deliveries )
     626                 :         18 :                 return 0;
     627                 :            : 
     628                 :       2270 :         uint32 delivered_seq = Endpoint()->StartSeq() + DataSeq();
     629                 :            : 
     630                 :            :         // Q. Can we say that?
     631                 :            :         // ASSERT(delivered_seq <= Endpoint()->LastSeq());
     632                 :            :         //
     633                 :            :         // A. Yes, but only if we express it with 64-bit comparison
     634                 :            :         // to handle sequence wrapping around.  (Or perhaps seq_delta
     635                 :            :         // is enough here?)
     636                 :            : 
     637                 :            :         // We've delivered everything if we're up to the penultimate
     638                 :            :         // sequence number (since a FIN consumes an octet in the
     639                 :            :         // sequence space), or right at it (because a RST does not).
     640   [ +  +  +  + ]:       2270 :         if ( delivered_seq != Endpoint()->LastSeq() - 1 &&
                 [ +  + ]
     641                 :            :              delivered_seq != Endpoint()->LastSeq() )
     642                 :         78 :                 return 1;
     643                 :            : 
     644                 :            :         // If we've sent RST, then we can't send ACKs any more.
     645 [ +  + ][ +  + ]:       2192 :         if ( Endpoint()->state != TCP_ENDPOINT_RESET &&
                 [ +  + ]
     646                 :            :              Endpoint()->peer->HasUndeliveredData() )
     647                 :        138 :                 return 1;
     648                 :            : 
     649                 :       2288 :         return 0;
     650 [ +  - ][ +  - ]:          6 :         }

Generated by: LCOV version 1.8