name change
[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@gmail.com>
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         GHashTable* interesting;
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,"reanalize_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,"reanalize_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,"analize_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 analize_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 ( ! ( gog = gop->gog ) ) {
389                 /* no gog, let's either find one or create it if due */
390                 dbg_print (dbg_gog,1,dbg_facility,"analize_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,"analize_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,"analize_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,"analize_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,"analize_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,"analize_gop: this is a new gog, not the old one, let's create it");
415                                                 
416                                                 gog_remove_keys(gog);
417                                                 
418                                                 gog = new_gog(gog->cfg,gop);
419                                                 
420                                                 break;
421                                         } else {
422                                                 dbg_print (dbg_gog,1,dbg_facility,"analize_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,"analize_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,"analize_gop: no such gog_cfg: %s",curr_gogkey->name);
443                                         }
444                                         
445                                         break;
446                                 }
447                                 
448                                 
449                                 delete_avpl(gogkey_match,TRUE);
450                                 gogkey_match = NULL;
451                         }
452                         
453                         if (key) g_free(key);
454                         key = NULL;
455
456                         dbg_print (dbg_gog,1,dbg_facility,"analize_gop: no gogkey_match: %s",key);
457                 }
458                 
459                 if (key) g_free(key);
460
461                 if (gogkey_match) delete_avpl(gogkey_match,TRUE);
462                 
463                 reanalyze_gop(gop);
464         } 
465 }
466
467
468
469 static void analize_pdu(mate_pdu* pdu) {
470         /* TODO: 
471     return a g_boolean to tell we've destroyed the pdu when the pdu is unnassigned
472         destroy the unassigned pdu
473         */
474         mate_cfg_gop* cfg = NULL;
475         mate_gop* gop = NULL;
476         gchar* gop_key;
477         gchar* orig_gop_key = NULL;
478         AVPL* candidate_start = NULL;
479         AVPL* candidate_stop = NULL;
480         AVPL* is_start = NULL;
481         AVPL* is_stop = NULL;
482         AVPL* gopkey_match = NULL;
483         LoAL* gog_keys = NULL;
484         AVPL* curr_gogkey = NULL;
485         void* cookie = NULL;
486         AVPL* gogkey_match = NULL;
487         gchar* gogkey = NULL;
488         
489         dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: %s",pdu->cfg->name);
490
491         if (! (cfg = g_hash_table_lookup(mc->gops_by_pduname,pdu->cfg->name)) )
492                 return;
493                 
494         if ((gopkey_match = new_avpl_exact_match("gop_key_match",pdu->avpl,cfg->key, TRUE))) {
495                 gop_key = avpl_to_str(gopkey_match);
496                 
497                 g_hash_table_lookup_extended(cfg->gop_index,(gconstpointer)gop_key,(gpointer*)&orig_gop_key,(gpointer*)&gop);
498                 
499                 if ( gop ) {
500                         g_free(gop_key);
501                         
502                         /* is the gop dead ? */
503                         if ( ! gop->released &&
504                                  ( ( gop->cfg->lifetime > 0.0 && gop->time_to_die >= rd->now) || 
505                                    ( gop->cfg->idle_timeout > 0.0 && gop->time_to_timeout >= rd->now) ) ) {
506                                 dbg_print (dbg_gop,4,dbg_facility,"analize_pdu: expiring released gop");
507                                 gop->released = TRUE;
508                                 
509                                 if (gop->gog && gop->cfg->start) gop->gog->num_of_released_gops++;
510                         }
511                         
512                         /* TODO: is the gop expired? */
513                         
514                         gop_key = orig_gop_key;
515                         
516                         dbg_print (dbg_gop,2,dbg_facility,"analize_pdu: got gop: %s",gop_key);
517                         
518                         if (( candidate_start = cfg->start )) {
519                                 
520                                 dbg_print (dbg_gop,2,dbg_facility,"analize_pdu: got candidate start");
521                                 
522                                 if (( is_start = new_avpl_exact_match("",pdu->avpl, candidate_start, FALSE) )) {
523                                         delete_avpl(is_start,FALSE); 
524                                         if ( gop->released ) {
525                                                 dbg_print (dbg_gop,3,dbg_facility,"analize_pdu: start on released gop, let's create a new gop");
526                                                 
527                                                 g_hash_table_remove(cfg->gop_index,gop_key);
528                                                 gop->gop_key = NULL;
529                                                 gop = new_gop(cfg,pdu,gop_key);
530                                                 g_hash_table_insert(cfg->gop_index,gop_key,gop);
531                                         } else {
532                                                 dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: duplicate start on gop");
533                                         }                                       
534                                 }
535                         }
536                         
537                         pdu->gop = gop;
538                         
539                         if (gop->last_pdu) gop->last_pdu->next = pdu;
540                         gop->last_pdu = pdu;
541                         pdu->next = NULL;
542                         pdu->time_in_gop = rd->now - gop->start_time;
543                         
544                         if (gop->released) pdu->after_release = TRUE;
545                         
546                 } else {
547
548                         dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: no gop already");
549                         
550                         if ( ! cfg->start ) {
551                                 /* there is no GopStart, we'll check for matching GogKeys
552                                 if we have one we'll create the Gop */
553                                 
554                                 apply_extras(pdu->avpl,gopkey_match,cfg->extra);
555                                 
556                                 gog_keys = g_hash_table_lookup(mc->gogs_by_gopname,cfg->name);
557                                 
558                                 if (gog_keys) {
559                                         
560                                         while (( curr_gogkey = get_next_avpl(gog_keys,&cookie) )) {
561                                                 if (( gogkey_match = new_avpl_exact_match(cfg->name,gopkey_match,curr_gogkey,FALSE) )) {
562                                                         gogkey = avpl_to_str(gogkey_match);
563                                                         
564                                                         if (g_hash_table_lookup(cfg->gog_index,gogkey)) {
565                                                                 gop = new_gop(cfg,pdu,gop_key);
566                                                                 g_hash_table_insert(cfg->gop_index,gop_key,gop);
567                                                                 delete_avpl(gogkey_match,FALSE);
568                                                                 g_free(gogkey);
569                                                                 break;
570                                                         } else {
571                                                                 delete_avpl(gogkey_match,FALSE);
572                                                                 g_free(gogkey);                                                         
573                                                         }
574                                                 }
575                                         }
576                                         
577                                         if ( ! gop ) {
578                                                 g_free(gop_key);
579                                                 delete_avpl(gopkey_match,TRUE);
580                                                 return;
581                                         }
582                                         
583                                 } else {
584                                         g_free(gop_key);
585                                         delete_avpl(gopkey_match,TRUE);
586                                         return;
587                                 }
588                                 
589                         } else {                                
590                                 candidate_start = cfg->start;
591                                 
592                                 if (( is_start = new_avpl_exact_match("",pdu->avpl, candidate_start, FALSE) )) {
593                                         delete_avpl(is_start,FALSE);
594                                         gop = new_gop(cfg,pdu,gop_key);
595                                 } else {
596                                         g_free(gop_key);
597                                         return;
598                                 }
599                                 
600                                 pdu->gop = gop;
601                         }
602                 }
603                 
604                 if (gop->last_pdu) gop->last_pdu->next = pdu;
605                 gop->last_pdu = pdu;
606                 pdu->next = NULL;
607                 
608                 pdu->time_in_gop = rd->now - gop->start_time;
609                 
610                 gop->num_of_pdus++;
611                 gop->time_to_timeout = cfg->idle_timeout > 0.0 ? cfg->idle_timeout + rd->now : (float) -1.0 ;
612                 
613                 dbg_print (dbg_gop,4,dbg_facility,"analize_pdu: merge with key");
614
615                 merge_avpl(gop->avpl,gopkey_match,TRUE);
616                 delete_avpl(gopkey_match,TRUE);
617                 
618                 dbg_print (dbg_gop,4,dbg_facility,"analize_pdu: apply extras");
619
620                 apply_extras(pdu->avpl,gop->avpl,gop->cfg->extra);
621                                 
622                 gop->last_time = pdu->rel_time;
623                 
624                 if ( ! gop->released) {
625                         candidate_stop = cfg->stop;
626                         
627                         if (candidate_stop) {
628                                 is_stop = new_avpl_exact_match("",pdu->avpl, candidate_stop,FALSE);
629                         } else {
630                                 is_stop = new_avpl("");
631                         }
632                         
633                         if(is_stop) {
634                                 dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: is a `stop");
635                                 delete_avpl(is_stop,FALSE);
636                                 
637                                 if (! gop->released) {
638                                         gop->released = TRUE;
639                                         gop->release_time = pdu->rel_time;
640                                         if (gop->gog && gop->cfg->start) gop->gog->num_of_released_gops++;
641                                 }
642                                 
643                                 pdu->is_stop = TRUE;
644                                 
645                         }
646                 }
647                         
648                 if (gop->last_n != gop->avpl->len) apply_transforms(gop->cfg->transforms,gop->avpl);
649                 
650                 gop->last_n = gop->avpl->len;
651                                 
652                 if (gop->gog) {
653                         reanalyze_gop(gop);
654                 } else {
655                         analize_gop(gop);
656                 }
657                 
658         } else {
659                 dbg_print (dbg_gop,4,dbg_facility,"analize_pdu: no match for this pdu");
660                 
661                 pdu->gop = NULL;
662         }
663 }
664
665 static void get_pdu_fields(gpointer k, gpointer v, gpointer p) {
666         int hfid = *((int*) k);
667         gchar* name = (gchar*) v;
668         tmp_pdu_data* data = (tmp_pdu_data*) p;
669         GPtrArray* fis;
670         field_info* fi;
671         guint i,j;
672         mate_range* curr_range;
673         guint start;
674         guint end;
675         AVP* avp;
676         gchar* s;
677                 
678
679         fis = (GPtrArray*) g_hash_table_lookup(data->interesting,(gpointer) hfid);
680         
681         if (fis) {
682                 for (i = 0; i < fis->len; i++) {
683                         fi = (field_info*) g_ptr_array_index(fis,i);
684                         
685                         
686                         start = fi->start;
687                         end = fi->start + fi->length;
688                         
689                         dbg_print(dbg_pdu,5,dbg_facility,"get_pdu_fields: found field %i-%i",start,end);
690                         
691                         for (j = 0; j < data->ranges->len; j++) {
692                                 
693                                 curr_range = (mate_range*) g_ptr_array_index(data->ranges,j);
694                                 
695                                 if (curr_range->end >= end && curr_range->start <= start) {
696                                         avp = new_avp_from_finfo(name, fi);
697                                         
698                                         if (*dbg_pdu > 4) {
699                                                 s = avp_to_str(avp);
700                                                 dbg_print(dbg_pdu,0,dbg_facility,"get_pdu_fields: got %s",s);
701                                                 g_free(s);
702                                         }
703                                         
704                                         if (! insert_avp(data->pdu->avpl,avp) ) {
705                                                 delete_avp(avp);
706                                         }
707                                         
708                                 }
709                         }
710                 }
711         }
712 }
713
714 static mate_pdu* new_pdu(mate_cfg_pdu* cfg, guint32 framenum, field_info* proto, GHashTable* interesting) {
715         mate_pdu* pdu = g_mem_chunk_alloc(rd->mate_items);
716         field_info* cfi;
717         GPtrArray* ptrs;
718         mate_range* range;
719         mate_range* proto_range;
720         tmp_pdu_data data;
721         guint i,j;
722         gint min_dist;
723         field_info* range_fi;
724         gint32 last_start;
725         gint32 first_end;
726         gint32 curr_end;
727         int hfid;
728
729         dbg_print (dbg_pdu,1,dbg_facility,"new_pdu: type=%s framenum=%i",cfg->name,framenum);
730         
731         pdu->id = ++(cfg->last_id);
732         pdu->cfg = cfg;
733         
734         pdu->avpl = new_avpl(cfg->name);
735         
736         pdu->frame = framenum;
737         pdu->next_in_frame = NULL;
738         pdu->rel_time = rd->now;
739
740         pdu->gop = NULL;
741         pdu->next = NULL;
742         pdu->time_in_gop = -1.0;
743         
744         pdu->first = FALSE;
745         pdu->is_start = FALSE;
746         pdu->is_stop = FALSE;
747         pdu->after_release = FALSE;
748         
749         data.ranges = g_ptr_array_new();
750         data.pdu  = pdu;
751         data.interesting = interesting;
752         
753         /* first we create the proto range */
754         proto_range = g_malloc(sizeof(mate_range));
755         proto_range->start = proto->start;
756         proto_range->end = proto->start + proto->length;
757         g_ptr_array_add(data.ranges,proto_range);
758         
759         dbg_print(dbg_pdu,3,dbg_facility,"new_pdu: proto range %u-%u",proto_range->start,proto_range->end);
760         
761         last_start = proto_range->start;
762         
763         /* we move forward in the tranport */
764         for (i = cfg->transport_ranges->len; i--; ) {
765                 hfid = *((int*)g_ptr_array_index(cfg->transport_ranges,i));
766                 ptrs = (GPtrArray*) g_hash_table_lookup(interesting,GINT_TO_POINTER(hfid));
767                 min_dist = 99999;
768                 range_fi = NULL;
769                 
770                 if (ptrs) {
771                         for (j=0; j < ptrs->len; j++) {
772                                 cfi = (field_info*) g_ptr_array_index(ptrs,j);
773                                 if (cfi->start < last_start && min_dist >= (last_start - cfi->start) ) {
774                                         range_fi = cfi;
775                                         min_dist = last_start - cfi->start;
776                                 }
777                         }
778                         
779                         if ( range_fi ) {
780                                 range = g_malloc(sizeof(range));
781                                 range->start = range_fi->start;
782                                 range->end = range_fi->start + range_fi->length;
783                                 g_ptr_array_add(data.ranges,range);
784                                 
785                                 last_start = range_fi->start;
786                                 
787                                 dbg_print(dbg_pdu,3,dbg_facility,"new_pdu: transport(%i) range %i-%i",hfid,range->start,range->end);
788                         } else {
789                                 /* we missed a range  */
790                                 dbg_print(dbg_pdu,6,dbg_facility,"new_pdu: transport(%i) missed",hfid);
791                         }
792                         
793                 }
794         }
795         
796         if (cfg->payload_ranges) {
797
798                 first_end = proto_range->end;
799                 
800                 for (i = 0 ; i < cfg->payload_ranges->len; i++) {
801                         hfid = *((int*)g_ptr_array_index(cfg->payload_ranges,i));
802                         ptrs = (GPtrArray*) g_hash_table_lookup(interesting,GINT_TO_POINTER(hfid));
803                         min_dist = 99999;
804                         range_fi = NULL;
805                         
806                         if (ptrs) {
807                                 for (j=0; j < ptrs->len; j++) {
808                                         cfi = (field_info*) g_ptr_array_index(ptrs,j);
809                                         curr_end = cfi->start + cfi->length;
810                                         if (curr_end > first_end && min_dist >= (curr_end - first_end) ) {
811                                                 range_fi = cfi;
812                                                 min_dist = curr_end - first_end;
813                                         }
814                                 }
815                                 
816                                 if ( range_fi ) {
817                                         range = g_malloc(sizeof(range));
818                                         range->start = range_fi->start;
819                                         range->end = range_fi->start + range_fi->length;
820                                         g_ptr_array_add(data.ranges,range);
821                                         
822                                         last_start = range_fi->start;
823                                         
824                                         dbg_print(dbg_pdu,3,dbg_facility,"new_pdu: payload(%i) range %i-%i",hfid,range->start,range->end);
825                                 } else {
826                                         /* we missed a range  */
827                                         dbg_print(dbg_pdu,5,dbg_facility,"new_pdu: payload(%i) missed",hfid);
828                                 }
829                                 
830                         }
831                 }
832         }
833
834         g_hash_table_foreach(cfg->hfids_attr,get_pdu_fields,&data);
835         
836         apply_transforms(pdu->cfg->transforms,pdu->avpl);
837
838         g_ptr_array_free(data.ranges,TRUE);
839         
840         return pdu;
841 }       
842
843
844 extern void mate_analyze_frame(packet_info *pinfo, proto_tree* tree) {
845         mate_cfg_pdu* cfg;
846         GPtrArray* protos;
847         field_info* proto;
848         guint i,j;
849         AVPL* criterium_match;
850         
851         mate_pdu* pdu = NULL;
852         mate_pdu* last = NULL;
853
854         rd->now = (float) nstime_to_sec(&pinfo->fd->rel_ts);
855
856         if ( tree->tree_data && tree->tree_data->interesting_hfids
857                  && rd->highest_analyzed_frame < pinfo->fd->num ) {
858                 for ( i = 0; i < mc->pducfglist->len; i++ ) {
859                         
860                         cfg = g_ptr_array_index(mc->pducfglist,i);
861                         
862                         dbg_print (dbg_pdu,4,dbg_facility,"mate_analyze_frame: tryning to extract: %s",cfg->name);
863                         protos = (GPtrArray*) g_hash_table_lookup(tree->tree_data->interesting_hfids,(gpointer) cfg->hfid_proto);
864                         
865                         if (protos)  {
866                                 pdu = NULL;
867                                 
868                                 for (j = 0; j < protos->len; j++) {
869
870                                         dbg_print (dbg_pdu,3,dbg_facility,"mate_analyze_frame: found matching proto, extracting: %s",cfg->name);
871                                         
872                                         proto = (field_info*) g_ptr_array_index(protos,j);
873                                         pdu = new_pdu(cfg, pinfo->fd->num, proto, tree->tree_data->interesting_hfids);
874                                         
875                                         if (cfg->criterium) {
876                                                 criterium_match = new_avpl_from_match(cfg->criterium_match_mode,"",pdu->avpl,cfg->criterium,FALSE);
877                                                 
878                                                 if (criterium_match) {
879                                                         delete_avpl(criterium_match,FALSE);
880                                                 }
881                                                 
882                                                 if ( (criterium_match && cfg->criterium_accept_mode == REJECT_MODE ) 
883                                                          || ( ! criterium_match && cfg->criterium_accept_mode == ACCEPT_MODE )) {
884                                                         
885                                                         delete_avpl(pdu->avpl,TRUE);
886                                                         g_mem_chunk_free(rd->mate_items,pdu);   
887                                                         pdu = NULL;
888                                                         
889                                                         continue;
890                                                 }
891                                         }
892                                                                                 
893                                         analize_pdu(pdu);
894                                         
895                                         if ( ! pdu->gop && cfg->drop_unassigned) {
896                                                 delete_avpl(pdu->avpl,TRUE);
897                                                 g_mem_chunk_free(rd->mate_items,pdu);
898                                                 pdu = NULL;
899                                                 continue;
900                                         }
901                                         
902                                         if ( cfg->discard ) {
903                                                 delete_avpl(pdu->avpl,TRUE);
904                                                 pdu->avpl = NULL;
905                                         }
906                                         
907                                         if (!last) {
908                                                 g_hash_table_insert(rd->frames,GINT_TO_POINTER(pinfo->fd->num),pdu);
909                                                 last = pdu;
910                                         } else {
911                                                 last->next_in_frame = pdu;
912                                                 last = pdu;
913                                         }
914                                         
915                                 }
916                                 
917                                 if ( pdu && cfg->last_extracted ) break;
918                         }
919                 }
920                 
921                 rd->highest_analyzed_frame = pinfo->fd->num;
922         }
923 }
924
925 extern mate_pdu* mate_get_pdus(guint32 framenum) {
926         
927         if (rd) {
928                 return (mate_pdu*) g_hash_table_lookup(rd->frames,GUINT_TO_POINTER(framenum));
929         } else {
930                 return NULL;
931         }
932 }
933
934
935