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