010a543c236a83e3a60546260fa51c27d13095ca
[metze/wireshark/wip.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  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11
12 #include <config.h>
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <string.h>
18 #include <errno.h>
19
20 #include <glib.h>
21
22 #include <wsutil/wsjson.h>
23 #include <wsutil/ws_printf.h>
24
25 #include <file.h>
26 #include <epan/epan_dissect.h>
27 #include <epan/exceptions.h>
28 #include <epan/color_filters.h>
29 #include <epan/prefs.h>
30 #include <epan/prefs-int.h>
31 #include <epan/uat-int.h>
32 #include <wiretap/wtap.h>
33
34 #include <epan/column.h>
35
36 #include <ui/ssl_key_export.h>
37
38 #include <ui/io_graph_item.h>
39 #include <epan/stats_tree_priv.h>
40 #include <epan/stat_tap_ui.h>
41 #include <epan/conversation_table.h>
42 #include <epan/sequence_analysis.h>
43 #include <epan/expert.h>
44 #include <epan/export_object.h>
45 #include <epan/follow.h>
46 #include <epan/rtd_table.h>
47 #include <epan/srt_table.h>
48
49 #include <epan/dissectors/packet-h225.h>
50 #include <epan/rtp_pt.h>
51 #include <ui/voip_calls.h>
52 #include <ui/rtp_stream.h>
53 #include <ui/tap-rtp-common.h>
54 #include <ui/tap-rtp-analysis.h>
55 #include <epan/to_str.h>
56
57 #include <epan/addr_resolv.h>
58 #include <epan/dissectors/packet-rtp.h>
59 #include <ui/rtp_media.h>
60 #ifdef HAVE_SPEEXDSP
61 # include <speex/speex_resampler.h>
62 #else
63 # include <codecs/speex/speex_resampler.h>
64 #endif /* HAVE_SPEEXDSP */
65
66 #include <epan/maxmind_db.h>
67
68 #include <wsutil/pint.h>
69 #include <wsutil/strtoi.h>
70
71 #include "globals.h"
72
73 #include "sharkd.h"
74
75 struct sharkd_filter_item
76 {
77         guint8 *filtered; /* can be NULL if all frames are matching for given filter. */
78 };
79
80 static GHashTable *filter_table = NULL;
81
82 static const char *
83 json_find_attr(const char *buf, const jsmntok_t *tokens, int count, const char *attr)
84 {
85         int i;
86
87         for (i = 0; i < count; i += 2)
88         {
89                 const char *tok_attr  = &buf[tokens[i + 0].start];
90                 const char *tok_value = &buf[tokens[i + 1].start];
91
92                 if (!strcmp(tok_attr, attr))
93                         return tok_value;
94         }
95
96         return NULL;
97 }
98
99 static void
100 json_puts_string(const char *s)
101 {
102         static const char json_cntrl[0x20][6] =
103         {
104                 "u0000", "u0001", "u0002", "u0003", "u0004", "u0005", "u0006", "u0007", "b",     "t",     "n",     "u000b", "f",     "r",     "u000e", "u000f",
105                 "u0010", "u0011", "u0012", "u0013", "u0014", "u0015", "u0016", "u0017", "u0018", "u0019", "u001a", "u001b", "u001c", "u001d", "u001e", "u001f"
106         };
107
108         const unsigned char *str = (const unsigned char *) s ? s : "";
109         int i;
110
111         putchar('"');
112         for (i = 0; str[i]; i++)
113         {
114                 if (str[i] < 0x20)
115                 {
116                         putchar('\\');
117                         fputs(json_cntrl[(guint)str[i]], stdout);
118                 }
119                 else
120                 {
121                         if (str[i] == '\\' || str[i] == '"')
122                                 putchar('\\');
123                         putchar(str[i]);
124                 }
125         }
126
127         putchar('"');
128 }
129
130 static void
131 json_print_base64_step(const guint8 *data, int *state1, int *state2)
132 {
133         gchar buf[(1 / 3 + 1) * 4 + 4 + 1];
134         gsize wrote;
135
136         if (data)
137                 wrote = g_base64_encode_step(data, 1, FALSE, buf, state1, state2);
138         else
139                 wrote = g_base64_encode_close(FALSE, buf, state1, state2);
140
141         if (wrote > 0)
142         {
143                 buf[wrote] = '\0';
144                 fputs(buf, stdout);
145         }
146 }
147
148 static void
149 json_print_base64(const guint8 *data, size_t len)
150 {
151         size_t i;
152         int base64_state1 = 0;
153         int base64_state2 = 0;
154
155         putchar('"');
156
157         for (i = 0; i < len; i++)
158                 json_print_base64_step(&data[i], &base64_state1, &base64_state2);
159
160         json_print_base64_step(NULL, &base64_state1, &base64_state2);
161
162         putchar('"');
163 }
164
165 static void G_GNUC_PRINTF(3, 4)
166 sharkd_json_value_anyf(gboolean sepa, const char *key, const char *valuef, ...)
167 {
168         if (sepa)
169                 putchar(',');
170
171         if (key)
172         {
173                 putchar('"');
174                 fputs(key, stdout);
175                 putchar('"');
176                 putchar(':');
177         }
178
179         if (valuef && *valuef)
180         {
181                 va_list ap;
182
183                 va_start(ap, valuef);
184                 vprintf(valuef, ap);
185                 va_end(ap);
186         }
187 }
188
189 static void
190 sharkd_json_value_string(gboolean sepa, const char *key, const char *str)
191 {
192         sharkd_json_value_anyf(sepa, key, NULL);
193         json_puts_string(str);
194 }
195
196 static void
197 sharkd_json_value_base64(gboolean sepa, const char *key, const guint8 *data, size_t len)
198 {
199         sharkd_json_value_anyf(sepa, key, NULL);
200         json_print_base64(data, len);
201 }
202
203 static void G_GNUC_PRINTF(3, 4)
204 sharkd_json_value_stringf(gboolean sepa, const char *key, const char *format, ...)
205 {
206         va_list ap;
207
208         sharkd_json_value_anyf(sepa, key, NULL);
209
210         va_start(ap, format);
211         putchar('"');
212         vprintf(format, ap);
213         putchar('"');
214         va_end(ap);
215 }
216
217 static void
218 sharkd_json_array_open(gboolean sepa, const char *key)
219 {
220         sharkd_json_value_anyf(sepa, key, "[");
221 }
222
223 static void
224 sharkd_json_array_close(void)
225 {
226         putchar(']');
227 }
228
229 static void
230 sharkd_json_object_open(gboolean sepa)
231 {
232         sharkd_json_value_anyf(sepa, NULL, "{");
233 }
234
235 static void
236 sharkd_json_object_close(void)
237 {
238         putchar('}');
239 }
240
241 static void
242 sharkd_json_finish(void)
243 {
244         putchar('\n');
245 }
246
247 static void
248 sharkd_json_simple_reply(int err, const char *errmsg)
249 {
250         sharkd_json_object_open(FALSE);
251         sharkd_json_value_anyf(FALSE, "err", "%d", err);
252         if (errmsg)
253                 sharkd_json_value_string(TRUE, "errmsg", errmsg);
254
255         sharkd_json_object_close();
256         sharkd_json_finish();
257 }
258
259 static void
260 sharkd_session_filter_free(gpointer data)
261 {
262         struct sharkd_filter_item *l = (struct sharkd_filter_item *) data;
263
264         g_free(l->filtered);
265         g_free(l);
266 }
267
268 static const struct sharkd_filter_item *
269 sharkd_session_filter_data(const char *filter)
270 {
271         struct sharkd_filter_item *l;
272
273         l = (struct sharkd_filter_item *) g_hash_table_lookup(filter_table, filter);
274         if (!l)
275         {
276                 guint8 *filtered = NULL;
277
278                 int ret = sharkd_filter(filter, &filtered);
279
280                 if (ret == -1)
281                         return NULL;
282
283                 l = (struct sharkd_filter_item *) g_malloc(sizeof(struct sharkd_filter_item));
284                 l->filtered = filtered;
285
286                 g_hash_table_insert(filter_table, g_strdup(filter), l);
287         }
288
289         return l;
290 }
291
292 static gboolean
293 sharkd_rtp_match_init(rtpstream_id_t *id, const char *init_str)
294 {
295         gboolean ret = FALSE;
296         char **arr;
297         guint32 tmp_addr_src, tmp_addr_dst;
298         address tmp_src_addr, tmp_dst_addr;
299
300         memset(id, 0, sizeof(*id));
301
302         arr = g_strsplit(init_str, "_", 7); /* pass larger value, so we'll catch incorrect input :) */
303         if (g_strv_length(arr) != 5)
304                 goto fail;
305
306         /* TODO, for now only IPv4 */
307         if (!get_host_ipaddr(arr[0], &tmp_addr_src))
308                 goto fail;
309
310         if (!ws_strtou16(arr[1], NULL, &id->src_port))
311                 goto fail;
312
313         if (!get_host_ipaddr(arr[2], &tmp_addr_dst))
314                 goto fail;
315
316         if (!ws_strtou16(arr[3], NULL, &id->dst_port))
317                 goto fail;
318
319         if (!ws_hexstrtou32(arr[4], NULL, &id->ssrc))
320                 goto fail;
321
322         set_address(&tmp_src_addr, AT_IPv4, 4, &tmp_addr_src);
323         copy_address(&id->src_addr, &tmp_src_addr);
324         set_address(&tmp_dst_addr, AT_IPv4, 4, &tmp_addr_dst);
325         copy_address(&id->dst_addr, &tmp_dst_addr);
326
327         ret = TRUE;
328
329 fail:
330         g_strfreev(arr);
331         return ret;
332 }
333
334 static gboolean
335 sharkd_session_process_info_nstat_cb(const void *key, void *value, void *userdata)
336 {
337         stat_tap_table_ui *stat_tap = (stat_tap_table_ui *) value;
338         int *pi = (int *) userdata;
339
340         sharkd_json_object_open(*pi != 0);
341                 sharkd_json_value_string(FALSE, "name", stat_tap->title);
342                 sharkd_json_value_stringf(TRUE, "tap", "nstat:%s", (const char *) key);
343         sharkd_json_object_close();
344
345         *pi = *pi + 1;
346         return FALSE;
347 }
348
349 static gboolean
350 sharkd_session_process_info_conv_cb(const void* key, void* value, void* userdata)
351 {
352         struct register_ct *table = (struct register_ct *) value;
353         int *pi = (int *) userdata;
354
355         const char *label = (const char *) key;
356
357         if (get_conversation_packet_func(table))
358         {
359                 sharkd_json_object_open(*pi != 0);
360                         sharkd_json_value_stringf(FALSE, "name", "Conversation List/%s", label);
361                         sharkd_json_value_stringf(TRUE, "tap", "conv:%s", label);
362                 sharkd_json_object_close();
363
364                 *pi = *pi + 1;
365         }
366
367         if (get_hostlist_packet_func(table))
368         {
369                 sharkd_json_object_open(*pi != 0);
370                         sharkd_json_value_stringf(FALSE, "name", "Endpoint/%s", label);
371                         sharkd_json_value_stringf(TRUE, "tap", "endpt:%s", label);
372                 sharkd_json_object_close();
373
374                 *pi = *pi + 1;
375         }
376         return FALSE;
377 }
378
379 static gboolean
380 sharkd_session_seq_analysis_cb(const void *key, void *value, void *userdata)
381 {
382         register_analysis_t *analysis = (register_analysis_t *) value;
383         int *pi = (int *) userdata;
384
385         sharkd_json_object_open(*pi != 0);
386                 sharkd_json_value_string(FALSE, "name", sequence_analysis_get_ui_name(analysis));
387                 sharkd_json_value_stringf(TRUE, "tap", "seqa:%s", (const char *) key);
388         sharkd_json_object_close();
389
390         *pi = *pi + 1;
391         return FALSE;
392 }
393
394 static gboolean
395 sharkd_export_object_visit_cb(const void *key _U_, void *value, void *user_data)
396 {
397         register_eo_t *eo = (register_eo_t *) value;
398         int *pi = (int *) user_data;
399
400         const int proto_id = get_eo_proto_id(eo);
401         const char *filter = proto_get_protocol_filter_name(proto_id);
402         const char *label  = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
403
404         sharkd_json_object_open(*pi != 0);
405                 sharkd_json_value_stringf(FALSE, "name", "Export Object/%s", label);
406                 sharkd_json_value_stringf(TRUE, "tap", "eo:%s", filter);
407         sharkd_json_object_close();
408
409         *pi = *pi + 1;
410         return FALSE;
411 }
412
413 static gboolean
414 sharkd_srt_visit_cb(const void *key _U_, void *value, void *user_data)
415 {
416         register_srt_t *srt = (register_srt_t *) value;
417         int *pi = (int *) user_data;
418
419         const int proto_id = get_srt_proto_id(srt);
420         const char *filter = proto_get_protocol_filter_name(proto_id);
421         const char *label  = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
422
423         sharkd_json_object_open(*pi != 0);
424                 sharkd_json_value_stringf(FALSE, "name", "Service Response Time/%s", label);
425                 sharkd_json_value_stringf(TRUE, "tap", "srt:%s", filter);
426         sharkd_json_object_close();
427
428         *pi = *pi + 1;
429         return FALSE;
430 }
431
432 static gboolean
433 sharkd_rtd_visit_cb(const void *key _U_, void *value, void *user_data)
434 {
435         register_rtd_t *rtd = (register_rtd_t *) value;
436         int *pi = (int *) user_data;
437
438         const int proto_id = get_rtd_proto_id(rtd);
439         const char *filter = proto_get_protocol_filter_name(proto_id);
440         const char *label  = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
441
442         sharkd_json_object_open(*pi != 0);
443                 sharkd_json_value_stringf(FALSE, "name", "Response Time Delay/%s", label);
444                 sharkd_json_value_stringf(TRUE, "tap", "rtd:%s", filter);
445         sharkd_json_object_close();
446
447         *pi = *pi + 1;
448         return FALSE;
449 }
450
451 static gboolean
452 sharkd_follower_visit_cb(const void *key _U_, void *value, void *user_data)
453 {
454         register_follow_t *follower = (register_follow_t *) value;
455         int *pi = (int *) user_data;
456
457         const int proto_id = get_follow_proto_id(follower);
458         const char *label  = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
459         const char *filter = label; /* correct: get_follow_by_name() is registered by short name */
460
461         sharkd_json_object_open(*pi != 0);
462                 sharkd_json_value_stringf(FALSE, "name", "Follow/%s", label);
463                 sharkd_json_value_stringf(TRUE, "tap", "follow:%s", filter);
464         sharkd_json_object_close();
465
466         *pi = *pi + 1;
467         return FALSE;
468 }
469
470 /**
471  * sharkd_session_process_info()
472  *
473  * Process info request
474  *
475  * Output object with attributes:
476  *   (m) version - version number
477  *
478  *   (m) columns - available column formats, array of object with attributes:
479  *                  'name'   - column name
480  *                  'format' - column format-name
481  *
482  *   (m) stats   - available statistics, array of object with attributes:
483  *                  'name' - statistic name
484  *                  'tap'  - sharkd tap-name for statistic
485  *
486  *   (m) convs   - available conversation list, array of object with attributes:
487  *                  'name' - conversation name
488  *                  'tap'  - sharkd tap-name for conversation
489  *
490  *   (m) eo      - available export object list, array of object with attributes:
491  *                  'name' - export object name
492  *                  'tap'  - sharkd tap-name for eo
493  *
494  *   (m) srt     - available service response time list, array of object with attributes:
495  *                  'name' - service response time name
496  *                  'tap'  - sharkd tap-name for srt
497  *
498  *   (m) rtd     - available response time delay list, array of object with attributes:
499  *                  'name' - response time delay name
500  *                  'tap'  - sharkd tap-name for rtd
501  *
502  *   (m) seqa    - available sequence analysis (flow) list, array of object with attributes:
503  *                  'name' - sequence analysis name
504  *                  'tap'  - sharkd tap-name
505  *
506  *   (m) taps    - available taps, array of object with attributes:
507  *                  'name' - tap name
508  *                  'tap'  - sharkd tap-name
509  *
510  *   (m) follow  - available followers, array of object with attributes:
511  *                  'name' - tap name
512  *                  'tap'  - sharkd tap-name
513  *
514  *   (m) ftypes  - conversation table for FT_ number to string, array of FT_xxx strings.
515  *
516  *   (m) nstat   - available table-based taps, array of object with attributes:
517  *                  'name' - tap name
518  *                  'tap'  - sharkd tap-name
519  *
520  */
521 static void
522 sharkd_session_process_info(void)
523 {
524         int i;
525
526         sharkd_json_object_open(FALSE);
527
528         sharkd_json_array_open(FALSE, "columns");
529         for (i = 0; i < NUM_COL_FMTS; i++)
530         {
531                 const char *col_format = col_format_to_string(i);
532                 const char *col_descr  = col_format_desc(i);
533
534                 sharkd_json_object_open(i != 0);
535                         sharkd_json_value_string(FALSE, "name", col_descr);
536                         sharkd_json_value_string(TRUE, "format", col_format);
537                 sharkd_json_object_close();
538         }
539         sharkd_json_array_close();
540
541         sharkd_json_array_open(TRUE, "stats");
542         {
543                 GList *cfg_list = stats_tree_get_cfg_list();
544                 GList *l;
545                 gboolean sepa = FALSE;
546
547                 for (l = cfg_list; l; l = l->next)
548                 {
549                         stats_tree_cfg *cfg = (stats_tree_cfg *) l->data;
550
551                         sharkd_json_object_open(sepa);
552                                 sharkd_json_value_string(FALSE, "name", cfg->name);
553                                 sharkd_json_value_stringf(TRUE, "tap", "stat:%s", cfg->abbr);
554                         sharkd_json_object_close();
555                         sepa = TRUE;
556                 }
557
558                 g_list_free(cfg_list);
559         }
560         sharkd_json_array_close();
561
562         sharkd_json_array_open(TRUE, "ftypes");
563         for (i = 0; i < FT_NUM_TYPES; i++)
564                 sharkd_json_value_string(i != 0, NULL, ftype_name((ftenum_t) i));
565         sharkd_json_array_close();
566
567         sharkd_json_value_string(TRUE, "version", sharkd_version());
568
569         sharkd_json_array_open(TRUE, "nstat");
570         i = 0;
571         stat_tap_iterate_tables(sharkd_session_process_info_nstat_cb, &i);
572         sharkd_json_array_close();
573
574         sharkd_json_array_open(TRUE, "convs");
575         i = 0;
576         conversation_table_iterate_tables(sharkd_session_process_info_conv_cb, &i);
577         sharkd_json_array_close();
578
579         sharkd_json_array_open(TRUE, "seqa");
580         i = 0;
581         sequence_analysis_table_iterate_tables(sharkd_session_seq_analysis_cb, &i);
582         sharkd_json_array_close();
583
584         sharkd_json_array_open(TRUE, "taps");
585         {
586                 sharkd_json_object_open(FALSE);
587                 sharkd_json_value_string(FALSE, "name", "RTP streams");
588                 sharkd_json_value_string(TRUE, "tap", "rtp-streams");
589                 sharkd_json_object_close();
590
591                 sharkd_json_object_open(TRUE);
592                 sharkd_json_value_string(FALSE, "name", "Expert Information");
593                 sharkd_json_value_string(TRUE, "tap", "expert");
594                 sharkd_json_object_close();
595         }
596         sharkd_json_array_close();
597
598         sharkd_json_array_open(TRUE, "eo");
599         i = 0;
600         eo_iterate_tables(sharkd_export_object_visit_cb, &i);
601         sharkd_json_array_close();
602
603         sharkd_json_array_open(TRUE, "srt");
604         i = 0;
605         srt_table_iterate_tables(sharkd_srt_visit_cb, &i);
606         sharkd_json_array_close();
607
608         sharkd_json_array_open(TRUE, "rtd");
609         i = 0;
610         rtd_table_iterate_tables(sharkd_rtd_visit_cb, &i);
611         sharkd_json_array_close();
612
613         sharkd_json_array_open(TRUE, "follow");
614         i = 0;
615         follow_iterate_followers(sharkd_follower_visit_cb, &i);
616         sharkd_json_array_close();
617
618         sharkd_json_object_close();
619         sharkd_json_finish();
620 }
621
622 /**
623  * sharkd_session_process_load()
624  *
625  * Process load request
626  *
627  * Input:
628  *   (m) file - file to be loaded
629  *
630  * Output object with attributes:
631  *   (m) err - error code
632  */
633 static void
634 sharkd_session_process_load(const char *buf, const jsmntok_t *tokens, int count)
635 {
636         const char *tok_file = json_find_attr(buf, tokens, count, "file");
637         int err = 0;
638
639         fprintf(stderr, "load: filename=%s\n", tok_file);
640
641         if (!tok_file)
642                 return;
643
644         if (sharkd_cf_open(tok_file, WTAP_TYPE_AUTO, FALSE, &err) != CF_OK)
645         {
646                 sharkd_json_simple_reply(err, NULL);
647                 return;
648         }
649
650         TRY
651         {
652                 err = sharkd_load_cap_file();
653         }
654         CATCH(OutOfMemoryError)
655         {
656                 fprintf(stderr, "load: OutOfMemoryError\n");
657                 err = ENOMEM;
658         }
659         ENDTRY;
660
661         sharkd_json_simple_reply(err, NULL);
662 }
663
664 /**
665  * sharkd_session_process_status()
666  *
667  * Process status request
668  *
669  * Output object with attributes:
670  *   (m) frames   - count of currently loaded frames
671  *   (m) duration - time difference between time of first frame, and last loaded frame
672  *   (o) filename - capture filename
673  *   (o) filesize - capture filesize
674  */
675 static void
676 sharkd_session_process_status(void)
677 {
678         sharkd_json_object_open(FALSE);
679
680         sharkd_json_value_anyf(FALSE, "frames", "%u", cfile.count);
681         sharkd_json_value_anyf(TRUE, "duration", "%.9f", nstime_to_sec(&cfile.elapsed_time));
682
683         if (cfile.filename)
684         {
685                 char *name = g_path_get_basename(cfile.filename);
686
687                 sharkd_json_value_string(TRUE, "filename", name);
688                 g_free(name);
689         }
690
691         if (cfile.provider.wth)
692         {
693                 gint64 file_size = wtap_file_size(cfile.provider.wth, NULL);
694
695                 if (file_size > 0)
696                         sharkd_json_value_anyf(TRUE, "filesize", "%" G_GINT64_FORMAT, file_size);
697         }
698
699         sharkd_json_object_close();
700         sharkd_json_finish();
701 }
702
703 struct sharkd_analyse_data
704 {
705         GHashTable *protocols_set;
706         nstime_t *first_time;
707         nstime_t *last_time;
708 };
709
710 static void
711 sharkd_session_process_analyse_cb(epan_dissect_t *edt, proto_tree *tree, struct epan_column_info *cinfo, const GSList *data_src, void *data)
712 {
713         struct sharkd_analyse_data *analyser = (struct sharkd_analyse_data *) data;
714         packet_info *pi = &edt->pi;
715         frame_data *fdata = pi->fd;
716
717         (void) tree;
718         (void) cinfo;
719         (void) data_src;
720
721         if (analyser->first_time == NULL || nstime_cmp(&fdata->abs_ts, analyser->first_time) < 0)
722                 analyser->first_time = &fdata->abs_ts;
723
724         if (analyser->last_time == NULL || nstime_cmp(&fdata->abs_ts, analyser->last_time) > 0)
725                 analyser->last_time = &fdata->abs_ts;
726
727         if (pi->layers)
728         {
729                 wmem_list_frame_t *frame;
730
731                 for (frame = wmem_list_head(pi->layers); frame; frame = wmem_list_frame_next(frame))
732                 {
733                         int proto_id = GPOINTER_TO_UINT(wmem_list_frame_data(frame));
734
735                         if (!g_hash_table_lookup_extended(analyser->protocols_set, GUINT_TO_POINTER(proto_id), NULL, NULL))
736                         {
737                                 guint proto_count = g_hash_table_size(analyser->protocols_set);
738
739                                 g_hash_table_insert(analyser->protocols_set, GUINT_TO_POINTER(proto_id), GUINT_TO_POINTER(proto_id));
740
741                                 sharkd_json_value_string(proto_count != 0, NULL, proto_get_protocol_filter_name(proto_id));
742                         }
743                 }
744         }
745
746 }
747
748 /**
749  * sharkd_session_process_status()
750  *
751  * Process analyse request
752  *
753  * Output object with attributes:
754  *   (m) frames  - count of currently loaded frames
755  *   (m) protocols - protocol list
756  *   (m) first     - earliest frame time
757  *   (m) last      - latest frame time
758  */
759 static void
760 sharkd_session_process_analyse(void)
761 {
762         unsigned int framenum;
763         struct sharkd_analyse_data analyser;
764
765         analyser.first_time = NULL;
766         analyser.last_time  = NULL;
767         analyser.protocols_set = g_hash_table_new(NULL /* g_direct_hash() */, NULL /* g_direct_equal */);
768
769         sharkd_json_object_open(FALSE);
770
771         sharkd_json_value_anyf(FALSE, "frames", "%u", cfile.count);
772
773         sharkd_json_array_open(TRUE, "protocols");
774         for (framenum = 1; framenum <= cfile.count; framenum++)
775                 sharkd_dissect_request(framenum, (framenum != 1) ? 1 : 0, framenum - 1, &sharkd_session_process_analyse_cb, SHARKD_DISSECT_FLAG_NULL, &analyser);
776         sharkd_json_array_close();
777
778         if (analyser.first_time)
779                 sharkd_json_value_anyf(TRUE, "first", "%.9f", nstime_to_sec(analyser.first_time));
780
781         if (analyser.last_time)
782                 sharkd_json_value_anyf(TRUE, "last", "%.9f", nstime_to_sec(analyser.last_time));
783
784         sharkd_json_object_close();
785         sharkd_json_finish();
786
787         g_hash_table_destroy(analyser.protocols_set);
788 }
789
790 static column_info *
791 sharkd_session_create_columns(column_info *cinfo, const char *buf, const jsmntok_t *tokens, int count)
792 {
793         const char *columns_custom[32];
794         guint16 columns_fmt[32];
795         gint16 columns_occur[32];
796
797         int i, cols;
798
799         for (i = 0; i < 32; i++)
800         {
801                 const char *tok_column;
802                 char tok_column_name[64];
803                 char *custom_sepa;
804
805                 ws_snprintf(tok_column_name, sizeof(tok_column_name), "column%d", i);
806                 tok_column = json_find_attr(buf, tokens, count, tok_column_name);
807                 if (tok_column == NULL)
808                         break;
809
810                 columns_custom[i] = NULL;
811                 columns_occur[i] = 0;
812
813                 if ((custom_sepa = strchr(tok_column, ':')))
814                 {
815                         *custom_sepa = '\0'; /* XXX, C abuse: discarding-const */
816
817                         columns_fmt[i] = COL_CUSTOM;
818                         columns_custom[i] = tok_column;
819
820                         if (!ws_strtoi16(custom_sepa + 1, NULL, &columns_occur[i]))
821                                 return NULL;
822                 }
823                 else
824                 {
825                         if (!ws_strtou16(tok_column, NULL, &columns_fmt[i]))
826                                 return NULL;
827
828                         if (columns_fmt[i] >= NUM_COL_FMTS)
829                                 return NULL;
830
831                         /* if custom, that it shouldn't be just custom number -> error */
832                         if (columns_fmt[i] == COL_CUSTOM)
833                                 return NULL;
834                 }
835         }
836
837         cols = i;
838
839         col_setup(cinfo, cols);
840
841         for (i = 0; i < cols; i++)
842         {
843                 col_item_t *col_item = &cinfo->columns[i];
844
845                 col_item->col_fmt = columns_fmt[i];
846                 col_item->col_title = NULL; /* no need for title */
847
848                 if (col_item->col_fmt == COL_CUSTOM)
849                 {
850                         col_item->col_custom_fields = g_strdup(columns_custom[i]);
851                         col_item->col_custom_occurrence = columns_occur[i];
852                 }
853
854                 col_item->col_fence = 0;
855         }
856
857         col_finalize(cinfo);
858
859         return cinfo;
860 }
861
862 /**
863  * sharkd_session_process_frames()
864  *
865  * Process frames request
866  *
867  * Input:
868  *   (o) column0...columnXX - requested columns either number in range [0..NUM_COL_FMTS), or custom (syntax <dfilter>:<occurence>).
869  *                            If column0 is not specified default column set will be used.
870  *   (o) filter - filter to be used
871  *   (o) skip=N   - skip N frames
872  *   (o) limit=N  - show only N frames
873  *   (o) refs  - list (comma separated) with sorted time reference frame numbers.
874  *
875  * Output array of frames with attributes:
876  *   (m) c   - array of column data
877  *   (m) num - frame number
878  *   (o) i   - if frame is ignored
879  *   (o) m   - if frame is marked
880  *   (o) ct  - if frame is commented
881  *   (o) bg  - color filter - background color in hex
882  *   (o) fg  - color filter - foreground color in hex
883  */
884 static void
885 sharkd_session_process_frames(const char *buf, const jsmntok_t *tokens, int count)
886 {
887         const char *tok_filter = json_find_attr(buf, tokens, count, "filter");
888         const char *tok_column = json_find_attr(buf, tokens, count, "column0");
889         const char *tok_skip   = json_find_attr(buf, tokens, count, "skip");
890         const char *tok_limit  = json_find_attr(buf, tokens, count, "limit");
891         const char *tok_refs   = json_find_attr(buf, tokens, count, "refs");
892
893         const guint8 *filter_data = NULL;
894
895         gboolean frame_sepa = FALSE;
896         int col;
897
898         guint32 framenum, prev_dis_num = 0;
899         guint32 current_ref_frame = 0, next_ref_frame = G_MAXUINT32;
900         guint32 skip;
901         guint32 limit;
902
903         column_info *cinfo = &cfile.cinfo;
904         column_info user_cinfo;
905
906         if (tok_column)
907         {
908                 memset(&user_cinfo, 0, sizeof(user_cinfo));
909                 cinfo = sharkd_session_create_columns(&user_cinfo, buf, tokens, count);
910                 if (!cinfo)
911                         return;
912         }
913
914         if (tok_filter)
915         {
916                 const struct sharkd_filter_item *filter_item;
917
918                 filter_item = sharkd_session_filter_data(tok_filter);
919                 if (!filter_item)
920                         return;
921                 filter_data = filter_item->filtered;
922         }
923
924         skip = 0;
925         if (tok_skip)
926         {
927                 if (!ws_strtou32(tok_skip, NULL, &skip))
928                         return;
929         }
930
931         limit = 0;
932         if (tok_limit)
933         {
934                 if (!ws_strtou32(tok_limit, NULL, &limit))
935                         return;
936         }
937
938         if (tok_refs)
939         {
940                 if (!ws_strtou32(tok_refs, &tok_refs, &next_ref_frame))
941                         return;
942         }
943
944         sharkd_json_array_open(FALSE, NULL);
945         for (framenum = 1; framenum <= cfile.count; framenum++)
946         {
947                 frame_data *fdata;
948                 guint32 ref_frame = (framenum != 1) ? 1 : 0;
949
950                 if (filter_data && !(filter_data[framenum / 8] & (1 << (framenum % 8))))
951                         continue;
952
953                 if (skip)
954                 {
955                         skip--;
956                         prev_dis_num = framenum;
957                         continue;
958                 }
959
960                 if (tok_refs)
961                 {
962                         if (framenum >= next_ref_frame)
963                         {
964                                 current_ref_frame = next_ref_frame;
965
966                                 if (*tok_refs != ',')
967                                         next_ref_frame = G_MAXUINT32;
968
969                                 while (*tok_refs == ',' && framenum >= next_ref_frame)
970                                 {
971                                         current_ref_frame = next_ref_frame;
972
973                                         if (!ws_strtou32(tok_refs + 1, &tok_refs, &next_ref_frame))
974                                         {
975                                                 fprintf(stderr, "sharkd_session_process_frames() wrong format for refs: %s\n", tok_refs);
976                                                 break;
977                                         }
978                                 }
979
980                                 if (*tok_refs == '\0' && framenum >= next_ref_frame)
981                                 {
982                                         current_ref_frame = next_ref_frame;
983                                         next_ref_frame = G_MAXUINT32;
984                                 }
985                         }
986
987                         if (current_ref_frame)
988                                 ref_frame = current_ref_frame;
989                 }
990
991                 fdata = sharkd_get_frame(framenum);
992                 sharkd_dissect_columns(fdata, ref_frame, prev_dis_num, cinfo, (fdata->color_filter == NULL));
993
994                 sharkd_json_object_open(frame_sepa);
995
996                 sharkd_json_array_open(FALSE, "c");
997                 for (col = 0; col < cinfo->num_cols; ++col)
998                 {
999                         const col_item_t *col_item = &cinfo->columns[col];
1000
1001                         sharkd_json_value_string(col != 0, NULL, col_item->col_data);
1002                 }
1003                 sharkd_json_array_close();
1004
1005                 sharkd_json_value_anyf(TRUE, "num", "%u", framenum);
1006
1007                 if (fdata->has_user_comment || fdata->has_phdr_comment)
1008                 {
1009                         if (!fdata->has_user_comment || sharkd_get_user_comment(fdata) != NULL)
1010                                 sharkd_json_value_anyf(TRUE, "ct", "true");
1011                 }
1012
1013                 if (fdata->ignored)
1014                         sharkd_json_value_anyf(TRUE, "i", "true");
1015
1016                 if (fdata->marked)
1017                         sharkd_json_value_anyf(TRUE, "m", "true");
1018
1019                 if (fdata->color_filter)
1020                 {
1021                         sharkd_json_value_stringf(TRUE, "bg", "%x", color_t_to_rgb(&fdata->color_filter->bg_color));
1022                         sharkd_json_value_stringf(TRUE, "fg", "%x", color_t_to_rgb(&fdata->color_filter->fg_color));
1023                 }
1024
1025                 sharkd_json_object_close();
1026                 frame_sepa = TRUE;
1027                 prev_dis_num = framenum;
1028
1029                 if (limit && --limit == 0)
1030                         break;
1031         }
1032         sharkd_json_array_close();
1033         sharkd_json_finish();
1034
1035         if (cinfo != &cfile.cinfo)
1036                 col_cleanup(cinfo);
1037 }
1038
1039 static void
1040 sharkd_session_process_tap_stats_node_cb(const stat_node *n)
1041 {
1042         stat_node *node;
1043         gboolean sepa = FALSE;
1044
1045         sharkd_json_array_open(FALSE, NULL);
1046         for (node = n->children; node; node = node->next)
1047         {
1048                 sharkd_json_object_open(sepa);
1049
1050                 /* code based on stats_tree_get_values_from_node() */
1051                 sharkd_json_value_string(FALSE, "name", node->name);
1052                 sharkd_json_value_anyf(TRUE, "count", "%d", node->counter);
1053                 if (node->counter && ((node->st_flags & ST_FLG_AVERAGE) || node->rng))
1054                 {
1055                         switch(node->datatype)
1056                         {
1057                         case STAT_DT_INT:
1058                                 sharkd_json_value_anyf(TRUE, "avg", "%.2f", ((float)node->total.int_total) / node->counter);
1059                                 sharkd_json_value_anyf(TRUE, "min", "%d", node->minvalue.int_min);
1060                                 sharkd_json_value_anyf(TRUE, "max", "%d", node->maxvalue.int_max);
1061                                 break;
1062                         case STAT_DT_FLOAT:
1063                                 sharkd_json_value_anyf(TRUE, "avg", "%.2f", node->total.float_total / node->counter);
1064                                 sharkd_json_value_anyf(TRUE, "min", "%f", node->minvalue.float_min);
1065                                 sharkd_json_value_anyf(TRUE, "max", "%f", node->maxvalue.float_max);
1066                                 break;
1067                         }
1068                 }
1069
1070                 if (node->st->elapsed)
1071                         sharkd_json_value_anyf(TRUE, "rate", "%.4f", ((float)node->counter) / node->st->elapsed);
1072
1073                 if (node->parent && node->parent->counter)
1074                         sharkd_json_value_anyf(TRUE, "perc", "%.2f", (node->counter * 100.0) / node->parent->counter);
1075                 else if (node->parent == &(node->st->root))
1076                         sharkd_json_value_anyf(TRUE, "perc", "100");
1077
1078                 if (prefs.st_enable_burstinfo && node->max_burst)
1079                 {
1080                         if (prefs.st_burst_showcount)
1081                                 sharkd_json_value_anyf(TRUE, "burstcount", "%d", node->max_burst);
1082                         else
1083                                 sharkd_json_value_anyf(TRUE, "burstrate", "%.4f", ((double)node->max_burst) / prefs.st_burst_windowlen);
1084
1085                         sharkd_json_value_anyf(TRUE, "bursttime", "%.3f", (node->burst_time / 1000.0));
1086                 }
1087
1088                 if (node->children)
1089                 {
1090                         sharkd_json_value_anyf(TRUE, "sub", NULL);
1091                         sharkd_session_process_tap_stats_node_cb(node);
1092                 }
1093                 sharkd_json_object_close();
1094                 sepa = TRUE;
1095         }
1096         sharkd_json_array_close();
1097 }
1098
1099 /**
1100  * sharkd_session_process_tap_stats_cb()
1101  *
1102  * Output stats tap:
1103  *
1104  *   (m) tap        - tap name
1105  *   (m) type:stats - tap output type
1106  *   (m) name       - stat name
1107  *   (m) stats      - array of object with attributes:
1108  *                  (m) name       - stat item name
1109  *                  (m) count      - stat item counter
1110  *                  (o) avg        - stat item averange value
1111  *                  (o) min        - stat item min value
1112  *                  (o) max        - stat item max value
1113  *                  (o) rate       - stat item rate value (ms)
1114  *                  (o) perc       - stat item percentage
1115  *                  (o) burstrate  - stat item burst rate
1116  *                  (o) burstcount - stat item burst count
1117  *                  (o) burstttme  - stat item burst start
1118  *                  (o) sub        - array of object with attributes like in stats node.
1119  */
1120 static void
1121 sharkd_session_process_tap_stats_cb(void *psp)
1122 {
1123         stats_tree *st = (stats_tree *) psp;
1124
1125         sharkd_json_object_open(FALSE);
1126
1127         sharkd_json_value_stringf(FALSE, "tap", "stats:%s", st->cfg->abbr);
1128         sharkd_json_value_string(TRUE, "type", "stats");
1129         sharkd_json_value_string(TRUE, "name", st->cfg->name);
1130
1131         sharkd_json_value_anyf(TRUE, "stats", NULL);
1132         sharkd_session_process_tap_stats_node_cb(&st->root);
1133
1134         sharkd_json_object_close();
1135         putchar(',');
1136 }
1137
1138 static void
1139 sharkd_session_free_tap_stats_cb(void *psp)
1140 {
1141         stats_tree *st = (stats_tree *) psp;
1142
1143         stats_tree_free(st);
1144 }
1145
1146 struct sharkd_expert_tap
1147 {
1148         GSList *details;
1149         GStringChunk *text;
1150 };
1151
1152 /**
1153  * sharkd_session_process_tap_expert_cb()
1154  *
1155  * Output expert tap:
1156  *
1157  *   (m) tap         - tap name
1158  *   (m) type:expert - tap output type
1159  *   (m) details     - array of object with attributes:
1160  *                  (m) f - frame number, which generated expert information
1161  *                  (o) s - severity
1162  *                  (o) g - group
1163  *                  (m) m - expert message
1164  *                  (o) p - protocol
1165  */
1166 static void
1167 sharkd_session_process_tap_expert_cb(void *tapdata)
1168 {
1169         struct sharkd_expert_tap *etd = (struct sharkd_expert_tap *) tapdata;
1170         GSList *list;
1171         gboolean sepa = FALSE;
1172
1173         sharkd_json_object_open(FALSE);
1174
1175         sharkd_json_value_string(FALSE, "tap", "expert");
1176         sharkd_json_value_string(TRUE, "type", "expert");
1177
1178         sharkd_json_array_open(TRUE, "details");
1179         for (list = etd->details; list; list = list->next)
1180         {
1181                 expert_info_t *ei = (expert_info_t *) list->data;
1182                 const char *tmp;
1183
1184                 sharkd_json_object_open(sepa);
1185
1186                 sharkd_json_value_anyf(FALSE, "f", "%u", ei->packet_num);
1187
1188                 tmp = try_val_to_str(ei->severity, expert_severity_vals);
1189                 if (tmp)
1190                         sharkd_json_value_string(TRUE, "s", tmp);
1191
1192                 tmp = try_val_to_str(ei->group, expert_group_vals);
1193                 if (tmp)
1194                         sharkd_json_value_string(TRUE, "g", tmp);
1195
1196                 sharkd_json_value_string(TRUE, "m", ei->summary);
1197
1198                 if (ei->protocol)
1199                         sharkd_json_value_string(TRUE, "p", ei->protocol);
1200
1201                 sharkd_json_object_close();
1202                 sepa = TRUE;
1203         }
1204         sharkd_json_array_close();
1205
1206         sharkd_json_object_close();
1207         putchar(',');
1208 }
1209
1210 static tap_packet_status
1211 sharkd_session_packet_tap_expert_cb(void *tapdata, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pointer)
1212 {
1213         struct sharkd_expert_tap *etd = (struct sharkd_expert_tap *) tapdata;
1214         const expert_info_t *ei       = (const expert_info_t *) pointer;
1215         expert_info_t *ei_copy;
1216
1217         if (ei == NULL)
1218                 return TAP_PACKET_DONT_REDRAW;
1219
1220         ei_copy = g_new(expert_info_t, 1);
1221         /* Note: this is a shallow copy */
1222         *ei_copy = *ei;
1223
1224         /* ei->protocol, ei->summary might be allocated in packet scope, make a copy. */
1225         ei_copy->protocol = g_string_chunk_insert_const(etd->text, ei_copy->protocol);
1226         ei_copy->summary  = g_string_chunk_insert_const(etd->text, ei_copy->summary);
1227
1228         etd->details = g_slist_prepend(etd->details, ei_copy);
1229
1230         return TAP_PACKET_REDRAW;
1231 }
1232
1233 static void
1234 sharkd_session_free_tap_expert_cb(void *tapdata)
1235 {
1236         struct sharkd_expert_tap *etd = (struct sharkd_expert_tap *) tapdata;
1237
1238         g_slist_free_full(etd->details, g_free);
1239         g_string_chunk_free(etd->text);
1240         g_free(etd);
1241 }
1242
1243 /**
1244  * sharkd_session_process_tap_flow_cb()
1245  *
1246  * Output flow tap:
1247  *   (m) tap         - tap name
1248  *   (m) type:flow   - tap output type
1249  *   (m) nodes       - array of strings with node address
1250  *   (m) flows       - array of object with attributes:
1251  *                  (m) t  - frame time string
1252  *                  (m) n  - array of two numbers with source node index and destination node index
1253  *                  (m) pn - array of two numbers with source and destination port
1254  *                  (o) c  - comment
1255  */
1256 static void
1257 sharkd_session_process_tap_flow_cb(void *tapdata)
1258 {
1259         seq_analysis_info_t *graph_analysis = (seq_analysis_info_t *) tapdata;
1260         GList *flow_list;
1261         guint i;
1262
1263         gboolean sepa = FALSE;
1264
1265         sequence_analysis_get_nodes(graph_analysis);
1266
1267         sharkd_json_object_open(FALSE);
1268         sharkd_json_value_stringf(FALSE, "tap", "seqa:%s", graph_analysis->name);
1269         sharkd_json_value_string(TRUE, "type", "flow");
1270
1271         sharkd_json_array_open(TRUE, "nodes");
1272         for (i = 0; i < graph_analysis->num_nodes; i++)
1273         {
1274                 char *addr_str;
1275
1276                 addr_str = address_to_display(NULL, &(graph_analysis->nodes[i]));
1277                 sharkd_json_value_string(i != 0, NULL, addr_str);
1278                 wmem_free(NULL, addr_str);
1279         }
1280         sharkd_json_array_close();
1281
1282         sharkd_json_array_open(TRUE, "flows");
1283         flow_list = g_queue_peek_nth_link(graph_analysis->items, 0);
1284         while (flow_list)
1285         {
1286                 seq_analysis_item_t *sai = (seq_analysis_item_t *) flow_list->data;
1287
1288                 flow_list = g_list_next(flow_list);
1289
1290                 if (!sai->display)
1291                         continue;
1292
1293                 sharkd_json_object_open(sepa);
1294
1295                 sharkd_json_value_string(FALSE, "t", sai->time_str);
1296                 sharkd_json_value_anyf(TRUE, "n", "[%u,%u]", sai->src_node, sai->dst_node);
1297                 sharkd_json_value_anyf(TRUE, "pn", "[%u,%u]", sai->port_src, sai->port_dst);
1298
1299                 if (sai->comment)
1300                         sharkd_json_value_string(TRUE, "c", sai->comment);
1301
1302                 sharkd_json_object_close();
1303                 sepa = TRUE;
1304         }
1305         sharkd_json_array_close();
1306
1307         sharkd_json_object_close();
1308         putchar(',');
1309 }
1310
1311 static void
1312 sharkd_session_free_tap_flow_cb(void *tapdata)
1313 {
1314         seq_analysis_info_t *graph_analysis = (seq_analysis_info_t *) tapdata;
1315
1316         sequence_analysis_info_free(graph_analysis);
1317 }
1318
1319 struct sharkd_conv_tap_data
1320 {
1321         const char *type;
1322         conv_hash_t hash;
1323         gboolean resolve_name;
1324         gboolean resolve_port;
1325 };
1326
1327 static gboolean
1328 sharkd_session_geoip_addr(address *addr, const char *suffix)
1329 {
1330         const mmdb_lookup_t *lookup = NULL;
1331         gboolean with_geoip = FALSE;
1332         char json_key[64];
1333
1334         if (addr->type == AT_IPv4)
1335         {
1336                 guint32 ip;
1337
1338                 memcpy(&ip, addr->data, 4);
1339                 lookup = maxmind_db_lookup_ipv4(ip);
1340         }
1341         else if (addr->type == AT_IPv6)
1342         {
1343                 const ws_in6_addr *ip6 = (const ws_in6_addr *) addr->data;
1344
1345                 lookup = maxmind_db_lookup_ipv6(ip6);
1346         }
1347
1348         if (!lookup || !lookup->found)
1349                 return FALSE;
1350
1351         if (lookup->country)
1352         {
1353                 snprintf(json_key, sizeof(json_key), "geoip_country%s", suffix);
1354                 sharkd_json_value_string(TRUE, json_key, lookup->country);
1355                 with_geoip = TRUE;
1356         }
1357
1358         if (lookup->country_iso)
1359         {
1360                 snprintf(json_key, sizeof(json_key), "geoip_country_iso%s", suffix);
1361                 sharkd_json_value_string(TRUE, json_key, lookup->country_iso);
1362                 with_geoip = TRUE;
1363         }
1364
1365         if (lookup->city)
1366         {
1367                 snprintf(json_key, sizeof(json_key), "geoip_city%s", suffix);
1368                 sharkd_json_value_string(TRUE, json_key, lookup->city);
1369                 with_geoip = TRUE;
1370         }
1371
1372         if (lookup->as_org)
1373         {
1374                 snprintf(json_key, sizeof(json_key), "geoip_as_org%s", suffix);
1375                 sharkd_json_value_string(TRUE, json_key, lookup->as_org);
1376                 with_geoip = TRUE;
1377         }
1378
1379         if (lookup->as_number > 0)
1380         {
1381                 snprintf(json_key, sizeof(json_key), "geoip_as%s", suffix);
1382                 sharkd_json_value_anyf(TRUE, json_key, "%u", lookup->as_number);
1383                 with_geoip = TRUE;
1384         }
1385
1386         if (lookup->latitude >= -90.0 && lookup->latitude <= 90.0)
1387         {
1388                 snprintf(json_key, sizeof(json_key), "geoip_lat%s", suffix);
1389                 sharkd_json_value_anyf(TRUE, json_key, "%f", lookup->latitude);
1390                 with_geoip = TRUE;
1391         }
1392
1393         if (lookup->longitude >= -180.0 && lookup->longitude <= 180.0)
1394         {
1395                 snprintf(json_key, sizeof(json_key), "geoip_lon%s", suffix);
1396                 sharkd_json_value_anyf(TRUE, json_key, "%f", lookup->longitude);
1397                 with_geoip = TRUE;
1398         }
1399
1400         return with_geoip;
1401 }
1402
1403 struct sharkd_analyse_rtp_items
1404 {
1405         guint32 frame_num;
1406         guint32 sequence_num;
1407
1408         double delta;
1409         double jitter;
1410         double skew;
1411         double bandwidth;
1412         gboolean marker;
1413
1414         double arrive_offset;
1415
1416         /* from tap_rtp_stat_t */
1417         guint32 flags;
1418         guint16 pt;
1419 };
1420
1421 struct sharkd_analyse_rtp
1422 {
1423         const char *tap_name;
1424         rtpstream_id_t id;
1425
1426         GSList *packets;
1427         double start_time;
1428         tap_rtp_stat_t statinfo;
1429 };
1430
1431 static void
1432 sharkd_session_process_tap_rtp_free_cb(void *tapdata)
1433 {
1434         struct sharkd_analyse_rtp *rtp_req = (struct sharkd_analyse_rtp *) tapdata;
1435
1436         g_slist_free_full(rtp_req->packets, g_free);
1437         g_free(rtp_req);
1438 }
1439
1440 static tap_packet_status
1441 sharkd_session_packet_tap_rtp_analyse_cb(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pointer)
1442 {
1443         struct sharkd_analyse_rtp *rtp_req = (struct sharkd_analyse_rtp *) tapdata;
1444         const struct _rtp_info *rtp_info = (const struct _rtp_info *) pointer;
1445
1446         if (rtpstream_id_equal_pinfo_rtp_info(&rtp_req->id, pinfo, rtp_info))
1447         {
1448                 tap_rtp_stat_t *statinfo = &(rtp_req->statinfo);
1449                 struct sharkd_analyse_rtp_items *item;
1450
1451                 rtppacket_analyse(statinfo, pinfo, rtp_info);
1452
1453                 item = (struct sharkd_analyse_rtp_items *) g_malloc(sizeof(struct sharkd_analyse_rtp_items));
1454
1455                 if (!rtp_req->packets)
1456                         rtp_req->start_time = nstime_to_sec(&pinfo->abs_ts);
1457
1458                 item->frame_num    = pinfo->num;
1459                 item->sequence_num = rtp_info->info_seq_num;
1460                 item->delta        = (statinfo->flags & STAT_FLAG_FIRST) ? 0.0 : statinfo->delta;
1461                 item->jitter       = (statinfo->flags & STAT_FLAG_FIRST) ? 0.0 : statinfo->jitter;
1462                 item->skew         = (statinfo->flags & STAT_FLAG_FIRST) ? 0.0 : statinfo->skew;
1463                 item->bandwidth    = statinfo->bandwidth;
1464                 item->marker       = rtp_info->info_marker_set ? TRUE : FALSE;
1465                 item->arrive_offset= nstime_to_sec(&pinfo->abs_ts) - rtp_req->start_time;
1466
1467                 item->flags = statinfo->flags;
1468                 item->pt    = statinfo->pt;
1469
1470                 /* XXX, O(n) optimize */
1471                 rtp_req->packets = g_slist_append(rtp_req->packets, item);
1472         }
1473
1474         return TAP_PACKET_REDRAW;
1475 }
1476
1477 /**
1478  * sharkd_session_process_tap_rtp_analyse_cb()
1479  *
1480  * Output rtp analyse tap:
1481  *   (m) tap   - tap name
1482  *   (m) type  - tap output type
1483  *   (m) ssrc         - RTP SSRC
1484  *   (m) max_delta    - Max delta (ms)
1485  *   (m) max_delta_nr - Max delta packet #
1486  *   (m) max_jitter   - Max jitter (ms)
1487  *   (m) mean_jitter  - Mean jitter (ms)
1488  *   (m) max_skew     - Max skew (ms)
1489  *   (m) total_nr     - Total number of RTP packets
1490  *   (m) seq_err      - Number of sequence errors
1491  *   (m) duration     - Duration (ms)
1492  *   (m) items      - array of object with attributes:
1493  *                  (m) f    - frame number
1494  *                  (m) o    - arrive offset
1495  *                  (m) sn   - sequence number
1496  *                  (m) d    - delta
1497  *                  (m) j    - jitter
1498  *                  (m) sk   - skew
1499  *                  (m) bw   - bandwidth
1500  *                  (o) s    - status string
1501  *                  (o) t    - status type
1502  *                  (o) mark - rtp mark
1503  */
1504 static void
1505 sharkd_session_process_tap_rtp_analyse_cb(void *tapdata)
1506 {
1507         const int RTP_TYPE_CN       = 1;
1508         const int RTP_TYPE_ERROR    = 2;
1509         const int RTP_TYPE_WARN     = 3;
1510         const int RTP_TYPE_PT_EVENT = 4;
1511
1512         const struct sharkd_analyse_rtp *rtp_req = (struct sharkd_analyse_rtp *) tapdata;
1513         const tap_rtp_stat_t *statinfo = &rtp_req->statinfo;
1514
1515         gboolean sepa = FALSE;
1516         GSList *l;
1517
1518         sharkd_json_object_open(FALSE);
1519
1520         sharkd_json_value_string(FALSE, "tap", rtp_req->tap_name);
1521         sharkd_json_value_string(TRUE, "type", "rtp-analyse");
1522         sharkd_json_value_anyf(TRUE, "ssrc", "%u", rtp_req->id.ssrc);
1523
1524         sharkd_json_value_anyf(TRUE, "max_delta", "%f", statinfo->max_delta);
1525         sharkd_json_value_anyf(TRUE, "max_delta_nr", "%u", statinfo->max_nr);
1526         sharkd_json_value_anyf(TRUE, "max_jitter", "%f", statinfo->max_jitter);
1527         sharkd_json_value_anyf(TRUE, "mean_jitter", "%f", statinfo->mean_jitter);
1528         sharkd_json_value_anyf(TRUE, "max_skew", "%f", statinfo->max_skew);
1529         sharkd_json_value_anyf(TRUE, "total_nr", "%u", statinfo->total_nr);
1530         sharkd_json_value_anyf(TRUE, "seq_err", "%u", statinfo->sequence);
1531         sharkd_json_value_anyf(TRUE, "duration", "%f", statinfo->time - statinfo->start_time);
1532
1533         sharkd_json_array_open(TRUE, "items");
1534         for (l = rtp_req->packets; l; l = l->next)
1535         {
1536                 struct sharkd_analyse_rtp_items *item = (struct sharkd_analyse_rtp_items *) l->data;
1537
1538                 sharkd_json_object_open(sepa);
1539
1540                 sharkd_json_value_anyf(FALSE, "f", "%u", item->frame_num);
1541                 sharkd_json_value_anyf(TRUE, "o", "%.9f", item->arrive_offset);
1542                 sharkd_json_value_anyf(TRUE, "sn", "%u", item->sequence_num);
1543                 sharkd_json_value_anyf(TRUE, "d", "%.2f", item->delta);
1544                 sharkd_json_value_anyf(TRUE, "j", "%.2f", item->jitter);
1545                 sharkd_json_value_anyf(TRUE, "sk", "%.2f", item->skew);
1546                 sharkd_json_value_anyf(TRUE, "bw", "%.2f", item->bandwidth);
1547
1548                 if (item->pt == PT_CN)
1549                 {
1550                         sharkd_json_value_string(TRUE, "s", "Comfort noise (PT=13, RFC 3389)");
1551                         sharkd_json_value_anyf(TRUE, "t", "%d", RTP_TYPE_CN);
1552                 }
1553                 else if (item->pt == PT_CN_OLD)
1554                 {
1555                         sharkd_json_value_string(TRUE, "s", "Comfort noise (PT=19, reserved)");
1556                         sharkd_json_value_anyf(TRUE, "t", "%d", RTP_TYPE_CN);
1557                 }
1558                 else if (item->flags & STAT_FLAG_WRONG_SEQ)
1559                 {
1560                         sharkd_json_value_string(TRUE, "s", "Wrong sequence number");
1561                         sharkd_json_value_anyf(TRUE, "t", "%d", RTP_TYPE_ERROR);
1562                 }
1563                 else if (item->flags & STAT_FLAG_DUP_PKT)
1564                 {
1565                         sharkd_json_value_string(TRUE, "s", "Suspected duplicate (MAC address) only delta time calculated");
1566                         sharkd_json_value_anyf(TRUE, "t", "%d", RTP_TYPE_WARN);
1567                 }
1568                 else if (item->flags & STAT_FLAG_REG_PT_CHANGE)
1569                 {
1570                         sharkd_json_value_stringf(TRUE, "s", "Payload changed to PT=%u%s",
1571                                 item->pt,
1572                                 (item->flags & STAT_FLAG_PT_T_EVENT) ? " telephone/event" : "");
1573                         sharkd_json_value_anyf(TRUE, "t", "%d", RTP_TYPE_WARN);
1574                 }
1575                 else if (item->flags & STAT_FLAG_WRONG_TIMESTAMP)
1576                 {
1577                         sharkd_json_value_string(TRUE, "s", "Incorrect timestamp");
1578                         sharkd_json_value_anyf(TRUE, "t", "%d", RTP_TYPE_WARN);
1579                 }
1580                 else if ((item->flags & STAT_FLAG_PT_CHANGE)
1581                         &&  !(item->flags & STAT_FLAG_FIRST)
1582                         &&  !(item->flags & STAT_FLAG_PT_CN)
1583                         &&  (item->flags & STAT_FLAG_FOLLOW_PT_CN)
1584                         &&  !(item->flags & STAT_FLAG_MARKER))
1585                 {
1586                         sharkd_json_value_string(TRUE, "s", "Marker missing?");
1587                         sharkd_json_value_anyf(TRUE, "t", "%d", RTP_TYPE_WARN);
1588                 }
1589                 else if (item->flags & STAT_FLAG_PT_T_EVENT)
1590                 {
1591                         sharkd_json_value_stringf(TRUE, "s", "PT=%u telephone/event", item->pt);
1592                         sharkd_json_value_anyf(TRUE, "t", "%d", RTP_TYPE_PT_EVENT);
1593                 }
1594                 else if (item->flags & STAT_FLAG_MARKER)
1595                 {
1596                         sharkd_json_value_anyf(TRUE, "t", "%d", RTP_TYPE_WARN);
1597                 }
1598
1599                 if (item->marker)
1600                         sharkd_json_value_anyf(TRUE, "mark", "1");
1601
1602                 sharkd_json_object_close();
1603                 sepa = TRUE;
1604         }
1605         sharkd_json_array_close();
1606
1607         sharkd_json_object_close();
1608         putchar(',');
1609 }
1610
1611 /**
1612  * sharkd_session_process_tap_conv_cb()
1613  *
1614  * Output conv tap:
1615  *   (m) tap        - tap name
1616  *   (m) type       - tap output type
1617  *   (m) proto      - protocol short name
1618  *   (o) filter     - filter string
1619  *   (o) geoip      - whether GeoIP information is available, boolean
1620  *
1621  *   (o) convs      - array of object with attributes:
1622  *                  (m) saddr - source address
1623  *                  (m) daddr - destination address
1624  *                  (o) sport - source port
1625  *                  (o) dport - destination port
1626  *                  (m) txf   - TX frame count
1627  *                  (m) txb   - TX bytes
1628  *                  (m) rxf   - RX frame count
1629  *                  (m) rxb   - RX bytes
1630  *                  (m) start - (relative) first packet time
1631  *                  (m) stop  - (relative) last packet time
1632  *                  (o) filter - conversation filter
1633  *
1634  *   (o) hosts      - array of object with attributes:
1635  *                  (m) host - host address
1636  *                  (o) port - host port
1637  *                  (m) txf  - TX frame count
1638  *                  (m) txb  - TX bytes
1639  *                  (m) rxf  - RX frame count
1640  *                  (m) rxb  - RX bytes
1641  */
1642 static void
1643 sharkd_session_process_tap_conv_cb(void *arg)
1644 {
1645         conv_hash_t *hash = (conv_hash_t *) arg;
1646         const struct sharkd_conv_tap_data *iu = (struct sharkd_conv_tap_data *) hash->user_data;
1647         const char *proto;
1648         int proto_with_port;
1649         guint i;
1650
1651         int with_geoip = 0;
1652
1653         sharkd_json_object_open(FALSE);
1654         sharkd_json_value_string(FALSE, "tap", iu->type);
1655
1656         if (!strncmp(iu->type, "conv:", 5))
1657         {
1658                 sharkd_json_value_string(TRUE, "type", "conv");
1659                 sharkd_json_array_open(TRUE, "convs");
1660                 proto = iu->type + 5;
1661         }
1662         else if (!strncmp(iu->type, "endpt:", 6))
1663         {
1664                 sharkd_json_value_string(TRUE, "type", "host");
1665                 sharkd_json_array_open(TRUE, "hosts");
1666                 proto = iu->type + 6;
1667         }
1668         else
1669         {
1670                 sharkd_json_value_string(TRUE, "type", "err");
1671                 proto = "";
1672         }
1673
1674         proto_with_port = (!strcmp(proto, "TCP") || !strcmp(proto, "UDP") || !strcmp(proto, "SCTP"));
1675
1676         if (iu->hash.conv_array != NULL && !strncmp(iu->type, "conv:", 5))
1677         {
1678                 for (i = 0; i < iu->hash.conv_array->len; i++)
1679                 {
1680                         conv_item_t *iui = &g_array_index(iu->hash.conv_array, conv_item_t, i);
1681                         char *src_addr, *dst_addr;
1682                         char *src_port, *dst_port;
1683                         char *filter_str;
1684
1685                         sharkd_json_object_open(i != 0);
1686
1687                         sharkd_json_value_string(FALSE, "saddr", (src_addr = get_conversation_address(NULL, &iui->src_address, iu->resolve_name)));
1688                         sharkd_json_value_string(TRUE,  "daddr", (dst_addr = get_conversation_address(NULL, &iui->dst_address, iu->resolve_name)));
1689
1690                         if (proto_with_port)
1691                         {
1692                                 sharkd_json_value_string(TRUE, "sport", (src_port = get_conversation_port(NULL, iui->src_port, iui->etype, iu->resolve_port)));
1693                                 sharkd_json_value_string(TRUE, "dport", (dst_port = get_conversation_port(NULL, iui->dst_port, iui->etype, iu->resolve_port)));
1694
1695                                 wmem_free(NULL, src_port);
1696                                 wmem_free(NULL, dst_port);
1697                         }
1698
1699                         sharkd_json_value_anyf(TRUE, "rxf", "%" G_GUINT64_FORMAT, iui->rx_frames);
1700                         sharkd_json_value_anyf(TRUE, "rxb", "%" G_GUINT64_FORMAT, iui->rx_bytes);
1701
1702                         sharkd_json_value_anyf(TRUE, "txf", "%" G_GUINT64_FORMAT, iui->tx_frames);
1703                         sharkd_json_value_anyf(TRUE, "txb", "%" G_GUINT64_FORMAT, iui->tx_bytes);
1704
1705                         sharkd_json_value_anyf(TRUE, "start", "%.9f", nstime_to_sec(&iui->start_time));
1706                         sharkd_json_value_anyf(TRUE, "stop", "%.9f", nstime_to_sec(&iui->stop_time));
1707
1708                         filter_str = get_conversation_filter(iui, CONV_DIR_A_TO_FROM_B);
1709                         if (filter_str)
1710                         {
1711                                 sharkd_json_value_string(TRUE, "filter", filter_str);
1712                                 g_free(filter_str);
1713                         }
1714
1715                         wmem_free(NULL, src_addr);
1716                         wmem_free(NULL, dst_addr);
1717
1718                         if (sharkd_session_geoip_addr(&(iui->src_address), "1"))
1719                                 with_geoip = 1;
1720                         if (sharkd_session_geoip_addr(&(iui->dst_address), "2"))
1721                                 with_geoip = 1;
1722
1723                         sharkd_json_object_close();
1724                 }
1725         }
1726         else if (iu->hash.conv_array != NULL && !strncmp(iu->type, "endpt:", 6))
1727         {
1728                 for (i = 0; i < iu->hash.conv_array->len; i++)
1729                 {
1730                         hostlist_talker_t *host = &g_array_index(iu->hash.conv_array, hostlist_talker_t, i);
1731                         char *host_str, *port_str;
1732                         char *filter_str;
1733
1734                         sharkd_json_object_open(i != 0);
1735
1736                         sharkd_json_value_string(FALSE, "host", (host_str = get_conversation_address(NULL, &host->myaddress, iu->resolve_name)));
1737
1738                         if (proto_with_port)
1739                         {
1740                                 sharkd_json_value_string(TRUE, "port", (port_str = get_conversation_port(NULL, host->port, host->etype, iu->resolve_port)));
1741
1742                                 wmem_free(NULL, port_str);
1743                         }
1744
1745                         sharkd_json_value_anyf(TRUE, "rxf", "%" G_GUINT64_FORMAT, host->rx_frames);
1746                         sharkd_json_value_anyf(TRUE, "rxb", "%" G_GUINT64_FORMAT, host->rx_bytes);
1747
1748                         sharkd_json_value_anyf(TRUE, "txf", "%" G_GUINT64_FORMAT, host->tx_frames);
1749                         sharkd_json_value_anyf(TRUE, "txb", "%" G_GUINT64_FORMAT, host->tx_bytes);
1750
1751                         filter_str = get_hostlist_filter(host);
1752                         if (filter_str)
1753                         {
1754                                 sharkd_json_value_string(TRUE, "filter", filter_str);
1755                                 g_free(filter_str);
1756                         }
1757
1758                         wmem_free(NULL, host_str);
1759
1760                         if (sharkd_session_geoip_addr(&(host->myaddress), ""))
1761                                 with_geoip = 1;
1762                         sharkd_json_object_close();
1763                 }
1764         }
1765         sharkd_json_array_close();
1766
1767         sharkd_json_value_string(TRUE, "proto", proto);
1768         sharkd_json_value_anyf(TRUE, "geoip", with_geoip ? "true" : "false");
1769
1770         sharkd_json_object_close();
1771         putchar(',');
1772 }
1773
1774 static void
1775 sharkd_session_free_tap_conv_cb(void *arg)
1776 {
1777         conv_hash_t *hash = (conv_hash_t *) arg;
1778         struct sharkd_conv_tap_data *iu = (struct sharkd_conv_tap_data *) hash->user_data;
1779
1780         if (!strncmp(iu->type, "conv:", 5))
1781         {
1782                 reset_conversation_table_data(hash);
1783         }
1784         else if (!strncmp(iu->type, "endpt:", 6))
1785         {
1786                 reset_hostlist_table_data(hash);
1787         }
1788
1789         g_free(iu);
1790 }
1791
1792 /**
1793  * sharkd_session_process_tap_nstat_cb()
1794  *
1795  * Output nstat tap:
1796  *   (m) tap        - tap name
1797  *   (m) type       - tap output type
1798  *   (m) fields: array of objects with attributes:
1799  *                  (m) c - name
1800  *
1801  *   (m) tables: array of object with attributes:
1802  *                  (m) t - table title
1803  *                  (m) i - array of items
1804  */
1805 static void
1806 sharkd_session_process_tap_nstat_cb(void *arg)
1807 {
1808         stat_data_t *stat_data = (stat_data_t *) arg;
1809         guint i, j, k;
1810
1811         sharkd_json_object_open(FALSE);
1812         sharkd_json_value_stringf(FALSE, "tap", "nstat:%s", stat_data->stat_tap_data->cli_string);
1813         sharkd_json_value_string(TRUE, "type", "nstat");
1814
1815         sharkd_json_array_open(TRUE, "fields");
1816         for (i = 0; i < stat_data->stat_tap_data->nfields; i++)
1817         {
1818                 stat_tap_table_item *field = &(stat_data->stat_tap_data->fields[i]);
1819
1820                 sharkd_json_object_open(i != 0);
1821                 sharkd_json_value_string(FALSE, "c", field->column_name);
1822                 sharkd_json_object_close();
1823         }
1824         sharkd_json_array_close();
1825
1826         sharkd_json_array_open(TRUE, "tables");
1827         for (i = 0; i < stat_data->stat_tap_data->tables->len; i++)
1828         {
1829                 stat_tap_table *table = g_array_index(stat_data->stat_tap_data->tables, stat_tap_table *, i);
1830                 gboolean sepa = FALSE;
1831
1832                 sharkd_json_object_open(i != 0);
1833
1834                 sharkd_json_value_string(FALSE, "t", table->title);
1835
1836                 sharkd_json_array_open(TRUE, "i");
1837                 for (j = 0; j < table->num_elements; j++)
1838                 {
1839                         stat_tap_table_item_type *field_data;
1840
1841                         field_data = stat_tap_get_field_data(table, j, 0);
1842                         if (field_data == NULL || field_data->type == TABLE_ITEM_NONE) /* Nothing for us here */
1843                                 continue;
1844
1845                         sharkd_json_array_open(sepa, NULL);
1846                         for (k = 0; k < table->num_fields; k++)
1847                         {
1848                                 field_data = stat_tap_get_field_data(table, j, k);
1849
1850                                 switch (field_data->type)
1851                                 {
1852                                         case TABLE_ITEM_UINT:
1853                                                 sharkd_json_value_anyf(k != 0, NULL, "%u", field_data->value.uint_value);
1854                                                 break;
1855
1856                                         case TABLE_ITEM_INT:
1857                                                 sharkd_json_value_anyf(k != 0, NULL, "%d", field_data->value.int_value);
1858                                                 break;
1859
1860                                         case TABLE_ITEM_STRING:
1861                                                 sharkd_json_value_string(k != 0, NULL, field_data->value.string_value);
1862                                                 break;
1863
1864                                         case TABLE_ITEM_FLOAT:
1865                                                 sharkd_json_value_anyf(k != 0, NULL, "%f", field_data->value.float_value);
1866                                                 break;
1867
1868                                         case TABLE_ITEM_ENUM:
1869                                                 sharkd_json_value_anyf(k != 0, NULL, "%d", field_data->value.enum_value);
1870                                                 break;
1871
1872                                         case TABLE_ITEM_NONE:
1873                                                 sharkd_json_value_anyf(k != 0, NULL, "null");
1874                                                 break;
1875                                 }
1876                         }
1877
1878                         sharkd_json_array_close();
1879                         sepa = TRUE;
1880                 }
1881                 sharkd_json_array_close();
1882                 sharkd_json_object_close();
1883         }
1884         sharkd_json_array_close();
1885
1886         sharkd_json_object_close();
1887         putchar(',');
1888 }
1889
1890 static void
1891 sharkd_session_free_tap_nstat_cb(void *arg)
1892 {
1893         stat_data_t *stat_data = (stat_data_t *) arg;
1894
1895         free_stat_tables(stat_data->stat_tap_data);
1896 }
1897
1898 /**
1899  * sharkd_session_process_tap_rtd_cb()
1900  *
1901  * Output rtd tap:
1902  *   (m) tap        - tap name
1903  *   (m) type       - tap output type
1904  *   (m) stats - statistics rows - array object with attributes:
1905  *                  (m) type - statistic name
1906  *                  (m) num - number of messages
1907  *                  (m) min - minimum SRT time
1908  *                  (m) max - maximum SRT time
1909  *                  (m) tot - total SRT time
1910  *                  (m) min_frame - minimal SRT
1911  *                  (m) max_frame - maximum SRT
1912  *                  (o) open_req - Open Requests
1913  *                  (o) disc_rsp - Discarded Responses
1914  *                  (o) req_dup  - Duplicated Requests
1915  *                  (o) rsp_dup  - Duplicated Responses
1916  *   (o) open_req   - Open Requests
1917  *   (o) disc_rsp   - Discarded Responses
1918  *   (o) req_dup    - Duplicated Requests
1919  *   (o) rsp_dup    - Duplicated Responses
1920  */
1921 static void
1922 sharkd_session_process_tap_rtd_cb(void *arg)
1923 {
1924         rtd_data_t *rtd_data = (rtd_data_t *) arg;
1925         register_rtd_t *rtd  = (register_rtd_t *) rtd_data->user_data;
1926
1927         guint i, j;
1928
1929         const char *filter = proto_get_protocol_filter_name(get_rtd_proto_id(rtd));
1930
1931         /* XXX, some dissectors are having single table and multiple timestats (mgcp, megaco),
1932          *      some multiple table and single timestat (radius, h225)
1933          *      and it seems that value_string is used one for timestamp-ID, other one for table-ID
1934          *      I wonder how it will gonna work with multiple timestats and multiple tables...
1935          * (for usage grep for: register_rtd_table)
1936          */
1937         const value_string *vs = get_rtd_value_string(rtd);
1938         gboolean sepa = FALSE;
1939
1940         sharkd_json_object_open(FALSE);
1941         sharkd_json_value_stringf(FALSE, "tap", "rtd:%s", filter);
1942         sharkd_json_value_string(TRUE, "type", "rtd");
1943
1944         if (rtd_data->stat_table.num_rtds == 1)
1945         {
1946                 const rtd_timestat *ms = &rtd_data->stat_table.time_stats[0];
1947
1948                 sharkd_json_value_anyf(TRUE, "open_req", "%u", ms->open_req_num);
1949                 sharkd_json_value_anyf(TRUE, "disc_rsp", "%u", ms->disc_rsp_num);
1950                 sharkd_json_value_anyf(TRUE, "req_dup", "%u", ms->req_dup_num);
1951                 sharkd_json_value_anyf(TRUE, "rsp_dup", "%u", ms->rsp_dup_num);
1952         }
1953
1954         sharkd_json_array_open(TRUE, "stats");
1955         for (i = 0; i < rtd_data->stat_table.num_rtds; i++)
1956         {
1957                 const rtd_timestat *ms = &rtd_data->stat_table.time_stats[i];
1958
1959                 for (j = 0; j < ms->num_timestat; j++)
1960                 {
1961                         const char *type_str;
1962
1963                         if (ms->rtd[j].num == 0)
1964                                 continue;
1965
1966                         sharkd_json_object_open(sepa);
1967
1968                         if (rtd_data->stat_table.num_rtds == 1)
1969                                 type_str = val_to_str_const(j, vs, "Other"); /* 1 table - description per row */
1970                         else
1971                                 type_str = val_to_str_const(i, vs, "Other"); /* multiple table - description per table */
1972                         sharkd_json_value_string(FALSE, "type", type_str);
1973
1974                         sharkd_json_value_anyf(TRUE, "num", "%u", ms->rtd[j].num);
1975                         sharkd_json_value_anyf(TRUE, "min", "%.9f", nstime_to_sec(&(ms->rtd[j].min)));
1976                         sharkd_json_value_anyf(TRUE, "max", "%.9f", nstime_to_sec(&(ms->rtd[j].max)));
1977                         sharkd_json_value_anyf(TRUE, "tot", "%.9f", nstime_to_sec(&(ms->rtd[j].tot)));
1978                         sharkd_json_value_anyf(TRUE, "min_frame", "%u", ms->rtd[j].min_num);
1979                         sharkd_json_value_anyf(TRUE, "max_frame", "%u", ms->rtd[j].max_num);
1980
1981                         if (rtd_data->stat_table.num_rtds != 1)
1982                         {
1983                                 /* like in tshark, display it on every row */
1984                                 sharkd_json_value_anyf(TRUE, "open_req", "%u", ms->open_req_num);
1985                                 sharkd_json_value_anyf(TRUE, "disc_rsp", "%u", ms->disc_rsp_num);
1986                                 sharkd_json_value_anyf(TRUE, "req_dup", "%u", ms->req_dup_num);
1987                                 sharkd_json_value_anyf(TRUE, "rsp_dup", "%u", ms->rsp_dup_num);
1988                         }
1989
1990                         sharkd_json_object_close();
1991                         sepa = TRUE;
1992                 }
1993         }
1994         sharkd_json_array_close();
1995
1996         sharkd_json_object_close();
1997         putchar(',');
1998 }
1999
2000 static void
2001 sharkd_session_free_tap_rtd_cb(void *arg)
2002 {
2003         rtd_data_t *rtd_data = (rtd_data_t *) arg;
2004
2005         free_rtd_table(&rtd_data->stat_table);
2006         g_free(rtd_data);
2007 }
2008
2009 /**
2010  * sharkd_session_process_tap_srt_cb()
2011  *
2012  * Output srt tap:
2013  *   (m) tap        - tap name
2014  *   (m) type       - tap output type
2015  *
2016  *   (m) tables - array of object with attributes:
2017  *                  (m) n - table name
2018  *                  (m) f - table filter
2019  *                  (o) c - table column name
2020  *                  (m) r - table rows - array object with attributes:
2021  *                            (m) n   - row name
2022  *                            (m) idx - procedure index
2023  *                            (m) num - number of events
2024  *                            (m) min - minimum SRT time
2025  *                            (m) max - maximum SRT time
2026  *                            (m) tot - total SRT time
2027  */
2028 static void
2029 sharkd_session_process_tap_srt_cb(void *arg)
2030 {
2031         srt_data_t *srt_data = (srt_data_t *) arg;
2032         register_srt_t *srt = (register_srt_t *) srt_data->user_data;
2033
2034         const char *filter = proto_get_protocol_filter_name(get_srt_proto_id(srt));
2035
2036         guint i;
2037
2038         sharkd_json_object_open(FALSE);
2039         sharkd_json_value_stringf(FALSE, "tap", "srt:%s", filter);
2040         sharkd_json_value_string(TRUE, "type", "srt");
2041
2042         sharkd_json_array_open(TRUE, "tables");
2043         for (i = 0; i < srt_data->srt_array->len; i++)
2044         {
2045                 /* SRT table */
2046                 srt_stat_table *rst = g_array_index(srt_data->srt_array, srt_stat_table *, i);
2047                 gboolean sepa = FALSE;
2048
2049                 int j;
2050
2051                 sharkd_json_object_open(i != 0);
2052
2053                 if (rst->name)
2054                         sharkd_json_value_string(FALSE, "n", rst->name);
2055                 else if (rst->short_name)
2056                         sharkd_json_value_string(FALSE, "n", rst->short_name);
2057                 else
2058                         sharkd_json_value_stringf(FALSE, "n", "table%u", i);
2059
2060                 if (rst->filter_string)
2061                         sharkd_json_value_string(TRUE, "f", rst->filter_string);
2062
2063                 if (rst->proc_column_name)
2064                         sharkd_json_value_string(TRUE, "c", rst->proc_column_name);
2065
2066                 sharkd_json_array_open(TRUE, "r");
2067                 for (j = 0; j < rst->num_procs; j++)
2068                 {
2069                         /* SRT row */
2070                         srt_procedure_t *proc = &rst->procedures[j];
2071
2072                         if (proc->stats.num == 0)
2073                                 continue;
2074
2075                         sharkd_json_object_open(sepa);
2076
2077                         sharkd_json_value_string(FALSE, "n", proc->procedure);
2078
2079                         if (rst->filter_string)
2080                                 sharkd_json_value_anyf(TRUE, "idx", "%d", proc->proc_index);
2081
2082                         sharkd_json_value_anyf(TRUE, "num", "%u", proc->stats.num);
2083
2084                         sharkd_json_value_anyf(TRUE, "min", "%.9f", nstime_to_sec(&proc->stats.min));
2085                         sharkd_json_value_anyf(TRUE, "max", "%.9f", nstime_to_sec(&proc->stats.max));
2086                         sharkd_json_value_anyf(TRUE, "tot", "%.9f", nstime_to_sec(&proc->stats.tot));
2087
2088                         sharkd_json_object_close();
2089                         sepa = TRUE;
2090                 }
2091                 sharkd_json_array_close();
2092
2093                 sharkd_json_object_close();
2094         }
2095         sharkd_json_array_close();
2096
2097         sharkd_json_object_close();
2098         putchar(',');
2099 }
2100
2101 static void
2102 sharkd_session_free_tap_srt_cb(void *arg)
2103 {
2104         srt_data_t *srt_data = (srt_data_t *) arg;
2105         register_srt_t *srt = (register_srt_t *) srt_data->user_data;
2106
2107         free_srt_table(srt, srt_data->srt_array);
2108         g_array_free(srt_data->srt_array, TRUE);
2109         g_free(srt_data);
2110 }
2111
2112 struct sharkd_export_object_list
2113 {
2114         struct sharkd_export_object_list *next;
2115
2116         char *type;
2117         const char *proto;
2118         GSList *entries;
2119 };
2120
2121 static struct sharkd_export_object_list *sharkd_eo_list;
2122
2123 /**
2124  * sharkd_session_process_tap_eo_cb()
2125  *
2126  * Output eo tap:
2127  *   (m) tap        - tap name
2128  *   (m) type       - tap output type
2129  *   (m) proto      - protocol short name
2130  *   (m) objects    - array of object with attributes:
2131  *                  (m) pkt - packet number
2132  *                  (o) hostname - hostname
2133  *                  (o) type - content type
2134  *                  (o) filename - filename
2135  *                  (m) len - object length
2136  */
2137 static void
2138 sharkd_session_process_tap_eo_cb(void *tapdata)
2139 {
2140         export_object_list_t *tap_object = (export_object_list_t *) tapdata;
2141         struct sharkd_export_object_list *object_list = (struct sharkd_export_object_list *) tap_object->gui_data;
2142         GSList *slist;
2143         int i = 0;
2144
2145         sharkd_json_object_open(FALSE);
2146         sharkd_json_value_string(FALSE, "tap", object_list->type);
2147         sharkd_json_value_string(TRUE, "type", "eo");
2148
2149         sharkd_json_value_string(TRUE, "proto", object_list->proto);
2150
2151         sharkd_json_array_open(TRUE, "objects");
2152         for (slist = object_list->entries; slist; slist = slist->next)
2153         {
2154                 const export_object_entry_t *eo_entry = (export_object_entry_t *) slist->data;
2155
2156                 sharkd_json_object_open(i != 0);
2157
2158                 sharkd_json_value_anyf(FALSE, "pkt", "%u", eo_entry->pkt_num);
2159
2160                 if (eo_entry->hostname)
2161                         sharkd_json_value_string(TRUE, "hostname", eo_entry->hostname);
2162
2163                 if (eo_entry->content_type)
2164                         sharkd_json_value_string(TRUE, "type", eo_entry->content_type);
2165
2166                 if (eo_entry->filename)
2167                         sharkd_json_value_string(TRUE, "filename", eo_entry->filename);
2168
2169                 sharkd_json_value_stringf(TRUE, "_download", "%s_%d", object_list->type, i);
2170
2171                 sharkd_json_value_anyf(TRUE, "len", "%" G_GINT64_FORMAT, eo_entry->payload_len);
2172
2173                 sharkd_json_object_close();
2174
2175                 i++;
2176         }
2177         sharkd_json_array_close();
2178
2179         sharkd_json_object_close();
2180         putchar(',');
2181 }
2182
2183 static void
2184 sharkd_eo_object_list_add_entry(void *gui_data, export_object_entry_t *entry)
2185 {
2186         struct sharkd_export_object_list *object_list = (struct sharkd_export_object_list *) gui_data;
2187
2188         object_list->entries = g_slist_append(object_list->entries, entry);
2189 }
2190
2191 static export_object_entry_t *
2192 sharkd_eo_object_list_get_entry(void *gui_data, int row)
2193 {
2194         struct sharkd_export_object_list *object_list = (struct sharkd_export_object_list *) gui_data;
2195
2196         return (export_object_entry_t *) g_slist_nth_data(object_list->entries, row);
2197 }
2198
2199 /**
2200  * sharkd_session_process_tap_rtp_cb()
2201  *
2202  * Output RTP streams tap:
2203  *   (m) tap        - tap name
2204  *   (m) type       - tap output type
2205  *   (m) streams    - array of object with attributes:
2206  *                  (m) ssrc        - RTP synchronization source identifier
2207  *                  (m) payload     - stream payload
2208  *                  (m) saddr       - source address
2209  *                  (m) sport       - source port
2210  *                  (m) daddr       - destination address
2211  *                  (m) dport       - destination port
2212  *                  (m) pkts        - packets count
2213  *                  (m) max_delta   - max delta (ms)
2214  *                  (m) max_jitter  - max jitter (ms)
2215  *                  (m) mean_jitter - mean jitter (ms)
2216  *                  (m) expectednr  -
2217  *                  (m) totalnr     -
2218  *                  (m) problem     - if analyser found the problem
2219  *                  (m) ipver       - address IP version (4 or 6)
2220  */
2221 static void
2222 sharkd_session_process_tap_rtp_cb(void *arg)
2223 {
2224         rtpstream_tapinfo_t *rtp_tapinfo = (rtpstream_tapinfo_t *) arg;
2225
2226         GList *listx;
2227         gboolean sepa = FALSE;
2228
2229         sharkd_json_object_open(FALSE);
2230         sharkd_json_value_string(FALSE, "tap", "rtp-streams");
2231         sharkd_json_value_string(TRUE, "type", "rtp-streams");
2232
2233         sharkd_json_array_open(TRUE, "streams");
2234         for (listx = g_list_first(rtp_tapinfo->strinfo_list); listx; listx = listx->next)
2235         {
2236                 rtpstream_info_t *streaminfo = (rtpstream_info_t *) listx->data;
2237                 rtpstream_info_calc_t calc;
2238
2239                 rtpstream_info_calculate(streaminfo, &calc);
2240
2241                 sharkd_json_object_open(sepa);
2242
2243                 sharkd_json_value_anyf(FALSE, "ssrc", "%u", calc.ssrc);
2244                 sharkd_json_value_string(TRUE, "payload", calc.all_payload_type_names);
2245
2246                 sharkd_json_value_string(TRUE, "saddr", calc.src_addr_str);
2247                 sharkd_json_value_anyf(TRUE, "sport", "%u", calc.src_port);
2248                 sharkd_json_value_string(TRUE, "daddr", calc.dst_addr_str);
2249                 sharkd_json_value_anyf(TRUE, "dport", "%u", calc.dst_port);
2250
2251                 sharkd_json_value_anyf(TRUE, "pkts", "%u", calc.packet_count);
2252
2253                 sharkd_json_value_anyf(TRUE, "max_delta", "%f",calc.max_delta);
2254                 sharkd_json_value_anyf(TRUE, "max_jitter", "%f", calc.max_jitter);
2255                 sharkd_json_value_anyf(TRUE, "mean_jitter", "%f", calc.mean_jitter);
2256
2257                 sharkd_json_value_anyf(TRUE, "expectednr", "%u", calc.packet_expected);
2258                 sharkd_json_value_anyf(TRUE, "totalnr", "%u", calc.total_nr);
2259
2260                 sharkd_json_value_anyf(TRUE, "problem", calc.problem ? "true" : "false");
2261
2262                 /* for filter */
2263                 sharkd_json_value_anyf(TRUE, "ipver", "%d", (streaminfo->id.src_addr.type == AT_IPv6) ? 6 : 4);
2264
2265                 rtpstream_info_calc_free(&calc);
2266
2267                 sharkd_json_object_close();
2268                 sepa = TRUE;
2269         }
2270         sharkd_json_array_close();
2271
2272         sharkd_json_object_close();
2273         putchar(',');
2274 }
2275
2276 /**
2277  * sharkd_session_process_tap()
2278  *
2279  * Process tap request
2280  *
2281  * Input:
2282  *   (m) tap0         - First tap request
2283  *   (o) tap1...tap15 - Other tap requests
2284  *
2285  * Output object with attributes:
2286  *   (m) taps  - array of object with attributes:
2287  *                  (m) tap  - tap name
2288  *                  (m) type - tap output type
2289  *                  ...
2290  *                  for type:stats see sharkd_session_process_tap_stats_cb()
2291  *                  for type:nstat see sharkd_session_process_tap_nstat_cb()
2292  *                  for type:conv see sharkd_session_process_tap_conv_cb()
2293  *                  for type:host see sharkd_session_process_tap_conv_cb()
2294  *                  for type:rtp-streams see sharkd_session_process_tap_rtp_cb()
2295  *                  for type:rtp-analyse see sharkd_session_process_tap_rtp_analyse_cb()
2296  *                  for type:eo see sharkd_session_process_tap_eo_cb()
2297  *                  for type:expert see sharkd_session_process_tap_expert_cb()
2298  *                  for type:rtd see sharkd_session_process_tap_rtd_cb()
2299  *                  for type:srt see sharkd_session_process_tap_srt_cb()
2300  *                  for type:flow see sharkd_session_process_tap_flow_cb()
2301  *
2302  *   (m) err   - error code
2303  */
2304 static void
2305 sharkd_session_process_tap(char *buf, const jsmntok_t *tokens, int count)
2306 {
2307         void *taps_data[16];
2308         GFreeFunc taps_free[16];
2309         int taps_count = 0;
2310         int i;
2311
2312         rtpstream_tapinfo_t rtp_tapinfo =
2313                 { NULL, NULL, NULL, NULL, 0, NULL, 0, TAP_ANALYSE, NULL, NULL, NULL, FALSE };
2314
2315         for (i = 0; i < 16; i++)
2316         {
2317                 char tapbuf[32];
2318                 const char *tok_tap;
2319
2320                 void *tap_data = NULL;
2321                 GFreeFunc tap_free = NULL;
2322                 const char *tap_filter = "";
2323                 GString *tap_error = NULL;
2324
2325                 ws_snprintf(tapbuf, sizeof(tapbuf), "tap%d", i);
2326                 tok_tap = json_find_attr(buf, tokens, count, tapbuf);
2327                 if (!tok_tap)
2328                         break;
2329
2330                 if (!strncmp(tok_tap, "stat:", 5))
2331                 {
2332                         stats_tree_cfg *cfg = stats_tree_get_cfg_by_abbr(tok_tap + 5);
2333                         stats_tree *st;
2334
2335                         if (!cfg)
2336                         {
2337                                 fprintf(stderr, "sharkd_session_process_tap() stat %s not found\n", tok_tap + 5);
2338                                 continue;
2339                         }
2340
2341                         st = stats_tree_new(cfg, NULL, tap_filter);
2342
2343                         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, NULL);
2344
2345                         if (!tap_error && cfg->init)
2346                                 cfg->init(st);
2347
2348                         tap_data = st;
2349                         tap_free = sharkd_session_free_tap_stats_cb;
2350                 }
2351                 else if (!strcmp(tok_tap, "expert"))
2352                 {
2353                         struct sharkd_expert_tap *expert_tap;
2354
2355                         expert_tap = g_new0(struct sharkd_expert_tap, 1);
2356                         expert_tap->text = g_string_chunk_new(100);
2357
2358                         tap_error = register_tap_listener("expert", expert_tap, NULL, 0, NULL, sharkd_session_packet_tap_expert_cb, sharkd_session_process_tap_expert_cb, NULL);
2359
2360                         tap_data = expert_tap;
2361                         tap_free = sharkd_session_free_tap_expert_cb;
2362                 }
2363                 else if (!strncmp(tok_tap, "seqa:", 5))
2364                 {
2365                         seq_analysis_info_t *graph_analysis;
2366                         register_analysis_t *analysis;
2367                         const char *tap_name;
2368                         tap_packet_cb tap_func;
2369                         guint tap_flags;
2370
2371                         analysis = sequence_analysis_find_by_name(tok_tap + 5);
2372                         if (!analysis)
2373                         {
2374                                 fprintf(stderr, "sharkd_session_process_tap() seq analysis %s not found\n", tok_tap + 5);
2375                                 continue;
2376                         }
2377
2378                         graph_analysis = sequence_analysis_info_new();
2379                         graph_analysis->name = tok_tap + 5;
2380                         /* TODO, make configurable */
2381                         graph_analysis->any_addr = FALSE;
2382
2383                         tap_name  = sequence_analysis_get_tap_listener_name(analysis);
2384                         tap_flags = sequence_analysis_get_tap_flags(analysis);
2385                         tap_func  = sequence_analysis_get_packet_func(analysis);
2386
2387                         tap_error = register_tap_listener(tap_name, graph_analysis, NULL, tap_flags, NULL, tap_func, sharkd_session_process_tap_flow_cb, NULL);
2388
2389                         tap_data = graph_analysis;
2390                         tap_free = sharkd_session_free_tap_flow_cb;
2391                 }
2392                 else if (!strncmp(tok_tap, "conv:", 5) || !strncmp(tok_tap, "endpt:", 6))
2393                 {
2394                         struct register_ct *ct = NULL;
2395                         const char *ct_tapname;
2396                         struct sharkd_conv_tap_data *ct_data;
2397                         tap_packet_cb tap_func = NULL;
2398
2399                         if (!strncmp(tok_tap, "conv:", 5))
2400                         {
2401                                 ct = get_conversation_by_proto_id(proto_get_id_by_short_name(tok_tap + 5));
2402
2403                                 if (!ct || !(tap_func = get_conversation_packet_func(ct)))
2404                                 {
2405                                         fprintf(stderr, "sharkd_session_process_tap() conv %s not found\n", tok_tap + 5);
2406                                         continue;
2407                                 }
2408                         }
2409                         else if (!strncmp(tok_tap, "endpt:", 6))
2410                         {
2411                                 ct = get_conversation_by_proto_id(proto_get_id_by_short_name(tok_tap + 6));
2412
2413                                 if (!ct || !(tap_func = get_hostlist_packet_func(ct)))
2414                                 {
2415                                         fprintf(stderr, "sharkd_session_process_tap() endpt %s not found\n", tok_tap + 6);
2416                                         continue;
2417                                 }
2418                         }
2419                         else
2420                         {
2421                                 fprintf(stderr, "sharkd_session_process_tap() conv/endpt(?): %s not found\n", tok_tap);
2422                                 continue;
2423                         }
2424
2425                         ct_tapname = proto_get_protocol_filter_name(get_conversation_proto_id(ct));
2426
2427                         ct_data = (struct sharkd_conv_tap_data *) g_malloc0(sizeof(struct sharkd_conv_tap_data));
2428                         ct_data->type = tok_tap;
2429                         ct_data->hash.user_data = ct_data;
2430
2431                         /* XXX: make configurable */
2432                         ct_data->resolve_name = TRUE;
2433                         ct_data->resolve_port = TRUE;
2434
2435                         tap_error = register_tap_listener(ct_tapname, &ct_data->hash, tap_filter, 0, NULL, tap_func, sharkd_session_process_tap_conv_cb, NULL);
2436
2437                         tap_data = &ct_data->hash;
2438                         tap_free = sharkd_session_free_tap_conv_cb;
2439                 }
2440                 else if (!strncmp(tok_tap, "nstat:", 6))
2441                 {
2442                         stat_tap_table_ui *stat_tap = stat_tap_by_name(tok_tap + 6);
2443                         stat_data_t *stat_data;
2444
2445                         if (!stat_tap)
2446                         {
2447                                 fprintf(stderr, "sharkd_session_process_tap() nstat=%s not found\n", tok_tap + 6);
2448                                 continue;
2449                         }
2450
2451                         stat_tap->stat_tap_init_cb(stat_tap);
2452
2453                         stat_data = g_new0(stat_data_t, 1);
2454                         stat_data->stat_tap_data = stat_tap;
2455                         stat_data->user_data = NULL;
2456
2457                         tap_error = register_tap_listener(stat_tap->tap_name, stat_data, tap_filter, 0, NULL, stat_tap->packet_func, sharkd_session_process_tap_nstat_cb, NULL);
2458
2459                         tap_data = stat_data;
2460                         tap_free = sharkd_session_free_tap_nstat_cb;
2461                 }
2462                 else if (!strncmp(tok_tap, "rtd:", 4))
2463                 {
2464                         register_rtd_t *rtd = get_rtd_table_by_name(tok_tap + 4);
2465                         rtd_data_t *rtd_data;
2466                         char *err;
2467
2468                         if (!rtd)
2469                         {
2470                                 fprintf(stderr, "sharkd_session_process_tap() rtd=%s not found\n", tok_tap + 4);
2471                                 continue;
2472                         }
2473
2474                         rtd_table_get_filter(rtd, "", &tap_filter, &err);
2475                         if (err != NULL)
2476                         {
2477                                 fprintf(stderr, "sharkd_session_process_tap() rtd=%s err=%s\n", tok_tap + 4, err);
2478                                 g_free(err);
2479                                 continue;
2480                         }
2481
2482                         rtd_data = g_new0(rtd_data_t, 1);
2483                         rtd_data->user_data = rtd;
2484                         rtd_table_dissector_init(rtd, &rtd_data->stat_table, NULL, NULL);
2485
2486                         tap_error = register_tap_listener(get_rtd_tap_listener_name(rtd), rtd_data, tap_filter, 0, NULL, get_rtd_packet_func(rtd), sharkd_session_process_tap_rtd_cb, NULL);
2487
2488                         tap_data = rtd_data;
2489                         tap_free = sharkd_session_free_tap_rtd_cb;
2490                 }
2491                 else if (!strncmp(tok_tap, "srt:", 4))
2492                 {
2493                         register_srt_t *srt = get_srt_table_by_name(tok_tap + 4);
2494                         srt_data_t *srt_data;
2495                         char *err;
2496
2497                         if (!srt)
2498                         {
2499                                 fprintf(stderr, "sharkd_session_process_tap() srt=%s not found\n", tok_tap + 4);
2500                                 continue;
2501                         }
2502
2503                         srt_table_get_filter(srt, "", &tap_filter, &err);
2504                         if (err != NULL)
2505                         {
2506                                 fprintf(stderr, "sharkd_session_process_tap() srt=%s err=%s\n", tok_tap + 4, err);
2507                                 g_free(err);
2508                                 continue;
2509                         }
2510
2511                         srt_data = g_new0(srt_data_t, 1);
2512                         srt_data->srt_array = g_array_new(FALSE, TRUE, sizeof(srt_stat_table *));
2513                         srt_data->user_data = srt;
2514                         srt_table_dissector_init(srt, srt_data->srt_array);
2515
2516                         tap_error = register_tap_listener(get_srt_tap_listener_name(srt), srt_data, tap_filter, 0, NULL, get_srt_packet_func(srt), sharkd_session_process_tap_srt_cb, NULL);
2517
2518                         tap_data = srt_data;
2519                         tap_free = sharkd_session_free_tap_srt_cb;
2520                 }
2521                 else if (!strncmp(tok_tap, "eo:", 3))
2522                 {
2523                         register_eo_t *eo = get_eo_by_name(tok_tap + 3);
2524                         export_object_list_t *eo_object;
2525                         struct sharkd_export_object_list *object_list;
2526
2527                         if (!eo)
2528                         {
2529                                 fprintf(stderr, "sharkd_session_process_tap() eo=%s not found\n", tok_tap + 3);
2530                                 continue;
2531                         }
2532
2533                         for (object_list = sharkd_eo_list; object_list; object_list = object_list->next)
2534                         {
2535                                 if (!strcmp(object_list->type, tok_tap))
2536                                 {
2537                                         g_slist_free_full(object_list->entries, (GDestroyNotify) eo_free_entry);
2538                                         object_list->entries = NULL;
2539                                         break;
2540                                 }
2541                         }
2542
2543                         if (!object_list)
2544                         {
2545                                 object_list = g_new(struct sharkd_export_object_list, 1);
2546                                 object_list->type = g_strdup(tok_tap);
2547                                 object_list->proto = proto_get_protocol_short_name(find_protocol_by_id(get_eo_proto_id(eo)));
2548                                 object_list->entries = NULL;
2549                                 object_list->next = sharkd_eo_list;
2550                                 sharkd_eo_list = object_list;
2551                         }
2552
2553                         eo_object  = g_new0(export_object_list_t, 1);
2554                         eo_object->add_entry = sharkd_eo_object_list_add_entry;
2555                         eo_object->get_entry = sharkd_eo_object_list_get_entry;
2556                         eo_object->gui_data = (void *) object_list;
2557
2558                         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, NULL);
2559
2560                         tap_data = eo_object;
2561                         tap_free = g_free; /* need to free only eo_object, object_list need to be kept for potential download */
2562                 }
2563                 else if (!strcmp(tok_tap, "rtp-streams"))
2564                 {
2565                         tap_error = register_tap_listener("rtp", &rtp_tapinfo, tap_filter, 0, rtpstream_reset_cb, rtpstream_packet_cb, sharkd_session_process_tap_rtp_cb, NULL);
2566
2567                         tap_data = &rtp_tapinfo;
2568                         tap_free = rtpstream_reset_cb;
2569                 }
2570                 else if (!strncmp(tok_tap, "rtp-analyse:", 12))
2571                 {
2572                         struct sharkd_analyse_rtp *rtp_req;
2573
2574                         rtp_req = (struct sharkd_analyse_rtp *) g_malloc0(sizeof(*rtp_req));
2575                         if (!sharkd_rtp_match_init(&rtp_req->id, tok_tap + 12))
2576                         {
2577                                 rtpstream_id_free(&rtp_req->id);
2578                                 g_free(rtp_req);
2579                                 continue;
2580                         }
2581
2582                         rtp_req->tap_name = tok_tap;
2583                         rtp_req->statinfo.first_packet = TRUE;
2584                         rtp_req->statinfo.reg_pt = PT_UNDEFINED;
2585
2586                         tap_error = register_tap_listener("rtp", rtp_req, tap_filter, 0, NULL, sharkd_session_packet_tap_rtp_analyse_cb, sharkd_session_process_tap_rtp_analyse_cb, NULL);
2587
2588                         tap_data = rtp_req;
2589                         tap_free = sharkd_session_process_tap_rtp_free_cb;
2590                 }
2591                 else
2592                 {
2593                         fprintf(stderr, "sharkd_session_process_tap() %s not recognized\n", tok_tap);
2594                         continue;
2595                 }
2596
2597                 if (tap_error)
2598                 {
2599                         fprintf(stderr, "sharkd_session_process_tap() name=%s error=%s", tok_tap, tap_error->str);
2600                         g_string_free(tap_error, TRUE);
2601                         if (tap_free)
2602                                 tap_free(tap_data);
2603                         continue;
2604                 }
2605
2606                 taps_data[taps_count] = tap_data;
2607                 taps_free[taps_count] = tap_free;
2608                 taps_count++;
2609         }
2610
2611         fprintf(stderr, "sharkd_session_process_tap() count=%d\n", taps_count);
2612         if (taps_count == 0)
2613                 return;
2614
2615         sharkd_json_object_open(FALSE);
2616
2617         sharkd_json_array_open(FALSE, "taps");
2618         sharkd_retap();
2619         // This dummy value exists to permit unconditionally adding ',' in the taps callback.
2620         // XXX convert to json_dumper and remove this.
2621         sharkd_json_value_anyf(FALSE, NULL, "null");
2622         sharkd_json_array_close();
2623
2624         sharkd_json_value_anyf(TRUE, "err", "0");
2625
2626         sharkd_json_object_close();
2627         sharkd_json_finish();
2628
2629         for (i = 0; i < taps_count; i++)
2630         {
2631                 if (taps_data[i])
2632                         remove_tap_listener(taps_data[i]);
2633
2634                 if (taps_free[i])
2635                         taps_free[i](taps_data[i]);
2636         }
2637 }
2638
2639 /**
2640  * sharkd_session_process_follow()
2641  *
2642  * Process follow request
2643  *
2644  * Input:
2645  *   (m) follow  - follow protocol request (e.g. HTTP)
2646  *   (m) filter  - filter request (e.g. tcp.stream == 1)
2647  *
2648  * Output object with attributes:
2649  *
2650  *   (m) err    - error code
2651  *   (m) shost  - server host
2652  *   (m) sport  - server port
2653  *   (m) sbytes - server send bytes count
2654  *   (m) chost  - client host
2655  *   (m) cport  - client port
2656  *   (m) cbytes - client send bytes count
2657  *   (o) payloads - array of object with attributes:
2658  *                  (o) s - set if server sent, else client
2659  *                  (m) n - packet number
2660  *                  (m) d - data base64 encoded
2661  */
2662 static void
2663 sharkd_session_process_follow(char *buf, const jsmntok_t *tokens, int count)
2664 {
2665         const char *tok_follow = json_find_attr(buf, tokens, count, "follow");
2666         const char *tok_filter = json_find_attr(buf, tokens, count, "filter");
2667
2668         register_follow_t *follower;
2669         GString *tap_error;
2670
2671         follow_info_t *follow_info;
2672         const char *host;
2673         char *port;
2674
2675         if (!tok_follow || !tok_filter)
2676                 return;
2677
2678         follower = get_follow_by_name(tok_follow);
2679         if (!follower)
2680         {
2681                 fprintf(stderr, "sharkd_session_process_follow() follower=%s not found\n", tok_follow);
2682                 return;
2683         }
2684
2685         /* follow_reset_stream ? */
2686         follow_info = g_new0(follow_info_t, 1);
2687         /* gui_data, filter_out_filter not set, but not used by dissector */
2688
2689         tap_error = register_tap_listener(get_follow_tap_string(follower), follow_info, tok_filter, 0, NULL, get_follow_tap_handler(follower), NULL, NULL);
2690         if (tap_error)
2691         {
2692                 fprintf(stderr, "sharkd_session_process_follow() name=%s error=%s", tok_follow, tap_error->str);
2693                 g_string_free(tap_error, TRUE);
2694                 g_free(follow_info);
2695                 return;
2696         }
2697
2698         sharkd_retap();
2699
2700         sharkd_json_object_open(FALSE);
2701
2702         sharkd_json_value_anyf(FALSE, "err", "0");
2703
2704         /* Server information: hostname, port, bytes sent */
2705         host = address_to_name(&follow_info->server_ip);
2706         sharkd_json_value_string(TRUE, "shost", host);
2707
2708         port = get_follow_port_to_display(follower)(NULL, follow_info->server_port);
2709         sharkd_json_value_string(TRUE, "sport", port);
2710         wmem_free(NULL, port);
2711
2712         sharkd_json_value_anyf(TRUE, "sbytes", "%u", follow_info->bytes_written[0]);
2713
2714         /* Client information: hostname, port, bytes sent */
2715         host = address_to_name(&follow_info->client_ip);
2716         sharkd_json_value_string(TRUE, "chost", host);
2717
2718         port = get_follow_port_to_display(follower)(NULL, follow_info->client_port);
2719         sharkd_json_value_string(TRUE, "cport", port);
2720         wmem_free(NULL, port);
2721
2722         sharkd_json_value_anyf(TRUE, "cbytes", "%u", follow_info->bytes_written[1]);
2723
2724         if (follow_info->payload)
2725         {
2726                 follow_record_t *follow_record;
2727                 GList *cur;
2728                 gboolean sepa = FALSE;
2729
2730                 sharkd_json_array_open(TRUE, "payloads");
2731                 for (cur = g_list_last(follow_info->payload); cur; cur = g_list_previous(cur))
2732                 {
2733                         follow_record = (follow_record_t *) cur->data;
2734
2735                         sharkd_json_object_open(sepa);
2736
2737                         sharkd_json_value_anyf(FALSE, "n", "%u", follow_record->packet_num);
2738                         sharkd_json_value_base64(TRUE, "d", follow_record->data->data, follow_record->data->len);
2739
2740                         if (follow_record->is_server)
2741                                 sharkd_json_value_anyf(TRUE, "s", "%d", 1);
2742
2743                         sharkd_json_object_close();
2744                         sepa = TRUE;
2745                 }
2746                 sharkd_json_array_close();
2747         }
2748
2749         sharkd_json_object_close();
2750         sharkd_json_finish();
2751
2752         remove_tap_listener(follow_info);
2753         follow_info_free(follow_info);
2754 }
2755
2756 static void
2757 sharkd_session_process_frame_cb_tree(epan_dissect_t *edt, proto_tree *tree, tvbuff_t **tvbs, gboolean display_hidden)
2758 {
2759         proto_node *node;
2760         gboolean sepa = FALSE;
2761
2762         sharkd_json_array_open(FALSE, NULL);
2763         for (node = tree->first_child; node; node = node->next)
2764         {
2765                 field_info *finfo = PNODE_FINFO(node);
2766
2767                 if (!finfo)
2768                         continue;
2769
2770                 if (!display_hidden && FI_GET_FLAG(finfo, FI_HIDDEN))
2771                         continue;
2772
2773                 sharkd_json_object_open(sepa);
2774
2775                 if (!finfo->rep)
2776                 {
2777                         char label_str[ITEM_LABEL_LENGTH];
2778
2779                         label_str[0] = '\0';
2780                         proto_item_fill_label(finfo, label_str);
2781                         sharkd_json_value_string(FALSE, "l", label_str);
2782                 }
2783                 else
2784                 {
2785                         sharkd_json_value_string(FALSE, "l", finfo->rep->representation);
2786                 }
2787
2788                 if (finfo->ds_tvb && tvbs && tvbs[0] != finfo->ds_tvb)
2789                 {
2790                         int idx;
2791
2792                         for (idx = 1; tvbs[idx]; idx++)
2793                         {
2794                                 if (tvbs[idx] == finfo->ds_tvb)
2795                                 {
2796                                         sharkd_json_value_anyf(TRUE, "ds", "%d", idx);
2797                                         break;
2798                                 }
2799                         }
2800                 }
2801
2802                 if (finfo->start >= 0 && finfo->length > 0)
2803                         sharkd_json_value_anyf(TRUE, "h", "[%d,%d]", finfo->start, finfo->length);
2804
2805                 if (finfo->appendix_start >= 0 && finfo->appendix_length > 0)
2806                         sharkd_json_value_anyf(TRUE, "i", "[%d,%d]", finfo->appendix_start, finfo->appendix_length);
2807
2808
2809                 if (finfo->hfinfo)
2810                 {
2811                         char *filter;
2812
2813                         if (finfo->hfinfo->type == FT_PROTOCOL)
2814                         {
2815                                 sharkd_json_value_string(TRUE, "t", "proto");
2816                         }
2817                         else if (finfo->hfinfo->type == FT_FRAMENUM)
2818                         {
2819                                 sharkd_json_value_string(TRUE, "t", "framenum");
2820                                 sharkd_json_value_anyf(TRUE, "fnum", "%u", finfo->value.value.uinteger);
2821                         }
2822                         else if (FI_GET_FLAG(finfo, FI_URL) && IS_FT_STRING(finfo->hfinfo->type))
2823                         {
2824                                 char *url = fvalue_to_string_repr(NULL, &finfo->value, FTREPR_DISPLAY, finfo->hfinfo->display);
2825
2826                                 sharkd_json_value_string(TRUE, "t", "url");
2827                                 sharkd_json_value_string(TRUE, "url", url);
2828                                 wmem_free(NULL, url);
2829                         }
2830
2831                         filter = proto_construct_match_selected_string(finfo, edt);
2832                         if (filter)
2833                         {
2834                                 sharkd_json_value_string(TRUE, "f", filter);
2835                                 wmem_free(NULL, filter);
2836                         }
2837                 }
2838
2839                 if (FI_GET_FLAG(finfo, FI_GENERATED))
2840                         sharkd_json_value_anyf(TRUE, "g", "true");
2841
2842                 if (FI_GET_FLAG(finfo, FI_HIDDEN))
2843                         sharkd_json_value_anyf(TRUE, "v", "true");
2844
2845                 if (FI_GET_FLAG(finfo, PI_SEVERITY_MASK))
2846                 {
2847                         const char *severity = try_val_to_str(FI_GET_FLAG(finfo, PI_SEVERITY_MASK), expert_severity_vals);
2848
2849                         g_assert(severity != NULL);
2850
2851                         sharkd_json_value_string(TRUE, "s", severity);
2852                 }
2853
2854                 if (((proto_tree *) node)->first_child)
2855                 {
2856                         if (finfo->tree_type != -1)
2857                                 sharkd_json_value_anyf(TRUE, "e", "%d", finfo->tree_type);
2858
2859                         sharkd_json_value_anyf(TRUE, "n", NULL);
2860                         sharkd_session_process_frame_cb_tree(edt, (proto_tree *) node, tvbs, display_hidden);
2861                 }
2862
2863                 sharkd_json_object_close();
2864                 sepa = TRUE;
2865         }
2866         sharkd_json_array_close();
2867 }
2868
2869 static gboolean
2870 sharkd_follower_visit_layers_cb(const void *key _U_, void *value, void *user_data)
2871 {
2872         register_follow_t *follower = (register_follow_t *) value;
2873         packet_info *pi = (packet_info *) user_data;
2874
2875         const int proto_id = get_follow_proto_id(follower);
2876
2877         guint32 ignore_stream;
2878
2879         if (proto_is_frame_protocol(pi->layers, proto_get_protocol_filter_name(proto_id)))
2880         {
2881                 const char *layer_proto = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
2882                 char *follow_filter;
2883
2884                 follow_filter = get_follow_conv_func(follower)(pi, &ignore_stream);
2885
2886                 sharkd_json_array_open(TRUE, NULL);
2887                 sharkd_json_value_string(FALSE, NULL, layer_proto);
2888                 sharkd_json_value_string(TRUE, NULL, follow_filter);
2889                 sharkd_json_array_close();
2890
2891                 g_free(follow_filter);
2892         }
2893
2894         return FALSE;
2895 }
2896
2897 struct sharkd_frame_request_data
2898 {
2899         gboolean display_hidden;
2900 };
2901
2902 static void
2903 sharkd_session_process_frame_cb(epan_dissect_t *edt, proto_tree *tree, struct epan_column_info *cinfo, const GSList *data_src, void *data)
2904 {
2905         packet_info *pi = &edt->pi;
2906         frame_data *fdata = pi->fd;
2907         const char *pkt_comment = NULL;
2908
2909         const struct sharkd_frame_request_data * const req_data = (const struct sharkd_frame_request_data * const) data;
2910         const gboolean display_hidden = (req_data) ? req_data->display_hidden : FALSE;
2911
2912         sharkd_json_object_open(FALSE);
2913
2914         sharkd_json_value_anyf(FALSE, "err", "0");
2915
2916         if (fdata->has_user_comment)
2917                 pkt_comment = sharkd_get_user_comment(fdata);
2918         else if (fdata->has_phdr_comment)
2919                 pkt_comment = pi->rec->opt_comment;
2920
2921         if (pkt_comment)
2922                 sharkd_json_value_string(TRUE, "comment", pkt_comment);
2923
2924         if (tree)
2925         {
2926                 tvbuff_t **tvbs = NULL;
2927
2928                 /* arrayize data src, to speedup searching for ds_tvb index */
2929                 if (data_src && data_src->next /* only needed if there are more than one data source */)
2930                 {
2931                         guint count = g_slist_length((GSList *) data_src);
2932                         guint i;
2933
2934                         tvbs = (tvbuff_t **) g_malloc((count + 1) * sizeof(*tvbs));
2935
2936                         for (i = 0; i < count; i++)
2937                         {
2938                                 const struct data_source *src = (const struct data_source *) g_slist_nth_data((GSList *) data_src, i);
2939
2940                                 tvbs[i] = get_data_source_tvb(src);
2941                         }
2942
2943                         tvbs[count] = NULL;
2944                 }
2945
2946                 sharkd_json_value_anyf(TRUE, "tree", NULL);
2947                 sharkd_session_process_frame_cb_tree(edt, tree, tvbs, display_hidden);
2948
2949                 g_free(tvbs);
2950         }
2951
2952         if (cinfo)
2953         {
2954                 int col;
2955
2956                 sharkd_json_array_open(TRUE, "col");
2957                 for (col = 0; col < cinfo->num_cols; ++col)
2958                 {
2959                         const col_item_t *col_item = &cinfo->columns[col];
2960
2961                         sharkd_json_value_string(col != 0, NULL, col_item->col_data);
2962                 }
2963                 sharkd_json_array_close();
2964         }
2965
2966         if (fdata->ignored)
2967                 sharkd_json_value_anyf(TRUE, "i", "true");
2968
2969         if (fdata->marked)
2970                 sharkd_json_value_anyf(TRUE, "m", "true");
2971
2972         if (fdata->color_filter)
2973         {
2974                 sharkd_json_value_stringf(TRUE, "bg", "%x", color_t_to_rgb(&fdata->color_filter->bg_color));
2975                 sharkd_json_value_stringf(TRUE, "fg", "%x", color_t_to_rgb(&fdata->color_filter->fg_color));
2976         }
2977
2978         if (data_src)
2979         {
2980                 struct data_source *src = (struct data_source *) data_src->data;
2981                 gboolean ds_sepa = FALSE;
2982                 gboolean ds_open = FALSE;
2983
2984                 tvbuff_t *tvb;
2985                 guint length;
2986
2987                 tvb = get_data_source_tvb(src);
2988                 length = tvb_captured_length(tvb);
2989
2990                 if (length != 0)
2991                 {
2992                         const guchar *cp = tvb_get_ptr(tvb, 0, length);
2993
2994                         /* XXX pi.fd->encoding */
2995                         sharkd_json_value_base64(TRUE, "bytes", cp, length);
2996                 }
2997                 else
2998                 {
2999                         sharkd_json_value_base64(TRUE, "bytes", "", 0);
3000                 }
3001
3002                 data_src = data_src->next;
3003                 if (data_src)
3004                 {
3005                         sharkd_json_array_open(TRUE, "ds");
3006                         ds_open = TRUE;
3007                 }
3008
3009                 while (data_src)
3010                 {
3011                         src = (struct data_source *) data_src->data;
3012
3013                         sharkd_json_object_open(ds_sepa);
3014
3015                         {
3016                                 char *src_name = get_data_source_name(src);
3017
3018                                 sharkd_json_value_string(FALSE, "name", src_name);
3019                                 wmem_free(NULL, src_name);
3020                         }
3021
3022                         tvb = get_data_source_tvb(src);
3023                         length = tvb_captured_length(tvb);
3024
3025                         if (length != 0)
3026                         {
3027                                 const guchar *cp = tvb_get_ptr(tvb, 0, length);
3028
3029                                 /* XXX pi.fd->encoding */
3030                                 sharkd_json_value_base64(TRUE, "bytes", cp, length);
3031                         }
3032                         else
3033                         {
3034                                 sharkd_json_value_base64(TRUE, "bytes", "", 0);
3035                         }
3036
3037                         sharkd_json_object_close();
3038                         ds_sepa = TRUE;
3039
3040                         data_src = data_src->next;
3041                 }
3042
3043                 /* close ds, only if was opened */
3044                 if (ds_open)
3045                         sharkd_json_array_close();
3046         }
3047
3048         sharkd_json_array_open(TRUE, "fol");
3049         // This dummy entry allows sharkd_follower_visit_layers_cb() to always insert ',' before dumping item.
3050         // XXX convert to json_dumper and remove the dummy entry.
3051         sharkd_json_value_anyf(FALSE, NULL, "0");
3052         follow_iterate_followers(sharkd_follower_visit_layers_cb, pi);
3053         sharkd_json_array_close();
3054
3055         sharkd_json_object_close();
3056         sharkd_json_finish();
3057 }
3058
3059 #define SHARKD_IOGRAPH_MAX_ITEMS 250000 /* 250k limit of items is taken from wireshark-qt, on x86_64 sizeof(io_graph_item_t) is 152, so single graph can take max 36 MB */
3060
3061 struct sharkd_iograph
3062 {
3063         /* config */
3064         int hf_index;
3065         io_graph_item_unit_t calc_type;
3066         guint32 interval;
3067
3068         /* result */
3069         int space_items;
3070         int num_items;
3071         io_graph_item_t *items;
3072         GString *error;
3073 };
3074
3075 static tap_packet_status
3076 sharkd_iograph_packet(void *g, packet_info *pinfo, epan_dissect_t *edt, const void *dummy _U_)
3077 {
3078         struct sharkd_iograph *graph = (struct sharkd_iograph *) g;
3079         int idx;
3080         gboolean update_succeeded;
3081
3082         idx = get_io_graph_index(pinfo, graph->interval);
3083         if (idx < 0 || idx >= SHARKD_IOGRAPH_MAX_ITEMS)
3084                 return TAP_PACKET_DONT_REDRAW;
3085
3086         if (idx + 1 > graph->num_items)
3087         {
3088                 if (idx + 1 > graph->space_items)
3089                 {
3090                         int new_size = idx + 1024;
3091
3092                         graph->items = (io_graph_item_t *) g_realloc(graph->items, sizeof(io_graph_item_t) * new_size);
3093                         reset_io_graph_items(&graph->items[graph->space_items], new_size - graph->space_items);
3094
3095                         graph->space_items = new_size;
3096                 }
3097                 else if (graph->items == NULL)
3098                 {
3099                         graph->items = (io_graph_item_t *) g_malloc(sizeof(io_graph_item_t) * graph->space_items);
3100                         reset_io_graph_items(graph->items, graph->space_items);
3101                 }
3102
3103                 graph->num_items = idx + 1;
3104         }
3105
3106         update_succeeded = update_io_graph_item(graph->items, idx, pinfo, edt, graph->hf_index, graph->calc_type, graph->interval);
3107         /* XXX - TAP_PACKET_FAILED if the item couldn't be updated, with an error message? */
3108         return update_succeeded ? TAP_PACKET_REDRAW : TAP_PACKET_DONT_REDRAW;
3109 }
3110
3111 /**
3112  * sharkd_session_process_iograph()
3113  *
3114  * Process iograph request
3115  *
3116  * Input:
3117  *   (o) interval - interval time in ms, if not specified: 1000ms
3118  *   (m) graph0             - First graph request
3119  *   (o) graph1...graph9    - Other graph requests
3120  *   (o) filter0            - First graph filter
3121  *   (o) filter1...filter9  - Other graph filters
3122  *
3123  * Graph requests can be one of: "packets", "bytes", "bits", "sum:<field>", "frames:<field>", "max:<field>", "min:<field>", "avg:<field>", "load:<field>",
3124  * if you use variant with <field>, you need to pass field name in filter request.
3125  *
3126  * Output object with attributes:
3127  *   (m) iograph - array of graph results with attributes:
3128  *                  errmsg - graph cannot be constructed
3129  *                  items  - graph values, zeros are skipped, if value is not a number it's next index encoded as hex string
3130  */
3131 static void
3132 sharkd_session_process_iograph(char *buf, const jsmntok_t *tokens, int count)
3133 {
3134         const char *tok_interval = json_find_attr(buf, tokens, count, "interval");
3135         struct sharkd_iograph graphs[10];
3136         gboolean is_any_ok = FALSE;
3137         int graph_count;
3138
3139         guint32 interval_ms = 1000; /* default: one per second */
3140         int i;
3141
3142         if (tok_interval)
3143         {
3144                 if (!ws_strtou32(tok_interval, NULL, &interval_ms) || interval_ms == 0)
3145                 {
3146                         fprintf(stderr, "Invalid interval parameter: %s.\n", tok_interval);
3147                         return;
3148                 }
3149         }
3150
3151         for (i = graph_count = 0; i < (int) G_N_ELEMENTS(graphs); i++)
3152         {
3153                 struct sharkd_iograph *graph = &graphs[graph_count];
3154
3155                 const char *tok_graph;
3156                 const char *tok_filter;
3157                 char tok_format_buf[32];
3158                 const char *field_name;
3159
3160                 snprintf(tok_format_buf, sizeof(tok_format_buf), "graph%d", i);
3161                 tok_graph = json_find_attr(buf, tokens, count, tok_format_buf);
3162                 if (!tok_graph)
3163                         break;
3164
3165                 snprintf(tok_format_buf, sizeof(tok_format_buf), "filter%d", i);
3166                 tok_filter = json_find_attr(buf, tokens, count, tok_format_buf);
3167
3168                 if (!strcmp(tok_graph, "packets"))
3169                         graph->calc_type = IOG_ITEM_UNIT_PACKETS;
3170                 else if (!strcmp(tok_graph, "bytes"))
3171                         graph->calc_type = IOG_ITEM_UNIT_BYTES;
3172                 else if (!strcmp(tok_graph, "bits"))
3173                         graph->calc_type = IOG_ITEM_UNIT_BITS;
3174                 else if (g_str_has_prefix(tok_graph, "sum:"))
3175                         graph->calc_type = IOG_ITEM_UNIT_CALC_SUM;
3176                 else if (g_str_has_prefix(tok_graph, "frames:"))
3177                         graph->calc_type = IOG_ITEM_UNIT_CALC_FRAMES;
3178                 else if (g_str_has_prefix(tok_graph, "fields:"))
3179                         graph->calc_type = IOG_ITEM_UNIT_CALC_FIELDS;
3180                 else if (g_str_has_prefix(tok_graph, "max:"))
3181                         graph->calc_type = IOG_ITEM_UNIT_CALC_MAX;
3182                 else if (g_str_has_prefix(tok_graph, "min:"))
3183                         graph->calc_type = IOG_ITEM_UNIT_CALC_MIN;
3184                 else if (g_str_has_prefix(tok_graph, "avg:"))
3185                         graph->calc_type = IOG_ITEM_UNIT_CALC_AVERAGE;
3186                 else if (g_str_has_prefix(tok_graph, "load:"))
3187                         graph->calc_type = IOG_ITEM_UNIT_CALC_LOAD;
3188                 else
3189                         break;
3190
3191                 field_name = strchr(tok_graph, ':');
3192                 if (field_name)
3193                         field_name = field_name + 1;
3194
3195                 graph->interval = interval_ms;
3196
3197                 graph->hf_index = -1;
3198                 graph->error = check_field_unit(field_name, &graph->hf_index, graph->calc_type);
3199
3200                 graph->space_items = 0; /* TODO, can avoid realloc()s in sharkd_iograph_packet() by calculating: capture_time / interval */
3201                 graph->num_items = 0;
3202                 graph->items = NULL;
3203
3204                 if (!graph->error)
3205                         graph->error = register_tap_listener("frame", graph, tok_filter, TL_REQUIRES_PROTO_TREE, NULL, sharkd_iograph_packet, NULL, NULL);
3206
3207                 graph_count++;
3208
3209                 if (graph->error == NULL)
3210                         is_any_ok = TRUE;
3211         }
3212
3213         /* retap only if we have at least one ok */
3214         if (is_any_ok)
3215                 sharkd_retap();
3216
3217         sharkd_json_object_open(FALSE);
3218
3219         sharkd_json_array_open(FALSE, "iograph");
3220         for (i = 0; i < graph_count; i++)
3221         {
3222                 struct sharkd_iograph *graph = &graphs[i];
3223
3224                 sharkd_json_object_open(i != 0);
3225
3226                 if (graph->error)
3227                 {
3228                         sharkd_json_value_string(FALSE, "errmsg", graph->error->str);
3229                         g_string_free(graph->error, TRUE);
3230                 }
3231                 else
3232                 {
3233                         int idx;
3234                         int next_idx = 0;
3235
3236                         sharkd_json_array_open(FALSE, "items");
3237                         for (idx = 0; idx < graph->num_items; idx++)
3238                         {
3239                                 double val;
3240
3241                                 val = get_io_graph_item(graph->items, graph->calc_type, idx, graph->hf_index, &cfile, graph->interval, graph->num_items);
3242
3243                                 /* if it's zero, don't display */
3244                                 if (val == 0.0)
3245                                         continue;
3246
3247                                 /* cause zeros are not printed, need to output index */
3248                                 if (next_idx != idx)
3249                                         sharkd_json_value_stringf(next_idx != 0, NULL, "%x", idx);
3250
3251                                 sharkd_json_value_anyf(idx != 0, NULL, "%f", val);
3252                                 next_idx = idx + 1;
3253                         }
3254                         sharkd_json_array_close();
3255                 }
3256                 sharkd_json_object_close();
3257
3258                 remove_tap_listener(graph);
3259                 g_free(graph->items);
3260         }
3261         sharkd_json_array_close();
3262
3263         sharkd_json_object_close();
3264         sharkd_json_finish();
3265 }
3266
3267 /**
3268  * sharkd_session_process_intervals()
3269  *
3270  * Process intervals request - generate basic capture file statistics per requested interval.
3271  *
3272  * Input:
3273  *   (o) interval - interval time in ms, if not specified: 1000ms
3274  *   (o) filter   - filter for generating interval request
3275  *
3276  * Output object with attributes:
3277  *   (m) intervals - array of intervals, with indexes:
3278  *             [0] - index of interval,
3279  *             [1] - number of frames during interval,
3280  *             [2] - number of bytes during interval.
3281  *
3282  *   (m) last   - last interval number.
3283  *   (m) frames - total number of frames
3284  *   (m) bytes  - total number of bytes
3285  *
3286  * NOTE: If frames are not in order, there might be items with same interval index, or even negative one.
3287  */
3288 static void
3289 sharkd_session_process_intervals(char *buf, const jsmntok_t *tokens, int count)
3290 {
3291         const char *tok_interval = json_find_attr(buf, tokens, count, "interval");
3292         const char *tok_filter = json_find_attr(buf, tokens, count, "filter");
3293
3294         const guint8 *filter_data = NULL;
3295
3296         struct
3297         {
3298                 unsigned int frames;
3299                 guint64 bytes;
3300         } st, st_total;
3301
3302         nstime_t *start_ts;
3303
3304         guint32 interval_ms = 1000; /* default: one per second */
3305
3306         gboolean sepa = FALSE;
3307         unsigned int framenum;
3308         gint64 idx;
3309         gint64 max_idx = 0;
3310
3311         if (tok_interval)
3312         {
3313                 if (!ws_strtou32(tok_interval, NULL, &interval_ms) || interval_ms == 0)
3314                 {
3315                         fprintf(stderr, "Invalid interval parameter: %s.\n", tok_interval);
3316                         return;
3317                 }
3318         }
3319
3320         if (tok_filter)
3321         {
3322                 const struct sharkd_filter_item *filter_item;
3323
3324                 filter_item = sharkd_session_filter_data(tok_filter);
3325                 if (!filter_item)
3326                         return;
3327                 filter_data = filter_item->filtered;
3328         }
3329
3330         st_total.frames = 0;
3331         st_total.bytes  = 0;
3332
3333         st.frames = 0;
3334         st.bytes  = 0;
3335
3336         idx = 0;
3337
3338         sharkd_json_object_open(FALSE);
3339         sharkd_json_array_open(FALSE, "intervals");
3340
3341         start_ts = (cfile.count >= 1) ? &(sharkd_get_frame(1)->abs_ts) : NULL;
3342
3343         for (framenum = 1; framenum <= cfile.count; framenum++)
3344         {
3345                 frame_data *fdata;
3346                 gint64 msec_rel;
3347                 gint64 new_idx;
3348
3349                 if (filter_data && !(filter_data[framenum / 8] & (1 << (framenum % 8))))
3350                         continue;
3351
3352                 fdata = sharkd_get_frame(framenum);
3353
3354                 msec_rel = (fdata->abs_ts.secs - start_ts->secs) * (gint64) 1000 + (fdata->abs_ts.nsecs - start_ts->nsecs) / 1000000;
3355                 new_idx  = msec_rel / interval_ms;
3356
3357                 if (idx != new_idx)
3358                 {
3359                         if (st.frames != 0)
3360                         {
3361                                 sharkd_json_value_anyf(sepa, NULL, "[%" G_GINT64_FORMAT ",%u,%" G_GUINT64_FORMAT "]", idx, st.frames, st.bytes);
3362                                 sepa = TRUE;
3363                         }
3364
3365                         idx = new_idx;
3366                         if (idx > max_idx)
3367                                 max_idx = idx;
3368
3369                         st.frames = 0;
3370                         st.bytes  = 0;
3371                 }
3372
3373                 st.frames += 1;
3374                 st.bytes  += fdata->pkt_len;
3375
3376                 st_total.frames += 1;
3377                 st_total.bytes  += fdata->pkt_len;
3378         }
3379
3380         if (st.frames != 0)
3381         {
3382                 sharkd_json_value_anyf(sepa, NULL, "[%" G_GINT64_FORMAT ",%u,%" G_GUINT64_FORMAT "]", idx, st.frames, st.bytes);
3383                 /* sepa = TRUE; */
3384         }
3385         sharkd_json_array_close();
3386
3387         sharkd_json_value_anyf(TRUE, "last", "%" G_GINT64_FORMAT, max_idx);
3388         sharkd_json_value_anyf(TRUE, "frames", "%u", st_total.frames);
3389         sharkd_json_value_anyf(TRUE, "bytes", "%" G_GUINT64_FORMAT, st_total.bytes);
3390
3391         sharkd_json_object_close();
3392         sharkd_json_finish();
3393 }
3394
3395 /**
3396  * sharkd_session_process_frame()
3397  *
3398  * Process frame request
3399  *
3400  * Input:
3401  *   (m) frame - requested frame number
3402  *   (o) ref_frame - time reference frame number
3403  *   (o) prev_frame - previously displayed frame number
3404  *   (o) proto - set if output frame tree
3405  *   (o) columns - set if output frame columns
3406  *   (o) color - set if output color-filter bg/fg
3407  *   (o) bytes - set if output frame bytes
3408  *   (o) hidden - set if output hidden tree fields
3409  *
3410  * Output object with attributes:
3411  *   (m) err   - 0 if succeed
3412  *   (o) tree  - array of frame nodes with attributes:
3413  *                  l - label
3414  *                  t: 'proto', 'framenum', 'url' - type of node
3415  *                  f - filter string
3416  *                  s - severity
3417  *                  e - subtree ett index
3418  *                  n - array of subtree nodes
3419  *                  h - two item array: (item start, item length)
3420  *                  i - two item array: (appendix start, appendix length)
3421  *                  p - [RESERVED] two item array: (protocol start, protocol length)
3422  *                  ds- data src index
3423  *                  url  - only for t:'url', url
3424  *                  fnum - only for t:'framenum', frame number
3425  *                  g - if field is generated by Wireshark
3426  *                  v - if field is hidden
3427  *
3428  *   (o) col   - array of column data
3429  *   (o) bytes - base64 of frame bytes
3430  *   (o) ds    - array of other data srcs
3431  *   (o) comment - frame comment
3432  *   (o) fol   - array of follow filters:
3433  *                  [0] - protocol
3434  *                  [1] - filter string
3435  *   (o) i   - if frame is ignored
3436  *   (o) m   - if frame is marked
3437  *   (o) bg  - color filter - background color in hex
3438  *   (o) fg  - color filter - foreground color in hex
3439  */
3440 static void
3441 sharkd_session_process_frame(char *buf, const jsmntok_t *tokens, int count)
3442 {
3443         const char *tok_frame = json_find_attr(buf, tokens, count, "frame");
3444         const char *tok_ref_frame = json_find_attr(buf, tokens, count, "ref_frame");
3445         const char *tok_prev_frame = json_find_attr(buf, tokens, count, "prev_frame");
3446
3447         guint32 framenum, ref_frame_num, prev_dis_num;
3448         guint32 dissect_flags = SHARKD_DISSECT_FLAG_NULL;
3449         struct sharkd_frame_request_data req_data;
3450
3451         if (!tok_frame || !ws_strtou32(tok_frame, NULL, &framenum) || framenum == 0)
3452                 return;
3453
3454         ref_frame_num = (framenum != 1) ? 1 : 0;
3455         if (tok_ref_frame && (!ws_strtou32(tok_ref_frame, NULL, &ref_frame_num) || ref_frame_num > framenum))
3456                 return;
3457
3458         prev_dis_num = framenum - 1;
3459         if (tok_prev_frame && (!ws_strtou32(tok_prev_frame, NULL, &prev_dis_num) || prev_dis_num >= framenum))
3460                 return;
3461
3462         if (json_find_attr(buf, tokens, count, "proto") != NULL)
3463                 dissect_flags |= SHARKD_DISSECT_FLAG_PROTO_TREE;
3464         if (json_find_attr(buf, tokens, count, "bytes") != NULL)
3465                 dissect_flags |= SHARKD_DISSECT_FLAG_BYTES;
3466         if (json_find_attr(buf, tokens, count, "columns") != NULL)
3467                 dissect_flags |= SHARKD_DISSECT_FLAG_COLUMNS;
3468         if (json_find_attr(buf, tokens, count, "color") != NULL)
3469                 dissect_flags |= SHARKD_DISSECT_FLAG_COLOR;
3470
3471         req_data.display_hidden = (json_find_attr(buf, tokens, count, "v") != NULL);
3472
3473         sharkd_dissect_request(framenum, ref_frame_num, prev_dis_num, &sharkd_session_process_frame_cb, dissect_flags, &req_data);
3474 }
3475
3476 /**
3477  * sharkd_session_process_check()
3478  *
3479  * Process check request.
3480  *
3481  * Input:
3482  *   (o) filter - filter to be checked
3483  *   (o) field - field to be checked
3484  *
3485  * Output object with attributes:
3486  *   (m) err - always 0
3487  *   (o) filter - 'ok', 'warn' or error message
3488  *   (o) field - 'ok', or 'notfound'
3489  */
3490 static int
3491 sharkd_session_process_check(char *buf, const jsmntok_t *tokens, int count)
3492 {
3493         const char *tok_filter = json_find_attr(buf, tokens, count, "filter");
3494         const char *tok_field = json_find_attr(buf, tokens, count, "field");
3495
3496         sharkd_json_object_open(FALSE);
3497         sharkd_json_value_anyf(FALSE, "err", "0");
3498
3499         if (tok_filter != NULL)
3500         {
3501                 char *err_msg = NULL;
3502                 dfilter_t *dfp;
3503
3504                 if (dfilter_compile(tok_filter, &dfp, &err_msg))
3505                 {
3506                         const char *s = "ok";
3507
3508                         if (dfp && dfilter_deprecated_tokens(dfp))
3509                                 s = "warn";
3510
3511                         sharkd_json_value_string(TRUE, "filter", s);
3512                         dfilter_free(dfp);
3513                 }
3514                 else
3515                 {
3516                         sharkd_json_value_string(TRUE, "filter", err_msg);
3517                         g_free(err_msg);
3518                 }
3519         }
3520
3521         if (tok_field != NULL)
3522         {
3523                 header_field_info *hfi = proto_registrar_get_byname(tok_field);
3524
3525                 sharkd_json_value_string(TRUE, "field", (hfi) ? "ok" : "notfound");
3526         }
3527
3528         sharkd_json_object_close();
3529         sharkd_json_finish();
3530
3531         return 0;
3532 }
3533
3534 struct sharkd_session_process_complete_pref_data
3535 {
3536         const char *module;
3537         const char *pref;
3538         gboolean sepa;
3539 };
3540
3541 static guint
3542 sharkd_session_process_complete_pref_cb(module_t *module, gpointer d)
3543 {
3544         struct sharkd_session_process_complete_pref_data *data = (struct sharkd_session_process_complete_pref_data *) d;
3545
3546         if (strncmp(data->pref, module->name, strlen(data->pref)) != 0)
3547                 return 0;
3548
3549         sharkd_json_object_open(data->sepa);
3550         sharkd_json_value_string(FALSE, "f", module->name);
3551         sharkd_json_value_string(TRUE, "d", module->title);
3552         sharkd_json_object_close();
3553
3554         data->sepa = TRUE;
3555
3556         return 0;
3557 }
3558
3559 static guint
3560 sharkd_session_process_complete_pref_option_cb(pref_t *pref, gpointer d)
3561 {
3562         struct sharkd_session_process_complete_pref_data *data = (struct sharkd_session_process_complete_pref_data *) d;
3563         const char *pref_name = prefs_get_name(pref);
3564         const char *pref_title = prefs_get_title(pref);
3565
3566         if (strncmp(data->pref, pref_name, strlen(data->pref)) != 0)
3567                 return 0;
3568
3569         sharkd_json_object_open(data->sepa);
3570         sharkd_json_value_stringf(FALSE, "f", "%s.%s", data->module, pref_name);
3571         sharkd_json_value_string(TRUE, "d", pref_title);
3572         sharkd_json_object_close();
3573
3574         data->sepa = TRUE;
3575
3576         return 0; /* continue */
3577 }
3578
3579 /**
3580  * sharkd_session_process_complete()
3581  *
3582  * Process complete request
3583  *
3584  * Input:
3585  *   (o) field - field to be completed
3586  *   (o) pref  - preference to be completed
3587  *
3588  * Output object with attributes:
3589  *   (m) err - always 0
3590  *   (o) field - array of object with attributes:
3591  *                  (m) f - field text
3592  *                  (o) t - field type (FT_ number)
3593  *                  (o) n - field name
3594  *   (o) pref  - array of object with attributes:
3595  *                  (m) f - pref name
3596  *                  (o) d - pref description
3597  */
3598 static int
3599 sharkd_session_process_complete(char *buf, const jsmntok_t *tokens, int count)
3600 {
3601         const char *tok_field = json_find_attr(buf, tokens, count, "field");
3602         const char *tok_pref  = json_find_attr(buf, tokens, count, "pref");
3603
3604         sharkd_json_object_open(FALSE);
3605         sharkd_json_value_anyf(FALSE, "err", "0");
3606
3607         if (tok_field != NULL && tok_field[0])
3608         {
3609                 const size_t filter_length = strlen(tok_field);
3610                 const int filter_with_dot = !!strchr(tok_field, '.');
3611
3612                 void *proto_cookie;
3613                 void *field_cookie;
3614                 int proto_id;
3615                 gboolean sepa = FALSE;
3616
3617                 sharkd_json_array_open(TRUE, "field");
3618
3619                 for (proto_id = proto_get_first_protocol(&proto_cookie); proto_id != -1; proto_id = proto_get_next_protocol(&proto_cookie))
3620                 {
3621                         protocol_t *protocol = find_protocol_by_id(proto_id);
3622                         const char *protocol_filter;
3623                         const char *protocol_name;
3624                         header_field_info *hfinfo;
3625
3626                         if (!proto_is_protocol_enabled(protocol))
3627                                 continue;
3628
3629                         protocol_name   = proto_get_protocol_long_name(protocol);
3630                         protocol_filter = proto_get_protocol_filter_name(proto_id);
3631
3632                         if (strlen(protocol_filter) >= filter_length && !g_ascii_strncasecmp(tok_field, protocol_filter, filter_length))
3633                         {
3634                                 sharkd_json_object_open(sepa);
3635                                 {
3636                                         sharkd_json_value_string(FALSE, "f", protocol_filter);
3637                                         sharkd_json_value_anyf(TRUE, "t", "%d", FT_PROTOCOL);
3638                                         sharkd_json_value_string(TRUE, "n", protocol_name);
3639                                 }
3640                                 sharkd_json_object_close();
3641                                 sepa = TRUE;
3642                         }
3643
3644                         if (!filter_with_dot)
3645                                 continue;
3646
3647                         for (hfinfo = proto_get_first_protocol_field(proto_id, &field_cookie); hfinfo != NULL; hfinfo = proto_get_next_protocol_field(proto_id, &field_cookie))
3648                         {
3649                                 if (hfinfo->same_name_prev_id != -1) /* ignore duplicate names */
3650                                         continue;
3651
3652                                 if (strlen(hfinfo->abbrev) >= filter_length && !g_ascii_strncasecmp(tok_field, hfinfo->abbrev, filter_length))
3653                                 {
3654                                         sharkd_json_object_open(sepa);
3655                                         {
3656                                                 sharkd_json_value_string(FALSE, "f", hfinfo->abbrev);
3657
3658                                                 /* XXX, skip displaying name, if there are multiple (to not confuse user) */
3659                                                 if (hfinfo->same_name_next == NULL)
3660                                                 {
3661                                                         sharkd_json_value_anyf(TRUE, "t", "%d", hfinfo->type);
3662                                                         sharkd_json_value_string(TRUE, "n", hfinfo->name);
3663                                                 }
3664                                         }
3665                                         sharkd_json_object_close();
3666                                         sepa = TRUE;
3667                                 }
3668                         }
3669                 }
3670
3671                 sharkd_json_array_close();
3672         }
3673
3674         if (tok_pref != NULL && tok_pref[0])
3675         {
3676                 struct sharkd_session_process_complete_pref_data data;
3677                 char *dot_sepa;
3678
3679                 data.module = tok_pref;
3680                 data.pref = tok_pref;
3681                 data.sepa = FALSE;
3682
3683                 sharkd_json_array_open(TRUE, "pref");
3684                 if ((dot_sepa = strchr(tok_pref, '.')))
3685                 {
3686                         module_t *pref_mod;
3687
3688                         *dot_sepa = '\0'; /* XXX, C abuse: discarding-const */
3689                         data.pref = dot_sepa + 1;
3690
3691                         pref_mod = prefs_find_module(data.module);
3692                         if (pref_mod)
3693                                 prefs_pref_foreach(pref_mod, sharkd_session_process_complete_pref_option_cb, &data);
3694
3695                         *dot_sepa = '.';
3696                 }
3697                 else
3698                 {
3699                         prefs_modules_foreach(sharkd_session_process_complete_pref_cb, &data);
3700                 }
3701                 sharkd_json_array_close();
3702         }
3703
3704         sharkd_json_object_close();
3705         sharkd_json_finish();
3706
3707         return 0;
3708 }
3709
3710 /**
3711  * sharkd_session_process_setcomment()
3712  *
3713  * Process setcomment request
3714  *
3715  * Input:
3716  *   (m) frame - frame number
3717  *   (o) comment - user comment
3718  *
3719  * Output object with attributes:
3720  *   (m) err   - error code: 0 succeed
3721  */
3722 static void
3723 sharkd_session_process_setcomment(char *buf, const jsmntok_t *tokens, int count)
3724 {
3725         const char *tok_frame   = json_find_attr(buf, tokens, count, "frame");
3726         const char *tok_comment = json_find_attr(buf, tokens, count, "comment");
3727
3728         guint32 framenum;
3729         frame_data *fdata;
3730         int ret;
3731
3732         if (!tok_frame || !ws_strtou32(tok_frame, NULL, &framenum) || framenum == 0)
3733                 return;
3734
3735         fdata = sharkd_get_frame(framenum);
3736         if (!fdata)
3737                 return;
3738
3739         ret = sharkd_set_user_comment(fdata, tok_comment);
3740
3741         sharkd_json_simple_reply(ret, NULL);
3742 }
3743
3744 /**
3745  * sharkd_session_process_setconf()
3746  *
3747  * Process setconf request
3748  *
3749  * Input:
3750  *   (m) name  - preference name
3751  *   (m) value - preference value
3752  *
3753  * Output object with attributes:
3754  *   (m) err   - error code: 0 succeed
3755  */
3756 static void
3757 sharkd_session_process_setconf(char *buf, const jsmntok_t *tokens, int count)
3758 {
3759         const char *tok_name = json_find_attr(buf, tokens, count, "name");
3760         const char *tok_value = json_find_attr(buf, tokens, count, "value");
3761         char pref[4096];
3762         char *errmsg = NULL;
3763
3764         prefs_set_pref_e ret;
3765
3766         if (!tok_name || tok_name[0] == '\0' || !tok_value)
3767                 return;
3768
3769         ws_snprintf(pref, sizeof(pref), "%s:%s", tok_name, tok_value);
3770
3771         ret = prefs_set_pref(pref, &errmsg);
3772
3773         sharkd_json_simple_reply(ret, errmsg);
3774         g_free(errmsg);
3775 }
3776
3777 struct sharkd_session_process_dumpconf_data
3778 {
3779         module_t *module;
3780         gboolean sepa;
3781 };
3782
3783 static guint
3784 sharkd_session_process_dumpconf_cb(pref_t *pref, gpointer d)
3785 {
3786         struct sharkd_session_process_dumpconf_data *data = (struct sharkd_session_process_dumpconf_data *) d;
3787         const char *pref_name = prefs_get_name(pref);
3788
3789         char json_pref_key[512];
3790
3791         snprintf(json_pref_key, sizeof(json_pref_key), "%s.%s", data->module->name, pref_name);
3792         sharkd_json_value_anyf(data->sepa, json_pref_key, "{");
3793
3794         switch (prefs_get_type(pref))
3795         {
3796                 case PREF_UINT:
3797                 case PREF_DECODE_AS_UINT:
3798                         sharkd_json_value_anyf(FALSE, "u", "%u", prefs_get_uint_value_real(pref, pref_current));
3799                         if (prefs_get_uint_base(pref) != 10)
3800                                 sharkd_json_value_anyf(TRUE, "ub", "%u", prefs_get_uint_base(pref));
3801                         break;
3802
3803                 case PREF_BOOL:
3804                         sharkd_json_value_anyf(FALSE, "b", prefs_get_bool_value(pref, pref_current) ? "1" : "0");
3805                         break;
3806
3807                 case PREF_STRING:
3808                 case PREF_SAVE_FILENAME:
3809                 case PREF_OPEN_FILENAME:
3810                 case PREF_DIRNAME:
3811                         sharkd_json_value_string(FALSE, "s", prefs_get_string_value(pref, pref_current));
3812                         break;
3813
3814                 case PREF_ENUM:
3815                 {
3816                         const enum_val_t *enums;
3817                         gboolean enum_sepa = FALSE;
3818
3819                         sharkd_json_array_open(FALSE, "e");
3820                         for (enums = prefs_get_enumvals(pref); enums->name; enums++)
3821                         {
3822                                 sharkd_json_object_open(enum_sepa);
3823
3824                                 sharkd_json_value_anyf(FALSE, "v", "%d", enums->value);
3825
3826                                 if (enums->value == prefs_get_enum_value(pref, pref_current))
3827                                         sharkd_json_value_anyf(TRUE, "s", "1");
3828
3829                                 sharkd_json_value_string(TRUE, "d", enums->description);
3830
3831                                 sharkd_json_object_close();
3832                                 enum_sepa = TRUE;
3833                         }
3834                         sharkd_json_array_close();
3835                         break;
3836                 }
3837