1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2009 Benjamin Poirier <benjamin.poirier@polymtl.ca>
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;
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.
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,
23 #include <arpa/inet.h>
34 #include "data_structures.h"
38 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
41 // TCP sequence numbers use clock arithmetic, these comparison functions take
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)
50 * Compare two ConnectionKey structures
53 * true if each field of the structure is equal
56 bool connectionKeyEqual(const ConnectionKey
* const a
, const
57 ConnectionKey
* const b
)
59 if (a
->saddr
== b
->saddr
&& a
->daddr
== b
->daddr
&& a
->source
== b
->source
60 && a
->dest
== b
->dest
)
72 * Check if a packet is an acknowledge of another packet.
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.
80 bool isAcking(const Message
* const ackSegment
, const Message
* const
83 g_assert(ackSegment
->inE
->type
== TCP
);
84 g_assert(ackSegment
->outE
->type
== TCP
);
86 if (SEQ_GT(ackSegment
->inE
->event
.tcpEvent
->segmentKey
->ack_seq
,
87 ackedSegment
->inE
->event
.tcpEvent
->segmentKey
->seq
))
99 * Convert an IP address from 32 bit form to dotted quad
102 * str: A preallocated string of length >= 17
105 void convertIP(char* const str
, const uint32_t addr
)
107 struct in_addr iaddr
;
109 iaddr
.s_addr
= htonl(addr
);
110 strcpy(str
, inet_ntoa(iaddr
));
115 * Print the content of a TCP Message structure
117 void printTCPSegment(const Message
* const segment
)
119 char saddr
[17], daddr
[17];
120 SegmentKey
* segmentKey
;
122 g_assert(segment
->inE
->type
== TCP
);
123 g_assert(segment
->inE
->event
.tcpEvent
->segmentKey
==
124 segment
->outE
->event
.tcpEvent
->segmentKey
);
126 segmentKey
= segment
->inE
->event
.tcpEvent
->segmentKey
;
128 convertIP(saddr
, segmentKey
->connectionKey
.saddr
);
129 convertIP(daddr
, segmentKey
->connectionKey
.daddr
);
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
,
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
);
140 * A GHashFunc for g_hash_table_new()
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.
149 * A hash of all fields in the SegmentKey
151 guint
ghfSegmentKeyHash(gconstpointer key
)
156 p
= (SegmentKey
*) key
;
158 a
= p
->connectionKey
.source
+ (p
->connectionKey
.dest
<< 16);
159 b
= p
->connectionKey
.saddr
;
160 c
= p
->connectionKey
.daddr
;
163 a
+= p
->ihl
+ (p
->tot_len
<< 8) + (p
->doff
<< 24);
168 a
+= p
->ack
+ (p
->rst
<< 8) + (p
->syn
<< 16) + (p
->fin
<< 24);
171 g_debug("segment key hash %p: %u", p
, c
);
178 * A GEqualFunc for g_hash_table_new()
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.
187 * TRUE if both values are equal
189 gboolean
gefSegmentKeyEqual(gconstpointer a
, gconstpointer b
)
191 const SegmentKey
* sA
, * sB
;
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
&&
207 g_debug("segment key equal %p %p: TRUE", sA
, sB
);
212 g_debug("segment key equal %p %p: FALSE", sA
, sB
);
219 * A GDestroyNotify function for g_hash_table_new_full()
224 void gdnDestroyEvent(gpointer data
)
228 event
->destroy(event
);
233 * A GDestroyNotify function for g_hash_table_new_full()
236 * data: GQueue* list[Packet]
238 void gdnTCPSegmentListDestroy(gpointer data
)
242 list
= (GQueue
*) data
;
244 g_debug("XXXX gdnTCPSegmentListDestroy\n");
246 g_queue_foreach(list
, &gfTCPSegmentDestroy
, NULL
);
252 * A GFunc for g_queue_foreach()
255 * data Message*, TCP message to destroy
258 void gfTCPSegmentDestroy(gpointer data
, gpointer user_data
)
260 g_debug("XXXX gfTCPSegmentDestroy\n");
261 destroyTCPSegment((Message
*) data
);
266 * Free the memory used by a TCP Message and the memory of all its associated
270 * segment TCP Message to destroy
272 void destroyTCPSegment(Message
* const segment
)
274 TCPEvent
* inE
, *outE
;
276 g_debug("XXXX destroyTCPSegment");
277 segment
->print(segment
);
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
);
285 outE
->segmentKey
= NULL
;
287 destroyTCPEvent(segment
->inE
);
288 destroyTCPEvent(segment
->outE
);
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()
300 * exchange TCP Exchange to destroy. The .message must be NULL
302 void destroyTCPExchange(Exchange
* const exchange
)
304 g_assert(exchange
->message
== NULL
);
306 if (exchange
->acks
!= NULL
)
308 g_queue_foreach(exchange
->acks
, &gfTCPSegmentDestroy
, NULL
);
309 g_queue_free(exchange
->acks
);
317 * Free the memory used by a TCP Event and its associated resources
319 void destroyTCPEvent(Event
* const event
)
321 g_assert(event
->type
== TCP
);
323 if (event
->event
.tcpEvent
->segmentKey
!= NULL
)
325 free(event
->event
.tcpEvent
->segmentKey
);
327 free(event
->event
.tcpEvent
);
328 event
->event
.tcpEvent
= NULL
;
333 * Free the memory used by a base Event
335 void destroyEvent(Event
* const event
)
337 g_assert(event
->event
.tcpEvent
== NULL
);
344 * Free the memory used by a UDP Event and its associated resources
346 void destroyUDPEvent(Event
* const event
)
348 g_assert(event
->type
== UDP
);
350 if (event
->event
.udpEvent
->datagramKey
!= NULL
)
352 free(event
->event
.udpEvent
->datagramKey
);
354 free(event
->event
.udpEvent
);
355 event
->event
.udpEvent
= NULL
;
361 * A GCompareFunc for g_queue_find_custom()
364 * a Message* acked packet
365 * b Message* ack packet
370 gint
gcfTCPSegmentAckCompare(gconstpointer a
, gconstpointer b
)
372 if (isAcking((const Message
*) b
, (const Message
*) a
))
384 * A GHashFunc for g_hash_table_new()
386 * Hash TCP connection keys. Here are a few possible implementations:
388 * 2.4 kernels used tcp_hashfn()
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);
397 * In 2.6 kernels, inet_ehashfn() handles connection hashing with the help of
398 * Jenkins hashing, jhash.h
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)
407 guint
ghfConnectionKeyHash(gconstpointer key
)
409 ConnectionKey
* connectionKey
;
412 connectionKey
= (ConnectionKey
*) key
;
414 a
= connectionKey
->source
+ (connectionKey
->dest
<< 16);
415 b
= connectionKey
->saddr
;
416 c
= connectionKey
->daddr
;
424 * A GEqualFunc for g_hash_table_new()
427 * a, b ConnectionKey*
430 * TRUE if both values are equal
432 gboolean
gefConnectionKeyEqual(gconstpointer a
, gconstpointer b
)
434 // Two packets in the same direction
435 if (connectionKeyEqual((const ConnectionKey
*) a
, (const ConnectionKey
*) b
))
447 * A GDestroyNotify function for g_hash_table_new_full()
450 * data: ConnectionKey*
452 void gdnConnectionKeyDestroy(gpointer data
)
454 free((ConnectionKey
*) data
);
This page took 0.078759 seconds and 4 git commands to generate.