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