HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / stream.c
blobf7df235ce3cd2bfa8c750b28ca6c49458d8b2823
1 /* stream.c
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
7 * $Id$
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
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.
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.
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.
28 #include "config.h"
30 #include <glib.h>
31 #include <epan/packet.h>
32 #include <epan/emem.h>
33 #include <epan/reassemble.h>
34 #include <epan/stream.h>
35 #include <epan/tvbuff.h>
38 typedef struct {
39 fragment_head *fd_head; /* the reassembled data, NULL
40 * until we add the last fragment */
41 guint32 pdu_number; /* Number of this PDU within the stream */
43 /* id of this pdu (globally unique) */
44 guint32 id;
45 } stream_pdu_t;
48 struct stream_pdu_fragment
50 guint32 len; /* the length of this fragment */
51 stream_pdu_t *pdu;
52 gboolean final_fragment;
55 struct stream {
56 /* the key used to add this stream to stream_hash */
57 struct stream_key *key;
59 /* pdu to add the next fragment to, or NULL if we need to start
60 * a new PDU.
62 stream_pdu_t *current_pdu;
64 /* number of PDUs added to this stream so far */
65 guint32 pdu_counter;
67 /* the framenumber and offset of the last fragment added;
68 used for sanity-checking */
69 guint32 lastfrag_framenum;
70 guint32 lastfrag_offset;
74 /*****************************************************************************
76 * Stream hash
79 /* key */
80 typedef struct stream_key {
81 /* streams can be attached to circuits or conversations, and we note
82 that here */
83 gboolean is_circuit;
84 union {
85 const struct circuit *circuit;
86 const struct conversation *conv;
87 } circ;
88 int p2p_dir;
89 } stream_key_t;
92 /* hash func */
93 static guint stream_hash_func(gconstpointer k)
95 const stream_key_t *key = (const stream_key_t *)k;
97 /* is_circuit is redundant to the circuit/conversation pointer */
98 return ((guint)(unsigned long)key->circ.circuit) ^ key->p2p_dir;
101 /* compare func */
102 static gboolean stream_compare_func(gconstpointer a,
103 gconstpointer b)
105 const stream_key_t *key1 = (const stream_key_t *)a;
106 const stream_key_t *key2 = (const stream_key_t *)b;
107 if( key1 -> p2p_dir != key2 -> p2p_dir ||
108 key1-> is_circuit != key2 -> is_circuit )
109 return FALSE;
111 if( key1 -> is_circuit )
112 return (key1 -> circ.circuit == key2 -> circ.circuit );
113 else
114 return (key1 -> circ.conv == key2 -> circ.conv );
117 /* the hash table */
118 static GHashTable *stream_hash;
121 /* cleanup reset function, call from stream_cleanup() */
122 static void cleanup_stream_hash( void ) {
123 if( stream_hash != NULL ) {
124 g_hash_table_destroy( stream_hash );
125 stream_hash = NULL;
129 /* init function, call from stream_init() */
130 static void init_stream_hash( void ) {
131 g_assert(stream_hash==NULL);
132 stream_hash = g_hash_table_new(stream_hash_func,
133 stream_compare_func);
136 /* lookup function, returns null if not found */
137 static stream_t *stream_hash_lookup_circ( const struct circuit *circuit, int p2p_dir )
139 stream_key_t key;
140 key.is_circuit=TRUE;
141 key.circ.circuit=circuit;
142 key.p2p_dir=p2p_dir;
143 return (stream_t *)g_hash_table_lookup(stream_hash, &key);
146 static stream_t *stream_hash_lookup_conv( const struct conversation *conv, int p2p_dir )
148 stream_key_t key;
149 key.is_circuit=FALSE;
150 key.circ.conv = conv;
151 key.p2p_dir=p2p_dir;
152 return (stream_t *)g_hash_table_lookup(stream_hash, &key);
156 static stream_t *new_stream( stream_key_t *key )
158 stream_t *val;
160 val = se_new(stream_t);
161 val -> key = key;
162 val -> pdu_counter = 0;
163 val -> current_pdu = NULL;
164 val -> lastfrag_framenum = 0;
165 val -> lastfrag_offset = 0;
166 g_hash_table_insert(stream_hash, key, val);
168 return val;
172 /* insert function */
173 static stream_t *stream_hash_insert_circ( const struct circuit *circuit, int p2p_dir )
175 stream_key_t *key;
177 key = se_new(stream_key_t);
178 key->is_circuit = TRUE;
179 key->circ.circuit = circuit;
180 key->p2p_dir = p2p_dir;
182 return new_stream(key);
185 static stream_t *stream_hash_insert_conv( const struct conversation *conv, int p2p_dir )
187 stream_key_t *key;
189 key = se_new(stream_key_t);
190 key->is_circuit = FALSE;
191 key->circ.conv = conv;
192 key->p2p_dir = p2p_dir;
194 return new_stream(key);
198 /******************************************************************************
200 * PDU data
203 /* pdu counter, for generating unique pdu ids */
204 static guint32 pdu_counter;
206 static void stream_cleanup_pdu_data(void)
210 static void stream_init_pdu_data(void)
212 pdu_counter = 0;
216 /* new pdu in this stream */
217 static stream_pdu_t *stream_new_pdu(stream_t *stream)
219 stream_pdu_t *pdu;
220 pdu = se_new(stream_pdu_t);
221 pdu -> fd_head = NULL;
222 pdu -> pdu_number = stream -> pdu_counter++;
223 pdu -> id = pdu_counter++;
224 return pdu;
227 /*****************************************************************************
229 * fragment hash
232 /* key */
233 typedef struct fragment_key {
234 const stream_t *stream;
235 guint32 framenum;
236 guint32 offset;
237 } fragment_key_t;
240 /* hash func */
241 static guint fragment_hash_func(gconstpointer k)
243 const fragment_key_t *key = (const fragment_key_t *)k;
244 return ((guint)(unsigned long)key->stream) + ((guint)key -> framenum) + ((guint)key->offset);
247 /* compare func */
248 static gboolean fragment_compare_func(gconstpointer a,
249 gconstpointer b)
251 const fragment_key_t *key1 = (const fragment_key_t *)a;
252 const fragment_key_t *key2 = (const fragment_key_t *)b;
253 return (key1 -> stream == key2 -> stream &&
254 key1 -> framenum == key2 -> framenum &&
255 key1 -> offset == key2 -> offset );
258 /* the hash table */
259 static GHashTable *fragment_hash;
262 /* cleanup function, call from stream_cleanup() */
263 static void cleanup_fragment_hash( void ) {
264 if( fragment_hash != NULL ) {
265 g_hash_table_destroy( fragment_hash );
266 fragment_hash = NULL;
270 /* init function, call from stream_init() */
271 static void init_fragment_hash( void ) {
272 g_assert(fragment_hash==NULL);
273 fragment_hash = g_hash_table_new(fragment_hash_func,
274 fragment_compare_func);
278 /* lookup function, returns null if not found */
279 static stream_pdu_fragment_t *fragment_hash_lookup( const stream_t *stream, guint32 framenum, guint32 offset )
281 fragment_key_t key;
282 stream_pdu_fragment_t *val;
284 key.stream = stream;
285 key.framenum = framenum;
286 key.offset = offset;
287 val = (stream_pdu_fragment_t *)g_hash_table_lookup(fragment_hash, &key);
289 return val;
293 /* insert function */
294 static stream_pdu_fragment_t *fragment_hash_insert( const stream_t *stream, guint32 framenum, guint32 offset,
295 guint32 length)
297 fragment_key_t *key;
298 stream_pdu_fragment_t *val;
300 key = se_new(fragment_key_t);
301 key->stream = stream;
302 key->framenum = framenum;
303 key->offset = offset;
305 val = se_new(stream_pdu_fragment_t);
306 val->len = length;
307 val->pdu = NULL;
308 val->final_fragment = FALSE;
310 g_hash_table_insert(fragment_hash, key, val);
311 return val;
314 /*****************************************************************************/
316 /* reassembly table */
317 static reassembly_table stream_reassembly_table;
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 )
323 stream_t * stream;
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 );
330 stream = stream_hash_insert_circ(circuit, p2p_dir);
332 return stream;
335 stream_t *stream_new_conv ( const struct conversation *conv, int p2p_dir )
337 stream_t * stream;
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 );
344 stream = stream_hash_insert_conv(conv, p2p_dir);
345 return stream;
349 /* retrieve a previously-created stream.
351 * Returns null if no matching stream was found.
353 stream_t *find_stream_circ ( const struct circuit *circuit, int p2p_dir )
355 return stream_hash_lookup_circ(circuit,p2p_dir);
357 stream_t *find_stream_conv ( const struct conversation *conv, int p2p_dir )
359 return stream_hash_lookup_conv(conv,p2p_dir);
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.
367 void stream_cleanup( void )
369 cleanup_stream_hash();
370 cleanup_fragment_hash();
371 stream_cleanup_pdu_data();
374 /* initialise the stream routines */
375 void stream_init( void )
377 init_stream_hash();
378 init_fragment_hash();
379 stream_init_pdu_data();
381 reassembly_table_init(&stream_reassembly_table,
382 &addresses_reassembly_table_functions);
385 /*****************************************************************************/
387 stream_pdu_fragment_t *stream_find_frag( stream_t *stream, guint32 framenum, guint32 offset )
389 return fragment_hash_lookup( stream, framenum, offset );
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 )
395 fragment_head *fd_head;
396 stream_pdu_t *pdu;
397 stream_pdu_fragment_t *frag_data;
399 DISSECTOR_ASSERT(stream);
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));
406 pdu = stream->current_pdu;
407 if( pdu == NULL ) {
408 /* start a new pdu */
409 pdu = stream->current_pdu = stream_new_pdu(stream);
412 /* add it to the reassembly tables */
413 fd_head = fragment_add_seq_next(&stream_reassembly_table,
414 tvb, 0, pinfo, pdu->id, NULL,
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;
420 if( fd_head != NULL ) {
421 /* if this was the last fragment, update the pdu data.
423 pdu -> fd_head = fd_head;
425 /* start a new pdu next time */
426 stream->current_pdu = NULL;
428 frag_data -> final_fragment = TRUE;
431 /* stashing the framenum and offset permit future sanity checks */
432 stream -> lastfrag_framenum = framenum;
433 stream -> lastfrag_offset = offset;
435 return frag_data;
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)
445 stream_pdu_t *pdu;
446 DISSECTOR_ASSERT(frag);
447 pdu = frag->pdu;
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);
457 return NULL;
460 return process_reassembled_data(tvb, offset, pinfo, name, pdu->fd_head,
461 fit, update_col_infop, tree);
464 guint32 stream_get_frag_length( const stream_pdu_fragment_t *frag)
466 DISSECTOR_ASSERT( frag );
467 return frag->len;
470 fragment_head *stream_get_frag_data( const stream_pdu_fragment_t *frag)
472 DISSECTOR_ASSERT( frag );
473 return frag->pdu->fd_head;
476 guint32 stream_get_pdu_no( const stream_pdu_fragment_t *frag)
478 DISSECTOR_ASSERT( frag );
479 return frag->pdu->pdu_number;