Plugin Interface: Add GUI callbacks

Rename ext_menubar to a more appropriate plugin_if.

 External menus can be implemented by plugins to present
 additional menus for deep-packet analysis. One side-effect
 of such menus being implemented as plugins is, that they
 are being executed in different threads and therefore can
 only use limited access to the main GUI. Also, there is
 no safe cross-gui (GTK and Qt) way for many features.

 This patch implements a first functionality, by which a
 plugin implemented using ext_menubar can apply a display
 filter to the main view.

 For now the implementation supports filtering, as well as
 saving a preference.

Change-Id: Iffe4caa954bbeb8ce356352de4dae348a50efba9
Reviewed-on: https://code.wireshark.org/review/8773
Reviewed-by: Roland Knall <rknall@gmail.com>
Petri-Dish: Anders Broman <a.broman58@gmail.com>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Roland Knall 2015-06-05 11:19:37 +02:00 committed by Anders Broman
parent d4aa1a1c24
commit acc581081e
12 changed files with 292 additions and 19 deletions

View File

@ -321,12 +321,14 @@ is encouraged to update their plugins as outlined below:
the DOCSIS plugin.
6 How to implement a plugin related menu
6 How to plugin related interface options
6.1 Implement a plugin GUI menu
A plugin (as well as built-in dissectors) may implement a menu within
Wireshark to be used to trigger options, start tools, open Websites, ...
This menu structure is built using the ext_menubar.h interface and it's
This menu structure is built using the plugin_if.h interface and it's
corresponding functions.
The menu items all call a callback provided by the plugin, which takes
@ -365,7 +367,25 @@ Using the Gtk Version and a Mac OSX operating system, this will not work, and
the Gtk interface is currently not supported on this plattform. The Qt interface
on Mac provides the menu.
For a more detailed information, please refer to ext_menubar.h
For a more detailed information, please refer to plugin_if.h
6.2 Implement interactions with the main interface
Due to memory constraints on most plattforms, plugin functionality cannot be
called directly from a DLL context. Instead special functions will be used, which
will implement certain options for plugins to utilize.
The following methods exist so far:
/* Applies the given filter string as display filter */
WS_DLL_PUBLIC void plugin_if_apply_filter
(const char * filter_string, gboolean force);
/* Saves the given preference to the main preference storage */
WS_DLL_PUBLIC void plugin_if_save_preference
(const char * pref_module, const char * pref_key, const char * pref_value);
----------------

View File

