Add convex hull algorithm-based synchronization
[lttv.git] / lttv / lttv / sync / data_structures_tcp.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
34#include "data_structures_tcp.h"
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:
75 * ackPacket packet that is the confirmation
76 * ackedPacket packet that contains the original data, both packets have to
77 * come from the same direction of the same connection
78 */
79bool isAcking(const Packet* const ackPacket, const Packet* const
80 ackedPacket)
81{
82 if (SEQ_GT(ackPacket->inE->packetKey->ack_seq,
83 ackedPacket->inE->packetKey->seq))
84 {
85 return true;
86 }
87 else
88 {
89 return false;
90 }
91}
92
93
94/*
95 * Convert an IP address from 32 bit form to dotted quad
96 *
97 * Args:
98 * str: A preallocated string of length >= 17
99 * addr: Address
100 */
101void convertIP(char* const str, const uint32_t addr)
102{
103 struct in_addr iaddr;
104
105 iaddr.s_addr= htonl(addr);
106 strcpy(str, inet_ntoa(iaddr));
107}
108
109
110/*
111 * Print the content of a Packet structure
112 */
113void printPacket(const Packet* const packet)
114{
115 char saddr[17], daddr[17];
116 PacketKey* packetKey;
117
118 packetKey= packet->inE->packetKey;
119
120 convertIP(saddr, packetKey->connectionKey.saddr);
121 convertIP(daddr, packetKey->connectionKey.daddr);
122 g_debug("%s:%u to %s:%u tot_len: %u ihl: %u seq: %u ack_seq: %u doff: %u "
123 "ack: %u rst: %u syn: %u fin: %u", saddr,
124 packetKey->connectionKey.source, daddr, packetKey->connectionKey.dest,
125 packetKey->tot_len, packetKey->ihl, packetKey->seq,
126 packetKey->ack_seq, packetKey->doff, packetKey->ack, packetKey->rst,
127 packetKey->syn, packetKey->fin);
128}
129
130
131/*
132 * A GHashFunc for g_hash_table_new()
133 *
134 * This function is for indexing netEvents in unMatched lists. All fields of
135 * the corresponding packet must match for two keys to be equal.
136 *
137 * Args:
138 * key PacketKey*
139 */
140guint ghfPacketKeyHash(gconstpointer key)
141{
142 const PacketKey* p;
143 uint32_t a, b, c;
144
145 p= (PacketKey*) key;
146
147 a= p->connectionKey.source + (p->connectionKey.dest << 16);
148 b= p->connectionKey.saddr;
149 c= p->connectionKey.daddr;
150 mix(a, b, c);
151
152 a+= p->ihl + (p->tot_len << 8) + (p->doff << 24);
153 b+= p->seq;
154 c+= p->ack_seq;
155 mix(a, b, c);
156
157 a+= p->ack + (p->rst << 8) + (p->syn << 16) + (p->fin << 24);
158 final(a, b, c);
159
160 return c;
161}
162
163
164/*
165 * A GEqualFunc for g_hash_table_new()
166 *
167 * This function is for indexing netEvents in unMatched lists. All fields of
168 * the corresponding packet must match for two keys to be equal.
169 *
170 * Args:
171 * a, b PacketKey*
172 *
173 * Returns:
174 * TRUE if both values are equal
175 */
176gboolean gefPacketKeyEqual(gconstpointer a, gconstpointer b)
177{
178 const PacketKey* pA, * pB;
179
180 pA= ((PacketKey*) a);
181 pB= ((PacketKey*) b);
182
183 if (connectionKeyEqual(&pA->connectionKey, &pB->connectionKey) &&
184 pA->ihl == pB->ihl &&
185 pA->tot_len == pB->tot_len &&
186 pA->seq == pB->seq &&
187 pA->ack_seq == pB->ack_seq &&
188 pA->doff == pB->doff &&
189 pA->ack == pB->ack &&
190 pA->rst == pB->rst &&
191 pA->syn == pB->syn &&
192 pA->fin == pB->fin)
193 {
194 return TRUE;
195 }
196 else
197 {
198 return FALSE;
199 }
200}
201
202
203/*
204 * A GDestroyNotify function for g_hash_table_new_full()
205 *
206 * Args:
207 * data: NetEvent*
208 */
209void gdnDestroyNetEvent(gpointer data)
210{
211 destroyNetEvent((NetEvent*) data);
212}
213
214
215/*
216 * A GDestroyNotify function for g_hash_table_new_full()
217 *
218 * Args:
219 * data: GQueue* list[Packet]
220 */
221void gdnPacketListDestroy(gpointer data)
222{
223 GQueue* list;
224
225 list= (GQueue*) data;
226
227 g_debug("XXXX gdnPacketListDestroy\n");
228
229 g_queue_foreach(list, &gfPacketDestroy, NULL);
230 g_queue_free(list);
231}
232
233
234/*
235 * A GFunc for g_queue_foreach()
236 *
237 * Args:
238 * data Packet*, packet to destroy
239 * user_data NULL
240 */
241void gfPacketDestroy(gpointer data, gpointer user_data)
242{
243 g_debug("XXXX gfPacketDestroy\n");
244 destroyPacket((Packet*) data);
245}
246
247
248/*
249 * Free the memory used by a Packet and the memory of all its associated
250 * resources
251 */
252void destroyPacket(Packet* const packet)
253{
254 g_debug("XXXX destroyPacket ");
255 printPacket(packet);
256 g_debug("\n");
257
258 g_assert(packet->inE != NULL && packet->outE != NULL &&
259 packet->inE->packetKey == packet->outE->packetKey);
260
261 packet->outE->packetKey= NULL;
262
263 destroyNetEvent(packet->inE);
264 destroyNetEvent(packet->outE);
265
266 if (packet->acks != NULL)
267 {
268 g_queue_foreach(packet->acks, &gfPacketDestroy, NULL);
269 g_queue_free(packet->acks);
270 }
271
272 free(packet);
273}
274
275
276/*
277 * Free the memory used by a NetEvent
278 */
279void destroyNetEvent(NetEvent* const event)
280{
281 g_debug("XXXX destroyNetEvent\n");
282
283 if (event->packetKey != NULL)
284 {
285 free(event->packetKey);
286 }
287 free(event);
288}
289
290
291/*
292 * A GCompareFunc for g_queue_find_custom()
293 *
294 * Args:
295 * a Packet* acked packet
296 * b Packet* ack packet
297 *
298 * Returns:
299 * 0 if b acks a
300 */
301gint gcfPacketAckCompare(gconstpointer a, gconstpointer b)
302{
303 if (isAcking((const Packet*) b, (const Packet*) a))
304 {
305 return 0;
306 }
307 else
308 {
309 return 1;
310 }
311}
312
313
314/*
315 * A GHashFunc for g_hash_table_new()
316 *
317 * Hash TCP connection keys. Here are a few possible implementations:
318 *
319 * 2.4 kernels used tcp_hashfn()
320 *
321 * I've seen something about an XOR hash:
322 * http://tservice.net.ru/~s0mbre/blog/2006/05/14#2006_05_14:
323 * unsigned int h = (laddr ^ lport) ^ (faddr ^ fport);
324 * h ^= h >> 16;
325 * h ^= h >> 8;
326 * return h;
327 *
328 * In 2.6 kernels, inet_ehashfn() handles connection hashing with the help of
329 * Jenkins hashing, jhash.h
330 *
331 * This function uses jenkins hashing. The hash is not the same for packets in
332 * opposite directions of the same connection. (Hence the name
333 * connection*key*hash)
334 *
335 * Args:
336 * key ConnectionKey*
337 */
338guint ghfConnectionKeyHash(gconstpointer key)
339{
340 ConnectionKey* connectionKey;
341 uint32_t a, b, c;
342
343 connectionKey= (ConnectionKey*) key;
344
345 a= connectionKey->source + (connectionKey->dest << 16);
346 b= connectionKey->saddr;
347 c= connectionKey->daddr;
348 final(a, b, c);
349
350 return c;
351}
352
353
354/*
355 * A GEqualFunc for g_hash_table_new()
356 *
357 * Args:
358 * a, b ConnectionKey*
359 *
360 * Returns:
361 * TRUE if both values are equal
362 */
363gboolean gefConnectionKeyEqual(gconstpointer a, gconstpointer b)
364{
365 // Two packets in the same direction
366 if (connectionKeyEqual((const ConnectionKey*) a, (const ConnectionKey*) b))
367 {
368 return TRUE;
369 }
370 else
371 {
372 return FALSE;
373 }
374}
375
376
377/*
378 * A GDestroyNotify function for g_hash_table_new_full()
379 *
380 * Args:
381 * data: ConnectionKey*
382 */
383void gdnConnectionKeyDestroy(gpointer data)
384{
385 free((ConnectionKey*) data);
386}
This page took 0.036085 seconds and 4 git commands to generate.