2 * Routines to register UI information for stats
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
19 #include <epan/stat_tap_ui.h>
20 #include <wsutil/ws_assert.h>
22 /* structure to keep track of what stats have registered command-line
25 typedef struct _stat_cmd_arg
{
28 void (*func
)(const char *arg
, void* userdata
);
32 static wmem_list_t
*stat_cmd_arg_list
;
34 /* structure to keep track of what stats have been specified on the
41 static GSList
*stats_requested
;
43 /* **********************************************************************
44 * Function called from stat to register the stat's command-line argument
45 * and initialization routine
46 * ********************************************************************** */
48 search_duplicate(const void *a
, const void *b
)
50 return strcmp(((const stat_cmd_arg
*)a
)->cmd
, (const char *)b
);
54 sort_by_name(const void *a
, const void *b
)
56 return strcmp(((const stat_cmd_arg
*)a
)->cmd
, ((const stat_cmd_arg
*)b
)->cmd
);
60 register_stat_tap_ui(stat_tap_ui
*ui
, void *userdata
)
64 if (stat_cmd_arg_list
== NULL
)
65 stat_cmd_arg_list
= wmem_list_new(wmem_epan_scope());
67 /* Key is already present */
68 if (wmem_list_find_custom(stat_cmd_arg_list
, ui
->cli_string
, search_duplicate
))
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
;
76 wmem_list_insert_sorted(stat_cmd_arg_list
, newsca
, sort_by_name
);
79 /* **********************************************************************
80 * Function called for a stat command-line argument
81 * ********************************************************************** */
83 process_stat_cmd_arg(const char *optstr
)
85 wmem_list_frame_t
*entry
;
88 char *stat_command
= g_strdup(optstr
);
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);
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
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);
103 tr
->arg
= stat_command
;
104 stats_requested
= g_slist_append(stats_requested
, tr
);
108 g_free(stat_command
);
112 /* **********************************************************************
113 * Function to list all possible tap command-line arguments
114 * ********************************************************************** */
116 list_stat_cmd_args_func(void *data
, void *userdata _U_
)
118 fprintf(stderr
," %s\n", ((stat_cmd_arg
*)data
)->cmd
);
122 list_stat_cmd_args(void)
124 wmem_list_foreach(stat_cmd_arg_list
, list_stat_cmd_args_func
, NULL
);
127 /* **********************************************************************
128 * Function to process stats requested with command-line arguments
129 * ********************************************************************** */
131 start_requested_stats(void)
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
);
144 static wmem_tree_t
*registered_stat_tables
;
146 void register_stat_tap_table_ui(stat_tap_table_ui
*ui
)
148 if (registered_stat_tables
== NULL
)
149 registered_stat_tables
= wmem_tree_new(wmem_epan_scope());
151 wmem_tree_insert_string(registered_stat_tables
, ui
->cli_string
, ui
, 0);
154 stat_tap_table_ui
*stat_tap_by_name(const char *name
)
156 return (stat_tap_table_ui
*) wmem_tree_lookup_string(registered_stat_tables
, name
, 0);
159 void stat_tap_iterate_tables(wmem_foreach_func func
, void *user_data
)
161 wmem_tree_foreach(registered_stat_tables
, func
, user_data
);
164 void stat_tap_get_filter(stat_tap_table_ui
* new_stat
, const char *opt_arg
, const char **filter
, char** err
)
166 unsigned len
= (unsigned) strlen(new_stat
->cli_string
);
170 if (!strncmp(opt_arg
, new_stat
->cli_string
, len
))
172 if (opt_arg
[len
] == ',')
174 *filter
= opt_arg
+ len
+1;
178 if (new_stat
->stat_filter_check_cb
)
179 new_stat
->stat_filter_check_cb(opt_arg
, filter
, err
);
182 stat_tap_table
* stat_tap_init_table(const char *name
, int num_fields
, int num_elements
,
183 const char *filter_string
)
185 stat_tap_table
* new_table
= g_new0(stat_tap_table
, 1);
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
);
196 stat_tap_table
*stat_tap_find_table(stat_tap_table_ui
*ui
, const char *name
)
199 stat_tap_table
*stat_table
;
201 if (ui
->tables
== NULL
)
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
)) {
214 void stat_tap_add_table(stat_tap_table_ui
* new_stat
, stat_tap_table
* table
)
216 if (new_stat
->tables
== NULL
)
217 new_stat
->tables
= g_array_new(false, true, sizeof(stat_tap_table
*));
219 g_array_insert_val(new_stat
->tables
, new_stat
->tables
->len
, table
);
222 void stat_tap_init_table_row(stat_tap_table
*stat_table
, unsigned table_index
, unsigned num_fields
, const stat_tap_table_item_type
* fields
)
224 /* we have discovered a new procedure. Extend the table accordingly */
225 if(table_index
>=stat_table
->num_elements
){
226 unsigned old_num_elements
=stat_table
->num_elements
;
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
);
235 memcpy(stat_table
->elements
[table_index
], fields
, num_fields
*sizeof(stat_tap_table_item_type
));
239 stat_tap_table_item_type
* stat_tap_get_field_data(const stat_tap_table
*stat_table
, unsigned table_index
, unsigned field_index
)
241 stat_tap_table_item_type
* field_value
;
242 ws_assert(table_index
< stat_table
->num_elements
);
244 field_value
= stat_table
->elements
[table_index
];
246 ws_assert(field_index
< stat_table
->num_fields
);
248 return &field_value
[field_index
];
251 void stat_tap_set_field_data(stat_tap_table
*stat_table
, unsigned table_index
, unsigned field_index
, stat_tap_table_item_type
* field_data
)
253 stat_tap_table_item_type
* field_value
;
254 ws_assert(table_index
< stat_table
->num_elements
);
256 field_value
= stat_table
->elements
[table_index
];
258 ws_assert(field_index
< stat_table
->num_fields
);
260 field_value
[field_index
] = *field_data
;
263 void reset_stat_table(stat_tap_table_ui
* new_stat
)
266 stat_tap_table
*stat_table
;
268 for (i
= 0; i
< new_stat
->tables
->len
; i
++)
270 stat_table
= g_array_index(new_stat
->tables
, stat_tap_table
*, i
);
272 if (new_stat
->stat_tap_reset_table_cb
)
273 new_stat
->stat_tap_reset_table_cb(stat_table
);
277 void free_stat_tables(stat_tap_table_ui
* new_stat
)
279 unsigned i
= 0, element
, field_index
;
280 stat_tap_table
*stat_table
;
281 stat_tap_table_item_type
* field_data
;
283 for (i
= 0; i
< new_stat
->tables
->len
; i
++)
285 stat_table
= g_array_index(new_stat
->tables
, stat_tap_table
*, i
);
287 for (element
= 0; element
< stat_table
->num_elements
; element
++)
289 for (field_index
= 0; field_index
< stat_table
->num_fields
; field_index
++)
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
);
297 g_free(stat_table
->elements
[element
]);
299 g_free(stat_table
->elements
);
302 g_array_set_size(new_stat
->tables
, 0);
312 * indent-tabs-mode: nil
315 * ex: set shiftwidth=4 tabstop=8 expandtab:
316 * :indentSize=4:tabSize=8:noTabs=true: