aboutsummaryrefslogtreecommitdiffstats
path: root/epan
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 /epan
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>
Diffstat (limited to 'epan')
-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
28 files changed, 635 insertions, 120 deletions
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();