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 : }
|