aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStig Bjørlykke <stig@bjorlykke.org>2015-08-11 14:08:08 +0200
committerStig Bjørlykke <stig@bjorlykke.org>2015-08-11 12:09:07 +0000
commitecc4f756bdb6175cc0b3b11af2f90884db1c602c (patch)
tree99d8ca48a72752e1257d4b8b321f41d1767ee020
parent70d06deb2e31bd605e672200a7755764febe94ae (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>
-rw-r--r--asn1/ldap/packet-ldap-template.c4
-rw-r--r--debian/libwireshark0.symbols17
-rw-r--r--epan/dissectors/packet-http.c4
-rw-r--r--epan/dissectors/packet-imf.c4
-rw-r--r--epan/dissectors/packet-ldap.c4
-rw-r--r--epan/expert.c5
-rw-r--r--epan/expert.h5
-rw-r--r--epan/funnel.c102
-rw-r--r--epan/funnel.h11
-rw-r--r--epan/packet.c70
-rw-r--r--epan/packet.h19
-rw-r--r--epan/prefs.c31
-rw-r--r--epan/prefs.h5
-rw-r--r--epan/proto.c47
-rw-r--r--epan/proto.h12
-rw-r--r--epan/wmem/wmem_tree.c16
-rw-r--r--epan/wmem/wmem_tree.h7
-rw-r--r--epan/wslua/init_wslua.c101
-rw-r--r--epan/wslua/init_wslua.h2
-rw-r--r--epan/wslua/wslua.h17
-rw-r--r--epan/wslua/wslua_dissector.c44
-rw-r--r--epan/wslua/wslua_field.c6
-rw-r--r--epan/wslua/wslua_file_handler.c5
-rw-r--r--epan/wslua/wslua_gui.c21
-rw-r--r--epan/wslua/wslua_listener.c49
-rw-r--r--epan/wslua/wslua_pref.c8
-rw-r--r--epan/wslua/wslua_proto.c110
-rw-r--r--epan/wslua/wslua_proto_expert.c16
-rw-r--r--epan/wslua/wslua_proto_field.c33
-rw-r--r--epan/wslua/wslua_tree.c1
-rw-r--r--register.h1
-rw-r--r--ui/cli/tap-funnel.c1
-rw-r--r--ui/gtk/funnel_stat.c1
-rw-r--r--ui/qt/funnel_statistics.cpp60
-rw-r--r--ui/qt/funnel_statistics.h4
-rw-r--r--ui/qt/funnel_string_dialog.cpp18
-rw-r--r--ui/qt/funnel_string_dialog.h3
-rw-r--r--ui/qt/main_window.cpp190
-rw-r--r--ui/qt/main_window.h7
-rw-r--r--ui/qt/main_window.ui12
-rw-r--r--ui/qt/main_window_slots.cpp28
-rw-r--r--ui/qt/simple_dialog.cpp8
-rw-r--r--ui/qt/splash_overlay.cpp3
-rw-r--r--ui/qt/wireshark_application.cpp60
-rw-r--r--ui/qt/wireshark_application.h9
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(&registered_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(&registered_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_;