GSM SMS: follow-up of gd65b7d5
[metze/wireshark/wip.git] / epan / stream.c
index 3e72efe8d54713c539cb3dd7f7e642686748953b..29a6ebbccd8501d7d5f918940b88ef1011dcba51 100644 (file)
@@ -4,10 +4,8 @@
  * which are handled as streams, and don't have lengths
  * and IDs such as are required for reassemble.h
  *
- * $Id: stream.c,v 1.9 2005/07/27 22:47:55 richardv Exp $
- *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
  * This program is free software; you can redistribute it and/or
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "config.h"
 
 #include <glib.h>
 #include <epan/packet.h>
+#include <epan/emem.h>
 #include <epan/reassemble.h>
 #include <epan/stream.h>
 #include <epan/tvbuff.h>
 
-/* number of streams to allocate memory for at once */
-#define MEMCHUNK_STREAM_COUNT 20
-
-/* ditto pdus */
-#define MEMCHUNK_PDU_COUNT 100
-
-/* ditto fragments */
-#define MEMCHUNK_FRAGMENT_COUNT 100
-
 
 typedef struct {
-    fragment_data *fd_head;          /* the reassembled data, NULL
-                                     * until we add the last fragment */
-    guint32 pdu_number;                     /* Number of this PDU within the stream */
+    fragment_head *fd_head;          /* the reassembled data, NULL
+                                      * until we add the last fragment */
+    guint32 pdu_number;              /* Number of this PDU within the stream */
 
     /* id of this pdu (globally unique) */
     guint32 id;
@@ -57,7 +45,7 @@ typedef struct {
 
 struct stream_pdu_fragment
 {
-    guint32 len;                    /* the length of this fragment */
+    guint32 len;                     /* the length of this fragment */
     stream_pdu_t *pdu;
     gboolean final_fragment;
 };
@@ -92,101 +80,73 @@ typedef struct stream_key {
        that here */
     gboolean is_circuit;
     union {
-       const struct circuit *circuit;
-       const struct conversation *conv;
+        const struct circuit *circuit;
+        const struct conversation *conv;
     } circ;
     int p2p_dir;
 } stream_key_t;
 
 
 /* hash func */
-guint stream_hash_func(gconstpointer k)
+static guint stream_hash_func(gconstpointer k)
 {
     const stream_key_t *key = (const stream_key_t *)k;
 
     /* is_circuit is redundant to the circuit/conversation pointer */
-    return ((guint)key->circ.circuit) ^ key->p2p_dir;
+    return ((guint)(unsigned long)key->circ.circuit) ^ key->p2p_dir;
 }
 
 /* compare func */
-gboolean stream_compare_func(gconstpointer a,
-                            gconstpointer b)
+static gboolean stream_compare_func(gconstpointer a,
+                             gconstpointer b)
 {
     const stream_key_t *key1 = (const stream_key_t *)a;
     const stream_key_t *key2 = (const stream_key_t *)b;
     if( key1 -> p2p_dir != key2 -> p2p_dir ||
-       key1-> is_circuit != key2 -> is_circuit )
-       return FALSE;
-    
+        key1-> is_circuit != key2 -> is_circuit )
+        return FALSE;
+
     if( key1 -> is_circuit )
-       return (key1 -> circ.circuit == key2 -> circ.circuit );
+        return (key1 -> circ.circuit == key2 -> circ.circuit );
     else
-       return (key1 -> circ.conv == key2 -> circ.conv );
+        return (key1 -> circ.conv == key2 -> circ.conv );
 }
 
-/* value destroy func */
-void stream_value_destroy_func(gpointer v)
-{
-    stream_t *val = (stream_t *)v;
-
-    /* this is only called when the entire hash (and hence the entire
-     * "streams" GMemChunk is being freed, so there is no need to free
-     * v.
-     */
-}
-           
-/* memory pools */
-static GMemChunk *stream_keys = NULL;
-static GMemChunk *streams = NULL;
-
-
 /* the hash table */
 static GHashTable *stream_hash;
 
 
-/* init/reset function, call from stream_init() */
-static void init_stream_hash( void ) {
+/* cleanup reset function, call from stream_cleanup() */
+static void cleanup_stream_hash( void ) {
     if( stream_hash != NULL ) {
-       g_hash_table_destroy( stream_hash );
-       stream_hash = NULL;
+        g_hash_table_destroy( stream_hash );
+        stream_hash = NULL;
     }
-
-    if( stream_keys != NULL ) {
-       g_mem_chunk_destroy( stream_keys );
-       stream_keys = NULL;
-    }
-
-    if( streams != NULL ) {
-       g_mem_chunk_destroy( streams );
-       streams = NULL;
-    }
-
-    streams = g_mem_chunk_create(stream_t,
-                                MEMCHUNK_STREAM_COUNT,
-                                G_ALLOC_ONLY);
-
-    stream_keys = g_mem_chunk_create(stream_key_t,
-                                    MEMCHUNK_STREAM_COUNT,
-                                    G_ALLOC_ONLY);
-
-    stream_hash = g_hash_table_new_full(stream_hash_func,
-                                       stream_compare_func,
-                                       NULL,
-                                       stream_value_destroy_func);
 }
 
+/* init function, call from stream_init() */
+static void init_stream_hash( void ) {
+    g_assert(stream_hash==NULL);
+    stream_hash = g_hash_table_new(stream_hash_func,
+                                   stream_compare_func);
+}
 
 /* lookup function, returns null if not found */
 static stream_t *stream_hash_lookup_circ( const struct circuit *circuit, int p2p_dir )
 {
-    stream_key_t key = {TRUE,{circuit}, p2p_dir};
+    stream_key_t key;
+    key.is_circuit=TRUE;
+    key.circ.circuit=circuit;
+    key.p2p_dir=p2p_dir;
     return (stream_t *)g_hash_table_lookup(stream_hash, &key);
 }
 
 static stream_t *stream_hash_lookup_conv( const struct conversation *conv, int p2p_dir )
 {
-    stream_key_t key = {FALSE,{NULL}, p2p_dir};
+    stream_key_t key;
+    key.is_circuit=FALSE;
     key.circ.conv = conv;
+    key.p2p_dir=p2p_dir;
     return (stream_t *)g_hash_table_lookup(stream_hash, &key);
 }
 
@@ -194,8 +154,8 @@ static stream_t *stream_hash_lookup_conv( const struct conversation *conv, int p
 static stream_t *new_stream( stream_key_t *key )
 {
     stream_t *val;
-    
-    val = g_mem_chunk_alloc(streams);
+
+    val = se_new(stream_t);
     val -> key = key;
     val -> pdu_counter = 0;
     val -> current_pdu = NULL;
@@ -212,7 +172,7 @@ static stream_t *stream_hash_insert_circ( const struct circuit *circuit, int p2p
 {
     stream_key_t *key;
 
-    key = g_mem_chunk_alloc(stream_keys);
+    key = se_new(stream_key_t);
     key->is_circuit = TRUE;
     key->circ.circuit = circuit;
     key->p2p_dir = p2p_dir;
@@ -224,7 +184,7 @@ static stream_t *stream_hash_insert_conv( const struct conversation *conv, int p
 {
     stream_key_t *key;
 
-    key = g_mem_chunk_alloc(stream_keys);
+    key = se_new(stream_key_t);
     key->is_circuit = FALSE;
     key->circ.conv = conv;
     key->p2p_dir = p2p_dir;
@@ -237,22 +197,16 @@ static stream_t *stream_hash_insert_conv( const struct conversation *conv, int p
  *
  * PDU data
  */
-static GMemChunk *pdus = NULL;
 
 /* pdu counter, for generating unique pdu ids */
 static guint32 pdu_counter;
 
+static void stream_cleanup_pdu_data(void)
+{
+}
 
 static void stream_init_pdu_data(void)
 {
-    if( pdus != NULL ) {
-       g_mem_chunk_destroy( pdus );
-       pdus = NULL;
-    }
-
-    pdus = g_mem_chunk_create(stream_pdu_t,
-                             MEMCHUNK_PDU_COUNT,
-                             G_ALLOC_ONLY);
     pdu_counter = 0;
 }
 
@@ -261,7 +215,7 @@ static void stream_init_pdu_data(void)
 static stream_pdu_t *stream_new_pdu(stream_t *stream)
 {
     stream_pdu_t *pdu;
-    pdu = g_mem_chunk_alloc(pdus);
+    pdu = se_new(stream_pdu_t);
     pdu -> fd_head = NULL;
     pdu -> pdu_number = stream -> pdu_counter++;
     pdu -> id = pdu_counter++;
@@ -282,66 +236,53 @@ typedef struct fragment_key {
 
 
 /* hash func */
-guint fragment_hash_func(gconstpointer k)
+static guint fragment_hash_func(gconstpointer k)
 {
     const fragment_key_t *key = (const fragment_key_t *)k;
-    return ((guint)key->stream) + ((guint)key -> framenum) + ((guint)key->offset);
+    return ((guint)(unsigned long)key->stream) + ((guint)key -> framenum) + ((guint)key->offset);
 }
 
 /* compare func */
-gboolean fragment_compare_func(gconstpointer a,
-                              gconstpointer b)
+static gboolean fragment_compare_func(gconstpointer a,
+                               gconstpointer b)
 {
     const fragment_key_t *key1 = (const fragment_key_t *)a;
     const fragment_key_t *key2 = (const fragment_key_t *)b;
     return (key1 -> stream == key2 -> stream &&
-           key1 -> framenum == key2 -> framenum &&
-           key1 -> offset == key2 -> offset );
+            key1 -> framenum == key2 -> framenum &&
+            key1 -> offset == key2 -> offset );
 }
-           
-/* memory pools */
-static GMemChunk *fragment_keys = NULL;
-static GMemChunk *fragment_vals = NULL;
 
 /* the hash table */
 static GHashTable *fragment_hash;
 
 
-/* init/reset function, call from stream_init() */
-static void init_fragment_hash( void ) {
+/* cleanup function, call from stream_cleanup() */
+static void cleanup_fragment_hash( void ) {
     if( fragment_hash != NULL ) {
-       g_hash_table_destroy( fragment_hash );
-       fragment_hash = NULL;
-    }
-
-    if( fragment_vals != NULL ) {
-       g_mem_chunk_destroy( fragment_vals );
-       fragment_vals = NULL;
-    }
-
-    if( fragment_keys != NULL ) {
-       g_mem_chunk_destroy( fragment_keys );
-       fragment_keys = NULL;
+        g_hash_table_destroy( fragment_hash );
+        fragment_hash = NULL;
     }
+}
 
-    fragment_keys = g_mem_chunk_create(fragment_key_t,
-                                      MEMCHUNK_FRAGMENT_COUNT,
-                                      G_ALLOC_ONLY);
-    
-    fragment_vals = g_mem_chunk_create(stream_pdu_fragment_t,
-                                      MEMCHUNK_FRAGMENT_COUNT,
-                                      G_ALLOC_ONLY);
-
+/* init function, call from stream_init() */
+static void init_fragment_hash( void ) {
+    g_assert(fragment_hash==NULL);
     fragment_hash = g_hash_table_new(fragment_hash_func,
-                                    fragment_compare_func);
+                                     fragment_compare_func);
 }
 
 
 /* lookup function, returns null if not found */
 static stream_pdu_fragment_t *fragment_hash_lookup( const stream_t *stream, guint32 framenum, guint32 offset )
 {
-    fragment_key_t key = {stream, framenum, offset};
-    stream_pdu_fragment_t *val = g_hash_table_lookup(fragment_hash, &key);
+    fragment_key_t key;
+    stream_pdu_fragment_t *val;
+
+    key.stream = stream;
+    key.framenum = framenum;
+    key.offset = offset;
+    val = (stream_pdu_fragment_t *)g_hash_table_lookup(fragment_hash, &key);
 
     return val;
 }
@@ -349,17 +290,17 @@ static stream_pdu_fragment_t *fragment_hash_lookup( const stream_t *stream, guin
 
 /* insert function */
 static stream_pdu_fragment_t *fragment_hash_insert( const stream_t *stream, guint32 framenum, guint32 offset,
-                                                   guint32 length)
+                                                    guint32 length)
 {
     fragment_key_t *key;
     stream_pdu_fragment_t *val;
 
-    key = g_mem_chunk_alloc(fragment_keys);
+    key = se_new(fragment_key_t);
     key->stream = stream;
     key->framenum = framenum;
     key->offset = offset;
 
-    val = g_mem_chunk_alloc(fragment_vals);
+    val = se_new(stream_pdu_fragment_t);
     val->len = length;
     val->pdu = NULL;
     val->final_fragment = FALSE;
@@ -370,9 +311,8 @@ static stream_pdu_fragment_t *fragment_hash_insert( const stream_t *stream, guin
 
 /*****************************************************************************/
 
-/* fragmentation hash tables */
-static GHashTable *stream_fragment_table = NULL;
-static GHashTable *stream_reassembled_table = NULL;
+/* reassembly table */
+static reassembly_table stream_reassembly_table;
 
 /* Initialise a new stream. Call this when you first identify a distinct
  * stream. */
@@ -383,10 +323,10 @@ stream_t *stream_new_circ ( const struct circuit *circuit, int p2p_dir )
     /* we don't want to replace the previous data if we get called twice on the
        same circuit, so do a lookup first */
     stream = stream_hash_lookup_circ(circuit, p2p_dir);
-    g_assert( stream == NULL );
+    DISSECTOR_ASSERT( stream == NULL );
 
     stream = stream_hash_insert_circ(circuit, p2p_dir);
-    
+
     return stream;
 }
 
@@ -397,15 +337,13 @@ stream_t *stream_new_conv ( const struct conversation *conv, int p2p_dir )
     /* we don't want to replace the previous data if we get called twice on the
        same conversation, so do a lookup first */
     stream = stream_hash_lookup_conv(conv, p2p_dir);
-    g_assert( stream == NULL );
+    DISSECTOR_ASSERT( stream == NULL );
 
     stream = stream_hash_insert_conv(conv, p2p_dir);
     return stream;
 }
 
 
-
-
 /* retrieve a previously-created stream.
  *
  * Returns null if no matching stream was found.
@@ -419,6 +357,17 @@ stream_t *find_stream_conv ( const struct conversation *conv, int p2p_dir )
     return stream_hash_lookup_conv(conv,p2p_dir);
 }
 
+/* cleanup the stream routines */
+/* Note: stream_cleanup must only be called when seasonal memory
+ *       is also freed since the hash tables countain pointers to
+ *       se_alloc'd memory.
+ */
+void stream_cleanup( void )
+{
+    cleanup_stream_hash();
+    cleanup_fragment_hash();
+    stream_cleanup_pdu_data();
+}
 
 /* initialise the stream routines */
 void stream_init( void )
@@ -427,55 +376,52 @@ void stream_init( void )
     init_fragment_hash();
     stream_init_pdu_data();
 
-    fragment_table_init(&stream_fragment_table);
-    reassembled_table_init(&stream_reassembled_table);
+    reassembly_table_init(&stream_reassembly_table,
+                          &addresses_reassembly_table_functions);
 }
 
-
-
-
 /*****************************************************************************/
 
 stream_pdu_fragment_t *stream_find_frag( stream_t *stream, guint32 framenum, guint32 offset )
 {
     return fragment_hash_lookup( stream, framenum, offset );
 }
-    
+
 stream_pdu_fragment_t *stream_add_frag( stream_t *stream, guint32 framenum, guint32 offset,
-                               tvbuff_t *tvb, packet_info *pinfo, gboolean more_frags )
+                                        tvbuff_t *tvb, packet_info *pinfo, gboolean more_frags )
 {
-    fragment_data *fd_head;
+    fragment_head *fd_head;
     stream_pdu_t *pdu;
     stream_pdu_fragment_t *frag_data;
 
-    g_assert(stream);
+    DISSECTOR_ASSERT(stream);
 
     /* check that this fragment is at the end of the stream */
-    g_assert( framenum > stream->lastfrag_framenum ||
-             (framenum == stream->lastfrag_framenum && offset > stream->lastfrag_offset));
+    DISSECTOR_ASSERT( framenum > stream->lastfrag_framenum ||
+                      (framenum == stream->lastfrag_framenum && offset > stream->lastfrag_offset));
 
 
     pdu = stream->current_pdu;
     if( pdu == NULL ) {
-       /* start a new pdu */
-       pdu = stream->current_pdu = stream_new_pdu(stream);
+        /* start a new pdu */
+        pdu = stream->current_pdu = stream_new_pdu(stream);
     }
-       
+
     /* add it to the reassembly tables */
-    fd_head = fragment_add_seq_next(tvb, 0, pinfo, pdu->id,
-                                   stream_fragment_table, stream_reassembled_table,
-                                   tvb_reported_length(tvb), more_frags);
+    fd_head = fragment_add_seq_next(&stream_reassembly_table,
+                                    tvb, 0, pinfo, pdu->id, NULL,
+                                    tvb_reported_length(tvb), more_frags);
     /* add it to our hash */
     frag_data = fragment_hash_insert( stream, framenum, offset, tvb_reported_length(tvb));
     frag_data -> pdu = pdu;
 
     if( fd_head != NULL ) {
-       /* if this was the last fragment, update the pdu data.
-        */
-       pdu -> fd_head = fd_head;
-       
-       /* start a new pdu next time */
-       stream->current_pdu = NULL;
+        /* if this was the last fragment, update the pdu data.
+         */
+        pdu -> fd_head = fd_head;
+
+        /* start a new pdu next time */
+        stream->current_pdu = NULL;
 
         frag_data -> final_fragment = TRUE;
     }
@@ -490,12 +436,12 @@ stream_pdu_fragment_t *stream_add_frag( stream_t *stream, guint32 framenum, guin
 
 tvbuff_t *stream_process_reassembled(
     tvbuff_t *tvb, int offset, packet_info *pinfo,
-    char *name, const stream_pdu_fragment_t *frag,
+    const char *name, const stream_pdu_fragment_t *frag,
     const struct _fragment_items *fit,
     gboolean *update_col_infop, proto_tree *tree)
 {
     stream_pdu_t *pdu;
-    g_assert(frag);
+    DISSECTOR_ASSERT(frag);
     pdu = frag->pdu;
 
     /* we handle non-terminal fragments ourselves, because
@@ -512,21 +458,21 @@ tvbuff_t *stream_process_reassembled(
     return process_reassembled_data(tvb, offset, pinfo, name, pdu->fd_head,
                                     fit, update_col_infop, tree);
 }
-    
+
 guint32 stream_get_frag_length( const stream_pdu_fragment_t *frag)
 {
-    g_assert( frag );
+    DISSECTOR_ASSERT( frag );
     return frag->len;
 }
 
-fragment_data *stream_get_frag_data( const stream_pdu_fragment_t *frag)
+fragment_head *stream_get_frag_data( const stream_pdu_fragment_t *frag)
 {
-    g_assert( frag );
+    DISSECTOR_ASSERT( frag );
     return frag->pdu->fd_head;
 }
 
 guint32 stream_get_pdu_no( const stream_pdu_fragment_t *frag)
 {
-    g_assert( frag );
+    DISSECTOR_ASSERT( frag );
     return frag->pdu->pdu_number;
 }