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