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