@ -1600,7 +1600,7 @@ set(LIBWIRESHARK_FILES
except.c
expert.c
exported_pdu.c
ext_menubar.c
plugin_if.c
filter_expressions.c
follow.c
frame_data.c

View File

@ -51,7 +51,7 @@ LIBWIRESHARK_SRC = \
except.c \
expert.c \
exported_pdu.c \
ext_menubar.c \
plugin_if.c \
filter_expressions.c \
follow.c \
frame_data.c \
@ -192,7 +192,7 @@ LIBWIRESHARK_INCLUDES = \
exceptions.h \
expert.h \
exported_pdu.h \
ext_menubar.h \
plugin_if.h \
filter_expressions.h \
follow.h \
frame_data.h \

View File

@ -1,9 +1,12 @@
/* ext_menubar.c
* A menubar API for Wireshark dissectors
/* plugin_if.c
* An API for Wireshark plugins
*
* This enables wireshark dissectors, especially those implemented by plugins
* to register menubar entries, which then will call a pre-defined callback
* function for the dissector or plugin
* function for the dissector or plugin.
*
* Also it implements additional methods, which allow plugins to interoperate
* with the main GUI.
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
@ -30,7 +33,7 @@
#include <epan/epan.h>
#include <epan/proto.h>
#include "ext_menubar.h"
#include "plugin_if.h"
static GList * menubar_entries = NULL;
static GList * menubar_menunames = NULL;
@ -158,6 +161,84 @@ extern void ext_menubar_add_separator(ext_menu_t *parent)
ext_menubar_add_generic_entry ( EXT_MENUBAR_SEPARATOR, parent, g_strdup("-"), NULL, NULL, NULL );
}
/* Implementation of GUI callback methods follows.
* This is a necessity, as using modern UI systems, gui interfaces often operate
* in different threads then the calling application. Even more so, if the calling
* application is implemented using a separate plugin. Therefore the external menubars
* cannot call gui functionality directly, the gui has to perform the function within
* it' own scope. */
static GHashTable * plugin_if_callback_functions;
static void
plugin_if_init_hashtable(void)
{
if ( plugin_if_callback_functions == 0 )
plugin_if_callback_functions = g_hash_table_new(g_int_hash, g_int_equal);
}
static void plugin_if_call_gui_cb(plugin_if_callback_t actionType, GHashTable * dataSet)
{
plugin_if_gui_cb action;
gint * key = 0;
key = (gint *)g_malloc0(sizeof(gint));
*key = (gint) actionType;
plugin_if_init_hashtable();
if ( g_hash_table_size(plugin_if_callback_functions) != 0 )
{
if ( g_hash_table_contains(plugin_if_callback_functions, key) )
{
action = (plugin_if_gui_cb)g_hash_table_lookup(plugin_if_callback_functions, key);
if ( action != NULL )
action(dataSet);
}
}
}
extern void plugin_if_apply_filter(const char * filter_string, gboolean force)
{
plugin_if_callback_t actionType;
GHashTable * dataSet = NULL;
actionType = ( force == TRUE ) ? PLUGIN_IF_FILTER_ACTION_APPLY : PLUGIN_IF_FILTER_ACTION_PREPARE;
dataSet = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_insert( dataSet, g_strdup("action_type"), (gpointer) &actionType );
g_hash_table_insert( dataSet, g_strdup("filter_string"), g_strdup(filter_string) );
g_hash_table_insert( dataSet, g_strdup("force"), (gpointer) &force );
plugin_if_call_gui_cb(actionType, dataSet);
}
extern void plugin_if_save_preference(const char * pref_module, const char * pref_key, const char * pref_value)
{
GHashTable * dataSet = NULL;
dataSet = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_insert( dataSet, g_strdup("pref_module"), g_strdup(pref_module) );
g_hash_table_insert( dataSet, g_strdup("pref_key"), g_strdup(pref_key) );
g_hash_table_insert( dataSet, g_strdup("pref_value"), g_strdup(pref_value) );
plugin_if_call_gui_cb(PLUGIN_IF_PREFERENCE_SAVE, dataSet);
}
extern void plugin_if_register_gui_cb(plugin_if_callback_t actionType, plugin_if_gui_cb callback)
{
gint * key = 0;
key = (gint *)g_malloc0(sizeof(gint));
*key = actionType;
plugin_if_init_hashtable();
if ( ! g_hash_table_contains(plugin_if_callback_functions, key ) )
g_hash_table_insert(plugin_if_callback_functions, key, callback);
}
/*
* Editor modelines
*

View File

@ -1,9 +1,12 @@
/* ext_menubar.h
* A menubar API for Wireshark dissectors
/* plugin_if.h
* An API for Wireshark plugins
*
* This enables wireshark dissectors, especially those implemented by plugins
* to register menubar entries, which then will call a pre-defined callback
* function for the dissector or plugin
* function for the dissector or plugin.
*
* Also it implements additional methods, which allow plugins to interoperate
* with the main GUI.
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
@ -23,8 +26,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef EPAN_EXT_MENUBAR_H_
#define EPAN_EXT_MENUBAR_H_
#ifndef EPAN_PLUGIN_IF_H
#define EPAN_PLUGIN_IF_H
#include <config.h>
@ -146,6 +149,33 @@ WS_DLL_PUBLIC void ext_menubar_add_separator(ext_menu_t *parent_menu);
WS_DLL_PUBLIC void ext_menubar_add_website(ext_menu_t * parent, const gchar *label,
const gchar *tooltip, const gchar *url);
/*
* Enumeration of possible actions, which are registered in GUI interfaces
*/
typedef enum
{
/* Applies a given string as filter */
PLUGIN_IF_FILTER_ACTION_APPLY,
/* Prepares the given string as filter */
PLUGIN_IF_FILTER_ACTION_PREPARE,
/* Saves a preference entry */
PLUGIN_IF_PREFERENCE_SAVE
} plugin_if_callback_t;
typedef void (*plugin_if_gui_cb)(gconstpointer user_data);
WS_DLL_PUBLIC void plugin_if_register_gui_cb(plugin_if_callback_t actionType, plugin_if_gui_cb callback);
/* Applies the given filter string as display filter */
WS_DLL_PUBLIC void plugin_if_apply_filter(const char * filter_string, gboolean force);
/* Saves the given preference to the main preference storage */
WS_DLL_PUBLIC void plugin_if_save_preference(const char * pref_module, const char * pref_key, const char * pref_value);
/* Private Method for retrieving the menubar entries
*
* Is only to be used by the UI interfaces to retrieve the menu entries
@ -156,7 +186,7 @@ WS_DLL_PUBLIC GList * ext_menubar_get_entries(void);
}
#endif /* __cplusplus */
#endif /* EPAN_EXT_MENUBAR_H_ */
#endif /* EPAN_PLUGIN_IF_H */
/*
* Editor modelines

View File

@ -39,6 +39,7 @@
#include "filter_autocomplete.h"
#include "epan/prefs.h"
#include "epan/plugin_if.h"
#include "keys.h"
#include "gtkglobals.h"
@ -109,6 +110,26 @@ filter_save_cb(GtkWidget *w _U_, GtkWindow *parent_w)
filter_expression_save_dlg(parent_w);
}
static void
plugin_if_filter_apply(gconstpointer filter_text)
{
/* code is derived from voip_calls_dlg.c::voip_calls_on_filter */
int pos = 0;
size_t filter_length;
size_t max_filter_length = 2048;
gchar *filter_string;
if ( main_display_filter_widget != 0 )
{
filter_string = g_strndup((const char *)filter_text, max_filter_length);
filter_length = strlen(filter_string);
pos = (int)filter_length;
if ( filter_length < max_filter_length )
gtk_editable_insert_text(GTK_EDITABLE(main_display_filter_widget), filter_string, -1, &pos);
}
}
GtkWidget *
filter_toolbar_new(void)
@ -279,6 +300,9 @@ filter_toolbar_new(void)
/* make current preferences effective */
toolbar_redraw_all();
plugin_if_register_gui_cb(PLUGIN_IF_FILTER_ACTION_APPLY, plugin_if_filter_apply );
plugin_if_register_gui_cb(PLUGIN_IF_FILTER_ACTION_PREPARE, plugin_if_filter_apply );
return filter_tb;
}

