diff options
author | Stig Bjørlykke <stig@bjorlykke.org> | 2015-08-11 14:08:08 +0200 |
---|---|---|
committer | Stig Bjørlykke <stig@bjorlykke.org> | 2015-08-11 12:09:07 +0000 |
commit | ecc4f756bdb6175cc0b3b11af2f90884db1c602c (patch) | |
tree | 99d8ca48a72752e1257d4b8b321f41d1767ee020 | |
parent | 70d06deb2e31bd605e672200a7755764febe94ae (diff) |
Added Reload Lua plugins.
This is initial support for reloading Lua plugins without
restarting the application.
Still todo:
- Deregister FileHandlers
- Support deregister ProtoField with existing abbrev (same_name_hfinfo)
- Add a progress dialog when reloading many plugins
- Search for memory leakages in wslua functions
Change-Id: I48870d8741251705ca15ffe1068613fcb0cb18c1
Reviewed-on: https://code.wireshark.org/review/5028
Reviewed-by: Stig Bjørlykke <stig@bjorlykke.org>
45 files changed, 980 insertions, 201 deletions
diff --git a/asn1/ldap/packet-ldap-template.c b/asn1/ldap/packet-ldap-template.c index 7e4b823db9..eff9506ff7 100644 --- a/asn1/ldap/packet-ldap-template.c +++ b/asn1/ldap/packet-ldap-template.c @@ -557,9 +557,9 @@ attribute_types_initialize_cb(void) if (attribute_types_hash && hf) { guint hf_size = g_hash_table_size (attribute_types_hash); - /* Unregister all fields */ + /* Deregister all fields */ for (i = 0; i < hf_size; i++) { - proto_unregister_field (proto_ldap, *(hf[i].p_id)); + proto_deregister_field (proto_ldap, *(hf[i].p_id)); g_free (hf[i].p_id); } g_hash_table_destroy (attribute_types_hash); diff --git a/debian/libwireshark0.symbols b/debian/libwireshark0.symbols index 0d95c9a4e4..98d313c888 100644 --- a/debian/libwireshark0.symbols +++ b/debian/libwireshark0.symbols @@ -233,6 +233,10 @@ libwireshark.so.0 libwireshark0 #MINVER# decode_tcp_ports@Base 1.99.0 decode_udp_ports@Base 1.99.0 delete_itu_tcap_subdissector@Base 1.9.1 + deregister_dissector@Base 1.99.9 + deregister_dissector_table@Base 1.99.9 + deregister_postdissector@Base 1.99.9 + destroy_dissector_handle@Base 1.99.9 destroy_print_stream@Base 1.12.0~rc1 dfilter_apply_edt@Base 1.9.1 dfilter_compile@Base 1.9.1 @@ -507,6 +511,7 @@ libwireshark.so.0 libwireshark0 #MINVER# expert_add_info@Base 1.12.0~rc1 expert_add_info_format@Base 1.9.1 expert_checksum_vals@Base 1.12.0~rc1 + expert_deregister_protocol@Base 1.99.9 expert_get_highest_severity@Base 1.9.1 expert_group_vals@Base 1.12.0~rc1 expert_register_field_array@Base 1.12.0~rc1 @@ -584,9 +589,11 @@ libwireshark.so.0 libwireshark0 #MINVER# ftype_can_slice@Base 1.9.1 ftype_name@Base 1.9.1 ftype_pretty_name@Base 1.9.1 + funnel_deregister_menus@Base 1.99.9 funnel_get_funnel_ops@Base 1.9.1 funnel_register_all_menus@Base 1.9.1 funnel_register_menu@Base 1.9.1 + funnel_reload_menus@Base 1.99.9 funnel_set_funnel_ops@Base 1.9.1 fvalue_from_unparsed@Base 1.9.1 fvalue_get@Base 1.9.1 @@ -868,6 +875,7 @@ libwireshark.so.0 libwireshark0 #MINVER# prefs_capture_device_monitor_mode@Base 1.9.1 prefs_capture_options_dialog_column_is_visible@Base 1.9.1 prefs_clear_string_list@Base 1.9.1 + prefs_deregister_protocol@Base 1.99.9 prefs_find_module@Base 1.9.1 prefs_find_preference@Base 1.9.1 prefs_get_string_list@Base 1.9.1 @@ -910,11 +918,13 @@ libwireshark.so.0 libwireshark0 #MINVER# process_reassembled_data@Base 1.9.1 process_stat_cmd_arg@Base 1.9.1 proto_all_finfos@Base 1.9.1 - proto_add_deregistered_data@Base 1.12.0~rc1 + proto_add_deregistered_data@Base 1.12.2 proto_can_match_selected@Base 1.9.1 proto_can_toggle_protocol@Base 1.9.1 proto_check_field_name@Base 1.9.1 proto_construct_match_selected_string@Base 1.9.1 + proto_deregister_field@Base 1.99.9 + proto_deregister_protocol@Base 1.99.9 proto_disable_proto_by_name@Base 1.99.8 proto_enable_all@Base 1.9.1 proto_enable_heuristic_by_name@Base 1.99.8 @@ -923,7 +933,7 @@ libwireshark.so.0 libwireshark0 #MINVER# proto_find_field_from_offset@Base 1.9.1 proto_find_finfo@Base 1.9.1 proto_find_undecoded_data@Base 1.99.3 - proto_free_deregistered_fields@Base 1.12.0~rc1 + proto_free_deregistered_fields@Base 1.12.2 proto_get_data_protocol@Base 1.9.1 proto_get_finfo_ptr_array@Base 1.9.1 proto_get_first_protocol@Base 1.9.1 @@ -1061,7 +1071,6 @@ libwireshark.so.0 libwireshark0 #MINVER# proto_tree_print@Base 1.12.0~rc1 proto_tree_set_appendix@Base 1.9.1 proto_tree_set_visible@Base 1.9.1 - proto_unregister_field@Base 1.9.1 protocols_module@Base 1.9.1 ptvcursor_add@Base 1.9.1 ptvcursor_add_no_advance@Base 1.9.1 @@ -1610,6 +1619,7 @@ libwireshark.so.0 libwireshark0 #MINVER# wmem_tree_lookup_string@Base 1.12.0~rc1 wmem_tree_new@Base 1.12.0~rc1 wmem_tree_new_autoreset@Base 1.12.0~rc1 + wmem_tree_remove_string@Base 1.99.9 wmem_unregister_callback@Base 1.12.0~rc1 write_carrays_hex_data@Base 1.99.1 write_csv_column_titles@Base 1.99.1 @@ -1629,6 +1639,7 @@ libwireshark.so.0 libwireshark0 #MINVER# wslua_count_plugins@Base 1.12.0~rc1 wslua_plugins_dump_all@Base 1.12.0~rc1 wslua_plugins_get_descriptions@Base 1.12.0~rc1 + wslua_reload_plugins@Base 1.99.9 wsp_vals_pdu_type_ext@Base 1.9.1 wsp_vals_status_ext@Base 1.9.1 xml_escape@Base 1.9.1 diff --git a/epan/dissectors/packet-http.c b/epan/dissectors/packet-http.c index e47fb13891..00e5e85a0a 100644 --- a/epan/dissectors/packet-http.c +++ b/epan/dissectors/packet-http.c @@ -2354,9 +2354,9 @@ header_fields_initialize_cb(void) if (header_fields_hash && hf) { guint hf_size = g_hash_table_size (header_fields_hash); - /* Unregister all fields */ + /* Deregister all fields */ for (i = 0; i < hf_size; i++) { - proto_unregister_field (proto_http, *(hf[i].p_id)); + proto_deregister_field (proto_http, *(hf[i].p_id)); g_free (hf[i].p_id); } g_hash_table_destroy (header_fields_hash); diff --git a/epan/dissectors/packet-imf.c b/epan/dissectors/packet-imf.c index 942ab19068..be1fdba95a 100644 --- a/epan/dissectors/packet-imf.c +++ b/epan/dissectors/packet-imf.c @@ -872,9 +872,9 @@ header_fields_initialize_cb (void) if (custom_field_table && hf) { guint hf_size = g_hash_table_size (custom_field_table); - /* Unregister all fields */ + /* Deregister all fields */ for (i = 0; i < hf_size; i++) { - proto_unregister_field (proto_imf, *(hf[i].p_id)); + proto_deregister_field (proto_imf, *(hf[i].p_id)); g_free (hf[i].p_id); } g_hash_table_destroy (custom_field_table); diff --git a/epan/dissectors/packet-ldap.c b/epan/dissectors/packet-ldap.c index d415971c12..8b247f8743 100644 --- a/epan/dissectors/packet-ldap.c +++ b/epan/dissectors/packet-ldap.c @@ -771,9 +771,9 @@ attribute_types_initialize_cb(void) if (attribute_types_hash && hf) { guint hf_size = g_hash_table_size (attribute_types_hash); - /* Unregister all fields */ + /* Deregister all fields */ for (i = 0; i < hf_size; i++) { - proto_unregister_field (proto_ldap, *(hf[i].p_id)); + proto_deregister_field (proto_ldap, *(hf[i].p_id)); g_free (hf[i].p_id); } g_hash_table_destroy (attribute_types_hash); diff --git a/epan/expert.c b/epan/expert.c index c54b5e18df..fe6943caa1 100644 --- a/epan/expert.c +++ b/epan/expert.c @@ -322,6 +322,11 @@ expert_module_t *expert_register_protocol(int id) return module; } +void expert_deregister_protocol (expert_module_t *module) +{ + wmem_free(wmem_epan_scope(), module); +} + static int expert_register_field_init(expert_field_info *expinfo, expert_module_t *module) { diff --git a/epan/expert.h b/epan/expert.h index dc994ba4fc..e1d9ff9106 100644 --- a/epan/expert.h +++ b/epan/expert.h @@ -171,6 +171,11 @@ proto_tree_add_expert_format(proto_tree *tree, packet_info *pinfo, expert_field */ WS_DLL_PUBLIC expert_module_t *expert_register_protocol(int id); +/** + * Deregister expert info from a protocol. + */ +WS_DLL_PUBLIC void expert_deregister_protocol (expert_module_t *module); + /** Register a expert field array. @param module the protocol handle from expert_register_protocol() @param ei the ei_register_info array diff --git a/epan/funnel.c b/epan/funnel.c index 02cd4f1171..fd1f8612bd 100644 --- a/epan/funnel.c +++ b/epan/funnel.c @@ -31,7 +31,7 @@ typedef struct _funnel_menu_t { const char *name; register_stat_group_t group; - void (*callback)(gpointer); + funnel_menu_callback callback; gpointer callback_data; gboolean retap; struct _funnel_menu_t* next; @@ -39,16 +39,69 @@ typedef struct _funnel_menu_t { /* XXX This assumes one main window and one capture file. */ static const funnel_ops_t* ops = NULL; -static funnel_menu_t* menus = NULL; +static funnel_menu_t* registered_menus = NULL; +static funnel_menu_t* added_menus = NULL; +static funnel_menu_t* removed_menus = NULL; +static gboolean menus_registered = FALSE; const funnel_ops_t* funnel_get_funnel_ops(void) { return ops; } void funnel_set_funnel_ops(const funnel_ops_t* o) { ops = o; } +static void funnel_insert_menu (funnel_menu_t** menu_list, funnel_menu_t *menu) +{ + if (!(*menu_list)) { + *menu_list = menu; + } else { + funnel_menu_t* c; + for (c = *menu_list; c->next; c = c->next); + c->next = menu; + } +} + +static void funnel_remove_menu (funnel_menu_t ** menu_list, funnel_menu_t *menu) +{ + funnel_menu_t *m = *menu_list, *p = NULL; + + while (m) { + if (m->callback == menu->callback) { + if (p) { + p->next = m->next; + } else { + *menu_list = m->next; + } + g_free((char *)m->name); + g_free(m); + if (p) { + m = p->next; + } else { + m = *menu_list ? (*menu_list)->next : NULL; + } + } else { + p = m; + m = m->next; + } + } +} + +static void funnel_clear_menu (funnel_menu_t** menu_list) +{ + funnel_menu_t *m; + + while (*menu_list) { + m = *menu_list; + *menu_list = m->next; + g_free((char *)m->name); + g_free(m); + } + *menu_list = NULL; +} + void funnel_register_menu(const char *name, register_stat_group_t group, - void (*callback)(gpointer), + funnel_menu_callback callback, gpointer callback_data, - gboolean retap) { + gboolean retap) +{ funnel_menu_t* m = (funnel_menu_t *)g_malloc(sizeof(funnel_menu_t)); m->name = g_strdup(name); m->group = group; @@ -57,20 +110,45 @@ void funnel_register_menu(const char *name, m->retap = retap; m->next = NULL; - if (!menus) { - menus = m; - } else { - funnel_menu_t* c; - for (c = menus; c->next; c = c->next); - c->next = m; + funnel_insert_menu(®istered_menus, m); + if (menus_registered) { + funnel_menu_t* m_r = (funnel_menu_t *)g_memdup(m, sizeof *m); + m_r->name = g_strdup(name); + funnel_insert_menu(&added_menus, m_r); } } -void funnel_register_all_menus(funnel_registration_cb_t r_cb) { +void funnel_deregister_menus(funnel_menu_callback callback) +{ + funnel_menu_t* m = (funnel_menu_t *)g_malloc0(sizeof(funnel_menu_t)); + m->callback = callback; + + funnel_remove_menu(®istered_menus, m); + funnel_insert_menu(&removed_menus, m); +} + +void funnel_register_all_menus(funnel_registration_cb_t r_cb) +{ funnel_menu_t* c; - for (c = menus; c; c = c->next) { + for (c = registered_menus; c; c = c->next) { r_cb(c->name,c->group,c->callback,c->callback_data,c->retap); } + menus_registered = TRUE; +} + +void funnel_reload_menus(funnel_deregistration_cb_t d_cb, + funnel_registration_cb_t r_cb) +{ + funnel_menu_t* c; + for (c = removed_menus; c; c = c->next) { + d_cb(c->callback); + } + for (c = added_menus; c; c = c->next) { + r_cb(c->name,c->group,c->callback,c->callback_data,c->retap); + } + + funnel_clear_menu(&removed_menus); + funnel_clear_menu(&added_menus); } /* diff --git a/epan/funnel.h b/epan/funnel.h index b7e2ac1d01..d7d00020e4 100644 --- a/epan/funnel.h +++ b/epan/funnel.h @@ -46,6 +46,8 @@ typedef void (*funnel_dlg_cb_t)(gchar** user_input, void* data); typedef gboolean (*funnel_bt_cb_t)(funnel_text_window_t* tw, void* data); +typedef void (* funnel_menu_callback)(gpointer); + typedef struct _funnel_bt_t { funnel_text_window_t* tw; funnel_bt_cb_t func; @@ -74,6 +76,7 @@ typedef struct _funnel_ops_t { funnel_dlg_cb_t dlg_cb, void* data); + void (*close_dialogs)(void); void (*logger)(const gchar *log_domain, GLogLevelFlags log_level, @@ -104,17 +107,21 @@ WS_DLL_PUBLIC void funnel_set_funnel_ops(const funnel_ops_t*); WS_DLL_PUBLIC void funnel_register_menu(const char *name, register_stat_group_t group, - void (*callback)(gpointer), + funnel_menu_callback callback, gpointer callback_data, gboolean retap); +WS_DLL_PUBLIC void funnel_deregister_menus(void (*callback)(gpointer)); typedef void (*funnel_registration_cb_t)(const char *name, register_stat_group_t group, - void (*callback)(gpointer), + funnel_menu_callback callback, gpointer callback_data, gboolean retap); +typedef void (*funnel_deregistration_cb_t)(funnel_menu_callback callback); WS_DLL_PUBLIC void funnel_register_all_menus(funnel_registration_cb_t r_cb); +WS_DLL_PUBLIC void funnel_reload_menus(funnel_deregistration_cb_t d_cb, + funnel_registration_cb_t r_cb); extern void initialize_funnel_ops(void); diff --git a/epan/packet.c b/epan/packet.c index 61547aef1e..40d005acdc 100644 --- a/epan/packet.c +++ b/epan/packet.c @@ -1021,6 +1021,14 @@ dissector_delete_all_check (gpointer key _U_, gpointer value, gpointer user_data dtbl_entry_t *dtbl_entry = (dtbl_entry_t *) value; dissector_handle_t handle = (dissector_handle_t) user_data; + if (!dtbl_entry->current->protocol) { + /* + * Not all dissectors are registered with a protocol, so we need this + * check when running from dissector_delete_from_all_tables. + */ + return FALSE; + } + return (proto_get_id (dtbl_entry->current->protocol) == proto_get_id (handle->protocol)); } @@ -1033,6 +1041,23 @@ void dissector_delete_all(const char *name, dissector_handle_t handle) g_hash_table_foreach_remove (sub_dissectors->hash_table, dissector_delete_all_check, handle); } +static void +dissector_delete_from_table(gpointer key _U_, gpointer value, gpointer user_data) +{ + dissector_table_t sub_dissectors = (dissector_table_t) value; + g_assert (sub_dissectors); + + g_hash_table_foreach_remove(sub_dissectors->hash_table, dissector_delete_all_check, user_data); + sub_dissectors->dissector_handles = g_slist_remove(sub_dissectors->dissector_handles, user_data); +} + +/* Delete handle from all tables and dissector_handles lists */ +static void +dissector_delete_from_all_tables(dissector_handle_t handle) +{ + g_hash_table_foreach(dissector_tables, dissector_delete_from_table, handle); +} + /* Change the entry for a dissector in a uint dissector table with a particular pattern to use a new dissector handle. */ void @@ -1927,6 +1952,15 @@ dissector_table_t register_custom_dissector_table(const char *name, return sub_dissectors; } +void +deregister_dissector_table(const char *name) +{ + dissector_table_t sub_dissectors = find_dissector_table(name); + if (!sub_dissectors) return; + + g_hash_table_remove(dissector_tables, (gpointer)name); +} + const char * get_dissector_table_ui_name(const char *name) { @@ -2428,6 +2462,7 @@ create_dissector_handle(dissector_t dissector, const int proto) return handle; } +/* Create an anonymous handle for a new dissector. */ dissector_handle_t new_create_dissector_handle(new_dissector_t dissector, const int proto) { @@ -2456,6 +2491,17 @@ dissector_handle_t new_create_dissector_handle_with_name(new_dissector_t dissect return handle; } +/* Destroy an anonymous handle for a dissector. */ +void +destroy_dissector_handle(dissector_handle_t handle) +{ + if (handle == NULL) return; + + dissector_delete_from_all_tables(handle); + deregister_postdissector(handle); + wmem_free(wmem_epan_scope(), handle); +} + /* Register a dissector by name. */ dissector_handle_t register_dissector(const char *name, dissector_t dissector, const int proto) @@ -2477,6 +2523,7 @@ register_dissector(const char *name, dissector_t dissector, const int proto) return handle; } +/* Register a new dissector by name. */ dissector_handle_t new_register_dissector(const char *name, new_dissector_t dissector, const int proto) { @@ -2497,6 +2544,19 @@ new_register_dissector(const char *name, new_dissector_t dissector, const int pr return handle; } +/* Deregister a dissector by name. */ +void +deregister_dissector(const char *name) +{ + dissector_handle_t handle = find_dissector(name); + if (handle == NULL) return; + + g_hash_table_remove(registered_dissectors, (gpointer)name); + g_hash_table_remove(heur_dissector_lists, (gpointer)name); + + destroy_dissector_handle(handle); +} + /* Call a dissector through a handle but if the dissector rejected it * return 0. */ @@ -2743,6 +2803,16 @@ register_postdissector(dissector_handle_t handle) num_of_postdissectors++; } +void +deregister_postdissector(dissector_handle_t handle) +{ + if (!post_dissectors) return; + + if (g_ptr_array_remove(post_dissectors, handle)) { + num_of_postdissectors--; + } +} + gboolean have_postdissector(void) { diff --git a/epan/packet.h b/epan/packet.h index b2dfe43986..cd81bc2ddb 100644 --- a/epan/packet.h +++ b/epan/packet.h @@ -213,6 +213,9 @@ WS_DLL_PUBLIC dissector_table_t register_dissector_table(const char *name, WS_DLL_PUBLIC dissector_table_t register_custom_dissector_table(const char *name, const char *ui_name, GHashFunc hash_func, GEqualFunc key_equal_func); +/** Deregister the dissector table by table name. */ +WS_DLL_PUBLIC void deregister_dissector_table(const char *name); + /* Find a dissector table by table name. */ WS_DLL_PUBLIC dissector_table_t find_dissector_table(const char *name); @@ -484,10 +487,13 @@ WS_DLL_PUBLIC void heur_dissector_delete(const char *name, heur_dissector_t diss extern void heur_dissector_set_enabled(const char *name, heur_dissector_t dissector, const int proto, const gboolean enabled); /** Register a dissector. */ -WS_DLL_PUBLIC dissector_handle_t register_dissector(const char *name, dissector_t dissector, - const int proto); -WS_DLL_PUBLIC dissector_handle_t new_register_dissector(const char *name, new_dissector_t dissector, - const int proto); +WS_DLL_PUBLIC dissector_handle_t register_dissector(const char *name, dissector_t dissector, const int proto); + +/** Register a new dissector. */ +WS_DLL_PUBLIC dissector_handle_t new_register_dissector(const char *name, new_dissector_t dissector, const int proto); + +/** Deregister a dissector. */ +WS_DLL_PUBLIC void deregister_dissector(const char *name); /** Get the long name of the protocol for a dissector handle. */ extern const char *dissector_handle_get_long_name(const dissector_handle_t handle); @@ -515,6 +521,9 @@ WS_DLL_PUBLIC dissector_handle_t new_create_dissector_handle(new_dissector_t dis WS_DLL_PUBLIC dissector_handle_t new_create_dissector_handle_with_name(new_dissector_t dissector, const int proto, const char* name); +/** Destroy an anonymous handle for a dissector. */ +WS_DLL_PUBLIC void destroy_dissector_handle(dissector_handle_t handle); + /** Call a dissector through a handle and if no dissector was found * pass it over to the "data" dissector instead. * @@ -699,6 +708,8 @@ WS_DLL_PUBLIC void dissector_dump_heur_decodes(void); * dissector has been called. */ WS_DLL_PUBLIC void register_postdissector(dissector_handle_t); +WS_DLL_PUBLIC void deregister_postdissector(dissector_handle_t handle); + extern gboolean have_postdissector(void); extern void call_all_postdissectors(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree); diff --git a/epan/prefs.c b/epan/prefs.c index 24cfdd8441..7c5613940c 100644 --- a/epan/prefs.c +++ b/epan/prefs.c @@ -305,6 +305,27 @@ prefs_register_module(module_t *parent, const char *name, const char *title, FALSE, apply_cb, use_gui); } +static void +prefs_deregister_module(module_t *parent, const char *name, const char *title) +{ + /* Remove this module from the list of all modules */ + module_t *module = (module_t *)wmem_tree_remove_string(prefs_modules, name, WMEM_TREE_STRING_NOCASE); + + if (!module) + return; + + if (parent == NULL) { + /* Remove from top */ + wmem_tree_remove_string(prefs_top_level_modules, title, WMEM_TREE_STRING_NOCASE); + } else if (parent->submodules) { + /* Remove from parent */ + wmem_tree_remove_string(parent->submodules, title, WMEM_TREE_STRING_NOCASE); + } + + free_module_prefs(module, NULL); + wmem_free(wmem_epan_scope(), module); +} + /* * Register a subtree that will have modules under it. * Specify the module under which to register it or NULL to register it @@ -454,6 +475,15 @@ prefs_register_protocol(int id, void (*apply_cb)(void)) proto_get_protocol_name(id), apply_cb, TRUE); } +void +prefs_deregister_protocol (int id) +{ + protocol_t *protocol = find_protocol_by_id(id); + prefs_deregister_module (protocols_module, + proto_get_protocol_filter_name(id), + proto_get_protocol_short_name(protocol)); +} + module_t * prefs_register_protocol_subtree(const char *subtree, int id, void (*apply_cb)(void)) { @@ -3331,6 +3361,7 @@ read_prefs_file(const char *pf_path, FILE *pf, /* Try to read in the profile name in the first line of the preferences file. */ if (fscanf(pf, "# Configuration file for %127[^\r\n]", ver) == 1) { /* Assume trailing period and remove it */ + g_free(prefs.saved_at_version); prefs.saved_at_version = g_strndup(ver, strlen(ver) - 1); } rewind(pf); diff --git a/epan/prefs.h b/epan/prefs.h index 03881edfb7..ec4e0c4f1f 100644 --- a/epan/prefs.h +++ b/epan/prefs.h @@ -289,6 +289,11 @@ module_t *prefs_register_subtree(module_t *parent, const char *title, */ WS_DLL_PUBLIC module_t *prefs_register_protocol(int id, void (*apply_cb)(void)); +/** + * Deregister preferences from a protocol. + */ +WS_DLL_PUBLIC void prefs_deregister_protocol(int id); + /* * Register that a statistical tap has preferences. * diff --git a/epan/proto.c b/epan/proto.c index 26fe71f974..28c9ff792a 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -324,6 +324,7 @@ static GPtrArray *deregistered_data = NULL; if((guint)hfindex >= gpa_hfinfo.len && getenv("WIRESHARK_ABORT_ON_DISSECTOR_BUG")) \ g_error("Unregistered hf! index=%d", hfindex); \ DISSECTOR_ASSERT_HINT((guint)hfindex < gpa_hfinfo.len, "Unregistered hf!"); \ + DISSECTOR_ASSERT_HINT(gpa_hfinfo.hfi[hfindex] != NULL, "Unregistered hf!"); \ hfinfo = gpa_hfinfo.hfi[hfindex]; /* List which stores protocols and fields that have been registered */ @@ -5240,6 +5241,48 @@ proto_register_protocol(const char *name, const char *short_name, return proto_id; } +gboolean +proto_deregister_protocol(const char *short_name) +{ + protocol_t *protocol; + header_field_info *hfinfo; + int proto_id; + gint *key; + guint i; + + proto_id = proto_get_id_by_short_name(short_name); + protocol = find_protocol_by_id(proto_id); + if (protocol == NULL) + return FALSE; + + key = (gint *)g_malloc(sizeof(gint)); + *key = wrs_str_hash(protocol->name); + + g_hash_table_remove(proto_names, key); + g_free(key); + + g_hash_table_remove(proto_short_names, (gpointer)short_name); + g_hash_table_remove(proto_filter_names, (gpointer)protocol->filter_name); + + for (i = 0; i < protocol->fields->len; i++) { + hfinfo = (header_field_info *)g_ptr_array_index(protocol->fields, i); + g_hash_table_steal(gpa_name_map, hfinfo->abbrev); + g_ptr_array_add(deregistered_fields, gpa_hfinfo.hfi[hfinfo->id]); + } + g_ptr_array_free(protocol->fields, TRUE); + + /* Remove this protocol from the list of known protocols */ + protocols = g_list_remove(protocols, protocol); + + g_ptr_array_add(deregistered_fields, gpa_hfinfo.hfi[proto_id]); + g_hash_table_steal(gpa_name_map, protocol->filter_name); + + g_free((gchar *)protocol->short_name); + g_free(protocol); + + return TRUE; +} + void proto_mark_private(const int proto_id) { @@ -5641,9 +5684,9 @@ proto_register_fields_manual(const int parent, header_field_info **hfi, const in } } -/* unregister already registered fields */ +/* deregister already registered fields */ void -proto_unregister_field (const int parent, gint hf_id) +proto_deregister_field (const int parent, gint hf_id) { header_field_info *hfi; protocol_t *proto; diff --git a/epan/proto.h b/epan/proto.h index 554754a2e1..2e9e1bbe09 100644 --- a/epan/proto.h +++ b/epan/proto.h @@ -1998,6 +1998,12 @@ proto_item_fill_label(field_info *fi, gchar *label_str); WS_DLL_PUBLIC int proto_register_protocol(const char *name, const char *short_name, const char *filter_name); +/** Deregister a protocol. + @param short_name abbreviated name of the protocol + @return TRUE if protocol is removed */ +WS_DLL_PUBLIC gboolean +proto_deregister_protocol(const char *short_name); + /** Mark protocol as private @param proto_id the handle of the protocol */ WS_DLL_PUBLIC @@ -2035,18 +2041,18 @@ WS_DLL_PUBLIC void proto_register_fields_section(const int parent, header_field_ WS_DLL_PUBLIC void proto_register_field_array(const int parent, hf_register_info *hf, const int num_records); -/** Unregister an already registered field. +/** Deregister an already registered field. @param parent the protocol handle from proto_register_protocol() @param hf_id the field to deregister */ WS_DLL_PUBLIC void -proto_unregister_field (const int parent, gint hf_id); +proto_deregister_field (const int parent, gint hf_id); /** Add data to be freed when deregistered fields are freed. @param data a pointer to data to free */ WS_DLL_PUBLIC void proto_add_deregistered_data (void *data); -/** Free fields deregistered in proto_unregister_field(). */ +/** Free fields deregistered in proto_deregister_field(). */ WS_DLL_PUBLIC void proto_free_deregistered_fields (void); diff --git a/epan/wmem/wmem_tree.c b/epan/wmem/wmem_tree.c index 1db2923a31..d82dc95b75 100644 --- a/epan/wmem/wmem_tree.c +++ b/epan/wmem/wmem_tree.c @@ -561,6 +561,17 @@ wmem_tree_lookup_string(wmem_tree_t* tree, const gchar* k, guint32 flags) return wmem_tree_lookup(tree, k, cmp); } +void * +wmem_tree_remove_string(wmem_tree_t* tree, const gchar* k, guint32 flags) +{ + void *ret = wmem_tree_lookup_string(tree, k, flags); + if (ret) { + /* Not really a remove, but set data to NULL so the lookup don't find it */ + wmem_tree_insert_string(tree, k, NULL, flags); + } + return ret; +} + static void * create_sub_tree(void* d) { @@ -655,10 +666,11 @@ wmem_tree_foreach_nodes(wmem_tree_node_t* node, wmem_foreach_func callback, } } - if (node->is_subtree == TRUE) { + if (node->is_subtree) { stop_traverse = wmem_tree_foreach((wmem_tree_t *)node->data, callback, user_data); - } else { + } else if (node->data) { + /* No callback for "removed" nodes */ stop_traverse = callback(node->data, user_data); } diff --git a/epan/wmem/wmem_tree.h b/epan/wmem/wmem_tree.h index 4c22824e18..2b551a5441 100644 --- a/epan/wmem/wmem_tree.h +++ b/epan/wmem/wmem_tree.h @@ -128,6 +128,13 @@ WS_DLL_PUBLIC void * wmem_tree_lookup_string(wmem_tree_t* tree, const gchar* key, guint32 flags); +/** Remove the value under a string key. This is not really a remove, but the + * value is set to NULL so that wmem_tree_lookup_string not will find it. + * See wmem_tree_insert_string for an explanation of flags. */ +WS_DLL_PUBLIC +void * +wmem_tree_remove_string(wmem_tree_t* tree, const gchar* key, guint32 flags); + typedef struct _wmem_tree_key_t { guint32 length; /**< length in guint32 words */ guint32 *key; diff --git a/epan/wslua/init_wslua.c b/epan/wslua/init_wslua.c index f0d64b3e3f..39b3447f23 100644 --- a/epan/wslua/init_wslua.c +++ b/epan/wslua/init_wslua.c @@ -349,10 +349,10 @@ static int init_error_handler(lua_State* LS) { } +static gboolean init_routine_initialized = FALSE; static void wslua_init_routine(void) { - static gboolean initialized = FALSE; - if ( ! initialized ) { + if ( ! init_routine_initialized ) { /* * This must be done only once during the entire life of * tshark/wireshark, because it must be done only once per the life of @@ -364,7 +364,7 @@ static void wslua_init_routine(void) { * Lua states, we'll need to change this. */ lua_prime_all_fields(NULL); - initialized = TRUE; + init_routine_initialized = TRUE; } if (L) { @@ -406,7 +406,7 @@ static int lua_main_error_handler(lua_State* LS) { return 0; } -static void wslua_add_plugin(gchar *name, gchar *version, gchar *filename) +static void wslua_add_plugin(const gchar *name, const gchar *version, const gchar *filename) { wslua_plugin *new_plug, *lua_plug; @@ -422,12 +422,26 @@ static void wslua_add_plugin(gchar *name, gchar *version, gchar *filename) lua_plug->next = new_plug; } - new_plug->name = name; - new_plug->version = version; - new_plug->filename = filename; + new_plug->name = g_strdup(name); + new_plug->version = g_strdup(version); + new_plug->filename = g_strdup(filename); new_plug->next = NULL; } +static void wslua_clear_plugin_list(void) +{ + wslua_plugin *lua_plug; + + while (wslua_plugin_list) { + lua_plug = wslua_plugin_list; + wslua_plugin_list = wslua_plugin_list->next; + g_free (lua_plug->name); + g_free (lua_plug->version); + g_free (lua_plug->filename); + g_free (lua_plug); + } +} + static int lua_script_push_args(const int script_num) { gchar* argname = g_strdup_printf("lua_script%d", script_num); const gchar* argvalue = NULL; @@ -562,9 +576,7 @@ static gboolean lua_load_plugin_script(const gchar* name, const int file_count) { if (lua_load_script(filename, dirname, file_count)) { - wslua_add_plugin(g_strdup(name), - g_strdup(get_current_plugin_version()), - g_strdup(filename)); + wslua_add_plugin(name, get_current_plugin_version(), filename); clear_current_plugin_version(); return TRUE; } @@ -705,13 +717,14 @@ wslua_get_expert_field(const int group, const int severity) return &ei_lua_error; } -int wslua_init(register_cb cb, gpointer client_data) { +void wslua_init(register_cb cb, gpointer client_data) { gchar* filename; const gchar *script_filename; const funnel_ops_t* ops = funnel_get_funnel_ops(); gboolean run_anyway = FALSE; expert_module_t* expert_lua; int file_count = 1; + static gboolean first_time = TRUE; static hf_register_info hf[] = { { &hf_wslua_fake, @@ -803,17 +816,19 @@ int wslua_init(register_cb cb, gpointer client_data) { { &ei_lua_error, { "_ws.lua.error", PI_UNDECODED, PI_ERROR ,"Lua Error", EXPFILL }}, }; - ws_lua_ei = ei; - ws_lua_ei_len = array_length(ei); + if (first_time) { + ws_lua_ei = ei; + ws_lua_ei_len = array_length(ei); - /* set up the logger */ - g_log_set_handler(LOG_DOMAIN_LUA, (GLogLevelFlags)(G_LOG_LEVEL_CRITICAL| + /* set up the logger */ + g_log_set_handler(LOG_DOMAIN_LUA, (GLogLevelFlags)(G_LOG_LEVEL_CRITICAL| G_LOG_LEVEL_WARNING| G_LOG_LEVEL_MESSAGE| G_LOG_LEVEL_INFO| G_LOG_LEVEL_DEBUG), ops ? ops->logger : basic_logger, NULL); + } if (!L) { L = luaL_newstate(); @@ -821,10 +836,12 @@ int wslua_init(register_cb cb, gpointer client_data) { WSLUA_INIT(L); - proto_lua = proto_register_protocol("Lua Dissection", "Lua Dissection", "_ws.lua"); - proto_register_field_array(proto_lua, hf, array_length(hf)); - expert_lua = expert_register_protocol(proto_lua); - expert_register_field_array(expert_lua, ei, array_length(ei)); + if (first_time) { + proto_lua = proto_register_protocol("Lua Dissection", "Lua Dissection", "_ws.lua"); + proto_register_field_array(proto_lua, hf, array_length(hf)); + expert_lua = expert_register_protocol(proto_lua); + expert_register_field_array(expert_lua, ei, array_length(ei)); + } lua_atpanic(L,wslua_panic); @@ -878,7 +895,7 @@ int wslua_init(register_cb cb, gpointer client_data) { /* disable lua */ lua_close(L); L = NULL; - return 0; + first_time = FALSE; } lua_pop(L,1); /* pop the getglobal result */ @@ -926,9 +943,11 @@ int wslua_init(register_cb cb, gpointer client_data) { } } - /* at this point we're set up so register the init and cleanup routines */ - register_init_routine(wslua_init_routine); - register_cleanup_routine(wslua_cleanup_routine); + if (first_time) { + /* at this point we're set up so register the init and cleanup routines */ + register_init_routine(wslua_init_routine); + register_cleanup_routine(wslua_cleanup_routine); + } /* * after this point it is too late to register a menu @@ -946,16 +965,44 @@ int wslua_init(register_cb cb, gpointer client_data) { Proto_commit(L); - return 0; + first_time = FALSE; +} + +/* @TODO: Reloading Lua plugins. + * + * - Deregister FileHandlers + * - Support deregister ProtoField with existing abbrev (same_name_hfinfo) + * - Add a progress dialog when reloading many plugins + * - Search for memory leakages in wslua functions + */ +void wslua_reload_plugins (register_cb cb, gpointer client_data) { + const funnel_ops_t* ops = funnel_get_funnel_ops(); + + if (cb) + (*cb)(RA_LUA_DEREGISTER, NULL, client_data); + + if (ops->close_dialogs) + ops->close_dialogs(); + + wslua_cleanup(); /* deregister */ + wslua_init(cb, client_data); /* reinitialize */ } -int wslua_cleanup(void) { +void wslua_cleanup(void) { /* cleanup lua */ - if (!L) { + if (L) { + wslua_deregister_protocols(L); + wslua_deregister_dissector_tables(L); + wslua_deregister_listeners(L); + wslua_deregister_filehandlers(L); + wslua_deregister_menus(); + wslua_clear_plugin_list(); + proto_free_deregistered_fields(); + lua_close(L); L = NULL; } - return 0; + init_routine_initialized = FALSE; } lua_State* wslua_state(void) { return L; } diff --git a/epan/wslua/init_wslua.h b/epan/wslua/init_wslua.h index e57818c081..850cc2e9e8 100644 --- a/epan/wslua/init_wslua.h +++ b/epan/wslua/init_wslua.h @@ -27,9 +27,11 @@ extern "C" { #endif /* __cplusplus */ +#include "register.h" #include "ws_symbol_export.h" WS_DLL_PUBLIC int wslua_count_plugins(void); +WS_DLL_PUBLIC void wslua_reload_plugins (register_cb cb, gpointer client_data); typedef void (*wslua_plugin_description_callback)(const char *, const char *, const char *, const char *, diff --git a/epan/wslua/wslua.h b/epan/wslua/wslua.h index b19725d258..7ad7926db6 100644 --- a/epan/wslua/wslua.h +++ b/epan/wslua/wslua.h @@ -188,12 +188,19 @@ typedef struct _wslua_proto_t { expert_module_t *expert_module; module_t *prefs_module; dissector_handle_t handle; + GArray *hfa; + GArray *etta; + GArray *eia; gboolean is_postdissector; + gboolean expired; } wslua_proto_t; struct _wslua_distbl_t { dissector_table_t table; const gchar* name; + const gchar* ui_name; + gboolean created; + gboolean expired; }; struct _wslua_col_info { @@ -716,8 +723,8 @@ extern void clear_outstanding_FieldInfo(void); extern void wslua_print_stack(char* s, lua_State* L); -extern int wslua_init(register_cb cb, gpointer client_data); -extern int wslua_cleanup(void); +extern void wslua_init(register_cb cb, gpointer client_data); +extern void wslua_cleanup(void); extern tap_extractor_t wslua_get_tap_extractor(const gchar* name); extern int wslua_set_tap_enums(lua_State* L); @@ -733,6 +740,12 @@ extern int luaopen_rex_glib(lua_State *L); extern const gchar* get_current_plugin_version(void); extern void clear_current_plugin_version(void); +extern int wslua_deregister_protocols(lua_State* L); +extern int wslua_deregister_dissector_tables(lua_State* L); +extern int wslua_deregister_listeners(lua_State* L); +extern int wslua_deregister_filehandlers(lua_State* L); +extern void wslua_deregister_menus(void); + #endif /* diff --git a/epan/wslua/wslua_dissector.c b/epan/wslua/wslua_dissector.c index d3ccc0413f..7472d76037 100644 --- a/epan/wslua/wslua_dissector.c +++ b/epan/wslua/wslua_dissector.c @@ -168,6 +168,8 @@ WSLUA_CLASS_DEFINE(DissectorTable,NOP,NOP); Useful to add more dissectors to a table so that they appear in the Decode As... dialog. */ +static int dissectortable_table_ref = LUA_NOREF; + WSLUA_CONSTRUCTOR DissectorTable_new (lua_State *L) { /* Creates a new DissectorTable for your dissector's use. */ #define WSLUA_ARG_DissectorTable_new_TABLENAME 1 /* The short name of the table. */ @@ -201,6 +203,15 @@ WSLUA_CONSTRUCTOR DissectorTable_new (lua_State *L) { dt->table = register_dissector_table(name, ui_name, type, base); dt->name = name; + dt->ui_name = ui_name; + dt->created = TRUE; + dt->expired = FALSE; + + lua_rawgeti(L, LUA_REGISTRYINDEX, dissectortable_table_ref); + lua_pushstring(L, name); + pushDissectorTable(L, dt); + lua_settable(L, -3); + pushDissectorTable(L, dt); } WSLUA_RETURN(1); /* The newly created DissectorTable. */ @@ -284,6 +295,9 @@ WSLUA_CONSTRUCTOR DissectorTable_get (lua_State *L) { DissectorTable dt = (DissectorTable)g_malloc(sizeof(struct _wslua_distbl_t)); dt->table = table; dt->name = g_strdup(name); + dt->ui_name = NULL; + dt->created = FALSE; + dt->expired = FALSE; pushDissectorTable(L, dt); @@ -648,7 +662,17 @@ WSLUA_METAMETHOD DissectorTable__tostring(lua_State* L) { /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ static int DissectorTable__gc(lua_State* L _U_) { - /* do NOT free DissectorTable */ + DissectorTable dt = toDissectorTable(L,1); + + if (dt->created && !dt->expired) { + /* Created DissectorTable will pass GC two times */ + dt->expired = TRUE; + } else { + g_free((char *)dt->name); + g_free((char *)dt->ui_name); + g_free(dt); + } + return 0; } @@ -674,9 +698,27 @@ WSLUA_META DissectorTable_meta[] = { int DissectorTable_register(lua_State* L) { WSLUA_REGISTER_CLASS(DissectorTable); + + lua_newtable (L); + dissectortable_table_ref = luaL_ref(L, LUA_REGISTRYINDEX); + return 0; } +int wslua_deregister_dissector_tables(lua_State* L) { + /* for each registered DissectorTable do... */ + lua_rawgeti(L, LUA_REGISTRYINDEX, dissectortable_table_ref); + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + DissectorTable dt = checkDissectorTable(L, -1); + if (dt->created) { + deregister_dissector_table(dt->name); + } + } + + lua_pop(L, 1); /* dissector_table_ref */ + + return 0; +} /* * Editor modelines - http://www.wireshark.org/tools/modelines.html diff --git a/epan/wslua/wslua_field.c b/epan/wslua/wslua_field.c index 2321a118c3..1429470397 100644 --- a/epan/wslua/wslua_field.c +++ b/epan/wslua/wslua_field.c @@ -590,7 +590,7 @@ void lua_prime_all_fields(proto_tree* tree _U_) { g_ptr_array_free(wanted_fields,TRUE); wanted_fields = NULL; - if (fake_tap) { + if (fake_tap && fake_tap_filter->len > strlen("frame")) { /* a boring tap :-) */ GString* error = register_tap_listener("frame", &fake_tap, @@ -611,8 +611,10 @@ void lua_prime_all_fields(proto_tree* tree _U_) { g_free(err_msg); } } + } else if (fake_tap) { + remove_tap_listener(&fake_tap); + fake_tap = FALSE; } - } WSLUA_CONSTRUCTOR Field_new(lua_State *L) { diff --git a/epan/wslua/wslua_file_handler.c b/epan/wslua/wslua_file_handler.c index 1ea8cb4555..033686bf17 100644 --- a/epan/wslua/wslua_file_handler.c +++ b/epan/wslua/wslua_file_handler.c @@ -982,6 +982,11 @@ int FileHandler_register(lua_State* L) { return 0; } +int wslua_deregister_filehandlers(lua_State* L _U_) { + /* TODO: Implement */ + return 0; +} + /* * Editor modelines - http://www.wireshark.org/tools/modelines.html diff --git a/epan/wslua/wslua_gui.c b/epan/wslua/wslua_gui.c index 0586293aa3..1fc3baeee7 100644 --- a/epan/wslua/wslua_gui.c +++ b/epan/wslua/wslua_gui.c @@ -121,8 +121,9 @@ WSLUA_FUNCTION wslua_register_menu(lua_State* L) { /* Register a menu item in o WSLUA_RETURN(0); } - - +void wslua_deregister_menus(void) { + funnel_deregister_menus(lua_menu_callback); +} struct _dlg_cb_data { lua_State* L; @@ -553,6 +554,20 @@ WSLUA_METHOD TextWindow_get_text(lua_State* L) { /* Get the text of the window * WSLUA_RETURN(1); /* The `TextWindow`'s text. */ } +WSLUA_METHOD TextWindow_close(lua_State* L) { /* Close the window */ + TextWindow tw = checkTextWindow(L,1); + + if (!ops->destroy_text_window) { + WSLUA_ERROR(TextWindow_get_text,"GUI not available"); + return 0; + } + + ops->destroy_text_window(tw->ws_tw); + tw->ws_tw = NULL; + + return 0; +} + /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ static int TextWindow__gc(lua_State* L) { TextWindow tw = toTextWindow(L,1); @@ -666,7 +681,6 @@ WSLUA_METHOD TextWindow_add_button(lua_State* L) { WSLUA_METHODS TextWindow_methods[] = { WSLUA_CLASS_FNREG(TextWindow,new), WSLUA_CLASS_FNREG(TextWindow,set), - WSLUA_CLASS_FNREG(TextWindow,new), WSLUA_CLASS_FNREG(TextWindow,append), WSLUA_CLASS_FNREG(TextWindow,prepend), WSLUA_CLASS_FNREG(TextWindow,clear), @@ -674,6 +688,7 @@ WSLUA_METHODS TextWindow_methods[] = { WSLUA_CLASS_FNREG(TextWindow,set_editable), WSLUA_CLASS_FNREG(TextWindow,get_text), WSLUA_CLASS_FNREG(TextWindow,add_button), + WSLUA_CLASS_FNREG(TextWindow,close), { NULL, NULL } }; diff --git a/epan/wslua/wslua_listener.c b/epan/wslua/wslua_listener.c index 64ed0610ff..cd4509985a 100644 --- a/epan/wslua/wslua_listener.c +++ b/epan/wslua/wslua_listener.c @@ -183,6 +183,18 @@ static void lua_tap_draw(void *tapdata) { } } +/* TODO: we should probably use a Lua table here */ +static GPtrArray *listeners = NULL; + +static void deregister_Listener (lua_State* L _U_, Listener tap) { + if (tap->all_fields) { + epan_set_always_visible(FALSE); + tap->all_fields = FALSE; + } + + remove_tap_listener(tap); +} + WSLUA_CONSTRUCTOR Listener_new(lua_State* L) { /* Creates a new `Listener` listener object. */ #define WSLUA_OPTARG_Listener_new_TAP 1 /* The name of this tap. */ @@ -231,6 +243,8 @@ WSLUA_CONSTRUCTOR Listener_new(lua_State* L) { epan_set_always_visible(TRUE); } + g_ptr_array_add(listeners, tap); + pushListener(L,tap); WSLUA_RETURN(1); /* The newly created Listener listener object */ } @@ -272,13 +286,10 @@ WSLUA_METHOD Listener_remove(lua_State* L) { /* Removes a tap `Listener`. */ Listener tap = checkListener(L,1); - if (tap->all_fields) { - epan_set_always_visible(FALSE); - tap->all_fields = FALSE; + if (g_ptr_array_remove(listeners, tap)) { + deregister_Listener(L, tap); } - remove_tap_listener(tap); - return 0; } @@ -326,7 +337,16 @@ WSLUA_ATTRIBUTE_FUNC_SETTER(Listener,reset); static int Listener__gc(lua_State* L _U_) { - /* do NOT free Listener, it's never free'd */ + Listener tap = toListener(L, 1); + + if (listeners && g_ptr_array_remove(listeners, tap)) { + deregister_Listener(L, tap); + } + + g_free(tap->filter); + g_free(tap->name); + g_free(tap); + return 0; } @@ -355,11 +375,28 @@ WSLUA_META Listener_meta[] = { int Listener_register(lua_State* L) { wslua_set_tap_enums(L); + + listeners = g_ptr_array_new(); + WSLUA_REGISTER_CLASS(Listener); WSLUA_REGISTER_ATTRIBUTES(Listener); return 0; } +static void deregister_tap_listener (gpointer data, gpointer userdata) { + lua_State *L = (lua_State *) userdata; + Listener tap = (Listener) data; + deregister_Listener(L, tap); +} + +int wslua_deregister_listeners(lua_State* L) { + g_ptr_array_foreach(listeners, deregister_tap_listener, L); + g_ptr_array_free(listeners, FALSE); + listeners = NULL; + + return 0; +} + /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * diff --git a/epan/wslua/wslua_pref.c b/epan/wslua/wslua_pref.c index cdde74d0c8..b154a27a69 100644 --- a/epan/wslua/wslua_pref.c +++ b/epan/wslua/wslua_pref.c @@ -232,11 +232,13 @@ static range_t* get_range(lua_State *L, int idx_r, int idx_m) return ret; } + /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ static int Pref__gc(lua_State* L) { - Pref pref = checkPref(L,1); + Pref pref = toPref(L,1); - if (pref && ! pref->name) { + if (! pref->name) { + /* Only free unregistered and deregistered Pref */ g_free(pref->label); g_free(pref->desc); if (pref->type == PREF_STRING) @@ -433,7 +435,7 @@ WSLUA_METAMETHOD Prefs__index(lua_State* L) { /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ static int Prefs__gc(lua_State* L _U_) { - /* do NOT free Prefs, it's never free'd */ + /* do NOT free Prefs, it's a static part of Proto */ return 0; } diff --git a/epan/wslua/wslua_proto.c b/epan/wslua/wslua_proto.c index 9f7d2f8b50..155d0fe194 100644 --- a/epan/wslua/wslua_proto.c +++ b/epan/wslua/wslua_proto.c @@ -5,6 +5,7 @@ * * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org> * (c) 2007, Tamas Regos <tamas.regos@ericsson.com> + * (c) 2014, Stig Bjorlykke <stig@bjorlykke.org> * * Wireshark - Network traffic analyzer * By Gerald Combs <gerald@wireshark.org> @@ -122,6 +123,7 @@ WSLUA_CONSTRUCTOR Proto_new(lua_State* L) { proto->hfid = proto_register_protocol(proto->desc,hiname,loname); proto->ett = -1; proto->is_postdissector = FALSE; + proto->expired = FALSE; lua_newtable (L); proto->fields = luaL_ref(L, LUA_REGISTRYINDEX); @@ -479,7 +481,18 @@ static int Proto_set_experts(lua_State* L) { /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ static int Proto__gc(lua_State* L _U_) { - /* do NOT free Proto, it's never free'd */ + /* Proto is registered twice, once in protocols_table_ref and once returned from Proto_new. + * It will not be freed unless deregistered. + */ + Proto proto = toProto(L,1); + + if (!proto->expired) { + proto->expired = TRUE; + } else if (proto->hfid == -2) { + /* Only free deregistered Proto */ + g_free(proto); + } + return 0; } @@ -553,6 +566,71 @@ ProtoField wslua_is_field_available(lua_State* L, const char* field_abbr) { return NULL; } +int wslua_deregister_protocols(lua_State* L) { + /* for each registered Proto protocol do... */ + lua_rawgeti(L, LUA_REGISTRYINDEX, protocols_table_ref); + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + Proto proto; + proto = checkProto(L, -1); + + if (proto->handle) { + deregister_dissector(proto->loname); + } + if (proto->prefs_module) { + Pref pref; + prefs_deregister_protocol(proto->hfid); + for (pref = proto->prefs.next; pref; pref = pref->next) { + g_free(pref->name); + pref->name = NULL; /* Deregister Pref, freed in Pref__gc */ + } + } + if (proto->expert_module) { + expert_deregister_protocol(proto->expert_module); + } + proto_deregister_protocol(proto->name); + + /* for each registered ProtoField do... */ + lua_rawgeti(L, LUA_REGISTRYINDEX, proto->fields); + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + ProtoField f = checkProtoField(L, -1); + f->hfid = -2; /* Deregister ProtoField, freed in ProtoField__gc */ + } + lua_pop(L, 1); + + /* for each registered ProtoExpert do... */ + lua_rawgeti(L, LUA_REGISTRYINDEX, proto->expert_info_table_ref); + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + ProtoExpert pe = checkProtoExpert(L,-1); + pe->ids.hf = -2; /* Deregister ProtoExpert, freed in ProtoExpert__gc */ + } + lua_pop(L, 1); + + if (proto->hfa->len) { + proto_add_deregistered_data(g_array_free(proto->hfa,FALSE)); + } else { + g_array_free(proto->hfa,TRUE); + } + + if (proto->etta->len) { + proto_add_deregistered_data(g_array_free(proto->etta,FALSE)); + } else { + g_array_free(proto->etta,TRUE); + } + + if (proto->eia->len) { + proto_add_deregistered_data(g_array_free(proto->eia,FALSE)); + } else { + g_array_free(proto->eia,TRUE); + } + + proto->hfid = -2; /* Deregister Proto, freed in Proto__gc */ + } + + lua_pop(L, 1); /* protocols_table_ref */ + + return 0; +} + int Proto_commit(lua_State* L) { lua_settop(L,0); /* the following gets the table of registered Proto protocols and puts it on the stack (index=1) */ @@ -566,16 +644,15 @@ int Proto_commit(lua_State* L) { to lua_pop(L, 2), and when lua_next() returns 0 (no more table entries), it will have pop'ed the final key itself, leaving just the protocols_table_ref table on the stack. */ - GArray* hfa = g_array_new(TRUE,TRUE,sizeof(hf_register_info)); - GArray* etta = g_array_new(TRUE,TRUE,sizeof(gint*)); - GArray* eia = g_array_new(TRUE,TRUE,sizeof(ei_register_info)); + Proto proto = checkProto(L,3); gint* ettp = NULL; - Proto proto; - /* const gchar* proto_name = lua_tostring(L,2); */ - proto = checkProto(L,3); + + proto->hfa = g_array_new(TRUE,TRUE,sizeof(hf_register_info)); + proto->etta = g_array_new(TRUE,TRUE,sizeof(gint*)); + proto->eia = g_array_new(TRUE,TRUE,sizeof(ei_register_info)); ettp = &(proto->ett); - g_array_append_val(etta,ettp); + g_array_append_val(proto->etta,ettp); /* get the Lua table of ProtoFields, push it on the stack (index=3) */ lua_rawgeti(L, LUA_REGISTRYINDEX, proto->fields); @@ -600,13 +677,13 @@ int Proto_commit(lua_State* L) { } f->hfid = -1; - g_array_append_val(hfa,hfri); - g_array_append_val(etta,ettp); + g_array_append_val(proto->hfa,hfri); + g_array_append_val(proto->etta,ettp); } /* register the proto fields */ - proto_register_field_array(proto->hfid,(hf_register_info*)(void*)hfa->data,hfa->len); - proto_register_subtree_array((gint**)(void*)etta->data,etta->len); + proto_register_field_array(proto->hfid,(hf_register_info*)(void*)proto->hfa->data,proto->hfa->len); + proto_register_subtree_array((gint**)(void*)proto->etta->data,proto->etta->len); lua_pop(L,1); /* pop the table of ProtoFields */ @@ -630,15 +707,10 @@ int Proto_commit(lua_State* L) { return luaL_error(L,"expert fields can be registered only once"); } - g_array_append_val(eia,eiri); + g_array_append_val(proto->eia,eiri); } - expert_register_field_array(proto->expert_module, (ei_register_info*)(void*)eia->data, eia->len); - - /* XXX: the registration routines say to use static arrays only, so is this safe? */ - g_array_free(hfa,FALSE); - g_array_free(etta,FALSE); - g_array_free(eia,FALSE); + expert_register_field_array(proto->expert_module, (ei_register_info*)(void*)proto->eia->data, proto->eia->len); /* Proto object and ProtoFields table will be pop'ed by lua_pop(L, 2) in for statement */ } diff --git a/epan/wslua/wslua_proto_expert.c b/epan/wslua/wslua_proto_expert.c index f1a36c13e3..8a8079152c 100644 --- a/epan/wslua/wslua_proto_expert.c +++ b/epan/wslua/wslua_proto_expert.c @@ -99,17 +99,11 @@ WSLUA_METAMETHOD ProtoExpert__tostring(lua_State* L) { static int ProtoExpert__gc(lua_State* L) { ProtoExpert pe = toProtoExpert(L,1); - /* - * A garbage collector for ProtoExpert makes little sense. - * Even if this cannot be used anymore because it has gone out of scope, - * we can destroy the ProtoExpert only if it is not part of a registered Proto, - * if it actually belongs to one we need to preserve it as it is pointed by - * a expert code causing a crash or memory corruption. - */ - - if (pe) { - luaL_argerror(L,1,"BUG: ProtoExpert_gc called for something not ProtoExpert"); - /* g_assert() ?? */ + if (pe->ids.hf == -2) { + /* Only free unregistered and deregistered ProtoExpert */ + g_free((gchar *)pe->abbrev); + g_free((gchar *)pe->text); + g_free(pe); } return 0; diff --git a/epan/wslua/wslua_proto_field.c b/epan/wslua/wslua_proto_field.c index bb91b6cbe8..f6d4421c99 100644 --- a/epan/wslua/wslua_proto_field.c +++ b/epan/wslua/wslua_proto_field.c @@ -916,21 +916,24 @@ WSLUA_METAMETHOD ProtoField__tostring(lua_State* L) { static int ProtoField__gc(lua_State* L) { ProtoField f = toProtoField(L,1); - /* - * A garbage collector for ProtoFields makes little sense. - * Even if This cannot be used anymore because it has gone out of scope, - * we can destroy the ProtoField only if it is not part of a ProtoFieldArray, - * if it actualy belongs to one we need to preserve it as it is pointed by - * a field array that may be registered afterwards causing a crash or memory corruption. - */ - - if (!f) { - luaL_argerror(L,1,"BUG: ProtoField_gc called for something not ProtoField"); - /* g_assert() ?? */ - } else if (f->hfid == -2) { - g_free(f->name); - g_free(f->abbrev); - g_free(f->blob); + if (f->hfid == -2) { + /* Only free unregistered and deregistered ProtoField */ + if (f->vs) { + if (f->type == FT_UINT64 || f->type == FT_INT64) { + val64_string *vs64 = (val64_string *)f->vs; + while (vs64->strptr) { + g_free((gchar *)vs64->strptr); + vs64++; + } + } else if (f->type != FT_BOOLEAN) { /* Other Integer types */ + value_string *vs = (value_string *)f->vs; + while (vs->strptr) { + g_free((gchar *)vs->strptr); + vs++; + } + } + g_free((void *)f->vs); + } g_free(f); } diff --git a/epan/wslua/wslua_tree.c b/epan/wslua/wslua_tree.c index 5a90d53c99..773b6b1c91 100644 --- a/epan/wslua/wslua_tree.c +++ b/epan/wslua/wslua_tree.c @@ -886,6 +886,7 @@ WSLUA_META TreeItem_meta[] = { int TreeItem_register(lua_State *L) { gint* etts[] = { &wslua_ett }; + wslua_ett = -1; /* Reset to support reload Lua plugins */ WSLUA_REGISTER_CLASS(TreeItem); WSLUA_REGISTER_ATTRIBUTES(TreeItem); outstanding_TreeItem = g_ptr_array_new(); diff --git a/register.h b/register.h index edd814422c..9e19696574 100644 --- a/register.h +++ b/register.h @@ -40,6 +40,7 @@ typedef enum { RA_HANDOFF, /* handoff */ RA_PLUGIN_HANDOFF, /* plugin handoff */ RA_LUA_PLUGINS, /* lua plugin register */ + RA_LUA_DEREGISTER, /* lua plugin deregister */ RA_PREFERENCES, /* module preferences */ RA_CONFIGURATION /* configuration files */ } register_action_e; diff --git a/ui/cli/tap-funnel.c b/ui/cli/tap-funnel.c index fe42dcbe03..6d9d48dd3d 100644 --- a/ui/cli/tap-funnel.c +++ b/ui/cli/tap-funnel.c @@ -98,6 +98,7 @@ static const funnel_ops_t funnel_ops = { NULL, /*...,*/ NULL, + NULL, funnel_logger, NULL, NULL, diff --git a/ui/gtk/funnel_stat.c b/ui/gtk/funnel_stat.c index b791b423cd..96781a11f2 100644 --- a/ui/gtk/funnel_stat.c +++ b/ui/gtk/funnel_stat.c @@ -558,6 +558,7 @@ static const funnel_ops_t funnel_ops = { text_window_add_button, /*...,*/ funnel_new_dialog, + NULL, funnel_logger, funnel_retap_packets, copy_to_clipboard, diff --git a/ui/qt/funnel_statistics.cpp b/ui/qt/funnel_statistics.cpp index a1cd51c62e..9a5d830191 100644 --- a/ui/qt/funnel_statistics.cpp +++ b/ui/qt/funnel_statistics.cpp @@ -67,8 +67,9 @@ static void progress_window_destroy(struct progdlg *progress_dialog); class FunnelAction : public QAction { public: - FunnelAction(const QString title, void (*callback)(gpointer), gpointer callback_data, gboolean retap) : + FunnelAction(const QString title, funnel_menu_callback callback, gpointer callback_data, gboolean retap) : QAction(NULL), + title_(title), callback_(callback), callback_data_(callback_data), retap_(retap) @@ -77,6 +78,14 @@ public: setObjectName(FunnelStatistics::actionName()); } + funnel_menu_callback callback() const { + return callback_; + } + + QString title() const { + return title_; + } + void triggerCallback() { if (callback_) { callback_(callback_data_); @@ -89,13 +98,15 @@ public: } private: - void (*callback_)(gpointer); + QString title_; + funnel_menu_callback callback_; gpointer callback_data_; gboolean retap_; }; -static QList<FunnelAction *> funnel_actions_; +static QHash<int, QList<FunnelAction *> > funnel_actions_; const QString FunnelStatistics::action_name_ = "FunnelStatisticsAction"; +static gboolean menus_registered = FALSE; FunnelStatistics::FunnelStatistics(QObject *parent, CaptureFile &cf) : QObject(parent), @@ -116,6 +127,7 @@ FunnelStatistics::FunnelStatistics(QObject *parent, CaptureFile &cf) : funnel_ops_->destroy_text_window = text_window_destroy; funnel_ops_->add_button = text_window_add_button; funnel_ops_->new_dialog = string_dialog_new; + funnel_ops_->close_dialogs = string_dialogs_close; funnel_ops_->logger = funnel_statistics_logger; funnel_ops_->retap_packets = funnel_statistics_retap_packets; funnel_ops_->copy_to_clipboard = funnel_statistics_copy_to_clipboard; @@ -191,6 +203,7 @@ void funnel_statistics_logger(const gchar *, gpointer) { qDebug() << message; } + void funnel_statistics_retap_packets(funnel_ops_id_t *ops_id) { FunnelStatistics *funnel_statistics = dynamic_cast<FunnelStatistics *>((FunnelStatistics *)ops_id); if (!funnel_statistics) return; @@ -274,18 +287,51 @@ extern "C" { static void register_menu_cb(const char *name, register_stat_group_t group, - void (*callback)(gpointer), + funnel_menu_callback callback, gpointer callback_data, - gboolean retap) { + gboolean retap) +{ FunnelAction *funnel_action = new FunnelAction(name, callback, callback_data, retap); - wsApp->addDynamicMenuGroupItem(group, funnel_action); - funnel_actions_ << funnel_action; + if (menus_registered) { + wsApp->appendDynamicMenuGroupItem(group, funnel_action); + } else { + wsApp->addDynamicMenuGroupItem(group, funnel_action); + } + if (!funnel_actions_.contains(group)) { + funnel_actions_[group] = QList<FunnelAction *>(); + } + funnel_actions_[group] << funnel_action; +} + +static void deregister_menu_cb(funnel_menu_callback callback) +{ + foreach (int group, funnel_actions_.uniqueKeys()) { + QList<FunnelAction *>::iterator it = funnel_actions_[group].begin(); + while (it != funnel_actions_[group].end()) { + FunnelAction *funnel_action = *it; + if (funnel_action->callback() == callback) { + // Must set back to title to find the correct sub-menu in Tools + funnel_action->setText(funnel_action->title()); + wsApp->removeDynamicMenuGroupItem(group, funnel_action); + it = funnel_actions_[group].erase(it); + } else { + ++it; + } + } + } } void register_tap_listener_qt_funnel(void) { funnel_register_all_menus(register_menu_cb); + menus_registered = TRUE; +} + +void +funnel_statistics_reload_menus(void) +{ + funnel_reload_menus(deregister_menu_cb, register_menu_cb); } } // extern "C" diff --git a/ui/qt/funnel_statistics.h b/ui/qt/funnel_statistics.h index 19778cef6e..3f22bbb3de 100644 --- a/ui/qt/funnel_statistics.h +++ b/ui/qt/funnel_statistics.h @@ -62,6 +62,10 @@ private: QByteArray display_filter_; }; +extern "C" { + void funnel_statistics_reload_menus(void); +} // extern "C" + #endif // FUNNELSTATISTICS_H /* diff --git a/ui/qt/funnel_string_dialog.cpp b/ui/qt/funnel_string_dialog.cpp index 187acbfd27..73ef55ddc9 100644 --- a/ui/qt/funnel_string_dialog.cpp +++ b/ui/qt/funnel_string_dialog.cpp @@ -72,19 +72,33 @@ void FunnelStringDialog::on_buttonBox_accepted() g_ptr_array_free(returns, FALSE); } -void FunnelStringDialog::stringDialogNew(const QString title, const QStringList field_name_list, funnel_dlg_cb_t dialog_cb, void *dialog_cb_data) +FunnelStringDialog *FunnelStringDialog::stringDialogNew(const QString title, const QStringList field_name_list, funnel_dlg_cb_t dialog_cb, void *dialog_cb_data) { FunnelStringDialog *fsd = new FunnelStringDialog(title, field_name_list, dialog_cb, dialog_cb_data); fsd->show(); + + return fsd; } +QList<FunnelStringDialog *> openDialogs; + void string_dialog_new(const gchar *title, const gchar **fieldnames, funnel_dlg_cb_t dialog_cb, void *dialog_cb_data) { QStringList field_name_list; for (int i = 0; fieldnames[i]; i++) { field_name_list << fieldnames[i]; } - FunnelStringDialog::stringDialogNew(title, field_name_list, dialog_cb, dialog_cb_data); + FunnelStringDialog *fsd = FunnelStringDialog::stringDialogNew(title, field_name_list, dialog_cb, dialog_cb_data); + + openDialogs.append (fsd); +} + +void string_dialogs_close(void) +{ + foreach (FunnelStringDialog *fsd, openDialogs) + delete fsd; + + openDialogs.clear(); } /* diff --git a/ui/qt/funnel_string_dialog.h b/ui/qt/funnel_string_dialog.h index 1f4dd9ae30..1086bcadd0 100644 --- a/ui/qt/funnel_string_dialog.h +++ b/ui/qt/funnel_string_dialog.h @@ -43,7 +43,7 @@ public: ~FunnelStringDialog(); // Funnel ops - static void stringDialogNew(const QString title, const QStringList field_name_list, funnel_dlg_cb_t dialog_cb, void* dialog_cb_data); + static FunnelStringDialog *stringDialogNew(const QString title, const QStringList field_name_list, funnel_dlg_cb_t dialog_cb, void* dialog_cb_data); private slots: void on_buttonBox_accepted(); @@ -57,6 +57,7 @@ private: extern "C" { void string_dialog_new(const gchar* title, const gchar** fieldnames, funnel_dlg_cb_t dialog_cb, void* dialog_cb_data); +void string_dialogs_close(void); } #endif // FUNNEL_STRING_DIALOG_H diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp index 6c9d92b7d4..e49b1b760f 100644 --- a/ui/qt/main_window.cpp +++ b/ui/qt/main_window.cpp @@ -1966,13 +1966,7 @@ void MainWindow::setForCaptureInProgress(gboolean capture_in_progress) #endif } -void MainWindow::addDynamicMenus() -{ - // Manual additions - wsApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_GSM, main_ui_->actionTelephonyGsmMapSummary); - - // Fill in each menu - QList<register_stat_group_t> menu_groups = QList<register_stat_group_t>() +static QList<register_stat_group_t> menu_groups = QList<register_stat_group_t>() << REGISTER_ANALYZE_GROUP_UNSORTED << REGISTER_ANALYZE_GROUP_CONVERSATION_FILTER << REGISTER_STAT_GROUP_UNSORTED @@ -1987,70 +1981,126 @@ void MainWindow::addDynamicMenus() << REGISTER_STAT_GROUP_TELEPHONY_SCTP << REGISTER_TOOLS_GROUP_UNSORTED; - foreach (register_stat_group_t menu_group, menu_groups) { - QList<QAction *>actions = wsApp->dynamicMenuGroupItems(menu_group); - foreach (QAction *action, actions) { - switch (menu_group) { - case REGISTER_ANALYZE_GROUP_UNSORTED: - case REGISTER_STAT_GROUP_UNSORTED: - main_ui_->menuStatistics->insertAction( +void MainWindow::addMenuActions(QList<QAction *> &actions, int menu_group) +{ + foreach (QAction *action, actions) { + switch (menu_group) { + case REGISTER_ANALYZE_GROUP_UNSORTED: + case REGISTER_STAT_GROUP_UNSORTED: + main_ui_->menuStatistics->insertAction( main_ui_->actionStatistics_REGISTER_STAT_GROUP_UNSORTED, action); - break; - case REGISTER_STAT_GROUP_RESPONSE_TIME: - main_ui_->menuServiceResponseTime->addAction(action); - break; - case REGISTER_STAT_GROUP_TELEPHONY: - main_ui_->menuTelephony->addAction(action); - break; - case REGISTER_STAT_GROUP_TELEPHONY_ANSI: - main_ui_->menuANSI->addAction(action); - break; - case REGISTER_STAT_GROUP_TELEPHONY_GSM: - main_ui_->menuGSM->addAction(action); - break; - case REGISTER_TOOLS_GROUP_UNSORTED: - { - // Allow the creation of submenus. Mimics the behavor of - // ui/gtk/main_menubar.c:add_menu_item_to_main_menubar - // and GtkUIManager. - // - // For now we limit the insanity to the "Tools" menu. - QStringList menu_path = action->text().split('/'); - QMenu *cur_menu = main_ui_->menuTools; - while (menu_path.length() > 1) { - QString menu_title = menu_path.takeFirst(); - #if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0)) - QMenu *submenu = cur_menu->findChild<QMenu *>(menu_title.toLower(), Qt::FindDirectChildrenOnly); - #else - QMenu *submenu = cur_menu->findChild<QMenu *>(menu_title.toLower()); - if (submenu && submenu->parent() != cur_menu) submenu = NULL; - #endif - if (!submenu) { - submenu = cur_menu->addMenu(menu_title); - submenu->setObjectName(menu_title.toLower()); - } - cur_menu = submenu; + break; + case REGISTER_STAT_GROUP_RESPONSE_TIME: + main_ui_->menuServiceResponseTime->addAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY: + main_ui_->menuTelephony->addAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_ANSI: + main_ui_->menuANSI->addAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_GSM: + main_ui_->menuGSM->addAction(action); + break; + case REGISTER_TOOLS_GROUP_UNSORTED: + { + // Allow the creation of submenus. Mimics the behavor of + // ui/gtk/main_menubar.c:add_menu_item_to_main_menubar + // and GtkUIManager. + // + // For now we limit the insanity to the "Tools" menu. + QStringList menu_path = action->text().split('/'); + QMenu *cur_menu = main_ui_->menuTools; + while (menu_path.length() > 1) { + QString menu_title = menu_path.takeFirst(); +#if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0)) + QMenu *submenu = cur_menu->findChild<QMenu *>(menu_title.toLower(), Qt::FindDirectChildrenOnly); +#else + QMenu *submenu = cur_menu->findChild<QMenu *>(menu_title.toLower()); + if (submenu && submenu->parent() != cur_menu) submenu = NULL; +#endif + if (!submenu) { + submenu = cur_menu->addMenu(menu_title); + submenu->setObjectName(menu_title.toLower()); } - action->setText(menu_path.last()); - cur_menu->addAction(action); - break; - } - default: -// qDebug() << "FIX: Add" << action->text() << "to the menu"; - break; + cur_menu = submenu; } + action->setText(menu_path.last()); + cur_menu->addAction(action); + break; + } + default: +// qDebug() << "FIX: Add" << action->text() << "to the menu"; + break; + } - // Connect each action type to its corresponding slot. We to - // distinguish various types of actions. Setting their objectName - // seems to work OK. - if (action->objectName() == TapParameterDialog::actionName()) { - connect(action, SIGNAL(triggered(bool)), this, SLOT(openTapParameterDialog())); - } else if (action->objectName() == FunnelStatistics::actionName()) { - connect(action, SIGNAL(triggered(bool)), funnel_statistics_, SLOT(funnelActionTriggered())); + // Connect each action type to its corresponding slot. We to + // distinguish various types of actions. Setting their objectName + // seems to work OK. + if (action->objectName() == TapParameterDialog::actionName()) { + connect(action, SIGNAL(triggered(bool)), this, SLOT(openTapParameterDialog())); + } else if (action->objectName() == FunnelStatistics::actionName()) { + connect(action, SIGNAL(triggered(bool)), funnel_statistics_, SLOT(funnelActionTriggered())); + } + } +} +void MainWindow::removeMenuActions(QList<QAction *> &actions, int menu_group) +{ + foreach (QAction *action, actions) { + switch (menu_group) { + case REGISTER_ANALYZE_GROUP_UNSORTED: + case REGISTER_STAT_GROUP_UNSORTED: + main_ui_->menuStatistics->removeAction(action); + break; + case REGISTER_STAT_GROUP_RESPONSE_TIME: + main_ui_->menuServiceResponseTime->removeAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY: + main_ui_->menuTelephony->removeAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_ANSI: + main_ui_->menuANSI->removeAction(action); + break; + case REGISTER_STAT_GROUP_TELEPHONY_GSM: + main_ui_->menuGSM->removeAction(action); + break; + case REGISTER_TOOLS_GROUP_UNSORTED: + { + // Allow removal of submenus. + // For now we limit the insanity to the "Tools" menu. + QStringList menu_path = action->text().split('/'); + QMenu *cur_menu = main_ui_->menuTools; + while (menu_path.length() > 1) { + QString menu_title = menu_path.takeFirst(); +#if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0)) + QMenu *submenu = cur_menu->findChild<QMenu *>(menu_title.toLower(), Qt::FindDirectChildrenOnly); +#else + QMenu *submenu = cur_menu->findChild<QMenu *>(menu_title.toLower()); + if (submenu && submenu->parent() != cur_menu) submenu = NULL; +#endif + cur_menu = submenu; } + cur_menu->removeAction(action); + break; + } + default: +// qDebug() << "FIX: Remove" << action->text() << "from the menu"; + break; } } +} + +void MainWindow::addDynamicMenus() +{ + // Manual additions + wsApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_GSM, main_ui_->actionTelephonyGsmMapSummary); + + // Fill in each menu + foreach (register_stat_group_t menu_group, menu_groups) { + QList<QAction *>actions = wsApp->dynamicMenuGroupItems(menu_group); + addMenuActions(actions, menu_group); + } // Empty menus don't show up: https://bugreports.qt.io/browse/QTBUG-33728 // We've added a placeholder in order to make sure the "Tools" menu is @@ -2063,6 +2113,20 @@ void MainWindow::addDynamicMenus() } } +void MainWindow::reloadDynamicMenus() +{ + foreach (register_stat_group_t menu_group, menu_groups) { + QList<QAction *>actions = wsApp->removedMenuGroupItems(menu_group); + removeMenuActions(actions, menu_group); + + actions = wsApp->addedMenuGroupItems(menu_group); + addMenuActions(actions, menu_group); + } + + wsApp->clearAddedMenuGroupItems(); + wsApp->clearRemovedMenuGroupItems(); +} + void MainWindow::externalMenuHelper(ext_menu_t * menu, QMenu * subMenu, gint depth) { QAction * itemAction = NULL; diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h index c61bc66500..49e9a90cde 100644 --- a/ui/qt/main_window.h +++ b/ui/qt/main_window.h @@ -192,6 +192,9 @@ private: void recursiveCopyProtoTreeItems(QTreeWidgetItem *item, QString &clip, int ident_level); void captureFileReadStarted(const QString &action); + void addMenuActions(QList<QAction *> &actions, int menu_group); + void removeMenuActions(QList<QAction *> &actions, int menu_group); + signals: void showProgress(struct progdlg **dlg_p, bool animate, const QString message, bool terminate_is_stop, bool *stop_flag, float pct); void setCaptureFile(capture_file *cf); @@ -264,6 +267,7 @@ private slots: void showPreferenceEditor(); // module_t *, pref * void addStatsPluginsToMenu(); void addDynamicMenus(); + void reloadDynamicMenus(); void addExternalMenus(); void startInterfaceCapture(bool valid); @@ -418,6 +422,9 @@ private slots: void on_actionAnalyzeEnabledProtocols_triggered(); void on_actionAnalyzeDecodeAs_triggered(); +#ifdef HAVE_LUA + void on_actionAnalyzeReloadLuaPlugins_triggered(); +#endif void openFollowStreamDialog(follow_type_t type); void on_actionAnalyzeFollowTCPStream_triggered(); diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui index dda94a9e5e..7a0e8ec493 100644 --- a/ui/qt/main_window.ui +++ b/ui/qt/main_window.ui @@ -386,6 +386,7 @@ <addaction name="separator"/> <addaction name="actionAnalyzeEnabledProtocols"/> <addaction name="actionAnalyzeDecodeAs"/> + <addaction name="actionAnalyzeReloadLuaPlugins"/> <addaction name="separator"/> <addaction name="menuSCTP"/> <addaction name="menuFollow"/> @@ -1790,6 +1791,17 @@ <string>Change the way packets are dissected</string> </property> </action> + <action name="actionAnalyzeReloadLuaPlugins"> + <property name="text"> + <string>Reload Lua Plugins</string> + </property> + <property name="toolTip"> + <string>Reload Lua plugins</string> + </property> + <property name="shortcut"> + <string>Ctrl+Shift+L</string> + </property> + </action> <action name="action29West"> <property name="text"> <string>29West</string> diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp index 4f8ab8a437..e284ea1841 100644 --- a/ui/qt/main_window_slots.cpp +++ b/ui/qt/main_window_slots.cpp @@ -55,6 +55,10 @@ #include "epan/prefs.h" #include "epan/value_string.h" +#ifdef HAVE_LUA +#include <epan/wslua/init_wslua.h> +#endif + #include "ui/alert_box.h" #ifdef HAVE_LIBPCAP #include "ui/capture_ui_utils.h" @@ -68,6 +72,7 @@ #include "ui/recent_utils.h" #include "ui/ssl_key_export.h" #include "ui/ui_util.h" +#include "ui/qt/simple_dialog.h" #ifdef HAVE_SOFTWARE_UPDATE #include "ui/software_update.h" @@ -94,6 +99,7 @@ #include "extcap_options_dialog.h" #endif #include "filter_dialog.h" +#include "funnel_statistics.h" #include "gsm_map_summary_dialog.h" #include "io_graph_dialog.h" #include "lbm_stream_dialog.h" @@ -2467,6 +2473,28 @@ void MainWindow::on_actionAnalyzeDecodeAs_triggered() da_dialog.exec(); } +#ifdef HAVE_LUA +void MainWindow::on_actionAnalyzeReloadLuaPlugins_triggered() +{ + if (wsApp->isReloadingLua()) + return; + + wsApp->setReloadingLua(true); + + wslua_reload_plugins(NULL, NULL); + funnel_statistics_reload_menus(); + reloadDynamicMenus(); + + char *gdp_path, *dp_path; + (void) wsApp->readConfigurationFiles(&gdp_path, &dp_path); + + fieldsChanged(); + + wsApp->setReloadingLua(false); + SimpleDialog::displayQueuedMessages(); +} +#endif + void MainWindow::openFollowStreamDialog(follow_type_t type) { FollowStreamDialog *fsd = new FollowStreamDialog(*this, capture_file_, type); connect(fsd, SIGNAL(updateFilter(QString&, bool)), this, SLOT(filterPackets(QString&, bool))); diff --git a/ui/qt/simple_dialog.cpp b/ui/qt/simple_dialog.cpp index 8996aebee1..2288751df2 100644 --- a/ui/qt/simple_dialog.cpp +++ b/ui/qt/simple_dialog.cpp @@ -104,7 +104,7 @@ SimpleDialog::SimpleDialog(QWidget *parent, ESD_TYPE_E type, int btn_mask, const return; } - if (!parent || !wsApp->isInitialized()) { + if (!parent || !wsApp->isInitialized() || wsApp->isReloadingLua()) { message_queue_ << msg_pair; if (type > max_severity_) { max_severity_ = type; @@ -168,7 +168,11 @@ void SimpleDialog::displayQueuedMessages(QWidget *parent) return; } - QMessageBox mb(parent); + // Use last parent if not set + static QWidget *parent_w = NULL; + if (parent) parent_w = parent; + + QMessageBox mb(parent_w); switch(max_severity_) { case ESD_TYPE_ERROR: diff --git a/ui/qt/splash_overlay.cpp b/ui/qt/splash_overlay.cpp index 5b169826f3..b797df7454 100644 --- a/ui/qt/splash_overlay.cpp +++ b/ui/qt/splash_overlay.cpp @@ -147,6 +147,9 @@ void SplashOverlay::splashUpdate(register_action_e action, const char *message) case RA_LUA_PLUGINS: action_msg = tr("Loading Lua plugins"); break; + case RA_LUA_DEREGISTER: + action_msg = tr("Removing Lua plugins"); + break; case RA_PREFERENCES: action_msg = tr("Loading module preferences"); break; diff --git a/ui/qt/wireshark_application.cpp b/ui/qt/wireshark_application.cpp index c6c32f12d6..5c9f4e318f 100644 --- a/ui/qt/wireshark_application.cpp +++ b/ui/qt/wireshark_application.cpp @@ -90,7 +90,8 @@ static char *last_open_dir = NULL; static bool updated_last_open_dir = FALSE; static QList<recent_item_status *> recent_items_; static QHash<int, QList<QAction *> > dynamic_menu_groups_; -static QHash<int, QList<QAction *> > funnel_groups_; +static QHash<int, QList<QAction *> > added_menu_groups_; +static QHash<int, QList<QAction *> > removed_menu_groups_; QString WiresharkApplication::window_title_separator_ = QString::fromUtf8(" " UTF8_MIDDLE_DOT " "); @@ -592,6 +593,24 @@ void WiresharkApplication::addDynamicMenuGroupItem(int group, QAction *sg_action dynamic_menu_groups_[group] << sg_action; } +void WiresharkApplication::appendDynamicMenuGroupItem(int group, QAction *sg_action) +{ + if (!added_menu_groups_.contains(group)) { + added_menu_groups_[group] = QList<QAction *>(); + } + added_menu_groups_[group] << sg_action; + addDynamicMenuGroupItem(group, sg_action); +} + +void WiresharkApplication::removeDynamicMenuGroupItem(int group, QAction *sg_action) +{ + if (!removed_menu_groups_.contains(group)) { + removed_menu_groups_[group] = QList<QAction *>(); + } + removed_menu_groups_[group] << sg_action; + dynamic_menu_groups_[group].removeAll(sg_action); +} + QList<QAction *> WiresharkApplication::dynamicMenuGroupItems(int group) { if (!dynamic_menu_groups_.contains(group)) { @@ -603,6 +622,45 @@ QList<QAction *> WiresharkApplication::dynamicMenuGroupItems(int group) return sgi_list; } +QList<QAction *> WiresharkApplication::addedMenuGroupItems(int group) +{ + if (!added_menu_groups_.contains(group)) { + return QList<QAction *>(); + } + + QList<QAction *> sgi_list = added_menu_groups_[group]; + std::sort(sgi_list.begin(), sgi_list.end(), qActionLessThan); + return sgi_list; +} + +QList<QAction *> WiresharkApplication::removedMenuGroupItems(int group) +{ + if (!removed_menu_groups_.contains(group)) { + return QList<QAction *>(); + } + + QList<QAction *> sgi_list = removed_menu_groups_[group]; + std::sort(sgi_list.begin(), sgi_list.end(), qActionLessThan); + return sgi_list; +} + +void WiresharkApplication::clearAddedMenuGroupItems() +{ + foreach (int group, added_menu_groups_.uniqueKeys()) { + added_menu_groups_[group].clear(); + } +} + +void WiresharkApplication::clearRemovedMenuGroupItems() +{ + foreach (int group, removed_menu_groups_.uniqueKeys()) { + foreach (QAction *action, removed_menu_groups_[group]) { + delete action; + } + removed_menu_groups_[group].clear(); + } +} + #ifdef HAVE_LIBPCAP static void diff --git a/ui/qt/wireshark_application.h b/ui/qt/wireshark_application.h index dcd9cb24ea..1173d84bc2 100644 --- a/ui/qt/wireshark_application.h +++ b/ui/qt/wireshark_application.h @@ -75,7 +75,13 @@ public: void emitStatCommandSignal(const QString &menu_path, const char *arg, void *userdata); void emitTapParameterSignal(const QString cfg_abbr, const QString arg, void *userdata); void addDynamicMenuGroupItem(int group, QAction *sg_action); + void appendDynamicMenuGroupItem(int group, QAction *sg_action); + void removeDynamicMenuGroupItem(int group, QAction *sg_action); QList<QAction *> dynamicMenuGroupItems(int group); + QList<QAction *> addedMenuGroupItems(int group); + QList<QAction *> removedMenuGroupItems(int group); + void clearAddedMenuGroupItems(); + void clearRemovedMenuGroupItems(); void allSystemsGo(); void refreshLocalInterfaces(); @@ -91,6 +97,8 @@ public: int monospaceTextSize(const char *str); void setConfigurationProfile(const gchar *profile_name); bool isInitialized() { return initialized_; } + void setReloadingLua(bool is_reloading) { is_reloading_lua_ = is_reloading; } + bool isReloadingLua() { return is_reloading_lua_; } const QIcon &normalIcon() const { return normal_icon_; } const QIcon &captureIcon() const { return capture_icon_; } const QString &windowTitleSeparator() const { return window_title_separator_; } @@ -103,6 +111,7 @@ public: private: bool initialized_; + bool is_reloading_lua_; QFont mono_font_; QTimer recent_timer_; QTimer addr_resolv_timer_; |