Adds wall time field to events
[lttv.git] / lttv / lttv / sync / data_structures.c
CommitLineData
70407e86
BP
1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2009 Benjamin Poirier <benjamin.poirier@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#include <arpa/inet.h>
24#include <glib.h>
25#include <stdint.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
08365995
BP
30#include <unistd.h>
31
70407e86
BP
32#include "lookup3.h"
33
10341d26 34#include "data_structures.h"
70407e86
BP
35
36
37#ifndef g_info
38#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
39#endif
40
41// TCP sequence numbers use clock arithmetic, these comparison functions take
42// that into account
43#define SEQ_LT(a,b) ((int32_t)((a)-(b)) < 0)
44#define SEQ_LEQ(a,b) ((int32_t)((a)-(b)) <= 0)
45#define SEQ_GT(a,b) ((int32_t)((a)-(b)) > 0)
46#define SEQ_GEQ(a,b) ((int32_t)((a)-(b)) >= 0)
47
48
49/*
50 * Compare two ConnectionKey structures
51 *
52 * Returns:
53 * true if each field of the structure is equal
54 * false otherwise
55 */
56bool connectionKeyEqual(const ConnectionKey* const a, const
57 ConnectionKey* const b)
58{
59 if (a->saddr == b->saddr && a->daddr == b->daddr && a->source == b->source
60 && a->dest == b->dest)
61 {
62 return true;
63 }
64 else
65 {
66 return false;
67 }
68}
69
70
71/*
72 * Check if a packet is an acknowledge of another packet.
73 *
74 * Args:
10341d26
BP
75 * ackSegment packet that is the confirmation
76 * ackedSegment packet that contains the original data, both packets have to
77 * come from the same direction of the same connection. Both
78 * messages have to contain TCP events.
70407e86 79 */
10341d26
BP
80bool isAcking(const Message* const ackSegment, const Message* const
81 ackedSegment)
70407e86 82{
10341d26
BP
83 g_assert(ackSegment->inE->type == TCP);
84 g_assert(ackSegment->outE->type == TCP);
85
86 if (SEQ_GT(ackSegment->inE->event.tcpEvent->segmentKey->ack_seq,
87 ackedSegment->inE->event.tcpEvent->segmentKey->seq))
70407e86
BP
88 {
89 return true;
90 }
91 else
92 {
93 return false;
94 }
95}
96
97
98/*
99 * Convert an IP address from 32 bit form to dotted quad
100 *
101 * Args:
102 * str: A preallocated string of length >= 17
103 * addr: Address
104 */
105void convertIP(char* const str, const uint32_t addr)
106{
107 struct in_addr iaddr;
108
109 iaddr.s_addr= htonl(addr);
110 strcpy(str, inet_ntoa(iaddr));
111}
112
113
114/*
10341d26 115 * Print the content of a TCP Message structure
70407e86 116 */
10341d26 117void printTCPSegment(const Message* const segment)
70407e86
BP
118{
119 char saddr[17], daddr[17];
10341d26
BP
120 SegmentKey* segmentKey;
121
122 g_assert(segment->inE->type == TCP);
123 g_assert(segment->inE->event.tcpEvent->segmentKey ==
124 segment->outE->event.tcpEvent->segmentKey);
70407e86 125
10341d26 126 segmentKey= segment->inE->event.tcpEvent->segmentKey;
70407e86 127
10341d26
BP
128 convertIP(saddr, segmentKey->connectionKey.saddr);
129 convertIP(daddr, segmentKey->connectionKey.daddr);
70407e86
BP
130 g_debug("%s:%u to %s:%u tot_len: %u ihl: %u seq: %u ack_seq: %u doff: %u "
131 "ack: %u rst: %u syn: %u fin: %u", saddr,
10341d26
BP
132 segmentKey->connectionKey.source, daddr, segmentKey->connectionKey.dest,
133 segmentKey->tot_len, segmentKey->ihl, segmentKey->seq,
134 segmentKey->ack_seq, segmentKey->doff, segmentKey->ack, segmentKey->rst,
135 segmentKey->syn, segmentKey->fin);
70407e86
BP
136}
137
138
139/*
140 * A GHashFunc for g_hash_table_new()
141 *
10341d26
BP
142 * This function is for indexing TCPEvents in unMatched lists. All fields of
143 * the corresponding SegmentKey must match for two keys to be equal.
70407e86
BP
144 *
145 * Args:
10341d26
BP
146 * key SegmentKey*
147 *
148 * Returns:
149 * A hash of all fields in the SegmentKey
70407e86 150 */
10341d26 151guint ghfSegmentKeyHash(gconstpointer key)
70407e86 152{
10341d26 153 const SegmentKey* p;
70407e86
BP
154 uint32_t a, b, c;
155
10341d26 156 p= (SegmentKey*) key;
70407e86
BP
157
158 a= p->connectionKey.source + (p->connectionKey.dest << 16);
159 b= p->connectionKey.saddr;
160 c= p->connectionKey.daddr;
161 mix(a, b, c);
162
163 a+= p->ihl + (p->tot_len << 8) + (p->doff << 24);
164 b+= p->seq;
165 c+= p->ack_seq;
166 mix(a, b, c);
167
168 a+= p->ack + (p->rst << 8) + (p->syn << 16) + (p->fin << 24);
169 final(a, b, c);
170
10341d26
BP
171 g_debug("segment key hash %p: %u", p, c);
172
70407e86
BP
173 return c;
174}
175
176
177/*
178 * A GEqualFunc for g_hash_table_new()
179 *
10341d26
BP
180 * This function is for indexing TCPEvents in unMatched lists. All fields of
181 * the corresponding SegmentKey must match for two keys to be equal.
70407e86
BP
182 *
183 * Args:
10341d26 184 * a, b SegmentKey*
70407e86
BP
185 *
186 * Returns:
187 * TRUE if both values are equal
188 */
10341d26 189gboolean gefSegmentKeyEqual(gconstpointer a, gconstpointer b)
70407e86 190{
10341d26
BP
191 const SegmentKey* sA, * sB;
192
193 sA= (SegmentKey*) a;
194 sB= (SegmentKey*) b;
195
196 if (connectionKeyEqual(&sA->connectionKey, &sB->connectionKey) &&
197 sA->ihl == sB->ihl &&
198 sA->tot_len == sB->tot_len &&
199 sA->seq == sB->seq &&
200 sA->ack_seq == sB->ack_seq &&
201 sA->doff == sB->doff &&
202 sA->ack == sB->ack &&
203 sA->rst == sB->rst &&
204 sA->syn == sB->syn &&
205 sA->fin == sB->fin)
70407e86 206 {
10341d26 207 g_debug("segment key equal %p %p: TRUE", sA, sB);
70407e86
BP
208 return TRUE;
209 }
210 else
211 {
10341d26 212 g_debug("segment key equal %p %p: FALSE", sA, sB);
70407e86
BP
213 return FALSE;
214 }
215}
216
217
218/*
219 * A GDestroyNotify function for g_hash_table_new_full()
220 *
221 * Args:
10341d26 222 * data: Event*
70407e86 223 */
10341d26 224void gdnDestroyEvent(gpointer data)
70407e86 225{
10341d26
BP
226 Event* event= data;
227
228 event->destroy(event);
70407e86
BP
229}
230
231
232/*
233 * A GDestroyNotify function for g_hash_table_new_full()
234 *
235 * Args:
236 * data: GQueue* list[Packet]
237 */
10341d26 238void gdnTCPSegmentListDestroy(gpointer data)
70407e86
BP
239{
240 GQueue* list;
241
242 list= (GQueue*) data;
243
10341d26 244 g_debug("XXXX gdnTCPSegmentListDestroy\n");
70407e86 245
10341d26 246 g_queue_foreach(list, &gfTCPSegmentDestroy, NULL);
70407e86
BP
247 g_queue_free(list);
248}
249
250
251/*
252 * A GFunc for g_queue_foreach()
253 *
254 * Args:
10341d26 255 * data Message*, TCP message to destroy
70407e86
BP
256 * user_data NULL
257 */
10341d26 258void gfTCPSegmentDestroy(gpointer data, gpointer user_data)
70407e86 259{
10341d26
BP
260 g_debug("XXXX gfTCPSegmentDestroy\n");
261 destroyTCPSegment((Message*) data);
70407e86
BP
262}
263
264
265/*
10341d26 266 * Free the memory used by a TCP Message and the memory of all its associated
70407e86 267 * resources
10341d26
BP
268 *
269 * Args:
270 * segment TCP Message to destroy
70407e86 271 */
10341d26 272void destroyTCPSegment(Message* const segment)
70407e86 273{
10341d26
BP
274 TCPEvent* inE, *outE;
275
276 g_debug("XXXX destroyTCPSegment");
277 segment->print(segment);
70407e86 278
10341d26
BP
279 g_assert(segment->inE != NULL && segment->outE != NULL);
280 g_assert(segment->inE->type == TCP && segment->outE->type == TCP);
281 inE= segment->inE->event.tcpEvent;
282 outE= segment->outE->event.tcpEvent;
283 g_assert(inE->segmentKey == outE->segmentKey);
70407e86 284
10341d26 285 outE->segmentKey= NULL;
70407e86 286
10341d26
BP
287 destroyTCPEvent(segment->inE);
288 destroyTCPEvent(segment->outE);
70407e86 289
10341d26
BP
290 free(segment);
291}
292
293
294/*
295 * Free the memory used by a TCP Exchange and the memory of SOME of its
296 * associated resources. The message is not destroyed. Use destroyTCPSegment()
297 * to free it.
298 *
299 * Args:
300 * exchange TCP Exchange to destroy. The .message must be NULL
301 */
302void destroyTCPExchange(Exchange* const exchange)
303{
304 g_assert(exchange->message == NULL);
305
306 if (exchange->acks != NULL)
70407e86 307 {
10341d26
BP
308 g_queue_foreach(exchange->acks, &gfTCPSegmentDestroy, NULL);
309 g_queue_free(exchange->acks);
70407e86
BP
310 }
311
10341d26 312 free(exchange);
70407e86
BP
313}
314
315
316/*
10341d26 317 * Free the memory used by a TCP Event and its associated resources
70407e86 318 */
10341d26 319void destroyTCPEvent(Event* const event)
70407e86 320{
10341d26 321 g_assert(event->type == TCP);
70407e86 322
10341d26 323 if (event->event.tcpEvent->segmentKey != NULL)
70407e86 324 {
10341d26 325 free(event->event.tcpEvent->segmentKey);
70407e86 326 }
10341d26
BP
327 free(event->event.tcpEvent);
328 event->event.tcpEvent= NULL;
329 destroyEvent(event);
330}
331
332/*
333 * Free the memory used by a base Event
334 */
335void destroyEvent(Event* const event)
336{
337 g_assert(event->event.tcpEvent == NULL);
338
70407e86
BP
339 free(event);
340}
341
342
10341d26
BP
343/*
344 * Free the memory used by a UDP Event and its associated resources
345 */
346void destroyUDPEvent(Event* const event)
347{
348 g_assert(event->type == UDP);
349
350 if (event->event.udpEvent->datagramKey != NULL)
351 {
352 free(event->event.udpEvent->datagramKey);
353 }
354 free(event->event.udpEvent);
355 event->event.udpEvent= NULL;
356 destroyEvent(event);
357}
358
359
70407e86
BP
360/*
361 * A GCompareFunc for g_queue_find_custom()
362 *
363 * Args:
10341d26
BP
364 * a Message* acked packet
365 * b Message* ack packet
70407e86
BP
366 *
367 * Returns:
368 * 0 if b acks a
369 */
10341d26 370gint gcfTCPSegmentAckCompare(gconstpointer a, gconstpointer b)
70407e86 371{
10341d26 372 if (isAcking((const Message*) b, (const Message*) a))
70407e86
BP
373 {
374 return 0;
375 }
376 else
377 {
378 return 1;
379 }
380}
381
382
383/*
384 * A GHashFunc for g_hash_table_new()
385 *
386 * Hash TCP connection keys. Here are a few possible implementations:
387 *
388 * 2.4 kernels used tcp_hashfn()
389 *
390 * I've seen something about an XOR hash:
391 * http://tservice.net.ru/~s0mbre/blog/2006/05/14#2006_05_14:
392 * unsigned int h = (laddr ^ lport) ^ (faddr ^ fport);
393 * h ^= h >> 16;
394 * h ^= h >> 8;
395 * return h;
396 *
397 * In 2.6 kernels, inet_ehashfn() handles connection hashing with the help of
398 * Jenkins hashing, jhash.h
399 *
400 * This function uses jenkins hashing. The hash is not the same for packets in
401 * opposite directions of the same connection. (Hence the name
402 * connection*key*hash)
403 *
404 * Args:
405 * key ConnectionKey*
406 */
407guint ghfConnectionKeyHash(gconstpointer key)
408{
409 ConnectionKey* connectionKey;
410 uint32_t a, b, c;
411
412 connectionKey= (ConnectionKey*) key;
413
414 a= connectionKey->source + (connectionKey->dest << 16);
415 b= connectionKey->saddr;
416 c= connectionKey->daddr;
417 final(a, b, c);
418
419 return c;
420}
421
422
423/*
424 * A GEqualFunc for g_hash_table_new()
425 *
426 * Args:
427 * a, b ConnectionKey*
428 *
429 * Returns:
430 * TRUE if both values are equal
431 */
432gboolean gefConnectionKeyEqual(gconstpointer a, gconstpointer b)
433{
434 // Two packets in the same direction
435 if (connectionKeyEqual((const ConnectionKey*) a, (const ConnectionKey*) b))
436 {
437 return TRUE;
438 }
439 else
440 {
441 return FALSE;
442 }
443}
444
445
446/*
447 * A GDestroyNotify function for g_hash_table_new_full()
448 *
449 * Args:
450 * data: ConnectionKey*
451 */
452void gdnConnectionKeyDestroy(gpointer data)
453{
454 free((ConnectionKey*) data);
455}
f6691532
BP
456
457
458/*
459 * A GHashFunc for g_hash_table_new()
460 *
461 * Args:
462 * key DatagramKey*
463 */
464guint ghfDatagramKeyHash(gconstpointer key)
465{
466 DatagramKey* datagramKey;
467 uint32_t a, b, c;
468
469 datagramKey= (DatagramKey*) key;
470
471 a= datagramKey->saddr;
472 b= datagramKey->daddr;
473 c= datagramKey->source + (datagramKey->dest << 16);
474 mix(a, b, c);
475
476 a+= datagramKey->ulen; // 16 bits left here
477 b+= *((uint32_t*) datagramKey->dataKey);
478 c+= *((uint32_t*) ((void*) datagramKey->dataKey + 4));
479 final(a, b, c);
480
481 return c;
482}
483
484
485/*
486 * A GEqualFunc for g_hash_table_new()
487 *
488 * Args:
489 * a, b DatagramKey*
490 *
491 * Returns:
492 * TRUE if both values are equal
493 */
494gboolean gefDatagramKeyEqual(gconstpointer a, gconstpointer b)
495{
496 const DatagramKey* dA, * dB;
497
498 dA= (DatagramKey*) a;
499 dB= (DatagramKey*) b;
500
501 if (dA->saddr == dB->saddr && dA->daddr == dB->daddr &&
502 dA->source == dB->source && dA->dest == dB->dest &&
503 dA->ulen == dB->ulen &&
504 memcmp(dA->dataKey, dB->dataKey, sizeof(dA->dataKey)) == 0)
505 {
506 return TRUE;
507 }
508 else
509 {
510 return FALSE;
511 }
512}
513
514
515/*
516 * A GDestroyNotify function for g_hash_table_new_full()
517 *
518 * Args:
519 * data: DatagramKey*
520 */
521void gdnDestroyDatagramKey(gpointer data)
522{
523 free((DatagramKey*) data);
524}
525
526
527/*
528 * A GDestroyNotify function for g_hash_table_new_full()
529 *
530 * Args:
531 * data: Broadcast*
532 */
533void gdnDestroyBroadcast(gpointer data)
534{
535 destroyBroadcast((Broadcast*) data);
536}
537
538
539/*
540 * Free a Broadcast struct and its associated ressources
541 *
542 * Args:
543 * broadcast: Broadcast*
544 */
545void destroyBroadcast(Broadcast* const broadcast)
546{
547 g_queue_foreach(broadcast->events, &gfDestroyEvent, NULL);
548 g_queue_clear(broadcast->events);
549 free(broadcast);
550}
551
552
553/*
554 * A GFunc for g_queue_foreach()
555 *
556 * Args:
557 * data Event*
558 * user_data NULL
559 */
560void gfDestroyEvent(gpointer data, gpointer user_data)
561{
562 Event* event= data;
563
564 event->destroy(event);
565}
76be6fc2
BP
566
567
568/* Subtract two WallTime structs
569 *
570 * Args:
571 * tA, tB: WallTime
572 *
573 * Returns:
574 * The result of tA - tB, as a double. This may incur a loss of
575 * precision.
576 */
577double wallTimeSub(const WallTime const* tA, const WallTime const* tB)
578{
579 return tA->seconds - tB->seconds + (tA->nanosec - tB->nanosec) / 1e9;
580}
This page took 0.047744 seconds and 4 git commands to generate.