tap_ui -> stat_tap_ui.
[metze/wireshark/wip.git] / epan / conversation_table.c
1 /* conversations_table.c
2  * conversations_table   2003 Ronnie Sahlberg
3  * Helper routines common to all endpoint conversations tap.
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include "config.h"
25
26 #include <string.h>
27
28 #include "packet_info.h"
29 #include "proto.h"
30 #include "conversation_table.h"
31 #include "addr_resolv.h"
32 #include "emem.h"
33
34 #include "stat_cmd_args.h"
35
36 GList *cmd_string_list_ = NULL;
37
38 struct register_ct {
39     gboolean hide_ports;       /* hide TCP / UDP port columns */
40     int proto_id;              /* protocol id (0-indexed) */
41     tap_packet_cb conv_func;   /* function to be called for new incoming packets for conversation*/
42     tap_packet_cb host_func;   /* function to be called for new incoming packets for hostlist */
43     host_tap_prefix prefix_func;  /* function to provide prefix if different than default (host) */
44     conv_gui_init_cb conv_gui_init; /* GUI specific function to initialize conversation */
45     host_gui_init_cb host_gui_init; /* GUI specific function to initialize hostlist */
46 };
47
48 gboolean get_conversation_hide_ports(register_ct_t* ct)
49 {
50     return ct->hide_ports;
51 }
52
53 int get_conversation_proto_id(register_ct_t* ct)
54 {
55     if (!ct) {
56         return -1;
57     }
58     return ct->proto_id;
59 }
60
61 tap_packet_cb get_conversation_packet_func(register_ct_t* ct)
62 {
63     return ct->conv_func;
64 }
65
66 tap_packet_cb get_hostlist_packet_func(register_ct_t* ct)
67 {
68     return ct->host_func;
69 }
70
71 host_tap_prefix get_hostlist_prefix_func(register_ct_t* ct)
72 {
73     return ct->prefix_func;
74 }
75
76
77 static GSList *registered_ct_tables = NULL;
78
79 void
80 dissector_conversation_init(const char *opt_arg, void* userdata)
81 {
82     register_ct_t *table = (register_ct_t*)userdata;
83     GString *cmd_str = g_string_new("conv,");
84     const char *filter=NULL;
85
86     g_string_append(cmd_str, proto_get_protocol_filter_name(table->proto_id));
87     if(!strncmp(opt_arg, cmd_str->str, cmd_str->len)){
88         filter = opt_arg + cmd_str->len;
89     } else {
90         filter = NULL;
91     }
92     g_string_free(cmd_str, TRUE);
93
94     if (table->conv_gui_init)
95         table->conv_gui_init(table, filter);
96 }
97
98 void
99 dissector_hostlist_init(const char *opt_arg, void* userdata)
100 {
101     register_ct_t *table = (register_ct_t*)userdata;
102     GString *cmd_str = g_string_new("");
103     const char *filter=NULL;
104
105     g_string_printf(cmd_str, "%s,%s,", (table->prefix_func != NULL) ? table->prefix_func() : "host", proto_get_protocol_filter_name(table->proto_id));
106     if(!strncmp(opt_arg, cmd_str->str, cmd_str->len)){
107         filter=opt_arg+cmd_str->len;
108     } else {
109         filter=NULL;
110     }
111
112     g_string_free(cmd_str, TRUE);
113
114     if (table->host_gui_init)
115         table->host_gui_init(table, filter);
116 }
117 /** get conversation from protocol ID
118  *
119  * @param proto_id protocol ID
120  * @return tap function handler of conversation
121  */
122 register_ct_t* get_conversation_by_proto_id(int proto_id)
123 {
124     GSList *ct;
125     register_ct_t *table;
126
127     for(ct = registered_ct_tables; ct != NULL; ct = g_slist_next(ct)){
128         table = (register_ct_t*)ct->data;
129         if ((table) && (table->proto_id == proto_id))
130             return table;
131     }
132
133     return NULL;
134 }
135
136 static gint
137 insert_sorted_by_table_name(gconstpointer aparam, gconstpointer bparam)
138 {
139     const register_ct_t *a = (register_ct_t *)aparam;
140     const register_ct_t *b = (register_ct_t *)bparam;
141
142     return g_ascii_strcasecmp(proto_get_protocol_short_name(find_protocol_by_id(a->proto_id)), proto_get_protocol_short_name(find_protocol_by_id(b->proto_id)));
143 }
144
145 void
146 register_conversation_table(const int proto_id, gboolean hide_ports, tap_packet_cb conv_packet_func, tap_packet_cb hostlist_func, host_tap_prefix prefix_func)
147 {
148     register_ct_t *table;
149     GString *conv_cmd_str = g_string_new("conv,");
150     GString *host_cmd_str = g_string_new("");
151     stat_tap_ui ui_info;
152
153     table = g_new(register_ct_t,1);
154
155     table->hide_ports    = hide_ports;
156     table->proto_id      = proto_id;
157     table->conv_func     = conv_packet_func;
158     table->host_func     = hostlist_func;
159     table->conv_gui_init = NULL;
160     table->host_gui_init = NULL;
161     table->prefix_func   = prefix_func;
162
163     registered_ct_tables = g_slist_insert_sorted(registered_ct_tables, table, insert_sorted_by_table_name);
164
165     g_string_append(conv_cmd_str, proto_get_protocol_filter_name(table->proto_id));
166     cmd_string_list_ = g_list_append(cmd_string_list_, conv_cmd_str->str);
167     ui_info.group = REGISTER_STAT_GROUP_CONVERSATION_LIST;
168     ui_info.title = NULL;       /* construct this from the protocol info? */
169     ui_info.cli_string = conv_cmd_str->str;
170     ui_info.tap_init_cb = dissector_conversation_init;
171     ui_info.index = -1;
172     ui_info.nparams = 0;
173     ui_info.params = NULL;
174     register_stat_tap_ui(&ui_info, table);
175     g_string_free(conv_cmd_str, FALSE);
176
177     g_string_printf(host_cmd_str, "%s,%s", (get_hostlist_prefix_func(table) != NULL) ? get_hostlist_prefix_func(table)() : "host",
178                     proto_get_protocol_filter_name(table->proto_id));
179     ui_info.group = REGISTER_STAT_GROUP_ENDPOINT_LIST;
180     ui_info.title = NULL;       /* construct this from the protocol info? */
181     ui_info.cli_string = host_cmd_str->str;
182     ui_info.tap_init_cb = dissector_hostlist_init;
183     ui_info.index = -1;
184     ui_info.nparams = 0;
185     ui_info.params = NULL;
186     register_stat_tap_ui(&ui_info, table);
187     g_string_free(host_cmd_str, FALSE);
188 }
189
190 /* Set GUI fields for register_ct list */
191 static void
192 set_conv_gui_data(gpointer data, gpointer user_data)
193 {
194     register_ct_t *table = (register_ct_t*)data;
195     table->conv_gui_init = (conv_gui_init_cb)user_data;
196 }
197
198 void conversation_table_set_gui_info(conv_gui_init_cb init_cb)
199 {
200     g_slist_foreach(registered_ct_tables, set_conv_gui_data, init_cb);
201 }
202
203 static void
204 set_host_gui_data(gpointer data, gpointer user_data)
205 {
206     register_ct_t *table = (register_ct_t*)data;
207     table->host_gui_init = (host_gui_init_cb)user_data;
208 }
209
210 void hostlist_table_set_gui_info(host_gui_init_cb init_cb)
211 {
212     g_slist_foreach(registered_ct_tables, set_host_gui_data, init_cb);
213 }
214
215 void conversation_table_iterate_tables(GFunc func, gpointer user_data)
216 {
217     g_slist_foreach(registered_ct_tables, func, user_data);
218 }
219
220 guint conversation_table_get_num(void)
221 {
222     return g_slist_length(registered_ct_tables);
223 }
224
225
226 register_ct_t *get_conversation_table_by_num(guint table_num)
227 {
228     return (register_ct_t *) g_slist_nth_data(registered_ct_tables, table_num);
229 }
230
231 /** Compute the hash value for two given address/port pairs.
232  * (Parameter type is gconstpointer for GHashTable compatibility.)
233  *
234  * @param v Conversation Key. MUST point to a conv_key_t struct.
235  * @return Computed key hash.
236  */
237 static guint
238 conversation_hash(gconstpointer v)
239 {
240     const conv_key_t *key = (const conv_key_t *)v;
241     guint hash_val;
242
243     hash_val = 0;
244     ADD_ADDRESS_TO_HASH(hash_val, &key->addr1);
245     hash_val += key->port1;
246     ADD_ADDRESS_TO_HASH(hash_val, &key->addr2);
247     hash_val += key->port2;
248     hash_val ^= key->conv_id;
249
250     return hash_val;
251 }
252
253 /** Compare two conversation keys for an exact match.
254  * (Parameter types are gconstpointer for GHashTable compatibility.)
255  *
256  * @param key1 First conversation. MUST point to a conv_key_t struct.
257  * @param key2 Second conversation. MUST point to a conv_key_t struct.
258  * @return TRUE if conversations are equal, FALSE otherwise.
259  */
260 static gboolean
261 conversation_equal(gconstpointer key1, gconstpointer key2)
262 {
263     const conv_key_t *ck1 = (const conv_key_t *)key1;
264     const conv_key_t *ck2 = (const conv_key_t *)key2;
265
266     if (ck1->conv_id == ck2->conv_id)
267     {
268         if (ck1->port1 == ck2->port1 &&
269             ck1->port2 == ck2->port2 &&
270             ADDRESSES_EQUAL(&ck1->addr1, &ck2->addr1) &&
271             ADDRESSES_EQUAL(&ck1->addr2, &ck2->addr2)) {
272             return TRUE;
273         }
274
275         if (ck1->port2 == ck2->port1 &&
276             ck1->port1 == ck2->port2 &&
277             ADDRESSES_EQUAL(&ck1->addr2, &ck2->addr1) &&
278             ADDRESSES_EQUAL(&ck1->addr1, &ck2->addr2)) {
279             return TRUE;
280         }
281     }
282
283     /*
284      * The addresses, ports, or conversation IDs don't match.
285      */
286     return FALSE;
287 }
288
289 void
290 reset_conversation_table_data(conv_hash_t *ch)
291 {
292     if (!ch) {
293         return;
294     }
295
296     if (ch->conv_array != NULL) {
297         guint i;
298         for(i = 0; i < ch->conv_array->len; i++){
299             conv_item_t *conv = &g_array_index(ch->conv_array, conv_item_t, i);
300             g_free((gpointer)conv->src_address.data);
301             g_free((gpointer)conv->dst_address.data);
302         }
303
304         g_array_free(ch->conv_array, TRUE);
305     }
306
307     if (ch->hashtable != NULL) {
308         g_hash_table_destroy(ch->hashtable);
309     }
310
311     ch->conv_array=NULL;
312     ch->hashtable=NULL;
313 }
314
315 void reset_hostlist_table_data(conv_hash_t *ch)
316 {
317     if (!ch) {
318         return;
319     }
320
321     if (ch->conv_array != NULL) {
322         guint i;
323         for(i = 0; i < ch->conv_array->len; i++){
324             hostlist_talker_t *host = &g_array_index(ch->conv_array, hostlist_talker_t, i);
325             g_free((gpointer)host->myaddress.data);
326         }
327
328         g_array_free(ch->conv_array, TRUE);
329     }
330
331     if (ch->hashtable != NULL) {
332         g_hash_table_destroy(ch->hashtable);
333     }
334
335     ch->conv_array=NULL;
336     ch->hashtable=NULL;
337 }
338
339 const char *get_conversation_address(address *addr, gboolean resolve_names)
340 {
341     if (resolve_names) {
342         return ep_address_to_display(addr);
343     } else {
344         return ep_address_to_str(addr);
345     }
346 }
347
348 const char *get_conversation_port(guint32 port, port_type ptype, gboolean resolve_names)
349 {
350
351     if(!resolve_names) ptype = PT_NONE;
352
353     switch(ptype) {
354     case(PT_TCP):
355         return ep_tcp_port_to_display(port);
356     case(PT_UDP):
357         return ep_udp_port_to_display(port);
358     case(PT_SCTP):
359         return ep_sctp_port_to_display(port);
360     default:
361         return ep_strdup_printf("%d", port);
362     }
363 }
364
365 /* given an address (to distinguish between ipv4 and ipv6 for tcp/udp),
366    a port_type and a name_type (FN_...)
367    return a string for the filter name.
368
369    Some addresses, like AT_ETHER may actually be any of multiple types
370    of protocols,   either ethernet, tokenring, fddi, wlan etc so we must be
371    more specific there;  that's why we need specific_addr_type.
372 */
373 static const char *
374 conversation_get_filter_name(conv_item_t *conv_item, conv_filter_type_e filter_type)
375 {
376
377     if ((conv_item == NULL) || (conv_item->dissector_info == NULL) || (conv_item->dissector_info->get_filter_type == NULL)) {
378         return CONV_FILTER_INVALID;
379     }
380
381     return conv_item->dissector_info->get_filter_type(conv_item, filter_type);
382 }
383
384 static const char *
385 hostlist_get_filter_name(hostlist_talker_t *host, conv_filter_type_e filter_type)
386 {
387
388     if ((host == NULL) || (host->dissector_info == NULL) || (host->dissector_info->get_filter_type == NULL)) {
389         return CONV_FILTER_INVALID;
390     }
391
392     return host->dissector_info->get_filter_type(host, filter_type);
393 }
394
395 /* Convert a port number into a string or NULL */
396 static char *
397 ct_port_to_str(port_type ptype, guint32 port)
398 {
399     switch(ptype){
400     case PT_TCP:
401     case PT_UDP:
402     case PT_SCTP:
403     case PT_NCP:
404         return g_strdup_printf("%d", port);
405     default:
406         break;
407     }
408     return NULL;
409 }
410
411 const char *get_conversation_filter(conv_item_t *conv_item, conv_direction_e direction)
412 {
413     char *sport, *dport;
414     const char *str = "INVALID";
415
416     sport = ct_port_to_str(conv_item->ptype, conv_item->src_port);
417     dport = ct_port_to_str(conv_item->ptype, conv_item->dst_port);
418
419     switch(direction){
420     case CONV_DIR_A_TO_FROM_B:
421         /* A <-> B */
422         str = ep_strdup_printf("%s==%s%s%s%s%s && %s==%s%s%s%s%s",
423                               conversation_get_filter_name(conv_item,  CONV_FT_ANY_ADDRESS),
424                               ep_address_to_str(&conv_item->src_address),
425                               sport?" && ":"",
426                               sport?conversation_get_filter_name(conv_item,  CONV_FT_ANY_PORT):"",
427                               sport?"==":"",
428                               sport?sport:"",
429                               conversation_get_filter_name(conv_item,  CONV_FT_ANY_ADDRESS),
430                               ep_address_to_str(&conv_item->dst_address),
431                               dport?" && ":"",
432                               dport?conversation_get_filter_name(conv_item,  CONV_FT_ANY_PORT):"",
433                               dport?"==":"",
434                               dport?dport:""
435             );
436         break;
437     case CONV_DIR_A_TO_B:
438         /* A --> B */
439         str = ep_strdup_printf("%s==%s%s%s%s%s && %s==%s%s%s%s%s",
440                               conversation_get_filter_name(conv_item,  CONV_FT_SRC_ADDRESS),
441                               ep_address_to_str(&conv_item->src_address),
442                               sport?" && ":"",
443                               sport?conversation_get_filter_name(conv_item,  CONV_FT_SRC_PORT):"",
444                               sport?"==":"",
445                               sport?sport:"",
446                               conversation_get_filter_name(conv_item,  CONV_FT_DST_ADDRESS),
447                               ep_address_to_str(&conv_item->dst_address),
448                               dport?" && ":"",
449                               dport?conversation_get_filter_name(conv_item,  CONV_FT_DST_PORT):"",
450                               dport?"==":"",
451                               dport?dport:""
452             );
453         break;
454     case CONV_DIR_A_FROM_B:
455         /* A <-- B */
456         str = ep_strdup_printf("%s==%s%s%s%s%s && %s==%s%s%s%s%s",
457                               conversation_get_filter_name(conv_item,  CONV_FT_DST_ADDRESS),
458                               ep_address_to_str(&conv_item->src_address),
459                               sport?" && ":"",
460                               sport?conversation_get_filter_name(conv_item,  CONV_FT_DST_PORT):"",
461                               sport?"==":"",
462                               sport?sport:"",
463                               conversation_get_filter_name(conv_item,  CONV_FT_SRC_ADDRESS),
464                               ep_address_to_str(&conv_item->dst_address),
465                               dport?" && ":"",
466                               dport?conversation_get_filter_name(conv_item,  CONV_FT_SRC_PORT):"",
467                               dport?"==":"",
468                               dport?dport:""
469             );
470         break;
471     case CONV_DIR_A_TO_FROM_ANY:
472         /* A <-> ANY */
473         str = ep_strdup_printf("%s==%s%s%s%s%s",
474                               conversation_get_filter_name(conv_item,  CONV_FT_ANY_ADDRESS),
475                               ep_address_to_str(&conv_item->src_address),
476                               sport?" && ":"",
477                               sport?conversation_get_filter_name(conv_item,  CONV_FT_ANY_PORT):"",
478                               sport?"==":"",
479                               sport?sport:""
480             );
481         break;
482     case CONV_DIR_A_TO_ANY:
483         /* A --> ANY */
484         str = ep_strdup_printf("%s==%s%s%s%s%s",
485                               conversation_get_filter_name(conv_item,  CONV_FT_SRC_ADDRESS),
486                               ep_address_to_str(&conv_item->src_address),
487                               sport?" && ":"",
488                               sport?conversation_get_filter_name(conv_item,  CONV_FT_SRC_PORT):"",
489                               sport?"==":"",
490                               sport?sport:""
491             );
492         break;
493     case CONV_DIR_A_FROM_ANY:
494         /* A <-- ANY */
495         str = ep_strdup_printf("%s==%s%s%s%s%s",
496                               conversation_get_filter_name(conv_item,  CONV_FT_DST_ADDRESS),
497                               ep_address_to_str(&conv_item->src_address),
498                               sport?" && ":"",
499                               sport?conversation_get_filter_name(conv_item,  CONV_FT_DST_PORT):"",
500                               sport?"==":"",
501                               sport?sport:""
502             );
503         break;
504     case CONV_DIR_ANY_TO_FROM_B:
505         /* ANY <-> B */
506         str = ep_strdup_printf("%s==%s%s%s%s%s",
507                               conversation_get_filter_name(conv_item,  CONV_FT_ANY_ADDRESS),
508                               ep_address_to_str(&conv_item->dst_address),
509                               dport?" && ":"",
510                               dport?conversation_get_filter_name(conv_item,  CONV_FT_ANY_PORT):"",
511                               dport?"==":"",
512                               dport?dport:""
513             );
514         break;
515     case CONV_DIR_ANY_FROM_B:
516         /* ANY <-- B */
517         str = ep_strdup_printf("%s==%s%s%s%s%s",
518                               conversation_get_filter_name(conv_item,  CONV_FT_SRC_ADDRESS),
519                               ep_address_to_str(&conv_item->dst_address),
520                               dport?" && ":"",
521                               dport?conversation_get_filter_name(conv_item,  CONV_FT_SRC_PORT):"",
522                               dport?"==":"",
523                               dport?dport:""
524             );
525         break;
526     case CONV_DIR_ANY_TO_B:
527         /* ANY --> B */
528         str = ep_strdup_printf("%s==%s%s%s%s%s",
529                               conversation_get_filter_name(conv_item,  CONV_FT_DST_ADDRESS),
530                               ep_address_to_str(&conv_item->dst_address),
531                               dport?" && ":"",
532                               dport?conversation_get_filter_name(conv_item,  CONV_FT_DST_PORT):"",
533                               dport?"==":"",
534                               dport?dport:""
535             );
536         break;
537     default:
538         break;
539     }
540     g_free(sport);
541     g_free(dport);
542     return str;
543 }
544
545 const char *get_hostlist_filter(hostlist_talker_t *host)
546 {
547     char *sport;
548     const char *str;
549
550     sport=ct_port_to_str(host->ptype, host->port);
551
552     str = g_strdup_printf("%s==%s%s%s%s%s",
553                           hostlist_get_filter_name(host, CONV_FT_ANY_ADDRESS),
554                           ep_address_to_str(&host->myaddress),
555                           sport?" && ":"",
556                           sport?hostlist_get_filter_name(host, CONV_FT_ANY_PORT):"",
557                           sport?"==":"",
558                           sport?sport:"");
559
560     return str;
561 }
562
563 void
564 add_conversation_table_data(conv_hash_t *ch, const address *src, const address *dst, guint32 src_port, guint32 dst_port, int num_frames, int num_bytes,
565         nstime_t *ts, nstime_t *abs_ts, ct_dissector_info_t *ct_info, port_type ptype)
566 {
567     add_conversation_table_data_with_conv_id(ch, src, dst, src_port, dst_port, CONV_ID_UNSET, num_frames, num_bytes, ts, abs_ts, ct_info, ptype);
568 }
569
570 void
571 add_conversation_table_data_with_conv_id(
572     conv_hash_t *ch,
573     const address *src,
574     const address *dst,
575     guint32 src_port,
576     guint32 dst_port,
577     conv_id_t conv_id,
578     int num_frames,
579     int num_bytes,
580     nstime_t *ts,
581     nstime_t *abs_ts,
582     ct_dissector_info_t *ct_info,
583     port_type ptype)
584 {
585     const address *addr1, *addr2;
586     guint32 port1, port2;
587     conv_item_t *conv_item = NULL;
588     unsigned int conversation_idx = 0;
589
590     if (src_port > dst_port) {
591         addr1 = src;
592         addr2 = dst;
593         port1 = src_port;
594         port2 = dst_port;
595     } else if (src_port < dst_port) {
596         addr2 = src;
597         addr1 = dst;
598         port2 = src_port;
599         port1 = dst_port;
600     } else if (CMP_ADDRESS(src, dst) < 0) {
601         addr1 = src;
602         addr2 = dst;
603         port1 = src_port;
604         port2 = dst_port;
605     } else {
606         addr2 = src;
607         addr1 = dst;
608         port2 = src_port;
609         port1 = dst_port;
610     }
611
612     /* if we don't have any entries at all yet */
613     if (ch->conv_array == NULL) {
614         ch->conv_array = g_array_sized_new(FALSE, FALSE, sizeof(conv_item_t), 10000);
615
616         ch->hashtable = g_hash_table_new_full(conversation_hash,
617                                               conversation_equal, /* key_equal_func */
618                                               g_free,             /* key_destroy_func */
619                                               NULL);              /* value_destroy_func */
620
621     } else {
622         /* try to find it among the existing known conversations */
623         conv_key_t existing_key;
624
625         existing_key.addr1 = *addr1;
626         existing_key.addr2 = *addr2;
627         existing_key.port1 = port1;
628         existing_key.port2 = port2;
629         existing_key.conv_id = conv_id;
630         if (g_hash_table_lookup_extended(ch->hashtable, &existing_key, NULL, (gpointer *) &conversation_idx)) {
631             conv_item = &g_array_index(ch->conv_array, conv_item_t, conversation_idx);
632         }
633     }
634
635     /* if we still don't know what conversation this is it has to be a new one
636        and we have to allocate it and append it to the end of the list */
637     if (conv_item == NULL) {
638         conv_key_t *new_key;
639         conv_item_t new_conv_item;
640
641         COPY_ADDRESS(&new_conv_item.src_address, addr1);
642         COPY_ADDRESS(&new_conv_item.dst_address, addr2);
643         new_conv_item.dissector_info = ct_info;
644         new_conv_item.ptype = ptype;
645         new_conv_item.src_port = port1;
646         new_conv_item.dst_port = port2;
647         new_conv_item.conv_id = conv_id;
648         new_conv_item.rx_frames = 0;
649         new_conv_item.tx_frames = 0;
650         new_conv_item.rx_bytes = 0;
651         new_conv_item.tx_bytes = 0;
652         new_conv_item.modified = TRUE;
653
654         if (ts) {
655             memcpy(&new_conv_item.start_time, ts, sizeof(new_conv_item.start_time));
656             memcpy(&new_conv_item.stop_time, ts, sizeof(new_conv_item.stop_time));
657             memcpy(&new_conv_item.start_abs_time, abs_ts, sizeof(new_conv_item.start_abs_time));
658         } else {
659             nstime_set_unset(&new_conv_item.start_abs_time);
660             nstime_set_unset(&new_conv_item.start_time);
661             nstime_set_unset(&new_conv_item.stop_time);
662         }
663         g_array_append_val(ch->conv_array, new_conv_item);
664         conversation_idx = ch->conv_array->len - 1;
665         conv_item = &g_array_index(ch->conv_array, conv_item_t, conversation_idx);
666
667         /* ct->conversations address is not a constant but src/dst_address.data are */
668         new_key = g_new(conv_key_t, 1);
669         SET_ADDRESS(&new_key->addr1, conv_item->src_address.type, conv_item->src_address.len, conv_item->src_address.data);
670         SET_ADDRESS(&new_key->addr2, conv_item->dst_address.type, conv_item->dst_address.len, conv_item->dst_address.data);
671         new_key->port1 = port1;
672         new_key->port2 = port2;
673         new_key->conv_id = conv_id;
674         g_hash_table_insert(ch->hashtable, new_key, GUINT_TO_POINTER(conversation_idx));
675     }
676
677     /* update the conversation struct */
678     conv_item->modified = TRUE;
679     if ( (!CMP_ADDRESS(src, addr1)) && (!CMP_ADDRESS(dst, addr2)) && (src_port==port1) && (dst_port==port2) ) {
680         conv_item->tx_frames += num_frames;
681         conv_item->tx_bytes += num_bytes;
682     } else {
683         conv_item->rx_frames += num_frames;
684         conv_item->rx_bytes += num_bytes;
685     }
686
687     if (ts) {
688         if (nstime_cmp(ts, &conv_item->stop_time) > 0) {
689             memcpy(&conv_item->stop_time, ts, sizeof(conv_item->stop_time));
690         } else if (nstime_cmp(ts, &conv_item->start_time) < 0) {
691             memcpy(&conv_item->start_time, ts, sizeof(conv_item->start_time));
692             memcpy(&conv_item->start_abs_time, abs_ts, sizeof(conv_item->start_abs_time));
693         }
694     }
695 }
696
697 /*
698  * Compute the hash value for a given address/port pairs if the match
699  * is to be exact.
700  */
701 static guint
702 host_hash(gconstpointer v)
703 {
704     const host_key_t *key = (const host_key_t *)v;
705     guint hash_val;
706
707     hash_val = 0;
708     ADD_ADDRESS_TO_HASH(hash_val, &key->myaddress);
709     hash_val += key->port;
710     return hash_val;
711 }
712
713 /*
714  * Compare two host keys for an exact match.
715  */
716 static gint
717 host_match(gconstpointer v, gconstpointer w)
718 {
719     const host_key_t *v1 = (const host_key_t *)v;
720     const host_key_t *v2 = (const host_key_t *)w;
721
722     if (v1->port == v2->port &&
723         ADDRESSES_EQUAL(&v1->myaddress, &v2->myaddress)) {
724         return 1;
725     }
726     /*
727      * The addresses or the ports don't match.
728      */
729     return 0;
730 }
731
732 void
733 add_hostlist_table_data(conv_hash_t *ch, const address *addr, guint32 port, gboolean sender, int num_frames, int num_bytes, hostlist_dissector_info_t *host_info, port_type port_type_val)
734 {
735     hostlist_talker_t *talker=NULL;
736     int talker_idx=0;
737
738     /* XXX should be optimized to allocate n extra entries at a time
739        instead of just one */
740     /* if we don't have any entries at all yet */
741     if(ch->conv_array==NULL){
742         ch->conv_array=g_array_sized_new(FALSE, FALSE, sizeof(hostlist_talker_t), 10000);
743         ch->hashtable = g_hash_table_new_full(host_hash,
744                                               host_match, /* key_equal_func */
745                                               g_free,     /* key_destroy_func */
746                                               NULL);      /* value_destroy_func */
747     }
748     else {
749         /* try to find it among the existing known conversations */
750         host_key_t existing_key;
751
752         existing_key.myaddress = *addr;
753         existing_key.port = port;
754
755         if (g_hash_table_lookup_extended(ch->hashtable, &existing_key, NULL, (gpointer *) &talker_idx)) {
756             talker = &g_array_index(ch->conv_array, hostlist_talker_t, talker_idx);
757         }
758     }
759
760     /* if we still don't know what talker this is it has to be a new one
761        and we have to allocate it and append it to the end of the list */
762     if(talker==NULL){
763         host_key_t *new_key;
764         hostlist_talker_t host;
765
766         COPY_ADDRESS(&host.myaddress, addr);
767         host.dissector_info = host_info;
768         host.ptype=port_type_val;
769         host.port=port;
770         host.rx_frames=0;
771         host.tx_frames=0;
772         host.rx_bytes=0;
773         host.tx_bytes=0;
774         host.modified = TRUE;
775
776         g_array_append_val(ch->conv_array, host);
777         talker_idx= ch->conv_array->len - 1;
778         talker=&g_array_index(ch->conv_array, hostlist_talker_t, talker_idx);
779
780         /* hl->hosts address is not a constant but address.data is */
781         new_key = g_new(host_key_t,1);
782         SET_ADDRESS(&new_key->myaddress, talker->myaddress.type, talker->myaddress.len, talker->myaddress.data);
783         new_key->port = port;
784         g_hash_table_insert(ch->hashtable, new_key, GUINT_TO_POINTER(talker_idx));
785     }
786
787     /* if this is a new talker we need to initialize the struct */
788     talker->modified = TRUE;
789
790     /* update the talker struct */
791     if( sender ){
792         talker->tx_frames+=num_frames;
793         talker->tx_bytes+=num_bytes;
794     } else {
795         talker->rx_frames+=num_frames;
796         talker->rx_bytes+=num_bytes;
797     }
798 }
799
800 /*
801  * Editor modelines
802  *
803  * Local Variables:
804  * c-basic-offset: 4
805  * tab-width: 8
806  * indent-tabs-mode: nil
807  * End:
808  *
809  * ex: set shiftwidth=4 tabstop=8 expandtab:
810  * :indentSize=4:tabSize=8:noTabs=true:
811  */