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