Add printf-format annotations, fix garbage
[metze/wireshark/wip.git] / plugins / mate / mate_runtime.c
1 /* mate_runtime.c
2 * MATE -- Meta Analysis Tracing Engine
3 *
4 * Copyright 2004, Luis E. Garcia Ontanon <luis@ontanon.org>
5 *
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 */
24
25 #include "mate.h"
26
27 typedef struct _mate_range mate_range;
28
29 struct _mate_range {
30         guint start;
31         guint end;
32 };
33
34
35 typedef struct _tmp_pdu_data {
36         GPtrArray* ranges;
37         proto_tree* tree;
38         mate_pdu* pdu;
39 } tmp_pdu_data;
40
41
42 typedef struct _gogkey {
43         gchar* key;
44         mate_cfg_gop* cfg;
45 } gogkey;
46
47
48 static mate_runtime_data* rd = NULL;
49 static mate_config* mc = NULL;
50
51 static int zero = 5;
52
53 static int* dbg = &zero;
54 static int* dbg_pdu = &zero;
55 static int* dbg_gop = &zero;
56 static int* dbg_gog = &zero;
57 static FILE* dbg_facility = NULL;
58
59 static gboolean destroy_mate_pdus(gpointer k _U_, gpointer v, gpointer p _U_) {
60         mate_pdu* pdu = (mate_pdu*) v;
61         if (pdu->avpl) delete_avpl(pdu->avpl,TRUE);
62         g_slice_free(mate_max_size, (mate_max_size *)pdu);
63         return TRUE;
64 }
65
66 static gboolean destroy_mate_gops(gpointer k _U_, gpointer v, gpointer p _U_) {
67         mate_gop* gop = (mate_gop*) v;
68
69         if (gop->avpl) delete_avpl(gop->avpl,TRUE);
70
71         if (gop->gop_key) {
72                 if (g_hash_table_lookup(gop->cfg->gop_index,gop->gop_key) == gop) {
73                         g_hash_table_remove(gop->cfg->gop_index,gop->gop_key);
74                 }
75
76                 g_free(gop->gop_key);
77         }
78
79         g_slice_free(mate_max_size,(mate_max_size*)gop);
80
81         return TRUE;
82 }
83
84
85 static void gog_remove_keys (mate_gog* gog);
86
87 static gboolean destroy_mate_gogs(gpointer k _U_, gpointer v, gpointer p _U_) {
88         mate_gog* gog = (mate_gog*) v;
89
90         if (gog->avpl) delete_avpl(gog->avpl,TRUE);
91
92         if (gog->gog_keys) {
93                 gog_remove_keys(gog);
94                 g_ptr_array_free(gog->gog_keys,FALSE);
95         }
96
97         g_slice_free(mate_max_size,(mate_max_size*)gog);
98
99         return TRUE;
100 }
101
102 static gboolean return_true(gpointer k _U_, gpointer v _U_, gpointer p _U_) {
103         return TRUE;
104 }
105
106 static void destroy_pdus_in_cfg(gpointer k _U_, gpointer v, gpointer p _U_) {
107         mate_cfg_pdu* c = (mate_cfg_pdu *)v;
108         g_hash_table_foreach_remove(c->items,destroy_mate_pdus,NULL);
109         c->last_id = 0;
110 }
111
112
113 static void destroy_gops_in_cfg(gpointer k _U_, gpointer v, gpointer p _U_) {
114         mate_cfg_gop* c = (mate_cfg_gop *)v;
115
116         g_hash_table_foreach_remove(c->gop_index,return_true,NULL);
117         g_hash_table_destroy(c->gop_index);
118         c->gop_index = g_hash_table_new(g_str_hash,g_str_equal);
119
120         g_hash_table_foreach_remove(c->gog_index,return_true,NULL);
121         g_hash_table_destroy(c->gog_index);
122         c->gog_index = g_hash_table_new(g_str_hash,g_str_equal);
123
124         g_hash_table_foreach_remove(c->items,destroy_mate_gops,NULL);
125         c->last_id = 0;
126 }
127
128 static void destroy_gogs_in_cfg(gpointer k _U_, gpointer v, gpointer p _U_) {
129         mate_cfg_gog* c = (mate_cfg_gog *)v;
130         g_hash_table_foreach_remove(c->items,destroy_mate_gogs,NULL);
131         c->last_id = 0;
132 }
133
134 extern void initialize_mate_runtime(void) {
135
136         dbg_print (dbg,5,dbg_facility,"initialize_mate: entering");
137
138         if (( mc = mate_cfg() )) {
139                 if (rd == NULL ) {
140                         rd = (mate_runtime_data *)g_malloc(sizeof(mate_runtime_data));
141                 } else {
142                         g_hash_table_foreach(mc->pducfgs,destroy_pdus_in_cfg,NULL);
143                         g_hash_table_foreach(mc->gopcfgs,destroy_gops_in_cfg,NULL);
144                         g_hash_table_foreach(mc->gogcfgs,destroy_gogs_in_cfg,NULL);
145
146                         g_hash_table_destroy(rd->frames);
147                 }
148
149                 rd->current_items = 0;
150                 rd->now = -1.0f;
151                 rd->highest_analyzed_frame = 0;
152                 rd->frames = g_hash_table_new(g_direct_hash,g_direct_equal);
153
154
155                 /*mc->dbg_gop_lvl = 5;
156                 mc->dbg_gog_lvl = 5;
157                 */
158                 dbg_pdu = &(mc->dbg_pdu_lvl);
159                 dbg_gop = &(mc->dbg_gop_lvl);
160                 dbg_gog = &(mc->dbg_gog_lvl);
161                 dbg = &(mc->dbg_lvl);
162                 dbg_facility = mc->dbg_facility;
163
164                 dbg_print(dbg, 1, dbg_facility, "starting mate");
165
166         } else {
167                 rd = NULL;
168         }
169 }
170
171
172 static mate_gop* new_gop(mate_cfg_gop* cfg, mate_pdu* pdu, gchar* key) {
173         mate_gop* gop = (mate_gop*)g_slice_new(mate_max_size);
174
175         gop->id = ++(cfg->last_id);
176         gop->cfg = cfg;
177
178         dbg_print(dbg_gop, 1, dbg_facility, "new_gop: %s: ``%s:%d''", key, gop->cfg->name, gop->id);
179
180         gop->gop_key = key;
181         gop->avpl = new_avpl(cfg->name);
182         gop->last_n = 0;
183
184         gop->gog = NULL;
185         gop->next = NULL;
186
187         gop->expiration = cfg->expiration > 0.0 ? cfg->expiration + rd->now : (float) -1.0 ;
188         gop->idle_expiration = cfg->idle_timeout > 0.0 ? cfg->idle_timeout + rd->now : (float) -1.0 ;
189         gop->time_to_die = cfg->lifetime > 0.0 ? cfg->lifetime + rd->now : (float) -1.0 ;
190         gop->time_to_timeout = 0.0f;
191
192         gop->last_time = gop->start_time = rd->now;
193         gop->release_time = 0.0f;
194
195         gop->num_of_pdus = 0;
196         gop->num_of_after_release_pdus = 0;
197
198         gop->pdus = pdu;
199         gop->last_pdu = pdu;
200
201         gop->released = FALSE;
202
203         pdu->gop = gop;
204         pdu->next = NULL;
205         pdu->is_start = TRUE;
206         pdu->time_in_gop = 0.0f;
207
208         g_hash_table_insert(cfg->gop_index,gop->gop_key,gop);
209         return gop;
210 }
211
212 static void adopt_gop(mate_gog* gog, mate_gop* gop) {
213         dbg_print (dbg_gog,5,dbg_facility,"adopt_gop: gog=%p gop=%p",gog,gop);
214
215         gop->gog = gog;
216         gop->next = NULL;
217
218         if (gop->cfg->start) {
219                 gog->num_of_counting_gops++;
220         }
221
222         gog->num_of_gops++;
223
224         if (gog->last_gop) {
225                 gog->last_gop->next = gop;
226         }
227
228         gog->last_gop = gop;
229
230         if (! gog->gops ) {
231                 gog->gops = gop;
232         }
233
234 }
235
236 static mate_gog* new_gog(mate_cfg_gog* cfg, mate_gop* gop) {
237         mate_gog* gog = (mate_gog*)g_slice_new(mate_max_size);
238         gog->id = ++(cfg->last_id);
239         gog->cfg = cfg;
240
241         dbg_print (dbg_gog,1,dbg_facility,"new_gog: %s:%u for %s:%u",gog->cfg->name,gog->id,gop->cfg->name,gop->id);
242
243         gog->avpl = new_avpl(cfg->name);
244         gog->last_n = 0;
245
246         gog->expiration = 0.0f;
247         gog->idle_expiration = 0.0f;
248
249         gog->start_time = rd->now;
250         gog->release_time = 0.0f;
251         gog->last_time = 0.0f;
252
253         gog->gops = NULL;
254         gog->last_gop = NULL;
255
256         gog->num_of_gops = 0;
257         gog->num_of_counting_gops = 0;
258         gog->num_of_released_gops = 0;
259
260         gog->gog_keys = g_ptr_array_new();
261
262         adopt_gop(gog,gop);
263
264         return gog;
265 }
266
267 static void apply_transforms(GPtrArray* transforms, AVPL* avpl) {
268         AVPL_Transf* transform = NULL;
269         guint i;
270
271         for (i = 0; i < transforms->len; i++) {
272                 transform = (AVPL_Transf *)g_ptr_array_index(transforms,i);
273                 avpl_transform(avpl, transform);
274         }
275 }
276
277
278 /* applies the extras for which type to what avpl */
279 static void apply_extras(AVPL* from, AVPL* to,  AVPL* extras) {
280         AVPL* our_extras = new_avpl_loose_match("",from, extras, FALSE) ;
281
282         if (our_extras) {
283                 merge_avpl(to,our_extras,TRUE);
284                 delete_avpl(our_extras,FALSE);
285         }
286 }
287
288 static void gog_remove_keys (mate_gog* gog) {
289         gogkey* gog_key;
290
291         while (gog->gog_keys->len) {
292                 gog_key = (gogkey *)g_ptr_array_remove_index_fast(gog->gog_keys,0);
293
294                 if (g_hash_table_lookup(gog_key->cfg->gog_index,gog_key->key) == gog) {
295                         g_hash_table_remove(gog_key->cfg->gog_index,gog_key->key);
296                 }
297
298                 g_free(gog_key->key);
299                 g_free(gog_key);
300         }
301
302 }
303
304 static void reanalyze_gop(mate_gop* gop) {
305         LoAL* gog_keys = NULL;
306         AVPL* curr_gogkey = NULL;
307         mate_cfg_gop* gop_cfg = NULL;
308         void* cookie = NULL;
309         AVPL* gogkey_match = NULL;
310         mate_gog* gog = gop->gog;
311         gogkey* gog_key;
312
313         if ( ! gog ) return;
314
315         gog->last_time = rd->now;
316
317         dbg_print (dbg_gog,1,dbg_facility,"reanalyze_gop: %s:%d",gop->cfg->name,gop->id);
318
319         apply_extras(gop->avpl,gog->avpl,gog->cfg->extra);
320
321         /* XXX: Instead of using the length of the avpl to check if an avpl has changed,
322                         which is not accurate at all,  we should have apply_extras,
323                         apply_transformations and other functions that can modify the avpl
324                     to flag the avpl if it has changed, then we'll check for the flag
325                     and clear it after analysis */
326
327         if (gog->last_n != gog->avpl->len) {
328
329                 dbg_print (dbg_gog,2,dbg_facility,"reanalyze_gop: gog has new attributes let's look for new keys");
330
331                 gog_keys = gog->cfg->keys;
332
333                 while (( curr_gogkey = get_next_avpl(gog_keys,&cookie) )) {
334                         gop_cfg = (mate_cfg_gop *)g_hash_table_lookup(mc->gopcfgs,curr_gogkey->name);
335
336                         if (( gogkey_match = new_avpl_exact_match(gop_cfg->name,gog->avpl,curr_gogkey,FALSE) )) {
337
338                                 gog_key = (gogkey *)g_malloc(sizeof(gogkey));
339
340                                 gog_key->key = avpl_to_str(gogkey_match);
341                                 delete_avpl(gogkey_match,FALSE);
342
343                                 gog_key->cfg = gop_cfg;
344
345                                 if (g_hash_table_lookup(gop_cfg->gog_index,gog_key->key)) {
346                                         g_free(gog_key->key);
347                                         g_free(gog_key);
348                                         gog_key = NULL;
349                                 }
350
351                                 if (! gog_key ) {
352                                         /* XXX: since these gogs actually share key info
353                                                         we should try to merge (non released) gogs
354                                                 that happen to have equal keys */
355                                 } else {
356                                         dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: new key for gog=%s:%d : %s",gog->cfg->name,gog->id,gog_key->key);
357                                         g_ptr_array_add(gog->gog_keys,gog_key);
358                                         g_hash_table_insert(gog_key->cfg->gog_index,gog_key->key,gog);
359                                 }
360
361                         }
362                 }
363
364                 gog->last_n = gog->avpl->len;
365         }
366
367         if (gog->num_of_released_gops == gog->num_of_counting_gops) {
368                 gog->released =  TRUE;
369                 gog->expiration = gog->cfg->expiration + rd->now;
370         } else {
371                 gog->released =  FALSE;
372         }
373 }
374
375 static void analyze_gop(mate_gop* gop) {
376         mate_cfg_gog* cfg = NULL;
377         LoAL* gog_keys = NULL;
378         AVPL* curr_gogkey = NULL;
379         void* cookie = NULL;
380         AVPL* gogkey_match = NULL;
381         mate_gog* gog = NULL;
382         gchar* key = NULL;
383
384         if ( ! gop->gog  ) {
385                 /* no gog, let's either find one or create it if due */
386                 dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: no gog");
387
388                 gog_keys = (LoAL *)g_hash_table_lookup(mc->gogs_by_gopname,gop->cfg->name);
389
390                 if ( ! gog_keys ) {
391                         dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: no gog_keys for this gop");
392                         return;
393                 }
394
395                 /* We have gog_keys! look for matching gogkeys */
396
397                 dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: got gog_keys: %s",gog_keys->name) ;
398
399                 while (( curr_gogkey = get_next_avpl(gog_keys,&cookie) )) {
400                         if (( gogkey_match = new_avpl_exact_match(gop->cfg->name,gop->avpl,curr_gogkey,TRUE) )) {
401
402                                 key = avpl_to_str(gogkey_match);
403
404                                 dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: got gogkey_match: %s",key);
405
406                                 if (( gog = (mate_gog *)g_hash_table_lookup(gop->cfg->gog_index,key) )) {
407                                         dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: got already a matching gog");
408
409                                         if (gog->num_of_counting_gops == gog->num_of_released_gops && gog->expiration < rd->now) {
410                                                 dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: this is a new gog, not the old one, let's create it");
411
412                                                 gog_remove_keys(gog);
413
414                                                 new_gog(gog->cfg,gop);
415
416                                                 break;
417                                         } else {
418                                                 dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: this is our gog");
419
420                                                 if (! gop->gog ) adopt_gop(gog,gop);
421
422                                                 break;
423                                         }
424                                 } else {
425                                         dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: no such gog in hash, let's create a new %s",curr_gogkey->name);
426
427                                         cfg = (mate_cfg_gog *)g_hash_table_lookup(mc->gogcfgs,curr_gogkey->name);
428
429                                         if (cfg) {
430                                                 gog = new_gog(cfg,gop);
431                                                 gog->num_of_gops = 1;
432
433                                                 if (gop->cfg->start) {
434                                                         gog->num_of_counting_gops = 1;
435                                                 }
436
437                                         } else {
438                                                 dbg_print (dbg_gog,0,dbg_facility,"analyze_gop: no such gog_cfg: %s",curr_gogkey->name);
439                                         }
440
441                                         break;
442                                 }
443
444                                 /** Can't get here because of "breaks" above */
445                                 g_assert_not_reached();
446                         }
447
448                         dbg_print (dbg_gog,1,dbg_facility,"analyze_gop: no gogkey_match: %s",key);
449                 } /* while */
450
451                 g_free(key);
452                 key = NULL;
453
454                 if (gogkey_match) delete_avpl(gogkey_match,TRUE);
455
456                 reanalyze_gop(gop);
457         }
458 }
459
460
461
462 static void analyze_pdu(mate_pdu* pdu) {
463         /* TODO:
464         return a g_boolean to tell we've destroyed the pdu when the pdu is unnassigned
465         destroy the unassigned pdu
466         */
467         mate_cfg_gop* cfg = NULL;
468         mate_gop* gop = NULL;
469         gchar* gop_key;
470         gchar* orig_gop_key = NULL;
471         AVPL* candidate_start = NULL;
472         AVPL* candidate_stop = NULL;
473         AVPL* is_start = NULL;
474         AVPL* is_stop = NULL;
475         AVPL* gopkey_match = NULL;
476         LoAL* gog_keys = NULL;
477         AVPL* curr_gogkey = NULL;
478         void* cookie = NULL;
479         AVPL* gogkey_match = NULL;
480         gchar* gogkey_str = NULL;
481
482         dbg_print (dbg_gop,1,dbg_facility,"analyze_pdu: %s",pdu->cfg->name);
483
484         if (! (cfg = (mate_cfg_gop *)g_hash_table_lookup(mc->gops_by_pduname,pdu->cfg->name)) )
485                 return;
486
487         if ((gopkey_match = new_avpl_exact_match("gop_key_match",pdu->avpl,cfg->key, TRUE))) {
488                 gop_key = avpl_to_str(gopkey_match);
489
490                 g_hash_table_lookup_extended(cfg->gop_index,(gconstpointer)gop_key,(gpointer *)&orig_gop_key,(gpointer *)&gop);
491
492                 if ( gop ) {
493                         g_free(gop_key);
494
495                         /* is the gop dead ? */
496                         if ( ! gop->released &&
497                                  ( ( gop->cfg->lifetime > 0.0 && gop->time_to_die >= rd->now) ||
498                                    ( gop->cfg->idle_timeout > 0.0 && gop->time_to_timeout >= rd->now) ) ) {
499                                 dbg_print (dbg_gop,4,dbg_facility,"analyze_pdu: expiring released gop");
500                                 gop->released = TRUE;
501
502                                 if (gop->gog && gop->cfg->start) gop->gog->num_of_released_gops++;
503                         }
504
505                         /* TODO: is the gop expired? */
506
507                         gop_key = orig_gop_key;
508
509                         dbg_print (dbg_gop,2,dbg_facility,"analyze_pdu: got gop: %s",gop_key);
510
511                         if (( candidate_start = cfg->start )) {
512
513                                 dbg_print (dbg_gop,2,dbg_facility,"analyze_pdu: got candidate start");
514
515                                 if (( is_start = new_avpl_exact_match("",pdu->avpl, candidate_start, FALSE) )) {
516                                         delete_avpl(is_start,FALSE);
517                                         if ( gop->released ) {
518                                                 dbg_print (dbg_gop,3,dbg_facility,"analyze_pdu: start on released gop, let's create a new gop");
519
520                                                 g_hash_table_remove(cfg->gop_index,gop_key);
521                                                 gop->gop_key = NULL;
522                                                 gop = new_gop(cfg,pdu,gop_key);
523                                                 g_hash_table_insert(cfg->gop_index,gop_key,gop);
524                                         } else {
525                                                 dbg_print (dbg_gop,1,dbg_facility,"analyze_pdu: duplicate start on gop");
526                                         }
527                                 }
528                         }
529
530                         pdu->gop = gop;
531
532                         if (gop->last_pdu) gop->last_pdu->next = pdu;
533                         gop->last_pdu = pdu;
534                         pdu->next = NULL;
535                         pdu->time_in_gop = rd->now - gop->start_time;
536
537                         if (gop->released) pdu->after_release = TRUE;
538
539                 } else {
540
541                         dbg_print (dbg_gop,1,dbg_facility,"analyze_pdu: no gop already");
542
543                         if ( ! cfg->start ) {
544                                 /* there is no GopStart, we'll check for matching GogKeys
545                                 if we have one we'll create the Gop */
546
547                                 apply_extras(pdu->avpl,gopkey_match,cfg->extra);
548
549                                 gog_keys = (LoAL *)g_hash_table_lookup(mc->gogs_by_gopname,cfg->name);
550
551                                 if (gog_keys) {
552
553                                         while (( curr_gogkey = get_next_avpl(gog_keys,&cookie) )) {
554                                                 if (( gogkey_match = new_avpl_exact_match(cfg->name,gopkey_match,curr_gogkey,FALSE) )) {
555                                                         gogkey_str = avpl_to_str(gogkey_match);
556
557                                                         if (g_hash_table_lookup(cfg->gog_index,gogkey_str)) {
558                                                                 gop = new_gop(cfg,pdu,gop_key);
559                                                                 g_hash_table_insert(cfg->gop_index,gop_key,gop);
560                                                                 delete_avpl(gogkey_match,FALSE);
561                                                                 g_free(gogkey_str);
562                                                                 break;
563                                                         } else {
564                                                                 delete_avpl(gogkey_match,FALSE);
565                                                                 g_free(gogkey_str);
566                                                         }
567                                                 }
568                                         }
569
570                                         if ( ! gop ) {
571                                                 g_free(gop_key);
572                                                 delete_avpl(gopkey_match,TRUE);
573                                                 return;
574                                         }
575
576                                 } else {
577                                         g_free(gop_key);
578                                         delete_avpl(gopkey_match,TRUE);
579                                         return;
580                                 }
581
582                         } else {
583                                 candidate_start = cfg->start;
584
585                                 if (( is_start = new_avpl_exact_match("",pdu->avpl, candidate_start, FALSE) )) {
586                                         delete_avpl(is_start,FALSE);
587                                         gop = new_gop(cfg,pdu,gop_key);
588                                 } else {
589                                         g_free(gop_key);
590                                         return;
591                                 }
592
593                                 pdu->gop = gop;
594                         }
595                 }
596
597                 if (gop->last_pdu) gop->last_pdu->next = pdu;
598                 gop->last_pdu = pdu;
599                 pdu->next = NULL;
600
601                 pdu->time_in_gop = rd->now - gop->start_time;
602
603                 gop->num_of_pdus++;
604                 gop->time_to_timeout = cfg->idle_timeout > 0.0 ? cfg->idle_timeout + rd->now : (float) -1.0 ;
605
606                 dbg_print (dbg_gop,4,dbg_facility,"analyze_pdu: merge with key");
607
608                 merge_avpl(gop->avpl,gopkey_match,TRUE);
609                 delete_avpl(gopkey_match,TRUE);
610
611                 dbg_print (dbg_gop,4,dbg_facility,"analyze_pdu: apply extras");
612
613                 apply_extras(pdu->avpl,gop->avpl,gop->cfg->extra);
614
615                 gop->last_time = pdu->rel_time;
616
617                 if ( ! gop->released) {
618                         candidate_stop = cfg->stop;
619
620                         if (candidate_stop) {
621                                 is_stop = new_avpl_exact_match("",pdu->avpl, candidate_stop,FALSE);
622                         } else {
623                                 is_stop = new_avpl("");
624                         }
625
626                         if(is_stop) {
627                                 dbg_print (dbg_gop,1,dbg_facility,"analyze_pdu: is a `stop");
628                                 delete_avpl(is_stop,FALSE);
629
630                                 if (! gop->released) {
631                                         gop->released = TRUE;
632                                         gop->release_time = pdu->rel_time;
633                                         if (gop->gog && gop->cfg->start) gop->gog->num_of_released_gops++;
634                                 }
635
636                                 pdu->is_stop = TRUE;
637
638                         }
639                 }
640
641                 if (gop->last_n != gop->avpl->len) apply_transforms(gop->cfg->transforms,gop->avpl);
642
643                 gop->last_n = gop->avpl->len;
644
645                 if (gop->gog) {
646                         reanalyze_gop(gop);
647                 } else {
648                         analyze_gop(gop);
649                 }
650
651         } else {
652                 dbg_print (dbg_gop,4,dbg_facility,"analyze_pdu: no match for this pdu");
653
654                 pdu->gop = NULL;
655         }
656 }
657
658 static void get_pdu_fields(gpointer k, gpointer v, gpointer p) {
659         int hfid = *((int*) k);
660         gchar* name = (gchar*) v;
661         tmp_pdu_data* data = (tmp_pdu_data*) p;
662         GPtrArray* fis;
663         field_info* fi;
664         guint i,j;
665         mate_range* curr_range;
666         guint start;
667         guint end;
668         AVP* avp;
669         gchar* s;
670
671
672         fis = proto_get_finfo_ptr_array(data->tree, hfid);
673
674         if (fis) {
675                 for (i = 0; i < fis->len; i++) {
676                         fi = (field_info*) g_ptr_array_index(fis,i);
677
678
679                         start = fi->start;
680                         end = fi->start + fi->length;
681
682                         dbg_print(dbg_pdu,5,dbg_facility,"get_pdu_fields: found field %i-%i",start,end);
683
684                         for (j = 0; j < data->ranges->len; j++) {
685
686                                 curr_range = (mate_range*) g_ptr_array_index(data->ranges,j);
687
688                                 if (curr_range->end >= end && curr_range->start <= start) {
689                                         avp = new_avp_from_finfo(name, fi);
690
691                                         if (*dbg_pdu > 4) {
692                                                 s = avp_to_str(avp);
693                                                 dbg_print(dbg_pdu,0,dbg_facility,"get_pdu_fields: got %s",s);
694                                                 g_free(s);
695                                         }
696
697                                         if (! insert_avp(data->pdu->avpl,avp) ) {
698                                                 delete_avp(avp);
699                                         }
700
701                                 }
702                         }
703                 }
704         }
705 }
706
707 static mate_pdu* new_pdu(mate_cfg_pdu* cfg, guint32 framenum, field_info* proto, proto_tree* tree) {
708         mate_pdu* pdu = (mate_pdu*)g_slice_new(mate_max_size);
709         field_info* cfi;
710         GPtrArray* ptrs;
711         mate_range* range;
712         mate_range* proto_range;
713         tmp_pdu_data data;
714         guint i,j;
715         gint min_dist;
716         field_info* range_fi;
717         gint32 last_start;
718         gint32 first_end;
719         gint32 curr_end;
720         int hfid;
721
722         dbg_print (dbg_pdu,1,dbg_facility,"new_pdu: type=%s framenum=%i",cfg->name,framenum);
723
724         pdu->id = ++(cfg->last_id);
725         pdu->cfg = cfg;
726
727         pdu->avpl = new_avpl(cfg->name);
728
729         pdu->frame = framenum;
730         pdu->next_in_frame = NULL;
731         pdu->rel_time = rd->now;
732
733         pdu->gop = NULL;
734         pdu->next = NULL;
735         pdu->time_in_gop = -1.0f;
736
737         pdu->first = FALSE;
738         pdu->is_start = FALSE;
739         pdu->is_stop = FALSE;
740         pdu->after_release = FALSE;
741
742         data.ranges = g_ptr_array_new();
743         data.pdu  = pdu;
744         data.tree = tree;
745
746         /* first we create the proto range */
747         proto_range = (mate_range *)g_malloc(sizeof(mate_range));
748         proto_range->start = proto->start;
749         proto_range->end = proto->start + proto->length;
750         g_ptr_array_add(data.ranges,proto_range);
751
752         dbg_print(dbg_pdu,3,dbg_facility,"new_pdu: proto range %u-%u",proto_range->start,proto_range->end);
753
754         last_start = proto_range->start;
755
756         /* we move forward in the tranport */
757         for (i = cfg->transport_ranges->len; i--; ) {
758                 hfid = *((int*)g_ptr_array_index(cfg->transport_ranges,i));
759                 ptrs = proto_get_finfo_ptr_array(tree, hfid);
760                 min_dist = 99999;
761                 range_fi = NULL;
762
763                 if (ptrs) {
764                         for (j=0; j < ptrs->len; j++) {
765                                 cfi = (field_info*) g_ptr_array_index(ptrs,j);
766                                 if (cfi->start < last_start && min_dist >= (last_start - cfi->start) ) {
767                                         range_fi = cfi;
768                                         min_dist = last_start - cfi->start;
769                                 }
770                         }
771
772                         if ( range_fi ) {
773                                 range = (mate_range *)g_malloc(sizeof(*range));
774                                 range->start = range_fi->start;
775                                 range->end = range_fi->start + range_fi->length;
776                                 g_ptr_array_add(data.ranges,range);
777
778                                 last_start = range_fi->start;
779
780                                 dbg_print(dbg_pdu,3,dbg_facility,"new_pdu: transport(%i) range %i-%i",hfid,range->start,range->end);
781                         } else {
782                                 /* we missed a range  */
783                                 dbg_print(dbg_pdu,6,dbg_facility,"new_pdu: transport(%i) missed",hfid);
784                         }
785
786                 }
787         }
788
789         if (cfg->payload_ranges) {
790
791                 first_end = proto_range->end;
792
793                 for (i = 0 ; i < cfg->payload_ranges->len; i++) {
794                         hfid = *((int*)g_ptr_array_index(cfg->payload_ranges,i));
795                         ptrs = proto_get_finfo_ptr_array(tree, hfid);
796                         min_dist = 99999;
797                         range_fi = NULL;
798
799                         if (ptrs) {
800                                 for (j=0; j < ptrs->len; j++) {
801                                         cfi = (field_info*) g_ptr_array_index(ptrs,j);
802                                         curr_end = cfi->start + cfi->length;
803                                         if (curr_end > first_end && min_dist >= (curr_end - first_end) ) {
804                                                 range_fi = cfi;
805                                                 min_dist = curr_end - first_end;
806                                         }
807                                 }
808
809                                 if ( range_fi ) {
810                                         range = (mate_range *)g_malloc(sizeof(*range));
811                                         range->start = range_fi->start;
812                                         range->end = range_fi->start + range_fi->length;
813                                         g_ptr_array_add(data.ranges,range);
814
815                                         dbg_print(dbg_pdu,3,dbg_facility,"new_pdu: payload(%i) range %i-%i",hfid,range->start,range->end);
816                                 } else {
817                                         /* we missed a range  */
818                                         dbg_print(dbg_pdu,5,dbg_facility,"new_pdu: payload(%i) missed",hfid);
819                                 }
820
821                         }
822                 }
823         }
824
825         g_hash_table_foreach(cfg->hfids_attr,get_pdu_fields,&data);
826
827         apply_transforms(pdu->cfg->transforms,pdu->avpl);
828
829         g_ptr_array_free(data.ranges,TRUE);
830
831         return pdu;
832 }
833
834
835 extern void mate_analyze_frame(packet_info *pinfo, proto_tree* tree) {
836         mate_cfg_pdu* cfg;
837         GPtrArray* protos;
838         field_info* proto;
839         guint i,j;
840         AVPL* criterium_match;
841
842         mate_pdu* pdu = NULL;
843         mate_pdu* last = NULL;
844
845         rd->now = (float) nstime_to_sec(&pinfo->rel_ts);
846
847         if ( proto_tracking_interesting_fields(tree)
848                  && rd->highest_analyzed_frame < pinfo->fd->num ) {
849                 for ( i = 0; i < mc->pducfglist->len; i++ ) {
850
851                         cfg = (mate_cfg_pdu *)g_ptr_array_index(mc->pducfglist,i);
852
853                         dbg_print (dbg_pdu,4,dbg_facility,"mate_analyze_frame: trying to extract: %s",cfg->name);
854                         protos = proto_get_finfo_ptr_array(tree, cfg->hfid_proto);
855
856                         if (protos)  {
857                                 pdu = NULL;
858
859                                 for (j = 0; j < protos->len; j++) {
860
861                                         dbg_print (dbg_pdu,3,dbg_facility,"mate_analyze_frame: found matching proto, extracting: %s",cfg->name);
862
863                                         proto = (field_info*) g_ptr_array_index(protos,j);
864                                         pdu = new_pdu(cfg, pinfo->fd->num, proto, tree);
865
866                                         if (cfg->criterium) {
867                                                 criterium_match = new_avpl_from_match(cfg->criterium_match_mode,"",pdu->avpl,cfg->criterium,FALSE);
868
869                                                 if (criterium_match) {
870                                                         delete_avpl(criterium_match,FALSE);
871                                                 }
872
873                                                 if ( (criterium_match && cfg->criterium_accept_mode == REJECT_MODE )
874                                                          || ( ! criterium_match && cfg->criterium_accept_mode == ACCEPT_MODE )) {
875
876                                                         delete_avpl(pdu->avpl,TRUE);
877                                                         g_slice_free(mate_max_size,(mate_max_size*)pdu);
878                                                         pdu = NULL;
879
880                                                         continue;
881                                                 }
882                                         }
883
884                                         analyze_pdu(pdu);
885
886                                         if ( ! pdu->gop && cfg->drop_unassigned) {
887                                                 delete_avpl(pdu->avpl,TRUE);
888                                                 g_slice_free(mate_max_size,(mate_max_size*)pdu);
889                                                 pdu = NULL;
890                                                 continue;
891                                         }
892
893                                         if ( cfg->discard ) {
894                                                 delete_avpl(pdu->avpl,TRUE);
895                                                 pdu->avpl = NULL;
896                                         }
897
898                                         if (!last) {
899                                                 g_hash_table_insert(rd->frames,GINT_TO_POINTER(pinfo->fd->num),pdu);
900                                                 last = pdu;
901                                         } else {
902                                                 last->next_in_frame = pdu;
903                                                 last = pdu;
904                                         }
905
906                                 }
907
908                                 if ( pdu && cfg->last_extracted ) break;
909                         }
910                 }
911
912                 rd->highest_analyzed_frame = pinfo->fd->num;
913         }
914 }
915
916 extern mate_pdu* mate_get_pdus(guint32 framenum) {
917
918         if (rd) {
919                 return (mate_pdu*) g_hash_table_lookup(rd->frames,GUINT_TO_POINTER(framenum));
920         } else {
921                 return NULL;
922         }
923 }
924
925
926