1 /* stat_tap_ui.c
2  * Routines to register UI information for stats
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #include "config.h"
12 
13 #include <stdio.h>
14 
15 #include <string.h>
16 
17 #include <glib.h>
18 
19 #include <epan/stat_tap_ui.h>
20 #include <wsutil/ws_assert.h>
21 
22 /* structure to keep track of what stats have registered command-line
23    arguments.
24  */
25 typedef struct _stat_cmd_arg {
26     stat_tap_ui *ui;
27     const char *cmd;
28     void (*func)(const char *arg, void* userdata);
29     void* userdata;
30 } stat_cmd_arg;
31 
32 static wmem_list_t *stat_cmd_arg_list=NULL;
33 
34 /* structure to keep track of what stats have been specified on the
35    command line.
36  */
37 typedef struct {
38     stat_cmd_arg *sca;
39     char *arg;
40 } stat_requested;
41 static GSList *stats_requested = NULL;
42 
43 /* **********************************************************************
44  * Function called from stat to register the stat's command-line argument
45  * and initialization routine
46  * ********************************************************************** */
47 static gint
search_duplicate(gconstpointer a,gconstpointer b)48 search_duplicate(gconstpointer a, gconstpointer b)
49 {
50     return strcmp(((const stat_cmd_arg *)a)->cmd, (const char *)b);
51 }
52 
53 static gint
sort_by_name(gconstpointer a,gconstpointer b)54 sort_by_name(gconstpointer a, gconstpointer b)
55 {
56     return strcmp(((const stat_cmd_arg *)a)->cmd, ((const stat_cmd_arg *)b)->cmd);
57 }
58 
59 void
register_stat_tap_ui(stat_tap_ui * ui,void * userdata)60 register_stat_tap_ui(stat_tap_ui *ui, void *userdata)
61 {
62     stat_cmd_arg *newsca;
63 
64     if (stat_cmd_arg_list == NULL)
65         stat_cmd_arg_list = wmem_list_new(wmem_epan_scope());
66 
67     /* Key is already present */
68     if (wmem_list_find_custom(stat_cmd_arg_list, ui->cli_string, search_duplicate))
69         return;
70 
71     newsca = wmem_new(wmem_epan_scope(), stat_cmd_arg);
72     newsca->cmd= wmem_strdup(wmem_epan_scope(), ui->cli_string);
73     newsca->func=ui->tap_init_cb;
74     newsca->userdata=userdata;
75 
76     wmem_list_insert_sorted(stat_cmd_arg_list, newsca, sort_by_name);
77 }
78 
79 /* **********************************************************************
80  * Function called for a stat command-line argument
81  * ********************************************************************** */
82 gboolean
process_stat_cmd_arg(const char * optstr)83 process_stat_cmd_arg(const char *optstr)
84 {
85     wmem_list_frame_t *entry;
86     stat_cmd_arg *sca;
87     stat_requested *tr;
88     char *stat_command = g_strdup(optstr);
89 
90     /* Renamed in Wireshark 3.0, backwards compatibility. */
91     if (!strncmp(stat_command, "follow,ssl", strlen("follow,ssl"))) {
92         memcpy(stat_command + 7, "tls", 3);
93     }
94 
95     /* The strings "ipx" or "ipv6" must be tested before "ip" to select the
96       right tap so the sorting does matter.  And it's also why the list is
97       walked backwards */
98     for (entry = wmem_list_tail(stat_cmd_arg_list); entry; entry = wmem_list_frame_prev(entry)) {
99         sca = (stat_cmd_arg*)wmem_list_frame_data(entry);
100         if (!strncmp(sca->cmd, stat_command, strlen(sca->cmd))) {
101             tr=g_new(stat_requested, 1);
102             tr->sca = sca;
103             tr->arg = stat_command;
104             stats_requested = g_slist_append(stats_requested, tr);
105             return TRUE;
106         }
107     }
108     g_free(stat_command);
109     return FALSE;
110 }
111 
112 /* **********************************************************************
113  * Function to list all possible tap command-line arguments
114  * ********************************************************************** */
115 static void
list_stat_cmd_args_func(gpointer data,gpointer userdata _U_)116 list_stat_cmd_args_func(gpointer data, gpointer userdata _U_)
117 {
118     fprintf(stderr,"     %s\n", ((stat_cmd_arg*)data)->cmd);
119 }
120 
121 void
list_stat_cmd_args(void)122 list_stat_cmd_args(void)
123 {
124     wmem_list_foreach(stat_cmd_arg_list, list_stat_cmd_args_func, NULL);
125 }
126 
127 /* **********************************************************************
128  * Function to process stats requested with command-line arguments
129  * ********************************************************************** */
130 void
start_requested_stats(void)131 start_requested_stats(void)
132 {
133     stat_requested *sr;
134 
135     while(stats_requested){
136         sr=(stat_requested *)stats_requested->data;
137         (*sr->sca->func)(sr->arg,sr->sca->userdata);
138         stats_requested=g_slist_remove(stats_requested, sr);
139         g_free(sr->arg);
140         g_free(sr);
141     }
142 }
143 
144 static wmem_tree_t *registered_stat_tables = NULL;
145 
register_stat_tap_table_ui(stat_tap_table_ui * ui)146 void register_stat_tap_table_ui(stat_tap_table_ui *ui)
147 {
148     if (registered_stat_tables == NULL)
149         registered_stat_tables = wmem_tree_new(wmem_epan_scope());
150 
151     wmem_tree_insert_string(registered_stat_tables, ui->cli_string, ui, 0);
152 }
153 
stat_tap_by_name(const char * name)154 stat_tap_table_ui *stat_tap_by_name(const char *name)
155 {
156     return (stat_tap_table_ui *) wmem_tree_lookup_string(registered_stat_tables, name, 0);
157 }
158 
stat_tap_iterate_tables(wmem_foreach_func func,gpointer user_data)159 void stat_tap_iterate_tables(wmem_foreach_func func, gpointer user_data)
160 {
161     wmem_tree_foreach(registered_stat_tables, func, user_data);
162 }
163 
stat_tap_get_filter(stat_tap_table_ui * new_stat,const char * opt_arg,const char ** filter,char ** err)164 void stat_tap_get_filter(stat_tap_table_ui* new_stat, const char *opt_arg, const char **filter, char** err)
165 {
166     guint len = (guint) strlen(new_stat->cli_string);
167     *filter=NULL;
168     *err=NULL;
169 
170     if (!strncmp(opt_arg, new_stat->cli_string, len))
171     {
172         if (opt_arg[len] == ',')
173         {
174            *filter = opt_arg + len+1;
175         }
176     }
177 
178     if (new_stat->stat_filter_check_cb)
179         new_stat->stat_filter_check_cb(opt_arg, filter, err);
180 }
181 
stat_tap_init_table(const char * name,int num_fields,int num_elements,const char * filter_string)182 stat_tap_table* stat_tap_init_table(const char *name, int num_fields, int num_elements,
183                 const char *filter_string)
184 {
185     stat_tap_table* new_table = g_new0(stat_tap_table, 1);
186 
187     new_table->title = name;
188     new_table->num_elements = num_elements;
189     new_table->num_fields = num_fields;
190     new_table->filter_string = filter_string;
191     new_table->elements = g_new0(stat_tap_table_item_type*, num_elements);
192 
193     return new_table;
194 }
195 
stat_tap_find_table(stat_tap_table_ui * ui,const char * name)196 stat_tap_table *stat_tap_find_table(stat_tap_table_ui *ui, const char *name)
197 {
198     guint i = 0;
199     stat_tap_table *stat_table;
200 
201     if (ui->tables == NULL)
202         return NULL;
203 
204     for (i = 0; i < ui->tables->len; i++) {
205         stat_table = g_array_index(ui->tables, stat_tap_table *, i);
206         if (!g_strcmp0(stat_table->title, name)) {
207             return stat_table;
208         }
209     }
210 
211     return NULL;
212 }
213 
stat_tap_add_table(stat_tap_table_ui * new_stat,stat_tap_table * table)214 void stat_tap_add_table(stat_tap_table_ui* new_stat, stat_tap_table* table)
215 {
216     if (new_stat->tables == NULL)
217         new_stat->tables = g_array_new(FALSE, TRUE, sizeof(stat_tap_table*));
218 
219     g_array_insert_val(new_stat->tables, new_stat->tables->len, table);
220 }
221 
stat_tap_init_table_row(stat_tap_table * stat_table,guint table_index,guint num_fields,const stat_tap_table_item_type * fields)222 void stat_tap_init_table_row(stat_tap_table *stat_table, guint table_index, guint num_fields, const stat_tap_table_item_type* fields)
223 {
224     /* we have discovered a new procedure. Extend the table accordingly */
225     if(table_index>=stat_table->num_elements){
226         guint old_num_elements=stat_table->num_elements;
227         guint i;
228 
229         stat_table->num_elements=table_index+1;
230         stat_table->elements = (stat_tap_table_item_type**)g_realloc(stat_table->elements, sizeof(stat_tap_table_item_type*)*(stat_table->num_elements));
231         for(i=old_num_elements;i<stat_table->num_elements;i++){
232             stat_table->elements[i] = g_new0(stat_tap_table_item_type, stat_table->num_fields);
233         }
234     }
235     memcpy(stat_table->elements[table_index], fields, num_fields*sizeof(stat_tap_table_item_type));
236 
237 }
238 
stat_tap_get_field_data(const stat_tap_table * stat_table,guint table_index,guint field_index)239 stat_tap_table_item_type* stat_tap_get_field_data(const stat_tap_table *stat_table, guint table_index, guint field_index)
240 {
241     stat_tap_table_item_type* field_value;
242     ws_assert(table_index < stat_table->num_elements);
243 
244     field_value = stat_table->elements[table_index];
245 
246     ws_assert(field_index < stat_table->num_fields);
247 
248     return &field_value[field_index];
249 }
250 
stat_tap_set_field_data(stat_tap_table * stat_table,guint table_index,guint field_index,stat_tap_table_item_type * field_data)251 void stat_tap_set_field_data(stat_tap_table *stat_table, guint table_index, guint field_index, stat_tap_table_item_type* field_data)
252 {
253     stat_tap_table_item_type* field_value;
254     ws_assert(table_index < stat_table->num_elements);
255 
256     field_value = stat_table->elements[table_index];
257 
258     ws_assert(field_index < stat_table->num_fields);
259 
260     field_value[field_index] = *field_data;
261 }
262 
reset_stat_table(stat_tap_table_ui * new_stat)263 void reset_stat_table(stat_tap_table_ui* new_stat)
264 {
265     guint i = 0;
266     stat_tap_table *stat_table;
267 
268     for (i = 0; i < new_stat->tables->len; i++)
269     {
270         stat_table = g_array_index(new_stat->tables, stat_tap_table*, i);
271 
272         if (new_stat->stat_tap_reset_table_cb)
273             new_stat->stat_tap_reset_table_cb(stat_table);
274     }
275 }
276 
free_stat_tables(stat_tap_table_ui * new_stat)277 void free_stat_tables(stat_tap_table_ui* new_stat)
278 {
279     guint i = 0, element, field_index;
280     stat_tap_table *stat_table;
281     stat_tap_table_item_type* field_data;
282 
283     for (i = 0; i < new_stat->tables->len; i++)
284     {
285         stat_table = g_array_index(new_stat->tables, stat_tap_table*, i);
286 
287         for (element = 0; element < stat_table->num_elements; element++)
288         {
289             for (field_index = 0; field_index < stat_table->num_fields; field_index++)
290             {
291                 field_data = stat_tap_get_field_data(stat_table, element, field_index);
292                 /* Give dissector a crack at it */
293                 /* XXX Should this be per-row instead? */
294                 if (new_stat->stat_tap_free_table_item_cb)
295                     new_stat->stat_tap_free_table_item_cb(stat_table, element, field_index, field_data);
296             }
297             g_free(stat_table->elements[element]);
298         }
299         g_free(stat_table->elements);
300         g_free(stat_table);
301     }
302     g_array_set_size(new_stat->tables, 0);
303 }
304 
305 
306 /*
307  * Editor modelines
308  *
309  * Local Variables:
310  * c-basic-offset: 4
311  * tab-width: 8
312  * indent-tabs-mode: nil
313  * End:
314  *
315  * ex: set shiftwidth=4 tabstop=8 expandtab:
316  * :indentSize=4:tabSize=8:noTabs=true:
317  */
318