View File

@ -36,7 +36,7 @@
#include <epan/epan_dissect.h>
#include <epan/column.h>
#include <epan/stats_tree_priv.h>
#include <epan/ext_menubar.h>
#include <epan/plugin_if.h>
#include "globals.h"
#include "color_filters.h"

View File

@ -34,6 +34,7 @@
#include <epan/packet.h>
#include <epan/column.h>
#include <epan/strutil.h>
#include <epan/plugin_if.h>
#include "ui/main_statusbar.h"
#include "ui/packet_list_utils.h"
@ -91,6 +92,7 @@ static void show_cell_data_func(GtkTreeViewColumn *col,
static gint row_number_from_iter(GtkTreeIter *iter);
static void scroll_to_current(void);
static gboolean query_packet_list_tooltip_cb(GtkWidget *widget, gint x, gint y, gboolean keyboard_tip, GtkTooltip *tooltip, gpointer data _U_);
static void plugin_if_pktlist_preference(gconstpointer user_data);
GtkWidget *
packet_list_create(void)
@ -105,6 +107,8 @@ packet_list_create(void)
g_object_set_data(G_OBJECT(popup_menu_object), E_MPACKET_LIST_KEY, view);
plugin_if_register_gui_cb(PLUGIN_IF_PREFERENCE_SAVE, plugin_if_pktlist_preference);
return scrollwin;
}
@ -1730,6 +1734,26 @@ query_packet_list_tooltip_cb(GtkWidget *widget, gint x, gint y, gboolean keyboar
return result;
}
void plugin_if_pktlist_preference(gconstpointer user_data)
{
if ( packetlist != NULL && user_data != NULL )
{
GHashTable * dataSet = (GHashTable *) user_data;
if ( g_hash_table_contains(dataSet, "pref_module" ) &&
g_hash_table_contains(dataSet, "pref_value" ) &&
g_hash_table_contains(dataSet, "pref_value" ) )
{
const char * module_name = (const char *)g_hash_table_lookup(dataSet, "pref_module");
const char * pref_name = (const char *)g_hash_table_lookup(dataSet, "pref_key");
const char * pref_value = (const char *)g_hash_table_lookup(dataSet, "pref_value");
if ( prefs_store_ext(module_name, pref_name, pref_value) )
packet_list_recreate();
}
}
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*

View File

@ -273,6 +273,48 @@ prefs_main_write(void)
}
}
gboolean
prefs_store_ext(const char * module_name, const char *pref_name, const char *pref_value)
{
module_t * module = NULL;
pref_t * pref = NULL;
gboolean pref_changed = TRUE;
if ( ! prefs_is_registered_protocol(module_name))
return FALSE;
module = prefs_find_module(module_name);
if ( ! module )
return FALSE;
pref = prefs_find_preference(module, pref_name);
if (!pref)
return FALSE;
if ( pref->type == PREF_STRING )
{
g_free((void *)pref->stashed_val.string);
pref->stashed_val.string = (gchar *) g_strdup(pref_value);
/* unstash - taken from preferences_util */
if (strcmp(*pref->varp.string, pref->stashed_val.string) != 0)
{
pref_changed = TRUE;
g_free((void *)*pref->varp.string);
*pref->varp.string = g_strdup(pref->stashed_val.string);
}
}
if ( pref_changed )
{
prefs_main_write();
prefs_apply_all();
prefs_to_capture_opts();
}
return TRUE;
}
gint
column_prefs_add_custom(gint fmt, const gchar *title, const gchar *custom_field, gint custom_occurrence)
{

View File

@ -80,6 +80,16 @@ extern void prefs_to_capture_opts(void);
*/
extern void prefs_main_write(void);
/** Convenient function for plugin_if
*
* @param module the module for the preference
* @param key the key for the preference
* @param value the new value as string for the preference
*
* @return true if the value has been stored successfully
*/
extern gboolean prefs_store_ext(const char * module, const char * key, const char * value);
/** Add a custom column.
*
* @param fmt column format

View File

@ -27,7 +27,7 @@
#include <wsutil/filesystem.h>
#include <epan/prefs.h>
#include <epan/stats_tree_priv.h>
#include <epan/ext_menubar.h>
#include <epan/plugin_if.h>
#ifdef HAVE_LIBPCAP
#include "ui/capture.h"
@ -42,6 +42,7 @@
#include "ui/main_statusbar.h"
#include "ui/recent.h"
#include "ui/util.h"
#include "ui/preference_utils.h"
#include "byte_view_tab.h"
#include "display_filter_edit.h"
@ -83,6 +84,42 @@ void pipe_input_set_handler(gint source, gpointer user_data, ws_process_id *chil
gbl_cur_main_window_->setPipeInputHandler(source, user_data, child_process, input_cb);
}
void plugin_if_mainwindow_apply_filter(gconstpointer user_data)
{
if ( gbl_cur_main_window_ != NULL && user_data != NULL )
{
GHashTable * dataSet = (GHashTable *) user_data;
if ( g_hash_table_contains(dataSet, "filter_string" ) )
{
QString filter((const char *)g_hash_table_lookup(dataSet, "filter_string"));
gbl_cur_main_window_->filterPackets(filter);
}
}
}
void plugin_if_mainwindow_preference(gconstpointer user_data)
{
if ( gbl_cur_main_window_ != NULL && user_data != NULL )
{
GHashTable * dataSet = (GHashTable *) user_data;
if ( g_hash_table_contains(dataSet, "pref_module" ) &&
g_hash_table_contains(dataSet, "pref_value" ) &&
g_hash_table_contains(dataSet, "pref_value" ) )
{
const char * module_name = (const char *)g_hash_table_lookup(dataSet, "pref_module");
const char * pref_name = (const char *)g_hash_table_lookup(dataSet, "pref_key");
const char * pref_value = (const char *)g_hash_table_lookup(dataSet, "pref_value");
if ( prefs_store_ext(module_name, pref_name, pref_value) )
{
wsApp->emitAppSignal(WiresharkApplication::PacketDissectionChanged);
wsApp->emitAppSignal(WiresharkApplication::PreferencesChanged);
}
}
}
}
gpointer
simple_dialog(ESD_TYPE_E type, gint btn_mask, const gchar *msg_format, ...)
{
@ -479,6 +516,11 @@ MainWindow::MainWindow(QWidget *parent) :
this->main_welcome_->getInterfaceTree(), SLOT(interfaceListChanged()));
#endif
/* Create plugin_if hooks */
plugin_if_register_gui_cb(PLUGIN_IF_FILTER_ACTION_APPLY, plugin_if_mainwindow_apply_filter );
plugin_if_register_gui_cb(PLUGIN_IF_FILTER_ACTION_PREPARE, plugin_if_mainwindow_apply_filter );
plugin_if_register_gui_cb(PLUGIN_IF_PREFERENCE_SAVE, plugin_if_mainwindow_preference);
main_ui_->mainStack->setCurrentWidget(main_welcome_);
}

View File

@ -33,7 +33,7 @@
#include "ui/ui_util.h"
#include <epan/prefs.h>
#include <epan/ext_menubar.h>
#include <epan/plugin_if.h>
#ifdef HAVE_LIBPCAP
#include "capture_opts.h"