extcap: Lazily load our interface list.

Add extcap_ensure_all_interfaces_loaded, which calls
extcap_load_interface_list if our interface list is empty. Call it in
each of our public functions that require a valid interface list.

Clean up the extcap API documentation and note which routines initialize
the interface list.

In tshark, don't unconditionally call extcap_register_preferences and
instead rely on lazy loading.

Change-Id: I8493ae5f4d703b0fd767246557d17723bcf207c6
Ping-Bug: 15295
Reviewed-on: https://code.wireshark.org/review/37750
Petri-Dish: Gerald Combs <gerald@wireshark.org>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Gerald Combs 2020-07-06 13:41:52 -07:00 committed by Anders Broman
parent 45378647d7
commit 9c53ac0187
3 changed files with 143 additions and 38 deletions

View File

@ -73,7 +73,7 @@ static GHashTable *_toolbars = NULL;
* values. These ensure that preferences can survive extcap if garbage
* collection, and does not lead to dangling pointers in the prefs subsystem.
*/
static GHashTable *extcap_prefs_dynamic_vals = NULL;
static GHashTable *_extcap_prefs_dynamic_vals = NULL;
typedef struct _extcap_callback_info_t
{
@ -127,6 +127,12 @@ typedef struct extcap_run_extcaps_info {
static void extcap_load_interface_list(void);
/* Used for lazily loading our interfaces. */
static void extcap_ensure_all_interfaces_loaded(void) {
if ( !_loaded_interfaces || g_hash_table_size(_loaded_interfaces) == 0 )
extcap_load_interface_list();
}
static gboolean
thread_pool_push(thread_pool_t *pool, gpointer data, GError **error)
{
@ -152,8 +158,7 @@ extcap_loaded_interfaces(void)
if (prefs.capture_no_extcap)
return NULL;
if ( !_loaded_interfaces || g_hash_table_size(_loaded_interfaces) == 0 )
extcap_load_interface_list();
extcap_ensure_all_interfaces_loaded();
return _loaded_interfaces;
}
@ -179,6 +184,8 @@ compare_tools(gconstpointer a, gconstpointer b)
void
extcap_get_descriptions(plugin_description_callback callback, void *callback_data)
{
extcap_ensure_all_interfaces_loaded();
GHashTable * tools = extcap_loaded_interfaces();
GPtrArray *tools_array = g_ptr_array_new();
@ -594,6 +601,9 @@ extcap_get_if_dlts(const gchar *ifname, char **err_str)
*err_str = NULL;
}
/* Update the extcap interfaces and get a list of their if_infos */
extcap_ensure_all_interfaces_loaded();
extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
if (interface)
{
@ -655,6 +665,8 @@ if_info_compare(gconstpointer a, gconstpointer b)
gchar *
extcap_get_help_for_ifname(const char *ifname)
{
extcap_ensure_all_interfaces_loaded();
extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
return interface != NULL ? interface->help : NULL;
}
@ -670,8 +682,7 @@ append_extcap_interface_list(GList *list, char **err_str _U_)
return list;
/* Update the extcap interfaces and get a list of their if_infos */
if ( !_loaded_interfaces || g_hash_table_size(_loaded_interfaces) == 0 )
extcap_load_interface_list();
extcap_ensure_all_interfaces_loaded();
ifutilkeys_head = g_hash_table_get_keys(_loaded_interfaces);
ifutilkeys = ifutilkeys_head;
@ -727,7 +738,7 @@ void extcap_register_preferences(void)
}
// Will load information about extcaps and their supported config.
extcap_load_interface_list();
extcap_ensure_all_interfaces_loaded();
}
/**
@ -736,8 +747,8 @@ void extcap_register_preferences(void)
*/
void extcap_cleanup(void)
{
if (extcap_prefs_dynamic_vals)
g_hash_table_destroy(extcap_prefs_dynamic_vals);
if (_extcap_prefs_dynamic_vals)
g_hash_table_destroy(_extcap_prefs_dynamic_vals);
if (_loaded_interfaces)
g_hash_table_destroy(_loaded_interfaces);
@ -759,19 +770,19 @@ void extcap_cleanup(void)
static gchar **extcap_prefs_dynamic_valptr(const char *name, char **pref_name)
{
gchar **valp;
if (!extcap_prefs_dynamic_vals)
if (!_extcap_prefs_dynamic_vals)
{
/* Initialize table only as needed, most preferences are not dynamic */
extcap_prefs_dynamic_vals = g_hash_table_new_full(g_str_hash, g_str_equal,
_extcap_prefs_dynamic_vals = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, g_free);
}
if (!g_hash_table_lookup_extended(extcap_prefs_dynamic_vals, name,
if (!g_hash_table_lookup_extended(_extcap_prefs_dynamic_vals, name,
(gpointer *)pref_name, (gpointer *)&valp))
{
/* New dynamic pref, allocate, initialize and store. */
valp = g_new0(gchar *, 1);
*pref_name = g_strdup(name);
g_hash_table_insert(extcap_prefs_dynamic_vals, *pref_name, valp);
g_hash_table_insert(_extcap_prefs_dynamic_vals, *pref_name, valp);
}
return valp;
}
@ -803,6 +814,8 @@ extcap_pref_for_argument(const gchar *ifname, struct _extcap_arg *arg)
{
struct preference *pref = NULL;
extcap_ensure_all_interfaces_loaded();
GRegex *regex_name = g_regex_new("[-]+", G_REGEX_RAW, (GRegexMatchFlags) 0, NULL);
GRegex *regex_ifname = g_regex_new("(?![a-zA-Z0-9_]).", G_REGEX_RAW, (GRegexMatchFlags) 0, NULL);
if (regex_name && regex_ifname)
@ -886,7 +899,7 @@ static gboolean cb_preference(extcap_callback_info_t cb_info)
/* Been here before, restore stored value */
if (arg->pref_valptr == NULL)
{
arg->pref_valptr = (gchar**)g_hash_table_lookup(extcap_prefs_dynamic_vals, pref_ifname);
arg->pref_valptr = (gchar**)g_hash_table_lookup(_extcap_prefs_dynamic_vals, pref_ifname);
}
}
@ -921,6 +934,8 @@ extcap_get_if_configuration(const char *ifname)
GList * arguments = NULL;
GList *ret = NULL;
extcap_ensure_all_interfaces_loaded();
extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
if (interface)
{
@ -965,6 +980,8 @@ extcap_get_if_configuration_values(const char * ifname, const char * argname, GH
GList * args = NULL;
GList *ret = NULL;
extcap_ensure_all_interfaces_loaded();
extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
if (interface)
{
@ -999,21 +1016,15 @@ extcap_get_if_configuration_values(const char * ifname, const char * argname, GH
return ret;
}
/**
* If is_required is FALSE: returns TRUE if the extcap interface has
* configurable options.
* If is_required is TRUE: returns TRUE when the extcap interface has
* configurable options that required modification. (For example, when an
* argument is required but empty.)
*/
gboolean
extcap_has_configuration(const char *ifname, gboolean is_required)
{
GList *arguments = 0;
GList *walker = 0, * item = 0;
gboolean found = FALSE;
extcap_ensure_all_interfaces_loaded();
arguments = extcap_get_if_configuration(ifname);
walker = g_list_first(arguments);
@ -1106,6 +1117,8 @@ extcap_verify_capture_filter(const char *ifname, const char *filter, gchar **err
GList * arguments = NULL;
extcap_filter_status status = EXTCAP_FILTER_UNKNOWN;
extcap_ensure_all_interfaces_loaded();
extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
if (interface)
{
@ -1132,6 +1145,8 @@ extcap_has_toolbar(const char *ifname)
return FALSE;
}
extcap_ensure_all_interfaces_loaded();
GList *toolbar_list = g_hash_table_get_values (_toolbars);
for (GList *walker = toolbar_list; walker; walker = walker->next)
{
@ -1586,6 +1601,8 @@ extcap_init_interfaces(capture_options *capture_opts)
interface_options *interface_opts;
ws_pipe_t *pipedata;
extcap_ensure_all_interfaces_loaded();
for (i = 0; i < capture_opts->ifaces->len; i++)
{
GPtrArray *args = NULL;
@ -1730,6 +1747,8 @@ extcap_ensure_interface(const gchar * toolname, gboolean create_if_nonexist)
extcap_info *
extcap_get_tool_by_ifname(const gchar *ifname)
{
extcap_ensure_all_interfaces_loaded();
if ( ifname && _tool_for_ifname )
{
gchar * toolname = (gchar *)g_hash_table_lookup(_tool_for_ifname, ifname);
@ -1743,6 +1762,8 @@ extcap_get_tool_by_ifname(const gchar *ifname)
extcap_info *
extcap_get_tool_info(const gchar * toolname)
{
extcap_ensure_all_interfaces_loaded();
return extcap_ensure_interface(toolname, FALSE);
}

116
extcap.h
View File

@ -67,57 +67,104 @@ struct _extcap_arg;
extern "C" {
#endif /* __cplusplus */
/* Registers preferences for all interfaces */
/**
* Registers preferences for all interfaces.
* Initializes the extcap interface list if that hasn't already been done.
*/
void
extcap_register_preferences(void);
/* try to get if capabilities from extcap */
/**
* Fetches the interface capabilities for the named extcap interface.
* Initializes the extcap interface list if that hasn't already been done.
* @param ifname The interface name.
* @param err_str Set to NULL on success, error description on failure.
* @return The interface capabilities on success, NULL on failure.
*/
if_capabilities_t *
extcap_get_if_dlts(const gchar * ifname, char ** err_str);
/* append a list of all extcap capture interfaces to the specified list */
/**
* Append a list of all extcap capture interfaces to the specified list.
* Initializes the extcap interface list if that hasn't already been done.
* @param list An existing GList of if_info_t.
* @param err_str Set to NULL on success, error description on failure.
* @return An updated list on success, an unchanged list on failure.
*/
GList *
append_extcap_interface_list(GList *list, char **err_str);
/**
* Retrieves information about an extcap executable.
* Initializes the extcap interface list if that hasn't already been done.
* @param toolname The extcap name.
* @return The extcap information on success, NULL on failure.
*/
extcap_info *
extcap_get_tool_info(const gchar * toolname);
/**
* Retrieves information about an extcap interface.
* Initializes the extcap interface list if that hasn't already been done.
* @param ifname The extcap interface name.
* @return The extcap information on success, NULL on failure.
*/
extcap_info *
extcap_get_tool_by_ifname(const gchar *ifname);
/* return the help page or NULL for the given ifname */
/**
* Retrieves help information for an extcap interface.
* Initializes the extcap interface list if that hasn't already been done.
* @param ifname The extcap interface name.
* @return A help string on success or NULL on failure.
*/
gchar *
extcap_get_help_for_ifname(const char *ifname);
/* remove all loaded interfaces */
/**
* Remove all loaded extcap interfaces.
*/
void
extcap_clear_interfaces(void);
/* get information about all available extcap executables */
/**
* Retrieves information about all available extcap executables.
* Initializes the extcap interface list if that hasn't already been done.
* @param callback The description callback routine.
* @param callback_data Data to be passed to the callback routine.
*/
void
extcap_get_descriptions(plugin_description_callback callback, void *callback_data);
/* print information about all available extcap executables */
/**
* Print information about all available extcap executables.
* Initializes the extcap interface list if that hasn't already been done.
*/
void
extcap_dump_all(void);
/* returns the configuration for the given interface name, or an
* empty list, if no configuration has been found
* @param ifname the interface name
/**
* Returns the configuration for the given interface name, or an
* empty list, if no configuration has been found.
* Initializes the extcap interface list if that hasn't already been done.
* @param ifname The interface name.
*/
GList *
extcap_get_if_configuration(const char * ifname);
/* returns the configuration values for the given argument, or an
* empty list, if no values could been found
* @param ifname the interface name
* @param argname the name of the argument, for which the values should be retrieved
/**
* Returns the configuration values for the given argument, or an
* empty list, if no values could been found.
* Initializes the extcap interface list if that hasn't already been done.
* @param ifname The interface name.
* @param argname The name of the argument for which the values should be retrieved.
*/
GList *
extcap_get_if_configuration_values(const char * ifname, const char * argname, GHashTable * arguments);
/**
* Check if the capture filter for the given interface name is valid.
* Initializes the extcap interface list if that hasn't already been done.
* @param ifname Interface to check
* @param filter Capture filter to check
* @param err_str Error string returned if filter is invalid
@ -135,23 +182,60 @@ extcap_verify_capture_filter(const char *ifname, const char *filter, gchar **err
void
extcap_free_if_configuration(GList *list, gboolean free_args);
/**
* Checks to see if an interface has configurable options.
* If is_required is FALSE: returns TRUE if the extcap interface has
* configurable options.
* If is_required is TRUE: returns TRUE when the extcap interface has
* configurable options that required modification. (For example, when an
* argument is required but empty.)
* Initializes the extcap interface list if that hasn't already been done.
* @param ifname Interface to check.
* @param is_required Required configuration flag.
* @return
*/
gboolean
extcap_has_configuration(const char * ifname, gboolean is_required);
/**
* Checks to see if the interface has an associated toolbar.
* Initializes the extcap interface list if that hasn't already been done.
* @param ifname Interface to check.
* @return TRUE if the interface has a toolbar, FALSE otherwise.
*/
gboolean
extcap_has_toolbar(const char *ifname);
/**
* Initializes each extcap interface with the supplied capture options.
* Initializes the extcap interface list if that hasn't already been done.
* @param capture_opts Capture options.
* @return TRUE on success, FALSE on failure.
*/
gboolean
extcap_init_interfaces(capture_options * capture_opts);
/* Clean up all if related stuff */
/**
* Clean up all if related stuff.
* @param capture_opts Capture options.
* @param errormsg Set to NULL on success, error description on failure.
*/
void
extcap_if_cleanup(capture_options * capture_opts, gchar ** errormsg);
/**
* Fetch an extcap preference for a given argument.
* Initializes the extcap interface list if that hasn't already been done.
* @param ifname The interface to check.
* @param arg The command line argument to check.
* @return The associated preference on success, NULL on failure.
*/
struct preference *
extcap_pref_for_argument(const gchar *ifname, struct _extcap_arg * arg);
/* Clean up global extcap stuff on program exit */
/**
* Clean up global extcap stuff on program exit.
*/
void extcap_cleanup(void);
#ifdef __cplusplus

View File

@ -940,7 +940,6 @@ main(int argc, char *argv[])
#ifdef HAVE_PLUGINS
register_all_plugin_tap_listeners();
#endif
extcap_register_preferences();
/* Register all tap listeners. */
for (tap_reg_t *t = tap_reg_listener; t->cb_func != NULL; t++) {
t->cb_func();
@ -968,6 +967,7 @@ main(int argc, char *argv[])
if (strcmp(argv[2], "column-formats") == 0)
column_dump_column_formats();
else if (strcmp(argv[2], "currentprefs") == 0) {
extcap_register_preferences();
epan_load_settings();
write_prefs(NULL);
}