sharkd: fix tap memleaks & support for links to frame, url & cleanup
[gd/wireshark/.git] / sharkd_session.c
1 /* sharkd_session.c
2  *
3  * Copyright (C) 2016 Jakub Zawadzki
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 <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include <glib.h>
32
33 #include <wsutil/wsjsmn.h>
34 #include <wsutil/ws_printf.h>
35
36 #include <file.h>
37 #include <epan/exceptions.h>
38 #include <epan/color_filters.h>
39 #include <epan/prefs.h>
40 #include <epan/prefs-int.h>
41 #include <epan/uat-int.h>
42 #include <wiretap/wtap.h>
43
44 #include <epan/column.h>
45
46 #include <epan/stats_tree_priv.h>
47 #include <epan/stat_tap_ui.h>
48 #include <epan/conversation_table.h>
49 #include <epan/export_object.h>
50 #include <epan/follow.h>
51
52 #include <epan/dissectors/packet-h225.h>
53 #include <epan/rtp_pt.h>
54 #include <ui/voip_calls.h>
55 #include <ui/rtp_stream.h>
56 #include <ui/tap-rtp-common.h>
57 #include <epan/to_str.h>
58
59 #ifdef HAVE_GEOIP
60 # include <GeoIP.h>
61 # include <epan/geoip_db.h>
62 # include <wsutil/pint.h>
63 #endif
64
65 #include <wsutil/glib-compat.h>
66 #include <wsutil/strtoi.h>
67
68 #include "sharkd.h"
69
70 static void
71 json_unescape_str(char *input)
72 {
73         char *output = input;
74
75         while (*input)
76         {
77                 char ch = *input++;
78
79                 if (ch == '\\')
80                 {
81                         /* TODO, add more escaping rules */
82                         ch = *input++;
83                 }
84
85                 *output = ch;
86                 output++;
87         }
88
89         *output = '\0';
90 }
91
92 static const char *
93 json_find_attr(const char *buf, const jsmntok_t *tokens, int count, const char *attr)
94 {
95         int i;
96
97         for (i = 0; i < count; i += 2)
98         {
99                 const char *tok_attr  = &buf[tokens[i + 0].start];
100                 const char *tok_value = &buf[tokens[i + 1].start];
101
102                 if (!strcmp(tok_attr, attr))
103                         return tok_value;
104         }
105
106         return NULL;
107 }
108
109 static void
110 json_puts_string(const char *str)
111 {
112         int i;
113
114         if (str == NULL)
115                 str = "";
116
117         putchar('"');
118         for (i = 0; str[i]; i++)
119         {
120                 switch (str[i])
121                 {
122                         case '\\':
123                         case '"':
124                                 putchar('\\');
125                                 putchar(str[i]);
126                                 break;
127
128                         case '\n':
129                                 putchar('\\');
130                                 putchar('n');
131                                 break;
132
133                         default:
134                                 putchar(str[i]);
135                                 break;
136                 }
137         }
138
139         putchar('"');
140 }
141
142 static void
143 json_print_base64(const guint8 *data, int len)
144 {
145         int i;
146         int base64_state1 = 0;
147         int base64_state2 = 0;
148         gsize wrote;
149         gchar buf[(1 / 3 + 1) * 4 + 4 + 1];
150
151         putchar('"');
152
153         for (i = 0; i < len; i++)
154         {
155                 wrote = g_base64_encode_step(&data[i], 1, FALSE, buf, &base64_state1, &base64_state2);
156                 if (wrote > 0)
157                 {
158                         buf[wrote] = '\0';
159                         printf("%s", buf);
160                 }
161         }
162
163         wrote = g_base64_encode_close(FALSE, buf, &base64_state1, &base64_state2);
164         if (wrote > 0)
165         {
166                 buf[wrote] = '\0';
167                 printf("%s", buf);
168         }
169
170         putchar('"');
171 }
172
173 struct filter_item
174 {
175         struct filter_item *next;
176
177         char *filter;
178         guint8 *filtered;
179 };
180
181 static struct filter_item *filter_list = NULL;
182
183 static const guint8 *
184 sharkd_session_filter_data(const char *filter)
185 {
186         struct filter_item *l;
187
188         for (l = filter_list; l; l = l->next)
189         {
190                 if (!strcmp(l->filter, filter))
191                         return l->filtered;
192         }
193
194         {
195                 guint8 *filtered = NULL;
196
197                 int ret = sharkd_filter(filter, &filtered);
198
199                 if (ret == -1)
200                         return NULL;
201
202                 l = (struct filter_item *) g_malloc(sizeof(struct filter_item));
203                 l->filter = g_strdup(filter);
204                 l->filtered = filtered;
205
206                 l->next = filter_list;
207                 filter_list = l;
208
209                 return filtered;
210         }
211 }
212
213 static gboolean
214 sharkd_session_process_info_conv_cb(const void* key, void* value, void* userdata)
215 {
216         struct register_ct *table = (struct register_ct *) value;
217         int *pi = (int *) userdata;
218
219         const char *label = (const char*)key;
220
221         if (get_conversation_packet_func(table))
222         {
223                 printf("%s{", (*pi) ? "," : "");
224                         printf("\"name\":\"Conversation List/%s\"", label);
225                         printf(",\"tap\":\"conv:%s\"", label);
226                 printf("}");
227
228                 *pi = *pi + 1;
229         }
230
231         if (get_hostlist_packet_func(table))
232         {
233                 printf("%s{", (*pi) ? "," : "");
234                         printf("\"name\":\"Endpoint/%s\"", label);
235                         printf(",\"tap\":\"endpt:%s\"", label);
236                 printf("}");
237
238                 *pi = *pi + 1;
239         }
240         return FALSE;
241 }
242
243 static gboolean
244 sharkd_export_object_visit_cb(const void *key _U_, void *value, void *user_data)
245 {
246         register_eo_t *eo = (register_eo_t*)value;
247         int *pi = (int *) user_data;
248
249         const int proto_id = get_eo_proto_id(eo);
250         const char *filter = proto_get_protocol_filter_name(proto_id);
251         const char *label  = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
252
253         printf("%s{", (*pi) ? "," : "");
254                 printf("\"name\":\"Export Object/%s\"", label);
255                 printf(",\"tap\":\"eo:%s\"", filter);
256         printf("}");
257
258         *pi = *pi + 1;
259         return FALSE;
260 }
261
262 static gboolean
263 sharkd_follower_visit_cb(const void *key _U_, void *value, void *user_data)
264 {
265         register_follow_t *follower = (register_follow_t*) value;
266         int *pi = (int *) user_data;
267
268         const int proto_id = get_follow_proto_id(follower);
269         const char *label  = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
270         const char *filter = label; /* correct: get_follow_by_name() is registered by short name */
271
272         printf("%s{", (*pi) ? "," : "");
273                 printf("\"name\":\"Follow/%s\"", label);
274                 printf(",\"tap\":\"follow:%s\"", filter);
275         printf("}");
276
277         *pi = *pi + 1;
278         return FALSE;
279 }
280
281 /**
282  * sharkd_session_process_info()
283  *
284  * Process info request
285  *
286  * Output object with attributes:
287  *   (m) columns - available column formats, array of object with attributes:
288  *                  'name'   - column name
289  *                  'format' - column format-name
290  *
291  *   (m) stats   - available statistics, array of object with attributes:
292  *                  'name' - statistic name
293  *                  'tap'  - sharkd tap-name for statistic
294  *
295  *   (m) convs   - available conversation list, array of object with attributes:
296  *                  'name' - conversation name
297  *                  'tap'  - sharkd tap-name for conversation
298  *
299  *   (m) eo      - available export object list, array of object with attributes:
300  *                  'name' - export object name
301  *                  'tap'  - sharkd tap-name for conversation
302  *
303  *   (m) taps - available taps, array of object with attributes:
304  *                  'name' - tap name
305  *                  'tap'  - sharkd tap-name
306
307  *   (m) follow - available followers, array of object with attributes:
308  *                  'name' - tap name
309  *                  'tap'  - sharkd tap-name
310  *
311  *   (m) ftypes   - conversation table for FT_ number to string
312  */
313 static void
314 sharkd_session_process_info(void)
315 {
316         int i;
317
318         printf("{\"columns\":[");
319         for (i = 0; i < NUM_COL_FMTS; i++)
320         {
321                 const char *col_format = col_format_to_string(i);
322                 const char *col_descr  = col_format_desc(i);
323
324                 printf("%s{", (i) ? "," : "");
325                         printf("\"name\":\"%s\"", col_descr);
326                         printf(",\"format\":\"%s\"", col_format);
327                 printf("}");
328         }
329         printf("]");
330
331         printf(",\"stats\":[");
332         {
333                 GList *cfg_list = stats_tree_get_cfg_list();
334                 GList *l;
335                 const char *sepa = "";
336
337                 for (l = cfg_list; l; l = l->next)
338                 {
339                         stats_tree_cfg *cfg = (stats_tree_cfg *) l->data;
340
341                         printf("%s{", sepa);
342                                 printf("\"name\":\"%s\"", cfg->name);
343                                 printf(",\"tap\":\"stat:%s\"", cfg->abbr);
344                         printf("}");
345                         sepa = ",";
346                 }
347
348                 g_list_free(cfg_list);
349         }
350         printf("]");
351
352         printf(",\"ftypes\":[");
353         for (i = 0; i < FT_NUM_TYPES; i++)
354         {
355                 if (i)
356                         printf(",");
357                 json_puts_string(ftype_name((ftenum_t) i));
358         }
359         printf("]");
360
361         printf(",\"version\":");
362         json_puts_string(sharkd_version());
363
364         printf(",\"convs\":[");
365         i = 0;
366         conversation_table_iterate_tables(sharkd_session_process_info_conv_cb, &i);
367         printf("]");
368
369         printf(",\"taps\":[");
370         {
371                 printf("{\"name\":\"%s\",\"tap\":\"%s\"}", "RTP streams", "rtp-streams");
372         }
373         printf("]");
374
375         printf(",\"eo\":[");
376         i = 0;
377         eo_iterate_tables(sharkd_export_object_visit_cb, &i);
378         printf("]");
379
380         printf(",\"follow\":[");
381         i = 0;
382         follow_iterate_followers(sharkd_follower_visit_cb, &i);
383         printf("]");
384
385         printf("}\n");
386 }
387
388 /**
389  * sharkd_session_process_load()
390  *
391  * Process load request
392  *
393  * Input:
394  *   (m) file - file to be loaded
395  *
396  * Output object with attributes:
397  *   (m) err - error code
398  */
399 static void
400 sharkd_session_process_load(const char *buf, const jsmntok_t *tokens, int count)
401 {
402         const char *tok_file = json_find_attr(buf, tokens, count, "file");
403         int err = 0;
404
405         fprintf(stderr, "load: filename=%s\n", tok_file);
406
407         if (!tok_file)
408                 return;
409
410         if (sharkd_cf_open(tok_file, WTAP_TYPE_AUTO, FALSE, &err) != CF_OK)
411         {
412                 printf("{\"err\":%d}\n", err);
413                 return;
414         }
415
416         TRY
417         {
418                 err = sharkd_load_cap_file();
419         }
420         CATCH(OutOfMemoryError)
421         {
422                 fprintf(stderr, "load: OutOfMemoryError\n");
423                 err = ENOMEM;
424         }
425         ENDTRY;
426
427         printf("{\"err\":%d}\n", err);
428 }
429
430 /**
431  * sharkd_session_process_status()
432  *
433  * Process status request
434  *
435  * Output object with attributes:
436  *   (m) frames  - count of currently loaded frames
437  */
438 static void
439 sharkd_session_process_status(void)
440 {
441         printf("{\"frames\":%d", cfile.count);
442
443         printf("}\n");
444 }
445
446 struct sharkd_analyse_data
447 {
448         GHashTable *protocols_set;
449         nstime_t *first_time;
450         nstime_t *last_time;
451 };
452
453 static void
454 sharkd_session_process_analyse_cb(packet_info *pi, proto_tree *tree, struct epan_column_info *cinfo, const GSList *data_src, void *data)
455 {
456         struct sharkd_analyse_data *analyser = (struct sharkd_analyse_data *) data;
457         frame_data *fdata = pi->fd;
458
459         (void) tree;
460         (void) cinfo;
461         (void) data_src;
462
463         if (analyser->first_time == NULL || nstime_cmp(&fdata->abs_ts, analyser->first_time) < 0)
464                 analyser->first_time = &fdata->abs_ts;
465
466         if (analyser->last_time == NULL || nstime_cmp(&fdata->abs_ts, analyser->last_time) > 0)
467                 analyser->last_time = &fdata->abs_ts;
468
469         if (pi->layers)
470         {
471                 wmem_list_frame_t *frame;
472
473                 for (frame = wmem_list_head(pi->layers); frame; frame = wmem_list_frame_next(frame))
474                 {
475                         int proto_id = GPOINTER_TO_UINT(wmem_list_frame_data(frame));
476
477                         if (!g_hash_table_lookup_extended(analyser->protocols_set, GUINT_TO_POINTER(proto_id), NULL, NULL))
478                         {
479                                 g_hash_table_insert(analyser->protocols_set, GUINT_TO_POINTER(proto_id), GUINT_TO_POINTER(proto_id));
480
481                                 if (g_hash_table_size(analyser->protocols_set) != 1)
482                                         printf(",");
483                                 json_puts_string(proto_get_protocol_filter_name(proto_id));
484                         }
485                 }
486         }
487
488 }
489
490 /**
491  * sharkd_session_process_status()
492  *
493  * Process analyse request
494  *
495  * Output object with attributes:
496  *   (m) frames  - count of currently loaded frames
497  *   (m) protocols - protocol list
498  *   (m) first     - earliest frame time
499  *   (m) last      - latest frame time
500  */
501 static void
502 sharkd_session_process_analyse(void)
503 {
504         unsigned int framenum;
505         struct sharkd_analyse_data analyser;
506
507         analyser.first_time = NULL;
508         analyser.last_time  = NULL;
509         analyser.protocols_set = g_hash_table_new(NULL /* g_direct_hash() */, NULL /* g_direct_equal */);
510
511         printf("{\"frames\":%d", cfile.count);
512
513         printf(",\"protocols\":[");
514         for (framenum = 1; framenum <= cfile.count; framenum++)
515                 sharkd_dissect_request(framenum, &sharkd_session_process_analyse_cb, 0, 0, 0, &analyser);
516         printf("]");
517
518         if (analyser.first_time)
519                 printf(",\"first\":%.9f", nstime_to_sec(analyser.first_time));
520
521         if (analyser.last_time)
522                 printf(",\"last\":%.9f", nstime_to_sec(analyser.last_time));
523
524         printf("}\n");
525
526         g_hash_table_destroy(analyser.protocols_set);
527 }
528
529 /**
530  * sharkd_session_process_frames()
531  *
532  * Process frames request
533  *
534  * Input:
535  *   (o) filter - filter to be used
536  *   (o) range  - packet range to be used [TODO]
537  *
538  * Output array of frames with attributes:
539  *   (m) c   - array of column data
540  *   (m) num - frame number
541  *   (m) i   - if frame is ignored
542  *   (m) m   - if frame is marked
543  *   (m) bg  - color filter - background color in hex
544  *   (m) fg  - color filter - foreground color in hex
545  */
546 static void
547 sharkd_session_process_frames(const char *buf, const jsmntok_t *tokens, int count)
548 {
549         const char *tok_filter = json_find_attr(buf, tokens, count, "filter");
550
551         const guint8 *filter_data = NULL;
552
553         const char *frame_sepa = "";
554         unsigned int framenum;
555         int col;
556
557         column_info *cinfo = &cfile.cinfo;
558
559         if (tok_filter)
560         {
561                 filter_data = sharkd_session_filter_data(tok_filter);
562                 if (!filter_data)
563                         return;
564         }
565
566         printf("[");
567         for (framenum = 1; framenum <= cfile.count; framenum++)
568         {
569                 frame_data *fdata = frame_data_sequence_find(cfile.frames, framenum);
570
571                 if (filter_data && !(filter_data[framenum / 8] & (1 << (framenum % 8))))
572                         continue;
573
574                 sharkd_dissect_columns(framenum, cinfo, (fdata->color_filter == NULL));
575
576                 printf("%s{\"c\":[", frame_sepa);
577                 for (col = 0; col < cinfo->num_cols; ++col)
578                 {
579                         const col_item_t *col_item = &cinfo->columns[col];
580
581                         if (col)
582                                 printf(",");
583
584                         json_puts_string(col_item->col_data);
585                 }
586                 printf("],\"num\":%u", framenum);
587
588                 if (fdata->flags.ignored)
589                         printf(",\"i\":true");
590
591                 if (fdata->flags.marked)
592                         printf(",\"m\":true");
593
594                 if (fdata->color_filter)
595                 {
596                         printf(",\"bg\":\"%x\"", color_t_to_rgb(&fdata->color_filter->bg_color));
597                         printf(",\"fg\":\"%x\"", color_t_to_rgb(&fdata->color_filter->fg_color));
598                 }
599
600                 printf("}");
601                 frame_sepa = ",";
602         }
603         printf("]\n");
604
605         if (cinfo != &cfile.cinfo)
606                 col_cleanup(cinfo);
607 }
608
609 static void
610 sharkd_session_process_tap_stats_node_cb(const stat_node *n)
611 {
612         stat_node *node;
613         const char *sepa = "";
614
615         printf("[");
616         for (node = n->children; node; node = node->next)
617         {
618                 /* code based on stats_tree_get_values_from_node() */
619                 printf("%s{\"name\":\"%s\"", sepa, node->name);
620                 printf(",\"count\":%u", node->counter);
621                 if (node->counter && ((node->st_flags & ST_FLG_AVERAGE) || node->rng))
622                 {
623                         printf(",\"avg\":%.2f", ((float)node->total) / node->counter);
624                         printf(",\"min\":%u", node->minvalue);
625                         printf(",\"max\":%u", node->maxvalue);
626                 }
627
628                 if (node->st->elapsed)
629                         printf(",\"rate\":%.4f",((float)node->counter) / node->st->elapsed);
630
631                 if (node->parent && node->parent->counter)
632                         printf(",\"perc\":%.2f", (node->counter * 100.0) / node->parent->counter);
633                 else if (node->parent == &(node->st->root))
634                         printf(",\"perc\":100");
635
636                 if (prefs.st_enable_burstinfo && node->max_burst)
637                 {
638                         if (prefs.st_burst_showcount)
639                                 printf(",\"burstcount\":%d", node->max_burst);
640                         else
641                                 printf(",\"burstrate\":%.4f", ((double)node->max_burst) / prefs.st_burst_windowlen);
642
643                         printf(",\"bursttime\":%.3f", ((double)node->burst_time / 1000.0));
644                 }
645
646                 if (node->children)
647                 {
648                         printf(",\"sub\":");
649                         sharkd_session_process_tap_stats_node_cb(node);
650                 }
651                 printf("}");
652                 sepa = ",";
653         }
654         printf("]");
655 }
656
657 /**
658  * sharkd_session_process_tap_stats_cb()
659  *
660  * Output stats tap:
661  *
662  *   (m) tap        - tap name
663  *   (m) type:stats - tap output type
664  *   (m) name       - stat name
665  *   (m) stats      - array of object with attributes:
666  *                  (m) name       - stat item name
667  *                  (m) count      - stat item counter
668  *                  (o) avg        - stat item averange value
669  *                  (o) min        - stat item min value
670  *                  (o) max        - stat item max value
671  *                  (o) rate       - stat item rate value (ms)
672  *                  (o) perc       - stat item percentage
673  *                  (o) burstrate  - stat item burst rate
674  *                  (o) burstcount - stat item burst count
675  *                  (o) burstttme  - stat item burst start
676  *                  (o) sub        - array of object with attributes like in stats node.
677  */
678 static void
679 sharkd_session_process_tap_stats_cb(void *psp)
680 {
681         stats_tree *st = (stats_tree *) psp;
682
683         printf("{\"tap\":\"stats:%s\",\"type\":\"stats\"", st->cfg->abbr);
684
685         printf(",\"name\":\"%s\",\"stats\":", st->cfg->name);
686         sharkd_session_process_tap_stats_node_cb(&st->root);
687         printf("},");
688 }
689
690 static void
691 sharkd_session_free_tap_stats_cb(void *psp)
692 {
693         stats_tree *st = (stats_tree *) psp;
694
695         stats_tree_free(st);
696 }
697
698 struct sharkd_conv_tap_data
699 {
700         const char *type;
701         conv_hash_t hash;
702         gboolean resolve_name;
703         gboolean resolve_port;
704 };
705
706 static int
707 sharkd_session_geoip_addr(address *addr, const char *suffix)
708 {
709         int with_geoip = 0;
710
711         (void) addr;
712         (void) suffix;
713
714 #ifdef HAVE_GEOIP
715         if (addr->type == AT_IPv4)
716         {
717                 guint32 ip = pntoh32(addr->data);
718
719                 guint num_dbs = geoip_db_num_dbs();
720                 guint dbnum;
721
722                 for (dbnum = 0; dbnum < num_dbs; dbnum++)
723                 {
724                         const char *geoip_key = NULL;
725                         char *geoip_val;
726
727                         int db_type = geoip_db_type(dbnum);
728
729                         switch (db_type)
730                         {
731                                 case GEOIP_COUNTRY_EDITION:
732                                         geoip_key = "geoip_country";
733                                         break;
734
735                                 case GEOIP_CITY_EDITION_REV0:
736                                 case GEOIP_CITY_EDITION_REV1:
737                                         geoip_key = "geoip_city";
738                                         break;
739
740                                 case GEOIP_ORG_EDITION:
741                                         geoip_key = "geoip_org";
742                                         break;
743
744                                 case GEOIP_ISP_EDITION:
745                                         geoip_key = "geoip_isp";
746                                         break;
747
748                                 case GEOIP_ASNUM_EDITION:
749                                         geoip_key = "geoip_as";
750                                         break;
751
752                                 case WS_LAT_FAKE_EDITION:
753                                         geoip_key = "geoip_lat";
754                                         break;
755
756                                 case WS_LON_FAKE_EDITION:
757                                         geoip_key = "geoip_lon";
758                                         break;
759                         }
760
761                         if (geoip_key && (geoip_val = geoip_db_lookup_ipv4(dbnum, ip, NULL)))
762                         {
763                                 printf(",\"%s%s\":", geoip_key, suffix);
764                                 json_puts_string(geoip_val);
765                                 with_geoip = 1;
766                         }
767                 }
768         }
769 #ifdef HAVE_GEOIP_V6
770         if (addr->type == AT_IPv6)
771         {
772                 const struct e_in6_addr *ip6 = (const struct e_in6_addr *) addr->data;
773
774                 guint num_dbs = geoip_db_num_dbs();
775                 guint dbnum;
776
777                 for (dbnum = 0; dbnum < num_dbs; dbnum++)
778                 {
779                         const char *geoip_key = NULL;
780                         char *geoip_val;
781
782                         int db_type = geoip_db_type(dbnum);
783
784                         switch (db_type)
785                         {
786                                 case GEOIP_COUNTRY_EDITION_V6:
787                                         geoip_key = "geoip_country";
788                                         break;
789 #if NUM_DB_TYPES > 31
790                                 case GEOIP_CITY_EDITION_REV0_V6:
791                                 case GEOIP_CITY_EDITION_REV1_V6:
792                                         geoip_key = "geoip_city";
793                                         break;
794
795                                 case GEOIP_ORG_EDITION_V6:
796                                         geoip_key = "geoip_org";
797                                         break;
798
799                                 case GEOIP_ISP_EDITION_V6:
800                                         geoip_key = "geoip_isp";
801                                         break;
802
803                                 case GEOIP_ASNUM_EDITION_V6:
804                                         geoip_key = "geoip_as";
805                                         break;
806 #endif /* DB_NUM_TYPES */
807                                 case WS_LAT_FAKE_EDITION:
808                                         geoip_key = "geoip_lat";
809                                         break;
810
811                                 case WS_LON_FAKE_EDITION:
812                                         geoip_key = "geoip_lon";
813                                         break;
814                         }
815
816                         if (geoip_key && (geoip_val = geoip_db_lookup_ipv6(dbnum, *ip6, NULL)))
817                         {
818                                 printf(",\"%s%s\":", geoip_key, suffix);
819                                 json_puts_string(geoip_val);
820                                 with_geoip = 1;
821                         }
822                 }
823         }
824 #endif /* HAVE_GEOIP_V6 */
825 #endif /* HAVE_GEOIP */
826
827         return with_geoip;
828 }
829
830 /**
831  * sharkd_session_process_tap_conv_cb()
832  *
833  * Output conv tap:
834  *   (m) tap        - tap name
835  *   (m) type       - tap output type
836  *   (m) proto      - protocol short name
837  *   (o) filter     - filter string
838  *
839  *   (o) convs      - array of object with attributes:
840  *                  (m) saddr - source address
841  *                  (m) daddr - destination address
842  *                  (o) sport - source port
843  *                  (o) dport - destination port
844  *                  (m) txf   - TX frame count
845  *                  (m) txb   - TX bytes
846  *                  (m) rxf   - RX frame count
847  *                  (m) rxb   - RX bytes
848  *                  (m) start - (relative) first packet time
849  *                  (m) stop  - (relative) last packet time
850  *
851  *   (o) hosts      - array of object with attributes:
852  *                  (m) host - host address
853  *                  (o) port - host port
854  *                  (m) txf  - TX frame count
855  *                  (m) txb  - TX bytes
856  *                  (m) rxf  - RX frame count
857  *                  (m) rxb  - RX bytes
858  */
859 static void
860 sharkd_session_process_tap_conv_cb(void *arg)
861 {
862         conv_hash_t *hash = (conv_hash_t *) arg;
863         const struct sharkd_conv_tap_data *iu = (struct sharkd_conv_tap_data *) hash->user_data;
864         const char *proto;
865         int proto_with_port;
866         guint i;
867
868         int with_geoip = 0;
869
870         if (!strncmp(iu->type, "conv:", 5))
871         {
872                 printf("{\"tap\":\"%s\",\"type\":\"conv\"", iu->type);
873                 printf(",\"convs\":[");
874                 proto = iu->type + 5;
875         }
876         else if (!strncmp(iu->type, "endpt:", 6))
877         {
878                 printf("{\"tap\":\"%s\",\"type\":\"host\"", iu->type);
879                 printf(",\"hosts\":[");
880                 proto = iu->type + 6;
881         }
882         else
883         {
884                 printf("{\"tap\":\"%s\",\"type\":\"err\"", iu->type);
885                 proto = "";
886         }
887
888         proto_with_port = (!strcmp(proto, "TCP") || !strcmp(proto, "UDP") || !strcmp(proto, "SCTP"));
889
890         if (iu->hash.conv_array != NULL && !strncmp(iu->type, "conv:", 5))
891         {
892                 for (i = 0; i < iu->hash.conv_array->len; i++)
893                 {
894                         conv_item_t *iui = &g_array_index(iu->hash.conv_array, conv_item_t, i);
895                         char *src_addr, *dst_addr;
896                         char *src_port, *dst_port;
897                         char *filter_str;
898
899                         printf("%s{", i ? "," : "");
900
901                         printf("\"saddr\":\"%s\"",  (src_addr = get_conversation_address(NULL, &iui->src_address, iu->resolve_name)));
902                         printf(",\"daddr\":\"%s\"", (dst_addr = get_conversation_address(NULL, &iui->dst_address, iu->resolve_name)));
903
904                         if (proto_with_port)
905                         {
906                                 printf(",\"sport\":\"%s\"", (src_port = get_conversation_port(NULL, iui->src_port, iui->ptype, iu->resolve_port)));
907                                 printf(",\"dport\":\"%s\"", (dst_port = get_conversation_port(NULL, iui->dst_port, iui->ptype, iu->resolve_port)));
908
909                                 wmem_free(NULL, src_port);
910                                 wmem_free(NULL, dst_port);
911                         }
912
913                         printf(",\"rxf\":%" G_GUINT64_FORMAT, iui->rx_frames);
914                         printf(",\"rxb\":%" G_GUINT64_FORMAT, iui->rx_bytes);
915
916                         printf(",\"txf\":%" G_GUINT64_FORMAT, iui->tx_frames);
917                         printf(",\"txb\":%" G_GUINT64_FORMAT, iui->tx_bytes);
918
919                         printf(",\"start\":%.9f", nstime_to_sec(&iui->start_time));
920                         printf(",\"stop\":%.9f", nstime_to_sec(&iui->stop_time));
921
922                         filter_str = get_conversation_filter(iui, CONV_DIR_A_TO_FROM_B);
923                         if (filter_str)
924                         {
925                                 printf(",\"filter\":\"%s\"", filter_str);
926                                 g_free(filter_str);
927                         }
928
929                         wmem_free(NULL, src_addr);
930                         wmem_free(NULL, dst_addr);
931
932                         if (sharkd_session_geoip_addr(&(iui->src_address), "1"))
933                                 with_geoip = 1;
934                         if (sharkd_session_geoip_addr(&(iui->dst_address), "2"))
935                                 with_geoip = 1;
936
937                         printf("}");
938                 }
939         }
940         else if (iu->hash.conv_array != NULL && !strncmp(iu->type, "endpt:", 6))
941         {
942                 for (i = 0; i < iu->hash.conv_array->len; i++)
943                 {
944                         hostlist_talker_t *host = &g_array_index(iu->hash.conv_array, hostlist_talker_t, i);
945                         char *host_str, *port_str;
946                         char *filter_str;
947
948                         printf("%s{", i ? "," : "");
949
950                         printf("\"host\":\"%s\"", (host_str = get_conversation_address(NULL, &host->myaddress, iu->resolve_name)));
951
952                         if (proto_with_port)
953                         {
954                                 printf(",\"port\":\"%s\"", (port_str = get_conversation_port(NULL, host->port, host->ptype, iu->resolve_port)));
955
956                                 wmem_free(NULL, port_str);
957                         }
958
959                         printf(",\"rxf\":%" G_GUINT64_FORMAT, host->rx_frames);
960                         printf(",\"rxb\":%" G_GUINT64_FORMAT, host->rx_bytes);
961
962                         printf(",\"txf\":%" G_GUINT64_FORMAT, host->tx_frames);
963                         printf(",\"txb\":%" G_GUINT64_FORMAT, host->tx_bytes);
964
965                         filter_str = get_hostlist_filter(host);
966                         if (filter_str)
967                         {
968                                 printf(",\"filter\":\"%s\"", filter_str);
969                                 g_free(filter_str);
970                         }
971
972                         wmem_free(NULL, host_str);
973
974                         if (sharkd_session_geoip_addr(&(host->myaddress), ""))
975                                 with_geoip = 1;
976                         printf("}");
977                 }
978         }
979
980         printf("],\"proto\":\"%s\",\"geoip\":%s},", proto, with_geoip ? "true" : "false");
981 }
982
983 static void
984 sharkd_session_free_tap_conv_cb(void *arg)
985 {
986         conv_hash_t *hash = (conv_hash_t *) arg;
987         struct sharkd_conv_tap_data *iu = (struct sharkd_conv_tap_data *) hash->user_data;
988
989         if (!strncmp(iu->type, "conv:", 5))
990         {
991                 reset_conversation_table_data(hash);
992         }
993         else if (!strncmp(iu->type, "endpt:", 6))
994         {
995                 reset_hostlist_table_data(hash);
996         }
997
998         g_free(iu);
999 }
1000
1001 struct sharkd_export_object_list
1002 {
1003         struct sharkd_export_object_list *next;
1004
1005         char *type;
1006         const char *proto;
1007         GSList *entries;
1008 };
1009
1010 static struct sharkd_export_object_list *sharkd_eo_list;
1011
1012 /**
1013  * sharkd_session_process_tap_eo_cb()
1014  *
1015  * Output eo tap:
1016  *   (m) tap        - tap name
1017  *   (m) type       - tap output type
1018  *   (m) proto      - protocol short name
1019  *   (m) objects    - array of object with attributes:
1020  *                  (m) pkt - packet number
1021  *                  (o) hostname - hostname
1022  *                  (o) type - content type
1023  *                  (o) filename - filename
1024  *                  (m) len - object length
1025  */
1026 static void
1027 sharkd_session_process_tap_eo_cb(void *tapdata)
1028 {
1029         export_object_list_t *tap_object = (export_object_list_t *) tapdata;
1030         struct sharkd_export_object_list *object_list = (struct sharkd_export_object_list*) tap_object->gui_data;
1031         GSList *slist;
1032         int i = 0;
1033
1034         printf("{\"tap\":\"%s\",\"type\":\"eo\"", object_list->type);
1035         printf(",\"proto\":\"%s\"", object_list->proto);
1036         printf(",\"objects\":[");
1037
1038         for (slist = object_list->entries; slist; slist = slist->next)
1039         {
1040                 const export_object_entry_t *eo_entry = (export_object_entry_t *) slist->data;
1041
1042                 printf("%s{", i ? "," : "");
1043
1044                 printf("\"pkt\":%u", eo_entry->pkt_num);
1045
1046                 if (eo_entry->hostname)
1047                 {
1048                         printf(",\"hostname\":");
1049                         json_puts_string(eo_entry->hostname);
1050                 }
1051
1052                 if (eo_entry->content_type)
1053                 {
1054                         printf(",\"type\":");
1055                         json_puts_string(eo_entry->content_type);
1056                 }
1057
1058                 if (eo_entry->filename)
1059                 {
1060                         printf(",\"filename\":");
1061                         json_puts_string(eo_entry->filename);
1062                 }
1063
1064                 printf(",\"_download\":\"%s_%d\"", object_list->type, i);
1065
1066                 printf(",\"len\":%" G_GUINT64_FORMAT, eo_entry->payload_len);
1067
1068                 printf("}");
1069
1070                 i++;
1071         }
1072
1073         printf("]},");
1074 }
1075
1076 static void
1077 sharkd_eo_object_list_add_entry(void *gui_data, export_object_entry_t *entry)
1078 {
1079         struct sharkd_export_object_list *object_list = (struct sharkd_export_object_list *) gui_data;
1080
1081         object_list->entries = g_slist_append(object_list->entries, entry);
1082 }
1083
1084 static export_object_entry_t *
1085 sharkd_eo_object_list_get_entry(void *gui_data, int row)
1086 {
1087         struct sharkd_export_object_list *object_list = (struct sharkd_export_object_list *) gui_data;
1088
1089         return (export_object_entry_t *) g_slist_nth_data(object_list->entries, row);
1090 }
1091
1092 /**
1093  * sharkd_session_process_tap_rtp_cb()
1094  *
1095  * Output RTP streams tap:
1096  *   (m) tap        - tap name
1097  *   (m) type       - tap output type
1098  *   (m) streams    - array of object with attributes:
1099  *                  (m) ssrc        - RTP synchronization source identifier
1100  *                  (m) payload     - stream payload
1101  *                  (m) saddr       - source address
1102  *                  (m) sport       - source port
1103  *                  (m) daddr       - destination address
1104  *                  (m) dport       - destination port
1105  *                  (m) pkts        - packets count
1106  *                  (m) max_delta   - max delta (ms)
1107  *                  (m) max_jitter  - max jitter (ms)
1108  *                  (m) mean_jitter - mean jitter (ms)
1109  *                  (m) expectednr  -
1110  *                  (m) totalnr     -
1111  *                  (m) problem     - if analyser found the problem
1112  *                  (m) ipver       - address IP version (4 or 6)
1113  */
1114 static void
1115 sharkd_session_process_tap_rtp_cb(void *arg)
1116 {
1117         rtpstream_tapinfo_t *rtp_tapinfo = (rtpstream_tapinfo_t *) arg;
1118
1119         GList *listx;
1120         const char *sepa = "";
1121
1122         printf("{\"tap\":\"%s\",\"type\":\"%s\"", "rtp-streams", "rtp-streams");
1123
1124         printf(",\"streams\":[");
1125         for (listx = g_list_first(rtp_tapinfo->strinfo_list); listx; listx = listx->next)
1126         {
1127                 rtp_stream_info_t *streaminfo = (rtp_stream_info_t *) listx->data;
1128
1129                 char *src_addr, *dst_addr;
1130                 char *payload;
1131                 guint32 expected;
1132
1133                 src_addr = address_to_display(NULL, &(streaminfo->src_addr));
1134                 dst_addr = address_to_display(NULL, &(streaminfo->dest_addr));
1135
1136                 if (streaminfo->payload_type_name != NULL)
1137                         payload = wmem_strdup(NULL, streaminfo->payload_type_name);
1138                 else
1139                         payload = val_to_str_ext_wmem(NULL, streaminfo->payload_type, &rtp_payload_type_short_vals_ext, "Unknown (%u)");
1140
1141                 printf("%s{\"ssrc\":%u", sepa, streaminfo->ssrc);
1142                 printf(",\"payload\":\"%s\"", payload);
1143
1144                 printf(",\"saddr\":\"%s\"", src_addr);
1145                 printf(",\"sport\":%u", streaminfo->src_port);
1146
1147                 printf(",\"daddr\":\"%s\"", dst_addr);
1148                 printf(",\"dport\":%u", streaminfo->dest_port);
1149
1150                 printf(",\"pkts\":%u", streaminfo->packet_count);
1151
1152                 printf(",\"max_delta\":%f", streaminfo->rtp_stats.max_delta);
1153                 printf(",\"max_jitter\":%f", streaminfo->rtp_stats.max_jitter);
1154                 printf(",\"mean_jitter\":%f", streaminfo->rtp_stats.mean_jitter);
1155
1156                 expected = (streaminfo->rtp_stats.stop_seq_nr + streaminfo->rtp_stats.cycles * 65536) - streaminfo->rtp_stats.start_seq_nr + 1;
1157                 printf(",\"expectednr\":%u", expected);
1158                 printf(",\"totalnr\":%u", streaminfo->rtp_stats.total_nr);
1159
1160                 printf(",\"problem\":%s", streaminfo->problem ? "true" : "false");
1161
1162                 /* for filter */
1163                 printf(",\"ipver\":%d", (streaminfo->src_addr.type == AT_IPv6) ? 6 : 4);
1164
1165                 wmem_free(NULL, src_addr);
1166                 wmem_free(NULL, dst_addr);
1167                 wmem_free(NULL, payload);
1168
1169                 printf("}");
1170                 sepa = ",";
1171         }
1172         printf("]},");
1173 }
1174
1175 /**
1176  * sharkd_session_process_tap()
1177  *
1178  * Process tap request
1179  *
1180  * Input:
1181  *   (m) tap0         - First tap request
1182  *   (o) tap1...tap15 - Other tap requests
1183  *
1184  * Output object with attributes:
1185  *   (m) taps  - array of object with attributes:
1186  *                  (m) tap  - tap name
1187  *                  (m) type - tap output type
1188  *                  ...
1189  *                  for type:stats see sharkd_session_process_tap_stats_cb()
1190  *                  for type:conv see sharkd_session_process_tap_conv_cb()
1191  *                  for type:host see sharkd_session_process_tap_conv_cb()
1192  *                  for type:rtp-streams see sharkd_session_process_tap_rtp_cb()
1193  *                  for type:eo see sharkd_session_process_tap_eo_cb()
1194  *
1195  *   (m) err   - error code
1196  */
1197 static void
1198 sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count)
1199 {
1200         void *taps_data[16];
1201         GFreeFunc taps_free[16];
1202         int taps_count = 0;
1203         int i;
1204
1205         rtpstream_tapinfo_t rtp_tapinfo =
1206                 {NULL, NULL, NULL, NULL, 0, NULL, 0, TAP_ANALYSE, NULL, NULL, NULL, FALSE};
1207
1208         for (i = 0; i < 16; i++)
1209         {
1210                 char tapbuf[32];
1211                 const char *tok_tap;
1212
1213                 void *tap_data = NULL;
1214                 GFreeFunc tap_free = NULL;
1215                 const char *tap_filter = "";
1216                 GString *tap_error = NULL;
1217
1218                 ws_snprintf(tapbuf, sizeof(tapbuf), "tap%d", i);
1219                 tok_tap = json_find_attr(buf, tokens, count, tapbuf);
1220                 if (!tok_tap)
1221                         break;
1222
1223                 if (!strncmp(tok_tap, "stat:", 5))
1224                 {
1225                         stats_tree_cfg *cfg = stats_tree_get_cfg_by_abbr(tok_tap + 5);
1226                         stats_tree *st;
1227
1228                         if (!cfg)
1229                         {
1230                                 fprintf(stderr, "sharkd_session_process_tap() stat %s not found\n", tok_tap + 5);
1231                                 continue;
1232                         }
1233
1234                         st = stats_tree_new(cfg, NULL, tap_filter);
1235
1236                         tap_error = register_tap_listener(st->cfg->tapname, st, st->filter, st->cfg->flags, stats_tree_reset, stats_tree_packet, sharkd_session_process_tap_stats_cb);
1237
1238                         if (!tap_error && cfg->init)
1239                                 cfg->init(st);
1240
1241                         tap_data = st;
1242                         tap_free = sharkd_session_free_tap_stats_cb;
1243                 }
1244                 else if (!strncmp(tok_tap, "conv:", 5) || !strncmp(tok_tap, "endpt:", 6))
1245                 {
1246                         struct register_ct *ct = NULL;
1247                         const char *ct_tapname;
1248                         struct sharkd_conv_tap_data *ct_data;
1249                         tap_packet_cb tap_func = NULL;
1250
1251                         if (!strncmp(tok_tap, "conv:", 5))
1252                         {
1253                                 ct = get_conversation_by_proto_id(proto_get_id_by_short_name(tok_tap + 5));
1254
1255                                 if (!ct || !(tap_func = get_conversation_packet_func(ct)))
1256                                 {
1257                                         fprintf(stderr, "sharkd_session_process_tap() conv %s not found\n", tok_tap + 5);
1258                                         continue;
1259                                 }
1260                         }
1261                         else if (!strncmp(tok_tap, "endpt:", 6))
1262                         {
1263                                 ct = get_conversation_by_proto_id(proto_get_id_by_short_name(tok_tap + 6));
1264
1265                                 if (!ct || !(tap_func = get_hostlist_packet_func(ct)))
1266                                 {
1267                                         fprintf(stderr, "sharkd_session_process_tap() endpt %s not found\n", tok_tap + 6);
1268                                         continue;
1269                                 }
1270                         }
1271                         else
1272                         {
1273                                 fprintf(stderr, "sharkd_session_process_tap() conv/endpt(?): %s not found\n", tok_tap);
1274                                 continue;
1275                         }
1276
1277                         ct_tapname = proto_get_protocol_filter_name(get_conversation_proto_id(ct));
1278
1279                         ct_data = (struct sharkd_conv_tap_data *) g_malloc0(sizeof(struct sharkd_conv_tap_data));
1280                         ct_data->type = tok_tap;
1281                         ct_data->hash.user_data = ct_data;
1282
1283                         /* XXX: make configurable */
1284                         ct_data->resolve_name = TRUE;
1285                         ct_data->resolve_port = TRUE;
1286
1287                         tap_error = register_tap_listener(ct_tapname, &ct_data->hash, tap_filter, 0, NULL, tap_func, sharkd_session_process_tap_conv_cb);
1288
1289                         tap_data = &ct_data->hash;
1290                         tap_free = sharkd_session_free_tap_conv_cb;
1291                 }
1292                 else if (!strncmp(tok_tap, "eo:", 3))
1293                 {
1294                         register_eo_t *eo = get_eo_by_name(tok_tap + 3);
1295                         export_object_list_t *eo_object;
1296                         struct sharkd_export_object_list *object_list;
1297
1298                         if (!eo)
1299                         {
1300                                 fprintf(stderr, "sharkd_session_process_tap() eo=%s not found\n", tok_tap + 3);
1301                                 continue;
1302                         }
1303
1304                         for (object_list = sharkd_eo_list; object_list; object_list = object_list->next)
1305                         {
1306                                 if (!strcmp(object_list->type, tok_tap))
1307                                 {
1308                                         g_slist_free_full(object_list->entries, (GDestroyNotify) eo_free_entry);
1309                                         object_list->entries = NULL;
1310                                         break;
1311                                 }
1312                         }
1313
1314                         if (!object_list)
1315                         {
1316                                 object_list = g_new(struct sharkd_export_object_list, 1);
1317                                 object_list->type = g_strdup(tok_tap);
1318                                 object_list->proto = proto_get_protocol_short_name(find_protocol_by_id(get_eo_proto_id(eo)));
1319                                 object_list->entries = NULL;
1320                                 object_list->next = sharkd_eo_list;
1321                                 sharkd_eo_list = object_list;
1322                         }
1323
1324                         eo_object  = g_new0(export_object_list_t, 1);
1325                         eo_object->add_entry = sharkd_eo_object_list_add_entry;
1326                         eo_object->get_entry = sharkd_eo_object_list_get_entry;
1327                         eo_object->gui_data = (void *) object_list;
1328
1329                         tap_error = register_tap_listener(get_eo_tap_listener_name(eo), eo_object, NULL, 0, NULL, get_eo_packet_func(eo), sharkd_session_process_tap_eo_cb);
1330
1331                         tap_data = eo_object;
1332                         tap_free = g_free; /* need to free only eo_object, object_list need to be kept for potential download */
1333                 }
1334                 else if (!strcmp(tok_tap, "rtp-streams"))
1335                 {
1336                         tap_error = register_tap_listener("rtp", &rtp_tapinfo, tap_filter, 0, rtpstream_reset_cb, rtpstream_packet, sharkd_session_process_tap_rtp_cb);
1337
1338                         tap_data = &rtp_tapinfo;
1339                         tap_free = rtpstream_reset_cb;
1340                 }
1341                 else
1342                 {
1343                         fprintf(stderr, "sharkd_session_process_tap() %s not recognized\n", tok_tap);
1344                         continue;
1345                 }
1346
1347                 if (tap_error)
1348                 {
1349                         fprintf(stderr, "sharkd_session_process_tap() name=%s error=%s", tok_tap, tap_error->str);
1350                         g_string_free(tap_error, TRUE);
1351                         if (tap_free)
1352                                 tap_free(tap_data);
1353                         continue;
1354                 }
1355
1356                 taps_data[taps_count] = tap_data;
1357                 taps_free[taps_count] = tap_free;
1358                 taps_count++;
1359         }
1360
1361         fprintf(stderr, "sharkd_session_process_tap() count=%d\n", taps_count);
1362         if (taps_count == 0)
1363                 return;
1364
1365         printf("{\"taps\":[");
1366         sharkd_retap();
1367         printf("null],\"err\":0}\n");
1368
1369         for (i = 0; i < taps_count; i++)
1370         {
1371                 if (taps_data[i])
1372                         remove_tap_listener(taps_data[i]);
1373
1374                 if (taps_free[i])
1375                         taps_free[i](taps_data[i]);
1376         }
1377 }
1378
1379 /**
1380  * sharkd_session_process_follow()
1381  *
1382  * Process follow request
1383  *
1384  * Input:
1385  *   (m) follow  - follow protocol request (e.g. HTTP)
1386  *   (m) filter  - filter request (e.g. tcp.stream == 1)
1387  *
1388  * Output object with attributes:
1389  *
1390  *   (m) err    - error code
1391  *   (m) shost  - server host
1392  *   (m) sport  - server port
1393  *   (m) sbytes - server send bytes count
1394  *   (m) chost  - client host
1395  *   (m) cport  - client port
1396  *   (m) cbytes - client send bytes count
1397  *   (o) payloads - array of object with attributes:
1398  *                  (o) s - set if server sent, else client
1399  *                  (m) n - packet number
1400  *                  (m) d - data base64 encoded
1401  */
1402 static void
1403 sharkd_session_process_follow(char *buf, const jsmntok_t *tokens, int count)
1404 {
1405         const char *tok_follow = json_find_attr(buf, tokens, count, "follow");
1406         const char *tok_filter = json_find_attr(buf, tokens, count, "filter");
1407
1408         register_follow_t *follower;
1409         GString *tap_error;
1410
1411         follow_info_t *follow_info;
1412         const char *host;
1413         char *port;
1414
1415         if (!tok_follow || !tok_filter)
1416                 return;
1417
1418         follower = get_follow_by_name(tok_follow);
1419         if (!follower)
1420         {
1421                 fprintf(stderr, "sharkd_session_process_follow() follower=%s not found\n", tok_follow);
1422                 return;
1423         }
1424
1425         /* follow_reset_stream ? */
1426         follow_info = g_new0(follow_info_t, 1);
1427         /* gui_data, filter_out_filter not set, but not used by dissector */
1428
1429         tap_error = register_tap_listener(get_follow_tap_string(follower), follow_info, tok_filter, 0, NULL, get_follow_tap_handler(follower), NULL);
1430         if (tap_error)
1431         {
1432                 fprintf(stderr, "sharkd_session_process_follow() name=%s error=%s", tok_follow, tap_error->str);
1433                 g_string_free(tap_error, TRUE);
1434                 g_free(follow_info);
1435                 return;
1436         }
1437
1438         sharkd_retap();
1439
1440         printf("{");
1441
1442         printf("\"err\":0");
1443
1444         /* Server information: hostname, port, bytes sent */
1445         host = address_to_name(&follow_info->server_ip);
1446         printf(",\"shost\":");
1447         json_puts_string(host);
1448
1449         port = get_follow_port_to_display(follower)(NULL, follow_info->server_port);
1450         printf(",\"sport\":");
1451         json_puts_string(port);
1452         wmem_free(NULL, port);
1453
1454         printf(",\"sbytes\":%u", follow_info->bytes_written[0]);
1455
1456         /* Client information: hostname, port, bytes sent */
1457         host = address_to_name(&follow_info->client_ip);
1458         printf(",\"chost\":");
1459         json_puts_string(host);
1460
1461         port = get_follow_port_to_display(follower)(NULL, follow_info->client_port);
1462         printf(",\"cport\":");
1463         json_puts_string(port);
1464         wmem_free(NULL, port);
1465
1466         printf(",\"cbytes\":%u", follow_info->bytes_written[1]);
1467
1468         if (follow_info->payload)
1469         {
1470                 follow_record_t *follow_record;
1471                 GList *cur;
1472                 const char *sepa = "";
1473
1474                 printf(",\"payloads\":[");
1475
1476                 for (cur = follow_info->payload; cur; cur = g_list_next(cur))
1477                 {
1478                         follow_record = (follow_record_t *) cur->data;
1479
1480                         printf("%s{", sepa);
1481
1482                         printf("\"n\":%u", follow_record->packet_num);
1483
1484                         printf(",\"d\":");
1485                         json_print_base64(follow_record->data->data, follow_record->data->len);
1486
1487                         if (follow_record->is_server)
1488                                 printf(",\"s\":%d", 1);
1489
1490                         printf("}");
1491                         sepa = ",";
1492                 }
1493
1494                 printf("]");
1495         }
1496
1497         printf("}\n");
1498
1499         remove_tap_listener(follow_info);
1500         follow_info_free(follow_info);
1501 }
1502
1503 static void
1504 sharkd_session_process_frame_cb_tree(proto_tree *tree, tvbuff_t **tvbs)
1505 {
1506         proto_node *node;
1507         const char *sepa = "";
1508
1509         printf("[");
1510         for (node = tree->first_child; node; node = node->next)
1511         {
1512                 field_info *finfo = PNODE_FINFO(node);
1513
1514                 if (!finfo)
1515                         continue;
1516
1517                 /* XXX, for now always skip hidden */
1518                 if (FI_GET_FLAG(finfo, FI_HIDDEN))
1519                         continue;
1520
1521                 printf("%s{", sepa);
1522
1523                 printf("\"l\":");
1524                 if (!finfo->rep)
1525                 {
1526                         char label_str[ITEM_LABEL_LENGTH];
1527
1528                         label_str[0] = '\0';
1529                         proto_item_fill_label(finfo, label_str);
1530                         json_puts_string(label_str);
1531                 }
1532                 else
1533                 {
1534                         json_puts_string(finfo->rep->representation);
1535                 }
1536
1537                 if (finfo->ds_tvb && tvbs && tvbs[0] != finfo->ds_tvb)
1538                 {
1539                         int idx;
1540
1541                         for (idx = 1; tvbs[idx]; idx++)
1542                         {
1543                                 if (tvbs[idx] == finfo->ds_tvb)
1544                                 {
1545                                         printf(",\"ds\":%d", idx);
1546                                         break;
1547                                 }
1548                         }
1549                 }
1550
1551                 if (finfo->start >= 0 && finfo->length > 0)
1552                         printf(",\"h\":[%u,%u]", finfo->start, finfo->length);
1553
1554                 if (finfo->appendix_start >= 0 && finfo->appendix_length > 0)
1555                         printf(",\"i\":[%u,%u]", finfo->appendix_start, finfo->appendix_length);
1556
1557
1558                 if (finfo->hfinfo)
1559                 {
1560                         if (finfo->hfinfo->type == FT_PROTOCOL)
1561                         {
1562                                 printf(",\"t\":\"proto\"");
1563                         }
1564                         else if (finfo->hfinfo->type == FT_FRAMENUM)
1565                         {
1566                                 printf(",\"t\":\"framenum\",\"fnum\":%u", finfo->value.value.uinteger);
1567                         }
1568                         else if (FI_GET_FLAG(finfo, FI_URL) && IS_FT_STRING(finfo->hfinfo->type))
1569                         {
1570                                 char *url = fvalue_to_string_repr(NULL, &finfo->value, FTREPR_DISPLAY, finfo->hfinfo->display);
1571
1572                                 printf(",\"t\":\"url\",\"url\":");
1573                                 json_puts_string(url);
1574                                 wmem_free(NULL, url);
1575                         }
1576                 }
1577
1578                 if (FI_GET_FLAG(finfo, PI_SEVERITY_MASK))
1579                 {
1580                         const char *severity = NULL;
1581
1582                         switch (FI_GET_FLAG(finfo, PI_SEVERITY_MASK))
1583                         {
1584                                 case PI_COMMENT:
1585                                         severity = "comment";
1586                                         break;
1587
1588                                 case PI_CHAT:
1589                                         severity = "chat";
1590                                         break;
1591
1592                                 case PI_NOTE:
1593                                         severity = "note";
1594                                         break;
1595
1596                                 case PI_WARN:
1597                                         severity = "warn";
1598                                         break;
1599
1600                                 case PI_ERROR:
1601                                         severity = "error";
1602                                         break;
1603                         }
1604                         g_assert(severity != NULL);
1605
1606                         printf(",\"s\":\"%s\"", severity);
1607                 }
1608
1609                 if (((proto_tree *) node)->first_child) {
1610                         if (finfo->tree_type != -1)
1611                                 printf(",\"e\":%d", finfo->tree_type);
1612                         printf(",\"n\":");
1613                         sharkd_session_process_frame_cb_tree((proto_tree *) node, tvbs);
1614                 }
1615
1616                 printf("}");
1617                 sepa = ",";
1618         }
1619         printf("]");
1620 }
1621
1622 static gboolean
1623 sharkd_follower_visit_layers_cb(const void *key _U_, void *value, void *user_data)
1624 {
1625         register_follow_t *follower = (register_follow_t *) value;
1626         packet_info *pi = (packet_info *) user_data;
1627
1628         const int proto_id = get_follow_proto_id(follower);
1629
1630         guint32 ignore_stream;
1631
1632         if (proto_is_frame_protocol(pi->layers, proto_get_protocol_filter_name(proto_id)))
1633         {
1634                 const char *layer_proto = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
1635                 char *follow_filter;
1636
1637                 follow_filter = get_follow_conv_func(follower)(pi, &ignore_stream);
1638
1639                 printf(",[\"%s\",", layer_proto);
1640                 json_puts_string(follow_filter);
1641                 printf("]");
1642
1643                 g_free(follow_filter);
1644         }
1645
1646         return FALSE;
1647 }
1648
1649 static void
1650 sharkd_session_process_frame_cb(packet_info *pi, proto_tree *tree, struct epan_column_info *cinfo, const GSList *data_src, void *data)
1651 {
1652         (void) pi;
1653         (void) data;
1654
1655         printf("{");
1656
1657         printf("\"err\":0");
1658
1659         if (tree)
1660         {
1661                 tvbuff_t **tvbs = NULL;
1662
1663                 printf(",\"tree\":");
1664
1665                 /* arrayize data src, to speedup searching for ds_tvb index */
1666                 if (data_src && data_src->next /* only needed if there are more than one data source */)
1667                 {
1668                         guint count = g_slist_length((GSList *) data_src);
1669                         guint i;
1670
1671                         tvbs = (tvbuff_t **) g_malloc((count + 1) * sizeof(*tvbs));
1672
1673                         for (i = 0; i < count; i++)
1674                         {
1675                                 struct data_source *src = (struct data_source *) g_slist_nth_data((GSList *) data_src, i);
1676
1677                                 tvbs[i] = get_data_source_tvb(src);
1678                         }
1679
1680                         tvbs[count] = NULL;
1681                 }
1682
1683                 sharkd_session_process_frame_cb_tree(tree, tvbs);
1684
1685                 g_free(tvbs);
1686         }
1687
1688         if (cinfo)
1689         {
1690                 int col;
1691
1692                 printf(",\"col\":[");
1693                 for (col = 0; col < cinfo->num_cols; ++col)
1694                 {
1695                         const col_item_t *col_item = &cinfo->columns[col];
1696
1697                         printf("%s\"%s\"", (col) ? "," : "", col_item->col_data);
1698                 }
1699                 printf("]");
1700         }
1701
1702         if (data_src)
1703         {
1704                 struct data_source *src = (struct data_source *)data_src->data;
1705                 const char *ds_sepa = NULL;
1706
1707                 tvbuff_t *tvb;
1708                 guint length;
1709
1710                 tvb = get_data_source_tvb(src);
1711                 length = tvb_captured_length(tvb);
1712
1713                 printf(",\"bytes\":");
1714                 if (length != 0)
1715                 {
1716                         const guchar *cp = tvb_get_ptr(tvb, 0, length);
1717
1718                         /* XXX pi.fd->flags.encoding */
1719                         json_print_base64(cp, length);
1720                 }
1721                 else
1722                 {
1723                         json_print_base64("", 0);
1724                 }
1725
1726                 data_src = data_src->next;
1727                 if (data_src)
1728                 {
1729                         printf(",\"ds\":[");
1730                         ds_sepa = "";
1731                 }
1732
1733                 while (data_src)
1734                 {
1735                         src = (struct data_source *)data_src->data;
1736
1737                         {
1738                                 char *src_name = get_data_source_name(src);
1739
1740                                 printf("%s{\"name\":", ds_sepa);
1741                                 json_puts_string(src_name);
1742                                 wmem_free(NULL, src_name);
1743                         }
1744
1745                         tvb = get_data_source_tvb(src);
1746                         length = tvb_captured_length(tvb);
1747
1748                         printf(",\"bytes\":");
1749                         if (length != 0)
1750                         {
1751                                 const guchar *cp = tvb_get_ptr(tvb, 0, length);
1752
1753                                 /* XXX pi.fd->flags.encoding */
1754                                 json_print_base64(cp, length);
1755                         }
1756                         else
1757                         {
1758                                 json_print_base64("", 0);
1759                         }
1760
1761                         printf("}");
1762                         ds_sepa = ",";
1763
1764                         data_src = data_src->next;
1765                 }
1766
1767                 /* close ds, only if was opened */
1768                 if (ds_sepa != NULL)
1769                         printf("]");
1770         }
1771
1772         printf(",\"fol\":[0");
1773         follow_iterate_followers(sharkd_follower_visit_layers_cb, pi);
1774         printf("]");
1775
1776         printf("}\n");
1777 }
1778
1779 /**
1780  * sharkd_session_process_intervals()
1781  *
1782  * Process intervals request - generate basic capture file statistics per requested interval.
1783  *
1784  * Input:
1785  *   (o) interval - interval time in ms, if not specified: 1000ms
1786  *   (o) filter   - filter for generating interval request
1787  *
1788  * Output object with attributes:
1789  *   (m) intervals - array of intervals, with indexes:
1790  *             [0] - index of interval,
1791  *             [1] - number of frames during interval,
1792  *             [2] - number of bytes during interval.
1793  *
1794  *   (m) last   - last interval number.
1795  *   (m) frames - total number of frames
1796  *   (m) bytes  - total number of bytes
1797  *
1798  * NOTE: If frames are not in order, there might be items with same interval index, or even negative one.
1799  */
1800 static void
1801 sharkd_session_process_intervals(char *buf, const jsmntok_t *tokens, int count)
1802 {
1803         const char *tok_interval = json_find_attr(buf, tokens, count, "interval");
1804         const char *tok_filter = json_find_attr(buf, tokens, count, "filter");
1805
1806         const guint8 *filter_data = NULL;
1807
1808         struct
1809         {
1810                 unsigned int frames;
1811                 guint64 bytes;
1812         } st, st_total;
1813
1814         nstime_t *start_ts = NULL;
1815
1816         guint32 interval_ms = 1000; /* default: one per second */
1817
1818         const char *sepa = "";
1819         unsigned int framenum;
1820         gint64 idx;
1821         gint64 max_idx = 0;
1822
1823         if (tok_interval) {
1824                 if (!ws_strtou32(tok_interval, NULL, &interval_ms) || interval_ms == 0) {
1825                         fprintf(stderr, "Invalid interval parameter: %s.\n", tok_interval);
1826                         return;
1827                 }
1828         }
1829
1830         if (tok_filter)
1831         {
1832                 filter_data = sharkd_session_filter_data(tok_filter);
1833                 if (!filter_data)
1834                         return;
1835         }
1836
1837         st_total.frames = 0;
1838         st_total.bytes  = 0;
1839
1840         st.frames = 0;
1841         st.bytes  = 0;
1842
1843         idx = 0;
1844
1845         printf("{\"intervals\":[");
1846
1847         for (framenum = 1; framenum <= cfile.count; framenum++)
1848         {
1849                 frame_data *fdata = frame_data_sequence_find(cfile.frames, framenum);
1850                 gint64 msec_rel;
1851                 gint64 new_idx;
1852
1853                 if (start_ts == NULL)
1854                         start_ts = &fdata->abs_ts;
1855
1856                 if (filter_data && !(filter_data[framenum / 8] & (1 << (framenum % 8))))
1857                         continue;
1858
1859                 msec_rel = (fdata->abs_ts.secs - start_ts->secs) * (gint64) 1000 + (fdata->abs_ts.nsecs - start_ts->nsecs) / 1000000;
1860                 new_idx  = msec_rel / interval_ms;
1861
1862                 if (idx != new_idx)
1863                 {
1864                         if (st.frames != 0)
1865                         {
1866                                 printf("%s[%" G_GINT64_FORMAT ",%u,%" G_GUINT64_FORMAT "]", sepa, idx, st.frames, st.bytes);
1867                                 sepa = ",";
1868                         }
1869
1870                         idx = new_idx;
1871                         if (idx > max_idx)
1872                                 max_idx = idx;
1873
1874                         st.frames = 0;
1875                         st.bytes  = 0;
1876                 }
1877
1878                 st.frames += 1;
1879                 st.bytes  += fdata->pkt_len;
1880
1881                 st_total.frames += 1;
1882                 st_total.bytes  += fdata->pkt_len;
1883         }
1884
1885         if (st.frames != 0)
1886         {
1887                 printf("%s[%" G_GINT64_FORMAT ",%u,%" G_GUINT64_FORMAT "]", sepa, idx, st.frames, st.bytes);
1888                 /* sepa = ","; */
1889         }
1890
1891         printf("],\"last\":%" G_GINT64_FORMAT ",\"frames\":%u,\"bytes\":%" G_GUINT64_FORMAT "}\n", max_idx, st_total.frames, st_total.bytes);
1892 }
1893
1894 /**
1895  * sharkd_session_process_frame()
1896  *
1897  * Process frame request
1898  *
1899  * Input:
1900  *   (m) frame - requested frame number
1901  *   (o) proto - set if output frame tree
1902  *   (o) columns - set if output frame columns
1903  *   (o) bytes - set if output frame bytes
1904  *
1905  * Output object with attributes:
1906  *   (m) err   - 0 if succeed
1907  *   (o) tree  - array of frame nodes with attributes:
1908  *                  l - label
1909  *                  t: 'proto', 'framenum', 'url' - type of node
1910  *                  s - severity
1911  *                  e - subtree ett index
1912  *                  n - array of subtree nodes
1913  *                  h - two item array: (item start, item length)
1914  *                  i - two item array: (appendix start, appendix length)
1915  *                  p - [RESERVED] two item array: (protocol start, protocol length)
1916  *                  ds- data src index
1917  *                  url  - only for t:'url', url
1918  *                  fnum - only for t:'framenum', frame number
1919  *
1920  *   (o) col   - array of column data
1921  *   (o) bytes - base64 of frame bytes
1922  *   (o) ds    - array of other data srcs
1923  *   (o) fol   - array of follow filters:
1924  *                  [0] - protocol
1925  *                  [1] - filter string
1926  */
1927 static void
1928 sharkd_session_process_frame(char *buf, const jsmntok_t *tokens, int count)
1929 {
1930         const char *tok_frame = json_find_attr(buf, tokens, count, "frame");
1931         int tok_proto   = (json_find_attr(buf, tokens, count, "proto") != NULL);
1932         int tok_bytes   = (json_find_attr(buf, tokens, count, "bytes") != NULL);
1933         int tok_columns = (json_find_attr(buf, tokens, count, "columns") != NULL);
1934
1935         guint32 framenum;
1936
1937         if (!tok_frame || !ws_strtou32(tok_frame, NULL, &framenum) || framenum == 0)
1938                 return;
1939
1940         sharkd_dissect_request(framenum, &sharkd_session_process_frame_cb, tok_bytes, tok_columns, tok_proto, NULL);
1941 }
1942
1943 /**
1944  * sharkd_session_process_check()
1945  *
1946  * Process check request.
1947  *
1948  * Input:
1949  *   (o) filter - filter to be checked
1950  *
1951  * Output object with attributes:
1952  *   (m) err - always 0
1953  *   (o) filter - 'ok', 'warn' or error message
1954  */
1955 static int
1956 sharkd_session_process_check(char *buf, const jsmntok_t *tokens, int count)
1957 {
1958         const char *tok_filter = json_find_attr(buf, tokens, count, "filter");
1959
1960         printf("{\"err\":0");
1961         if (tok_filter != NULL)
1962         {
1963                 char *err_msg = NULL;
1964                 dfilter_t *dfp;
1965
1966                 if (dfilter_compile(tok_filter, &dfp, &err_msg))
1967                 {
1968                         const char *s = "ok";
1969
1970                         if (dfilter_deprecated_tokens(dfp))
1971                                 s = "warn";
1972
1973                         printf(",\"filter\":\"%s\"", s);
1974                         dfilter_free(dfp);
1975                 }
1976                 else
1977                 {
1978                         printf(",\"filter\":");
1979                         json_puts_string(err_msg);
1980                         g_free(err_msg);
1981                 }
1982         }
1983
1984         printf("}\n");
1985         return 0;
1986 }
1987
1988 struct sharkd_session_process_complete_pref_data
1989 {
1990         const char *module;
1991         const char *pref;
1992         const char *sepa;
1993 };
1994
1995 static guint
1996 sharkd_session_process_complete_pref_cb(module_t *module, gpointer d)
1997 {
1998         struct sharkd_session_process_complete_pref_data *data = (struct sharkd_session_process_complete_pref_data *) d;
1999
2000         if (strncmp(data->pref, module->name, strlen(data->pref)) != 0)
2001                 return 0;
2002
2003         printf("%s{\"f\":\"%s\",\"d\":\"%s\"}", data->sepa, module->name, module->title);
2004         data->sepa = ",";
2005
2006         return 0;
2007 }
2008
2009 static guint
2010 sharkd_session_process_complete_pref_option_cb(pref_t *pref, gpointer d)
2011 {
2012         struct sharkd_session_process_complete_pref_data *data = (struct sharkd_session_process_complete_pref_data *) d;
2013         const char *pref_name = prefs_get_name(pref);
2014         const char *pref_title = prefs_get_title(pref);
2015
2016         if (strncmp(data->pref, pref_name, strlen(data->pref)) != 0)
2017                 return 0;
2018
2019         printf("%s{\"f\":\"%s.%s\",\"d\":\"%s\"}", data->sepa, data->module, pref_name, pref_title);
2020         data->sepa = ",";
2021
2022         return 0; /* continue */
2023 }
2024
2025 /**
2026  * sharkd_session_process_complete()
2027  *
2028  * Process complete request
2029  *
2030  * Input:
2031  *   (o) field - field to be completed
2032  *   (o) pref  - preference to be completed
2033  *
2034  * Output object with attributes:
2035  *   (m) err - always 0
2036  *   (o) field - array of object with attributes:
2037  *                  (m) f - field text
2038  *                  (o) t - field type (FT_ number)
2039  *                  (o) n - field name
2040  *   (o) pref  - array of object with attributes:
2041  *                  (m) f - pref name
2042  *                  (o) d - pref description
2043  */
2044 static int
2045 sharkd_session_process_complete(char *buf, const jsmntok_t *tokens, int count)
2046 {
2047         const char *tok_field = json_find_attr(buf, tokens, count, "field");
2048         const char *tok_pref  = json_find_attr(buf, tokens, count, "pref");
2049
2050         printf("{\"err\":0");
2051         if (tok_field != NULL && tok_field[0])
2052         {
2053                 const size_t filter_length = strlen(tok_field);
2054                 const int filter_with_dot = !!strchr(tok_field, '.');
2055
2056                 void *proto_cookie;
2057                 void *field_cookie;
2058                 int proto_id;
2059                 const char *sepa = "";
2060
2061                 printf(",\"field\":[");
2062
2063                 for (proto_id = proto_get_first_protocol(&proto_cookie); proto_id != -1; proto_id = proto_get_next_protocol(&proto_cookie))
2064                 {
2065                         protocol_t *protocol = find_protocol_by_id(proto_id);
2066                         const char *protocol_filter;
2067                         const char *protocol_name;
2068                         header_field_info *hfinfo;
2069
2070                         if (!proto_is_protocol_enabled(protocol))
2071                                 continue;
2072
2073                         protocol_name   = proto_get_protocol_long_name(protocol);
2074                         protocol_filter = proto_get_protocol_filter_name(proto_id);
2075
2076                         if (strlen(protocol_filter) >= filter_length && !g_ascii_strncasecmp(tok_field, protocol_filter, filter_length))
2077                         {
2078                                 printf("%s{", sepa);
2079                                 {
2080                                         printf("\"f\":");
2081                                         json_puts_string(protocol_filter);
2082                                         printf(",\"t\":%d", FT_PROTOCOL);
2083                                         printf(",\"n\":");
2084                                         json_puts_string(protocol_name);
2085                                 }
2086                                 printf("}");
2087                                 sepa = ",";
2088                         }
2089
2090                         if (!filter_with_dot)
2091                                 continue;
2092
2093                         for (hfinfo = proto_get_first_protocol_field(proto_id, &field_cookie); hfinfo != NULL; hfinfo = proto_get_next_protocol_field(proto_id, &field_cookie))
2094                         {
2095                                 if (hfinfo->same_name_prev_id != -1) /* ignore duplicate names */
2096                                         continue;
2097
2098                                 if (strlen(hfinfo->abbrev) >= filter_length && !g_ascii_strncasecmp(tok_field, hfinfo->abbrev, filter_length))
2099                                 {
2100                                         printf("%s{", sepa);
2101                                         {
2102                                                 printf("\"f\":");
2103                                                 json_puts_string(hfinfo->abbrev);
2104
2105                                                 /* XXX, skip displaying name, if there are multiple (to not confuse user) */
2106                                                 if (hfinfo->same_name_next == NULL)
2107                                                 {
2108                                                         printf(",\"t\":%d", hfinfo->type);
2109                                                         printf(",\"n\":");
2110                                                         json_puts_string(hfinfo->name);
2111                                                 }
2112                                         }
2113                                         printf("}");
2114                                         sepa = ",";
2115                                 }
2116                         }
2117                 }
2118
2119                 printf("]");
2120         }
2121
2122         if (tok_pref != NULL && tok_pref[0])
2123         {
2124                 struct sharkd_session_process_complete_pref_data data;
2125                 char *dot_sepa;
2126
2127                 data.module = tok_pref;
2128                 data.pref = tok_pref;
2129                 data.sepa = "";
2130
2131                 printf(",\"pref\":[");
2132
2133                 if ((dot_sepa = strchr(tok_pref, '.')))
2134                 {
2135                         module_t *pref_mod;
2136
2137                         *dot_sepa = '\0'; /* XXX, C abuse: discarding-const */
2138                         data.pref = dot_sepa + 1;
2139
2140                         pref_mod = prefs_find_module(data.module);
2141                         if (pref_mod)
2142                                 prefs_pref_foreach(pref_mod, sharkd_session_process_complete_pref_option_cb, &data);
2143
2144                         *dot_sepa = '.';
2145                 }
2146                 else
2147                 {
2148                         prefs_modules_foreach(sharkd_session_process_complete_pref_cb, &data);
2149                 }
2150
2151                 printf("]");
2152         }
2153
2154
2155         printf("}\n");
2156         return 0;
2157 }
2158
2159 /**
2160  * sharkd_session_process_setconf()
2161  *
2162  * Process setconf request
2163  *
2164  * Input:
2165  *   (m) name  - preference name
2166  *   (m) value - preference value
2167  *
2168  * Output object with attributes:
2169  *   (m) err   - error code: 0 succeed
2170  */
2171 static void
2172 sharkd_session_process_setconf(char *buf, const jsmntok_t *tokens, int count)
2173 {
2174         const char *tok_name = json_find_attr(buf, tokens, count, "name");
2175         const char *tok_value = json_find_attr(buf, tokens, count, "value");
2176         char pref[4096];
2177
2178         prefs_set_pref_e ret;
2179
2180         if (!tok_name || tok_name[0] == '\0' || !tok_value)
2181                 return;
2182
2183         ws_snprintf(pref, sizeof(pref), "%s:%s", tok_name, tok_value);
2184
2185         ret = prefs_set_pref(pref);
2186         printf("{\"err\":%d}\n", ret);
2187 }
2188
2189 struct sharkd_session_process_dumpconf_data
2190 {
2191         module_t *module;
2192         const char *sepa;
2193 };
2194
2195 static guint
2196 sharkd_session_process_dumpconf_cb(pref_t *pref, gpointer d)
2197 {
2198         struct sharkd_session_process_dumpconf_data *data = (struct sharkd_session_process_dumpconf_data *) d;
2199         const char *pref_name = prefs_get_name(pref);
2200
2201         printf("%s\"%s.%s\":{", data->sepa, data->module->name, pref_name);
2202
2203         switch (prefs_get_type(pref))
2204         {
2205                 case PREF_UINT:
2206                 case PREF_DECODE_AS_UINT:
2207                         printf("\"u\":%u", prefs_get_uint_value_real(pref, pref_current));
2208                         if (prefs_get_uint_base(pref) != 10)
2209                                 printf(",\"ub\":%d", prefs_get_uint_base(pref));
2210                         break;
2211
2212                 case PREF_BOOL:
2213                         printf("\"b\":%s", prefs_get_bool_value(pref, pref_current) ? "1" : "0");
2214                         break;
2215
2216                 case PREF_STRING:
2217                         printf("\"s\":");
2218                         json_puts_string(prefs_get_string_value(pref, pref_current));
2219                         break;
2220
2221                 case PREF_ENUM:
2222                 {
2223                         const enum_val_t *enums;
2224                         const char *enum_sepa = "";
2225
2226                         printf("\"e\":[");
2227                         for (enums = prefs_get_enumvals(pref); enums->name; enums++)
2228                         {
2229                                 printf("%s{\"v\":%d", enum_sepa, enums->value);
2230
2231                                 if (enums->value == prefs_get_enum_value(pref, pref_current))
2232                                         printf(",\"s\":1");
2233
2234                                 printf(",\"d\":");
2235                                 json_puts_string(enums->description);
2236
2237                                 printf("}");
2238                                 enum_sepa = ",";
2239                         }
2240                         printf("]");
2241                         break;
2242                 }
2243
2244                 case PREF_RANGE:
2245                 case PREF_DECODE_AS_RANGE:
2246                 {
2247                         char *range_str = range_convert_range(NULL, prefs_get_range_value_real(pref, pref_current));
2248                         printf("\"r\":\"%s\"", range_str);
2249                         wmem_free(NULL, range_str);
2250                         break;
2251                 }
2252
2253                 case PREF_UAT:
2254                 case PREF_COLOR:
2255                 case PREF_CUSTOM:
2256                 case PREF_STATIC_TEXT:
2257                 case PREF_OBSOLETE:
2258                         /* TODO */
2259                         break;
2260         }
2261
2262 #if 0
2263         printf(",\"t\":");
2264         json_puts_string(prefs_get_title(pref));
2265 #endif
2266
2267         printf("}");
2268         data->sepa = ",";
2269
2270         return 0; /* continue */
2271 }
2272
2273 static guint
2274 sharkd_session_process_dumpconf_mod_cb(module_t *module, gpointer d)
2275 {
2276         struct sharkd_session_process_dumpconf_data *data = (struct sharkd_session_process_dumpconf_data *) d;
2277
2278         data->module = module;
2279         prefs_pref_foreach(module, sharkd_session_process_dumpconf_cb, data);
2280
2281         return 0;
2282 }
2283
2284 /**
2285  * sharkd_session_process_dumpconf()
2286  *
2287  * Process dumpconf request
2288  *
2289  * Input:
2290  *   (o) pref - module, or preference, NULL for all
2291  *
2292  * Output object with attributes:
2293  *   (o) prefs   - object with module preferences
2294  *                  (m) [KEY] - preference name
2295  *                  (o) u - preference value (only for PREF_UINT)
2296  *                  (o) ub - preference value suggested base for display (only for PREF_UINT) and if different than 10
2297  *                  (o) b - preference value (only for PREF_BOOL) (1 true, 0 false)
2298  *                  (o) s - preference value (only for PREF_STRING)
2299  *                  (o) e - preference possible values (only for PREF_ENUM)
2300  *                  (o) r - preference value (only for PREF_RANGE)
2301  *                  (o) t - preference value (only for PREF_UAT)
2302  */
2303 static void
2304 sharkd_session_process_dumpconf(char *buf, const jsmntok_t *tokens, int count)
2305 {
2306         const char *tok_pref = json_find_attr(buf, tokens, count, "pref");
2307         module_t *pref_mod;
2308         char *dot_sepa;
2309
2310         if (!tok_pref)
2311         {
2312                 struct sharkd_session_process_dumpconf_data data;
2313
2314                 data.module = NULL;
2315                 data.sepa = "";
2316
2317                 printf("{\"prefs\":{");
2318                 prefs_modules_foreach(sharkd_session_process_dumpconf_mod_cb, &data);
2319                 printf("}}\n");
2320                 return;
2321         }
2322
2323         if ((dot_sepa = strchr(tok_pref, '.')))
2324         {
2325                 pref_t *pref = NULL;
2326
2327                 *dot_sepa = '\0'; /* XXX, C abuse: discarding-const */
2328                 pref_mod = prefs_find_module(tok_pref);
2329                 if (pref_mod)
2330                         pref = prefs_find_preference(pref_mod, dot_sepa + 1);
2331                 *dot_sepa = '.';
2332
2333                 if (pref)
2334                 {
2335                         struct sharkd_session_process_dumpconf_data data;
2336
2337                         data.module = pref_mod;
2338                         data.sepa = "";
2339
2340                         printf("{\"prefs\":{");
2341                         sharkd_session_process_dumpconf_cb(pref, &data);
2342                         printf("}}\n");
2343                 }
2344
2345                 return;
2346         }
2347
2348         pref_mod = prefs_find_module(tok_pref);
2349         if (pref_mod)
2350         {
2351                 struct sharkd_session_process_dumpconf_data data;
2352
2353                 data.module = pref_mod;
2354                 data.sepa = "";
2355
2356                 printf("{\"prefs\":{");
2357                 prefs_pref_foreach(pref_mod, sharkd_session_process_dumpconf_cb, &data);
2358                 printf("}}\n");
2359     }
2360 }
2361
2362 /**
2363  * sharkd_session_process_download()
2364  *
2365  * Process download request
2366  *
2367  * Input:
2368  *   (m) token  - token to download
2369  *
2370  * Output object with attributes:
2371  *   (o) file - suggested name of file
2372  *   (o) mime - suggested content type
2373  *   (o) data - payload base64 encoded
2374  */
2375 static void
2376 sharkd_session_process_download(char *buf, const jsmntok_t *tokens, int count)
2377 {
2378         const char *tok_token      = json_find_attr(buf, tokens, count, "token");
2379
2380         if (!tok_token)
2381                 return;
2382
2383         if (!strncmp(tok_token, "eo:", 3))
2384         {
2385                 struct sharkd_export_object_list *object_list;
2386                 const export_object_entry_t *eo_entry = NULL;
2387
2388                 for (object_list = sharkd_eo_list; object_list; object_list = object_list->next)
2389                 {
2390                         size_t eo_type_len = strlen(object_list->type);
2391
2392                         if (!strncmp(tok_token, object_list->type, eo_type_len) && tok_token[eo_type_len] == '_')
2393                         {
2394                                 int row;
2395
2396                                 sscanf(&tok_token[eo_type_len + 1], "%d", &row);
2397
2398                                 eo_entry = (export_object_entry_t *) g_slist_nth_data(object_list->entries, row);
2399                                 break;
2400                         }
2401                 }
2402
2403                 if (eo_entry)
2404                 {
2405                         const char *mime     = (eo_entry->content_type) ? eo_entry->content_type : "application/octet-stream";
2406                         const char *filename = (eo_entry->filename) ? eo_entry->filename : tok_token;
2407
2408                         printf("{\"file\":");
2409                         json_puts_string(filename);
2410                         printf(",\"mime\":");
2411                         json_puts_string(mime);
2412                         printf(",\"data\":");
2413                         json_print_base64(eo_entry->payload_data, (int) eo_entry->payload_len); /* XXX, export object will be truncated if >= 2^31 */
2414                         printf("}\n");
2415                 }
2416         }
2417 }
2418
2419 static void
2420 sharkd_session_process(char *buf, const jsmntok_t *tokens, int count)
2421 {
2422         int i;
2423
2424         /* sanity check, and split strings */
2425         if (count < 1 || tokens[0].type != JSMN_OBJECT)
2426         {
2427                 fprintf(stderr, "sanity check(1): [0] not object\n");
2428                 return;
2429         }
2430
2431         /* don't need [0] token */
2432         tokens++;
2433         count--;
2434
2435         if (count & 1)
2436         {
2437                 fprintf(stderr, "sanity check(2): %d not even\n", count);
2438                 return;
2439         }
2440
2441         for (i = 0; i < count; i += 2)
2442         {
2443                 if (tokens[i].type != JSMN_STRING)
2444                 {
2445                         fprintf(stderr, "sanity check(3): [%d] not string\n", i);
2446                         return;
2447                 }
2448
2449                 buf[tokens[i + 0].end] = '\0';
2450                 buf[tokens[i + 1].end] = '\0';
2451
2452                 json_unescape_str(&buf[tokens[i + 0].start]);
2453                 json_unescape_str(&buf[tokens[i + 1].start]);
2454         }
2455
2456         {
2457                 const char *tok_req = json_find_attr(buf, tokens, count, "req");
2458
2459                 if (!tok_req)
2460                 {
2461                         fprintf(stderr, "sanity check(4): no \"req\".\n");
2462                         return;
2463                 }
2464
2465                 if (!strcmp(tok_req, "load"))
2466                         sharkd_session_process_load(buf, tokens, count);
2467                 else if (!strcmp(tok_req, "status"))
2468                         sharkd_session_process_status();
2469                 else if (!strcmp(tok_req, "analyse"))
2470                         sharkd_session_process_analyse();
2471                 else if (!strcmp(tok_req, "info"))
2472                         sharkd_session_process_info();
2473                 else if (!strcmp(tok_req, "check"))
2474                         sharkd_session_process_check(buf, tokens, count);
2475                 else if (!strcmp(tok_req, "complete"))
2476                         sharkd_session_process_complete(buf, tokens, count);
2477                 else if (!strcmp(tok_req, "frames"))
2478                         sharkd_session_process_frames(buf, tokens, count);
2479                 else if (!strcmp(tok_req, "tap"))
2480                         sharkd_session_process_tap(buf, tokens, count);
2481                 else if (!strcmp(tok_req, "follow"))
2482                         sharkd_session_process_follow(buf, tokens, count);
2483                 else if (!strcmp(tok_req, "intervals"))
2484                         sharkd_session_process_intervals(buf, tokens, count);
2485                 else if (!strcmp(tok_req, "frame"))
2486                         sharkd_session_process_frame(buf, tokens, count);
2487                 else if (!strcmp(tok_req, "setconf"))
2488                         sharkd_session_process_setconf(buf, tokens, count);
2489                 else if (!strcmp(tok_req, "dumpconf"))
2490                         sharkd_session_process_dumpconf(buf, tokens, count);
2491                 else if (!strcmp(tok_req, "download"))
2492                         sharkd_session_process_download(buf, tokens, count);
2493                 else if (!strcmp(tok_req, "bye"))
2494                         exit(0);
2495                 else
2496                         fprintf(stderr, "::: req = %s\n", tok_req);
2497
2498                 /* reply for every command are 0+ lines of JSON reply (outputed above), finished by empty new line */
2499                 printf("\n");
2500
2501                 /*
2502                  * We do an explicit fflush after every line, because
2503                  * we want output to be written to the socket as soon
2504                  * as the line is complete.
2505                  *
2506                  * The stream is fully-buffered by default, so it's
2507                  * only flushed when the buffer fills or the FILE *
2508                  * is closed.  On UN*X, we could set it to be line
2509                  * buffered, but the MSVC standard I/O routines don't
2510                  * support line buffering - they only support *byte*
2511                  * buffering, doing a write for every byte written,
2512                  * which is too inefficient, and full buffering,
2513                  * which is what you get if you request line buffering.
2514                  */
2515                 fflush(stdout);
2516         }
2517 }
2518
2519 int
2520 sharkd_session_main(void)
2521 {
2522         char buf[16 * 1024];
2523         jsmntok_t *tokens = NULL;
2524         int tokens_max = -1;
2525
2526         fprintf(stderr, "Hello in child.\n");
2527
2528         while (fgets(buf, sizeof(buf), stdin))
2529         {
2530                 /* every command is line seperated JSON */
2531                 int ret;
2532
2533                 ret = wsjsmn_parse(buf, NULL, 0);
2534                 if (ret < 0)
2535                 {
2536                         fprintf(stderr, "invalid JSON -> closing\n");
2537                         return 1;
2538                 }
2539
2540                 /* fprintf(stderr, "JSON: %d tokens\n", ret); */
2541                 ret += 1;
2542
2543                 if (tokens == NULL || tokens_max < ret)
2544                 {
2545                         tokens_max = ret;
2546                         tokens = (jsmntok_t *) g_realloc(tokens, sizeof(jsmntok_t) * tokens_max);
2547                 }
2548
2549                 memset(tokens, 0, ret * sizeof(jsmntok_t));
2550
2551                 ret = wsjsmn_parse(buf, tokens, ret);
2552                 if (ret < 0)
2553                 {
2554                         fprintf(stderr, "invalid JSON(2) -> closing\n");
2555                         return 2;
2556                 }
2557
2558                 sharkd_session_process(buf, tokens, ret);
2559         }
2560
2561         g_free(tokens);
2562
2563         return 0;
2564 }
2565
2566 /*
2567  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
2568  *
2569  * Local variables:
2570  * c-basic-offset: 8
2571  * tab-width: 8
2572  * indent-tabs-mode: t
2573  * End:
2574  *
2575  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2576  * :indentSize=8:tabSize=8:noTabs=false:
2577  */