We always HAVE_CONFIG_H so don't bother checking whether we have it or not.
[metze/wireshark/wip.git] / epan / stream.c
1 /* stream.c
2  *
3  * Definititions for handling circuit-switched protocols
4  * which are handled as streams, and don't have lengths
5  * and IDs such as are required for reassemble.h
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27
28 #include "config.h"
29
30 #include <glib.h>
31 #include <epan/packet.h>
32 #include <epan/reassemble.h>
33 #include <epan/stream.h>
34 #include <epan/tvbuff.h>
35
36
37 typedef struct {
38     fragment_data *fd_head;          /* the reassembled data, NULL
39                                       * until we add the last fragment */
40     guint32 pdu_number;              /* Number of this PDU within the stream */
41
42     /* id of this pdu (globally unique) */
43     guint32 id;
44 } stream_pdu_t;
45
46
47 struct stream_pdu_fragment
48 {
49     guint32 len;                     /* the length of this fragment */
50     stream_pdu_t *pdu;
51     gboolean final_fragment;
52 };
53
54 struct stream {
55     /* the key used to add this stream to stream_hash */
56     struct stream_key *key;
57
58     /* pdu to add the next fragment to, or NULL if we need to start
59      * a new PDU.
60      */
61     stream_pdu_t *current_pdu;
62
63     /* number of PDUs added to this stream so far */
64     guint32 pdu_counter;
65
66     /* the framenumber and offset of the last fragment added;
67        used for sanity-checking */
68     guint32 lastfrag_framenum;
69     guint32 lastfrag_offset;
70 };
71
72
73 /*****************************************************************************
74  *
75  * Stream hash
76  */
77
78 /* key */
79 typedef struct stream_key {
80     /* streams can be attached to circuits or conversations, and we note
81        that here */
82     gboolean is_circuit;
83     union {
84         const struct circuit *circuit;
85         const struct conversation *conv;
86     } circ;
87     int p2p_dir;
88 } stream_key_t;
89
90
91 /* hash func */
92 static guint stream_hash_func(gconstpointer k)
93 {
94     const stream_key_t *key = (const stream_key_t *)k;
95
96     /* is_circuit is redundant to the circuit/conversation pointer */
97     return ((guint)(unsigned long)key->circ.circuit) ^ key->p2p_dir;
98 }
99
100 /* compare func */
101 static gboolean stream_compare_func(gconstpointer a,
102                              gconstpointer b)
103 {
104     const stream_key_t *key1 = (const stream_key_t *)a;
105     const stream_key_t *key2 = (const stream_key_t *)b;
106     if( key1 -> p2p_dir != key2 -> p2p_dir ||
107         key1-> is_circuit != key2 -> is_circuit )
108         return FALSE;
109
110     if( key1 -> is_circuit )
111         return (key1 -> circ.circuit == key2 -> circ.circuit );
112     else
113         return (key1 -> circ.conv == key2 -> circ.conv );
114 }
115
116 /* the hash table */
117 static GHashTable *stream_hash;
118
119
120 /* cleanup reset function, call from stream_cleanup() */
121 static void cleanup_stream_hash( void ) {
122     if( stream_hash != NULL ) {
123         g_hash_table_destroy( stream_hash );
124         stream_hash = NULL;
125     }
126 }
127
128 /* init function, call from stream_init() */
129 static void init_stream_hash( void ) {
130     g_assert(stream_hash==NULL);
131     stream_hash = g_hash_table_new(stream_hash_func,
132                                    stream_compare_func);
133 }
134
135 /* lookup function, returns null if not found */
136 static stream_t *stream_hash_lookup_circ( const struct circuit *circuit, int p2p_dir )
137 {
138     stream_key_t key;
139     key.is_circuit=TRUE;
140     key.circ.circuit=circuit;
141     key.p2p_dir=p2p_dir;
142     return (stream_t *)g_hash_table_lookup(stream_hash, &key);
143 }
144
145 static stream_t *stream_hash_lookup_conv( const struct conversation *conv, int p2p_dir )
146 {
147     stream_key_t key;
148     key.is_circuit=FALSE;
149     key.circ.conv = conv;
150     key.p2p_dir=p2p_dir;
151     return (stream_t *)g_hash_table_lookup(stream_hash, &key);
152 }
153
154
155 static stream_t *new_stream( stream_key_t *key )
156 {
157     stream_t *val;
158
159     val = se_alloc(sizeof(stream_t));
160     val -> key = key;
161     val -> pdu_counter = 0;
162     val -> current_pdu = NULL;
163     val -> lastfrag_framenum = 0;
164     val -> lastfrag_offset = 0;
165     g_hash_table_insert(stream_hash, key, val);
166
167     return val;
168 }
169
170
171 /* insert function */
172 static stream_t *stream_hash_insert_circ( const struct circuit *circuit, int p2p_dir )
173 {
174     stream_key_t *key;
175
176     key = se_alloc(sizeof(stream_key_t));
177     key->is_circuit = TRUE;
178     key->circ.circuit = circuit;
179     key->p2p_dir = p2p_dir;
180
181     return new_stream(key);
182 }
183
184 static stream_t *stream_hash_insert_conv( const struct conversation *conv, int p2p_dir )
185 {
186     stream_key_t *key;
187
188     key = se_alloc(sizeof(stream_key_t));
189     key->is_circuit = FALSE;
190     key->circ.conv = conv;
191     key->p2p_dir = p2p_dir;
192
193     return new_stream(key);
194 }
195
196
197 /******************************************************************************
198  *
199  * PDU data
200  */
201
202 /* pdu counter, for generating unique pdu ids */
203 static guint32 pdu_counter;
204
205 static void stream_cleanup_pdu_data(void)
206 {
207 }
208
209 static void stream_init_pdu_data(void)
210 {
211     pdu_counter = 0;
212 }
213
214
215 /* new pdu in this stream */
216 static stream_pdu_t *stream_new_pdu(stream_t *stream)
217 {
218     stream_pdu_t *pdu;
219     pdu = se_alloc(sizeof(stream_pdu_t));
220     pdu -> fd_head = NULL;
221     pdu -> pdu_number = stream -> pdu_counter++;
222     pdu -> id = pdu_counter++;
223     return pdu;
224 }
225
226 /*****************************************************************************
227  *
228  * fragment hash
229  */
230
231 /* key */
232 typedef struct fragment_key {
233     const stream_t *stream;
234     guint32 framenum;
235     guint32 offset;
236 } fragment_key_t;
237
238
239 /* hash func */
240 static guint fragment_hash_func(gconstpointer k)
241 {
242     const fragment_key_t *key = (const fragment_key_t *)k;
243     return ((guint)(unsigned long)key->stream) + ((guint)key -> framenum) + ((guint)key->offset);
244 }
245
246 /* compare func */
247 static gboolean fragment_compare_func(gconstpointer a,
248                                gconstpointer b)
249 {
250     const fragment_key_t *key1 = (const fragment_key_t *)a;
251     const fragment_key_t *key2 = (const fragment_key_t *)b;
252     return (key1 -> stream == key2 -> stream &&
253             key1 -> framenum == key2 -> framenum &&
254             key1 -> offset == key2 -> offset );
255 }
256
257 /* the hash table */
258 static GHashTable *fragment_hash;
259
260
261 /* cleanup function, call from stream_cleanup() */
262 static void cleanup_fragment_hash( void ) {
263     if( fragment_hash != NULL ) {
264         g_hash_table_destroy( fragment_hash );
265         fragment_hash = NULL;
266     }
267 }
268
269 /* init function, call from stream_init() */
270 static void init_fragment_hash( void ) {
271     g_assert(fragment_hash==NULL);
272     fragment_hash = g_hash_table_new(fragment_hash_func,
273                                      fragment_compare_func);
274 }
275
276
277 /* lookup function, returns null if not found */
278 static stream_pdu_fragment_t *fragment_hash_lookup( const stream_t *stream, guint32 framenum, guint32 offset )
279 {
280     fragment_key_t key;
281     stream_pdu_fragment_t *val;
282
283     key.stream = stream;
284     key.framenum = framenum;
285     key.offset = offset;
286     val = g_hash_table_lookup(fragment_hash, &key);
287
288     return val;
289 }
290
291
292 /* insert function */
293 static stream_pdu_fragment_t *fragment_hash_insert( const stream_t *stream, guint32 framenum, guint32 offset,
294                                                     guint32 length)
295 {
296     fragment_key_t *key;
297     stream_pdu_fragment_t *val;
298
299     key = se_alloc(sizeof(fragment_key_t));
300     key->stream = stream;
301     key->framenum = framenum;
302     key->offset = offset;
303
304     val = se_alloc(sizeof(stream_pdu_fragment_t));
305     val->len = length;
306     val->pdu = NULL;
307     val->final_fragment = FALSE;
308
309     g_hash_table_insert(fragment_hash, key, val);
310     return val;
311 }
312
313 /*****************************************************************************/
314
315 /* fragmentation hash tables */
316 static GHashTable *stream_fragment_table = NULL;
317 static GHashTable *stream_reassembled_table = NULL;
318
319 /* Initialise a new stream. Call this when you first identify a distinct
320  * stream. */
321 stream_t *stream_new_circ ( const struct circuit *circuit, int p2p_dir )
322 {
323     stream_t * stream;
324
325     /* we don't want to replace the previous data if we get called twice on the
326        same circuit, so do a lookup first */
327     stream = stream_hash_lookup_circ(circuit, p2p_dir);
328     DISSECTOR_ASSERT( stream == NULL );
329
330     stream = stream_hash_insert_circ(circuit, p2p_dir);
331
332     return stream;
333 }
334
335 stream_t *stream_new_conv ( const struct conversation *conv, int p2p_dir )
336 {
337     stream_t * stream;
338
339     /* we don't want to replace the previous data if we get called twice on the
340        same conversation, so do a lookup first */
341     stream = stream_hash_lookup_conv(conv, p2p_dir);
342     DISSECTOR_ASSERT( stream == NULL );
343
344     stream = stream_hash_insert_conv(conv, p2p_dir);
345     return stream;
346 }
347
348
349 /* retrieve a previously-created stream.
350  *
351  * Returns null if no matching stream was found.
352  */
353 stream_t *find_stream_circ ( const struct circuit *circuit, int p2p_dir )
354 {
355     return stream_hash_lookup_circ(circuit,p2p_dir);
356 }
357 stream_t *find_stream_conv ( const struct conversation *conv, int p2p_dir )
358 {
359     return stream_hash_lookup_conv(conv,p2p_dir);
360 }
361
362 /* cleanup the stream routines */
363 /* Note: stream_cleanup must only be called when seasonal memory
364  *       is also freed since the hash tables countain pointers to 
365  *       se_alloc'd memory.
366  */
367 void stream_cleanup( void )
368 {
369     cleanup_stream_hash();
370     cleanup_fragment_hash();
371     stream_cleanup_pdu_data();
372 }
373
374 /* initialise the stream routines */
375 void stream_init( void )
376 {
377     init_stream_hash();
378     init_fragment_hash();
379     stream_init_pdu_data();
380
381     fragment_table_init(&stream_fragment_table);
382     reassembled_table_init(&stream_reassembled_table);
383 }
384
385 /*****************************************************************************/
386
387 stream_pdu_fragment_t *stream_find_frag( stream_t *stream, guint32 framenum, guint32 offset )
388 {
389     return fragment_hash_lookup( stream, framenum, offset );
390 }
391
392 stream_pdu_fragment_t *stream_add_frag( stream_t *stream, guint32 framenum, guint32 offset,
393                                         tvbuff_t *tvb, packet_info *pinfo, gboolean more_frags )
394 {
395     fragment_data *fd_head;
396     stream_pdu_t *pdu;
397     stream_pdu_fragment_t *frag_data;
398
399     DISSECTOR_ASSERT(stream);
400
401     /* check that this fragment is at the end of the stream */
402     DISSECTOR_ASSERT( framenum > stream->lastfrag_framenum ||
403                       (framenum == stream->lastfrag_framenum && offset > stream->lastfrag_offset));
404
405
406     pdu = stream->current_pdu;
407     if( pdu == NULL ) {
408         /* start a new pdu */
409         pdu = stream->current_pdu = stream_new_pdu(stream);
410     }
411
412     /* add it to the reassembly tables */
413     fd_head = fragment_add_seq_next(tvb, 0, pinfo, pdu->id,
414                                     stream_fragment_table, stream_reassembled_table,
415                                     tvb_reported_length(tvb), more_frags);
416     /* add it to our hash */
417     frag_data = fragment_hash_insert( stream, framenum, offset, tvb_reported_length(tvb));
418     frag_data -> pdu = pdu;
419
420     if( fd_head != NULL ) {
421         /* if this was the last fragment, update the pdu data.
422          */
423         pdu -> fd_head = fd_head;
424
425         /* start a new pdu next time */
426         stream->current_pdu = NULL;
427
428         frag_data -> final_fragment = TRUE;
429     }
430
431     /* stashing the framenum and offset permit future sanity checks */
432     stream -> lastfrag_framenum = framenum;
433     stream -> lastfrag_offset = offset;
434
435     return frag_data;
436 }
437
438
439 tvbuff_t *stream_process_reassembled(
440     tvbuff_t *tvb, int offset, packet_info *pinfo,
441     const char *name, const stream_pdu_fragment_t *frag,
442     const struct _fragment_items *fit,
443     gboolean *update_col_infop, proto_tree *tree)
444 {
445     stream_pdu_t *pdu;
446     DISSECTOR_ASSERT(frag);
447     pdu = frag->pdu;
448
449     /* we handle non-terminal fragments ourselves, because
450        reassemble.c messes them up */
451     if(!frag->final_fragment) {
452         if (pdu->fd_head != NULL && fit->hf_reassembled_in != NULL) {
453             proto_tree_add_uint(tree,
454                                 *(fit->hf_reassembled_in), tvb,
455                                 0, 0, pdu->fd_head->reassembled_in);
456         }
457         return NULL;
458     }
459
460     return process_reassembled_data(tvb, offset, pinfo, name, pdu->fd_head,
461                                     fit, update_col_infop, tree);
462 }
463
464 guint32 stream_get_frag_length( const stream_pdu_fragment_t *frag)
465 {
466     DISSECTOR_ASSERT( frag );
467     return frag->len;
468 }
469
470 fragment_data *stream_get_frag_data( const stream_pdu_fragment_t *frag)
471 {
472     DISSECTOR_ASSERT( frag );
473     return frag->pdu->fd_head;
474 }
475
476 guint32 stream_get_pdu_no( const stream_pdu_fragment_t *frag)
477 {
478     DISSECTOR_ASSERT( frag );
479     return frag->pdu->pdu_number;
480 }