--- /dev/null
+/* This file is part of the Linux Trace Toolkit viewer
+ * Copyright (C) 2009 Benjamin Poirier <benjamin.poirier@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <arpa/inet.h>
+#include <glib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lookup3.h"
+
+#include "data_structures_tcp.h"
+
+
+#ifndef g_info
+#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
+#endif
+
+// TCP sequence numbers use clock arithmetic, these comparison functions take
+// that into account
+#define SEQ_LT(a,b) ((int32_t)((a)-(b)) < 0)
+#define SEQ_LEQ(a,b) ((int32_t)((a)-(b)) <= 0)
+#define SEQ_GT(a,b) ((int32_t)((a)-(b)) > 0)
+#define SEQ_GEQ(a,b) ((int32_t)((a)-(b)) >= 0)
+
+
+/*
+ * Compare two ConnectionKey structures
+ *
+ * Returns:
+ * true if each field of the structure is equal
+ * false otherwise
+ */
+bool connectionKeyEqual(const ConnectionKey* const a, const
+ ConnectionKey* const b)
+{
+ if (a->saddr == b->saddr && a->daddr == b->daddr && a->source == b->source
+ && a->dest == b->dest)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+/*
+ * Check if a packet is an acknowledge of another packet.
+ *
+ * Args:
+ * ackPacket packet that is the confirmation
+ * ackedPacket packet that contains the original data, both packets have to
+ * come from the same direction of the same connection
+ */
+bool isAcking(const Packet* const ackPacket, const Packet* const
+ ackedPacket)
+{
+ if (SEQ_GT(ackPacket->inE->packetKey->ack_seq,
+ ackedPacket->inE->packetKey->seq))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+/*
+ * Convert an IP address from 32 bit form to dotted quad
+ *
+ * Args:
+ * str: A preallocated string of length >= 17
+ * addr: Address
+ */
+void convertIP(char* const str, const uint32_t addr)
+{
+ struct in_addr iaddr;
+
+ iaddr.s_addr= htonl(addr);
+ strcpy(str, inet_ntoa(iaddr));
+}
+
+
+/*
+ * Print the content of a Packet structure
+ */
+void printPacket(const Packet* const packet)
+{
+ char saddr[17], daddr[17];
+ PacketKey* packetKey;
+
+ packetKey= packet->inE->packetKey;
+
+ convertIP(saddr, packetKey->connectionKey.saddr);
+ convertIP(daddr, packetKey->connectionKey.daddr);
+ g_debug("%s:%u to %s:%u tot_len: %u ihl: %u seq: %u ack_seq: %u doff: %u "
+ "ack: %u rst: %u syn: %u fin: %u", saddr,
+ packetKey->connectionKey.source, daddr, packetKey->connectionKey.dest,
+ packetKey->tot_len, packetKey->ihl, packetKey->seq,
+ packetKey->ack_seq, packetKey->doff, packetKey->ack, packetKey->rst,
+ packetKey->syn, packetKey->fin);
+}
+
+
+/*
+ * A GHashFunc for g_hash_table_new()
+ *
+ * This function is for indexing netEvents in unMatched lists. All fields of
+ * the corresponding packet must match for two keys to be equal.
+ *
+ * Args:
+ * key PacketKey*
+ */
+guint ghfPacketKeyHash(gconstpointer key)
+{
+ const PacketKey* p;
+ uint32_t a, b, c;
+
+ p= (PacketKey*) key;
+
+ a= p->connectionKey.source + (p->connectionKey.dest << 16);
+ b= p->connectionKey.saddr;
+ c= p->connectionKey.daddr;
+ mix(a, b, c);
+
+ a+= p->ihl + (p->tot_len << 8) + (p->doff << 24);
+ b+= p->seq;
+ c+= p->ack_seq;
+ mix(a, b, c);
+
+ a+= p->ack + (p->rst << 8) + (p->syn << 16) + (p->fin << 24);
+ final(a, b, c);
+
+ return c;
+}
+
+
+/*
+ * A GEqualFunc for g_hash_table_new()
+ *
+ * This function is for indexing netEvents in unMatched lists. All fields of
+ * the corresponding packet must match for two keys to be equal.
+ *
+ * Args:
+ * a, b PacketKey*
+ *
+ * Returns:
+ * TRUE if both values are equal
+ */
+gboolean gefPacketKeyEqual(gconstpointer a, gconstpointer b)
+{
+ const PacketKey* pA, * pB;
+
+ pA= ((PacketKey*) a);
+ pB= ((PacketKey*) b);
+
+ if (connectionKeyEqual(&pA->connectionKey, &pB->connectionKey) &&
+ pA->ihl == pB->ihl &&
+ pA->tot_len == pB->tot_len &&
+ pA->seq == pB->seq &&
+ pA->ack_seq == pB->ack_seq &&
+ pA->doff == pB->doff &&
+ pA->ack == pB->ack &&
+ pA->rst == pB->rst &&
+ pA->syn == pB->syn &&
+ pA->fin == pB->fin)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+/*
+ * A GDestroyNotify function for g_hash_table_new_full()
+ *
+ * Args:
+ * data: NetEvent*
+ */
+void gdnDestroyNetEvent(gpointer data)
+{
+ destroyNetEvent((NetEvent*) data);
+}
+
+
+/*
+ * A GDestroyNotify function for g_hash_table_new_full()
+ *
+ * Args:
+ * data: GQueue* list[Packet]
+ */
+void gdnPacketListDestroy(gpointer data)
+{
+ GQueue* list;
+
+ list= (GQueue*) data;
+
+ g_debug("XXXX gdnPacketListDestroy\n");
+
+ g_queue_foreach(list, &gfPacketDestroy, NULL);
+ g_queue_free(list);
+}
+
+
+/*
+ * A GFunc for g_queue_foreach()
+ *
+ * Args:
+ * data Packet*, packet to destroy
+ * user_data NULL
+ */
+void gfPacketDestroy(gpointer data, gpointer user_data)
+{
+ g_debug("XXXX gfPacketDestroy\n");
+ destroyPacket((Packet*) data);
+}
+
+
+/*
+ * Free the memory used by a Packet and the memory of all its associated
+ * resources
+ */
+void destroyPacket(Packet* const packet)
+{
+ g_debug("XXXX destroyPacket ");
+ printPacket(packet);
+ g_debug("\n");
+
+ g_assert(packet->inE != NULL && packet->outE != NULL &&
+ packet->inE->packetKey == packet->outE->packetKey);
+
+ packet->outE->packetKey= NULL;
+
+ destroyNetEvent(packet->inE);
+ destroyNetEvent(packet->outE);
+
+ if (packet->acks != NULL)
+ {
+ g_queue_foreach(packet->acks, &gfPacketDestroy, NULL);
+ g_queue_free(packet->acks);
+ }
+
+ free(packet);
+}
+
+
+/*
+ * Free the memory used by a NetEvent
+ */
+void destroyNetEvent(NetEvent* const event)
+{
+ g_debug("XXXX destroyNetEvent\n");
+
+ if (event->packetKey != NULL)
+ {
+ free(event->packetKey);
+ }
+ free(event);
+}
+
+
+/*
+ * A GCompareFunc for g_queue_find_custom()
+ *
+ * Args:
+ * a Packet* acked packet
+ * b Packet* ack packet
+ *
+ * Returns:
+ * 0 if b acks a
+ */
+gint gcfPacketAckCompare(gconstpointer a, gconstpointer b)
+{
+ if (isAcking((const Packet*) b, (const Packet*) a))
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+
+/*
+ * A GHashFunc for g_hash_table_new()
+ *
+ * Hash TCP connection keys. Here are a few possible implementations:
+ *
+ * 2.4 kernels used tcp_hashfn()
+ *
+ * I've seen something about an XOR hash:
+ * http://tservice.net.ru/~s0mbre/blog/2006/05/14#2006_05_14:
+ * unsigned int h = (laddr ^ lport) ^ (faddr ^ fport);
+ * h ^= h >> 16;
+ * h ^= h >> 8;
+ * return h;
+ *
+ * In 2.6 kernels, inet_ehashfn() handles connection hashing with the help of
+ * Jenkins hashing, jhash.h
+ *
+ * This function uses jenkins hashing. The hash is not the same for packets in
+ * opposite directions of the same connection. (Hence the name
+ * connection*key*hash)
+ *
+ * Args:
+ * key ConnectionKey*
+ */
+guint ghfConnectionKeyHash(gconstpointer key)
+{
+ ConnectionKey* connectionKey;
+ uint32_t a, b, c;
+
+ connectionKey= (ConnectionKey*) key;
+
+ a= connectionKey->source + (connectionKey->dest << 16);
+ b= connectionKey->saddr;
+ c= connectionKey->daddr;
+ final(a, b, c);
+
+ return c;
+}
+
+
+/*
+ * A GEqualFunc for g_hash_table_new()
+ *
+ * Args:
+ * a, b ConnectionKey*
+ *
+ * Returns:
+ * TRUE if both values are equal
+ */
+gboolean gefConnectionKeyEqual(gconstpointer a, gconstpointer b)
+{
+ // Two packets in the same direction
+ if (connectionKeyEqual((const ConnectionKey*) a, (const ConnectionKey*) b))
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+/*
+ * A GDestroyNotify function for g_hash_table_new_full()
+ *
+ * Args:
+ * data: ConnectionKey*
+ */
+void gdnConnectionKeyDestroy(gpointer data)
+{
+ free((ConnectionKey*) data);
+}
+