| File: | epan/funnel.c |
| Warning: | line 100, column 26 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * funnel.c | |||
| 3 | * | |||
| 4 | * EPAN's GUI mini-API | |||
| 5 | * | |||
| 6 | * (c) 2006, Luis E. Garcia Ontanon <[email protected]> | |||
| 7 | * | |||
| 8 | * Wireshark - Network traffic analyzer | |||
| 9 | * By Gerald Combs <[email protected]> | |||
| 10 | * Copyright 1998 Gerald Combs | |||
| 11 | * | |||
| 12 | * SPDX-License-Identifier: GPL-2.0-or-later | |||
| 13 | */ | |||
| 14 | ||||
| 15 | #include "config.h" | |||
| 16 | ||||
| 17 | #include <epan/funnel.h> | |||
| 18 | #include <wsutil/glib-compat.h> | |||
| 19 | ||||
| 20 | typedef struct _funnel_menu_t { | |||
| 21 | char *name; | |||
| 22 | register_stat_group_t group; | |||
| 23 | funnel_menu_callback callback; | |||
| 24 | void *callback_data; | |||
| 25 | funnel_menu_callback_data_free callback_data_free; | |||
| 26 | bool_Bool retap; | |||
| 27 | } funnel_menu_t; | |||
| 28 | ||||
| 29 | typedef struct _console_menu { | |||
| 30 | char *name; | |||
| 31 | funnel_console_eval_cb_t eval_cb; | |||
| 32 | funnel_console_open_cb_t open_cb; | |||
| 33 | funnel_console_close_cb_t close_cb; | |||
| 34 | void *user_data; | |||
| 35 | funnel_console_data_free_cb_t data_free_cb; | |||
| 36 | } funnel_console_menu_t; | |||
| 37 | ||||
| 38 | /** | |||
| 39 | * Represents a single packet menu entry and callback | |||
| 40 | */ | |||
| 41 | typedef struct _funnel_packet_menu_t { | |||
| 42 | char *name; /**< Name to display in the GUI */ | |||
| 43 | char *required_fields; /**< comma-separated list of fields | |||
| 44 | that must be present for the | |||
| 45 | packet menu to be displayed */ | |||
| 46 | funnel_packet_menu_callback callback; /**< Lua function to be called on | |||
| 47 | menu item selection. */ | |||
| 48 | void *callback_data; /**< Lua state for the callback | |||
| 49 | function */ | |||
| 50 | bool_Bool retap; /**< Whether or not to rescan the | |||
| 51 | capture file's packets */ | |||
| 52 | } funnel_packet_menu_t; | |||
| 53 | ||||
| 54 | ||||
| 55 | /* XXX This assumes one main window and one capture file. */ | |||
| 56 | static const funnel_ops_t* ops; | |||
| 57 | static GSList* registered_menus; | |||
| 58 | static GSList* added_menus; | |||
| 59 | static GSList* removed_menus; | |||
| 60 | static bool_Bool menus_registered; | |||
| 61 | ||||
| 62 | /* | |||
| 63 | * List of all registered funnel_packet_menu_t's | |||
| 64 | */ | |||
| 65 | static GSList* registered_packet_menus; | |||
| 66 | static GSList* registered_console_menus; | |||
| 67 | ||||
| 68 | /* | |||
| 69 | * true if the packet menus were modified since the last registration | |||
| 70 | */ | |||
| 71 | static bool_Bool packet_menus_modified; | |||
| 72 | ||||
| 73 | static void free_funnel_packet_menu(gpointer data, gpointer user_data); | |||
| 74 | ||||
| 75 | const funnel_ops_t* funnel_get_funnel_ops(void) | |||
| 76 | { | |||
| 77 | return ops; | |||
| 78 | } | |||
| 79 | ||||
| 80 | static void free_funnel_menu(gpointer data, gpointer user_data _U___attribute__((unused))) | |||
| 81 | { | |||
| 82 | funnel_menu_t* m = (funnel_menu_t*)data; | |||
| 83 | ||||
| 84 | g_free(m->name); | |||
| 85 | g_free(m); | |||
| 86 | } | |||
| 87 | ||||
| 88 | static void funnel_remove_menu(GSList** menu_list, funnel_menu_t *menu) | |||
| 89 | { | |||
| 90 | GSList* current = *menu_list; | |||
| 91 | ||||
| 92 | while (current != NULL((void*)0)) { | |||
| 93 | GSList* next = current->next; // Store the next pointer BEFORE potentially removing current | |||
| 94 | funnel_menu_t* m = (funnel_menu_t*)current->data; | |||
| 95 | if (m->callback == menu->callback) { | |||
| 96 | if (m->callback_data_free) { | |||
| 97 | m->callback_data_free(m->callback_data); | |||
| 98 | } | |||
| 99 | free_funnel_menu(m, NULL((void*)0)); | |||
| 100 | *menu_list = g_slist_remove(*menu_list, current->data); | |||
| ||||
| 101 | } | |||
| 102 | ||||
| 103 | current = next; // Move to the stored next pointer | |||
| 104 | } | |||
| 105 | } | |||
| 106 | ||||
| 107 | static void funnel_clear_menu(GSList** menu_list, GFunc free_func) | |||
| 108 | { | |||
| 109 | g_slist_foreach(*menu_list, free_func, NULL((void*)0)); | |||
| 110 | g_slist_free(*menu_list); | |||
| 111 | ||||
| 112 | *menu_list = NULL((void*)0); | |||
| 113 | } | |||
| 114 | ||||
| 115 | void funnel_register_menu(const char *name, | |||
| 116 | register_stat_group_t group, | |||
| 117 | funnel_menu_callback callback, | |||
| 118 | void *callback_data, | |||
| 119 | funnel_menu_callback_data_free callback_data_free, | |||
| 120 | bool_Bool retap) | |||
| 121 | { | |||
| 122 | funnel_menu_t* m = g_new(funnel_menu_t, 1)((funnel_menu_t *) g_malloc_n ((1), sizeof (funnel_menu_t))); | |||
| 123 | ||||
| 124 | m->name = g_strdup(name)g_strdup_inline (name); | |||
| 125 | m->group = group; | |||
| 126 | m->callback = callback; | |||
| 127 | m->callback_data = callback_data; | |||
| 128 | m->callback_data_free = callback_data_free; | |||
| 129 | m->retap = retap; | |||
| 130 | ||||
| 131 | registered_menus = g_slist_append(registered_menus, m); | |||
| 132 | ||||
| 133 | if (menus_registered) { | |||
| 134 | funnel_menu_t* m_r = (funnel_menu_t *)g_memdup2(m, sizeof *m); | |||
| 135 | m_r->name = g_strdup(name)g_strdup_inline (name); | |||
| 136 | added_menus = g_slist_append(added_menus, m_r); | |||
| 137 | } | |||
| 138 | } | |||
| 139 | ||||
| 140 | void funnel_deregister_menus(funnel_menu_callback callback) | |||
| 141 | { | |||
| 142 | funnel_menu_t* m = g_new0(funnel_menu_t, 1)((funnel_menu_t *) g_malloc0_n ((1), sizeof (funnel_menu_t))); | |||
| 143 | ||||
| 144 | m->callback = callback; | |||
| 145 | ||||
| 146 | funnel_remove_menu(®istered_menus, m); | |||
| ||||
| 147 | removed_menus = g_slist_append(removed_menus, m); | |||
| 148 | ||||
| 149 | // Clear and free memory of packet menus | |||
| 150 | funnel_clear_menu(®istered_packet_menus, free_funnel_packet_menu); | |||
| 151 | packet_menus_modified = true1; | |||
| 152 | } | |||
| 153 | ||||
| 154 | static void funnel_register_all_menus(funnel_registration_cb_t r_cb) | |||
| 155 | { | |||
| 156 | if (r_cb == NULL((void*)0)) { | |||
| 157 | return; | |||
| 158 | } | |||
| 159 | ||||
| 160 | for (GSList* l = registered_menus; l; l = l->next) { | |||
| 161 | funnel_menu_t* c = (funnel_menu_t*)l->data; | |||
| 162 | r_cb(c->name,c->group,c->callback,c->callback_data,c->retap); | |||
| 163 | } | |||
| 164 | } | |||
| 165 | ||||
| 166 | void funnel_reload_menus(funnel_deregistration_cb_t d_cb, | |||
| 167 | funnel_registration_cb_t r_cb) | |||
| 168 | { | |||
| 169 | for (GSList* l = removed_menus; l; l = l->next) { | |||
| 170 | funnel_menu_t* c = (funnel_menu_t*)l->data; | |||
| 171 | d_cb(c->callback); | |||
| 172 | } | |||
| 173 | ||||
| 174 | for (GSList* l = added_menus; l; l = l->next) { | |||
| 175 | funnel_menu_t* c = (funnel_menu_t*)l->data; | |||
| 176 | r_cb(c->name,c->group,c->callback,c->callback_data,c->retap); | |||
| 177 | } | |||
| 178 | ||||
| 179 | funnel_clear_menu(&removed_menus, free_funnel_menu); | |||
| 180 | funnel_clear_menu(&added_menus, free_funnel_menu); | |||
| 181 | } | |||
| 182 | ||||
| 183 | /** | |||
| 184 | * Entry point for Lua code to register a packet menu | |||
| 185 | * | |||
| 186 | * Stores the menu name and callback from the Lua code | |||
| 187 | * into registered_packet_menus so that the | |||
| 188 | * Wireshark GUI code can retrieve it with | |||
| 189 | * funnel_register_all_packet_menus(). | |||
| 190 | */ | |||
| 191 | void funnel_register_packet_menu(const char *name, | |||
| 192 | const char *required_fields, | |||
| 193 | funnel_packet_menu_callback callback, | |||
| 194 | void *callback_data, | |||
| 195 | bool_Bool retap) | |||
| 196 | { | |||
| 197 | funnel_packet_menu_t* m = g_new0(funnel_packet_menu_t, 1)((funnel_packet_menu_t *) g_malloc0_n ((1), sizeof (funnel_packet_menu_t ))); | |||
| 198 | ||||
| 199 | m->name = g_strdup(name)g_strdup_inline (name); | |||
| 200 | m->required_fields = g_strdup(required_fields)g_strdup_inline (required_fields); | |||
| 201 | m->callback = callback; | |||
| 202 | m->callback_data = callback_data; | |||
| 203 | m->retap = retap; | |||
| 204 | ||||
| 205 | registered_packet_menus = g_slist_append(registered_packet_menus, m); | |||
| 206 | ||||
| 207 | packet_menus_modified = true1; | |||
| 208 | } | |||
| 209 | ||||
| 210 | static void free_funnel_packet_menu(gpointer data, gpointer user_data _U___attribute__((unused))) | |||
| 211 | { | |||
| 212 | funnel_packet_menu_t* m = (funnel_packet_menu_t*)data; | |||
| 213 | ||||
| 214 | g_free(m->name); | |||
| 215 | g_free(m->required_fields); | |||
| 216 | if (m->callback_data) { | |||
| 217 | g_free(m->callback_data); | |||
| 218 | } | |||
| 219 | g_free(m); | |||
| 220 | } | |||
| 221 | ||||
| 222 | /** | |||
| 223 | * Entry point for Wireshark GUI to obtain all registered packet menus | |||
| 224 | * | |||
| 225 | * Calls the supplied callback for each packet menu registered with | |||
| 226 | * funnel_register_packet_menu(). | |||
| 227 | * | |||
| 228 | * @param r_cb the callback function to call with each registered packet menu | |||
| 229 | */ | |||
| 230 | void funnel_register_all_packet_menus(funnel_registration_packet_cb_t r_cb) | |||
| 231 | { | |||
| 232 | for (GSList* l = registered_packet_menus; l; l = l->next) { | |||
| 233 | funnel_packet_menu_t* c = (funnel_packet_menu_t*)l->data; | |||
| 234 | r_cb(c->name, c->required_fields, c->callback, c->callback_data, c->retap); | |||
| 235 | } | |||
| 236 | ||||
| 237 | packet_menus_modified = false0; | |||
| 238 | } | |||
| 239 | ||||
| 240 | /** | |||
| 241 | * Returns whether the packet menus have been modified since they were last registered | |||
| 242 | * | |||
| 243 | * @return true if the packet menus were modified since the last registration | |||
| 244 | */ | |||
| 245 | bool_Bool funnel_packet_menus_modified(void) | |||
| 246 | { | |||
| 247 | return packet_menus_modified; | |||
| 248 | } | |||
| 249 | ||||
| 250 | /** | |||
| 251 | * Entry point for code to register a console menu | |||
| 252 | */ | |||
| 253 | void funnel_register_console_menu(const char *name, | |||
| 254 | funnel_console_eval_cb_t eval_cb, | |||
| 255 | funnel_console_open_cb_t open_cb, | |||
| 256 | funnel_console_close_cb_t close_cb, | |||
| 257 | void *callback_data, | |||
| 258 | funnel_console_data_free_cb_t free_data) | |||
| 259 | { | |||
| 260 | funnel_console_menu_t* m = g_new0(funnel_console_menu_t, 1)((funnel_console_menu_t *) g_malloc0_n ((1), sizeof (funnel_console_menu_t ))); | |||
| 261 | ||||
| 262 | m->name = g_strdup(name)g_strdup_inline (name); | |||
| 263 | m->eval_cb = eval_cb; | |||
| 264 | m->open_cb = open_cb; | |||
| 265 | m->close_cb = close_cb; | |||
| 266 | m->user_data = callback_data; | |||
| 267 | m->data_free_cb = free_data; | |||
| 268 | ||||
| 269 | registered_console_menus = g_slist_prepend(registered_console_menus, m); | |||
| 270 | } | |||
| 271 | ||||
| 272 | static void funnel_register_all_console_menus(funnel_registration_console_cb_t r_cb) | |||
| 273 | { | |||
| 274 | if (r_cb == NULL((void*)0)) { | |||
| 275 | return; | |||
| 276 | } | |||
| 277 | ||||
| 278 | for (GSList* l = registered_console_menus; l != NULL((void*)0); l = l->next) { | |||
| 279 | funnel_console_menu_t *m = l->data; | |||
| 280 | r_cb(m->name, m->eval_cb, m->open_cb, m->close_cb, m->user_data); | |||
| 281 | } | |||
| 282 | } | |||
| 283 | ||||
| 284 | static void free_funnel_console_menu(gpointer data, gpointer user_data _U___attribute__((unused))) | |||
| 285 | { | |||
| 286 | funnel_console_menu_t* m = data; | |||
| 287 | ||||
| 288 | g_free(m->name); | |||
| 289 | if (m->data_free_cb) { | |||
| 290 | m->data_free_cb(m->user_data); | |||
| 291 | } | |||
| 292 | g_free(m); | |||
| 293 | } | |||
| 294 | ||||
| 295 | void funnel_ops_init(const funnel_ops_t* o, funnel_registration_cb_t r_cb, funnel_registration_console_cb_t rconsole_cb) | |||
| 296 | { | |||
| 297 | ops = o; | |||
| 298 | funnel_register_all_menus(r_cb); | |||
| 299 | funnel_register_all_console_menus(rconsole_cb); | |||
| 300 | menus_registered = true1; | |||
| 301 | } | |||
| 302 | ||||
| 303 | bool_Bool funnel_menu_registered(void) | |||
| 304 | { | |||
| 305 | return menus_registered; | |||
| 306 | } | |||
| 307 | ||||
| 308 | void funnel_cleanup(void) | |||
| 309 | { | |||
| 310 | funnel_clear_menu(®istered_menus, free_funnel_menu); | |||
| 311 | funnel_clear_menu(®istered_packet_menus, free_funnel_packet_menu); | |||
| 312 | funnel_clear_menu(®istered_console_menus, free_funnel_console_menu); | |||
| 313 | } | |||
| 314 | ||||
| 315 | /* | |||
| 316 | * Editor modelines - https://www.wireshark.org/tools/modelines.html | |||
| 317 | * | |||
| 318 | * Local variables: | |||
| 319 | * c-basic-offset: 4 | |||
| 320 | * tab-width: 8 | |||
| 321 | * indent-tabs-mode: nil | |||
| 322 | * End: | |||
| 323 | * | |||
| 324 | * vi: set shiftwidth=4 tabstop=8 expandtab: | |||
| 325 | * :indentSize=4:tabSize=8:noTabs=true: | |||
| 326 | */ |