core: device-factory: implement match_connection()

Make it possible to register different factories for the same setting
type, and add a match_connection() method to let each factory decide
if it's capable of handling a connection.

This will be used to decide whether a PPPoE connection must be handled
through the legacy Ethernet factory or through the new PPP factory.
This commit is contained in:
Beniamino Galvani 2017-06-30 16:33:07 +02:00
parent df72cad107
commit 8665cdfeff
4 changed files with 74 additions and 27 deletions

View file

@ -26,6 +26,7 @@
#include <gmodule.h>
#include "devices/nm-device-factory.h"
#include "devices/nm-device-bridge.h"
#include "nm-setting-bluetooth.h"
#include "settings/nm-settings.h"
#include "nm-bluez4-manager.h"
@ -417,6 +418,21 @@ create_device (NMDeviceFactory *factory,
return NULL;
}
static gboolean
match_connection (NMDeviceFactory *factory,
NMConnection *connection)
{
const char *type = nm_connection_get_connection_type (connection);
nm_assert (nm_streq (type, NM_SETTING_BLUETOOTH_SETTING_NAME));
if ( nm_bt_vtable_network_server
&& _nm_connection_get_setting_bluetooth_for_nap (connection))
return FALSE; /* handled by the bridge factory */
return TRUE;
}
/*****************************************************************************/
static void
@ -461,5 +477,6 @@ nm_bluez_manager_class_init (NMBluezManagerClass *klass)
factory_class->get_supported_types = get_supported_types;
factory_class->create_device = create_device;
factory_class->match_connection = match_connection;
factory_class->start = start;
}

View file

@ -538,8 +538,24 @@ create_device (NMDeviceFactory *factory,
NULL);
}
static gboolean
match_connection (NMDeviceFactory *factory,
NMConnection *connection)
{
const char *type = nm_connection_get_connection_type (connection);
if (nm_streq (type, NM_SETTING_BRIDGE_SETTING_NAME))
return TRUE;
nm_assert (nm_streq (type, NM_SETTING_BLUETOOTH_SETTING_NAME));
return nm_bt_vtable_network_server
&& _nm_connection_get_setting_bluetooth_for_nap (connection);
}
NM_DEVICE_FACTORY_DEFINE_INTERNAL (BRIDGE, Bridge, bridge,
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BRIDGE)
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BRIDGE_SETTING_NAME),
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BLUETOOTH_SETTING_NAME),
factory_class->create_device = create_device;
factory_class->match_connection = match_connection;
);

View file

@ -235,34 +235,24 @@ nm_device_factory_manager_find_factory_for_link_type (NMLinkType link_type)
NMDeviceFactory *
nm_device_factory_manager_find_factory_for_connection (NMConnection *connection)
{
NMDeviceFactoryClass *klass;
NMDeviceFactory *factory;
const char *type;
GSList *list;
g_return_val_if_fail (factories_by_setting, NULL);
type = nm_connection_get_connection_type (connection);
list = g_hash_table_lookup (factories_by_setting, type);
if ( nm_streq (type, NM_SETTING_BLUETOOTH_SETTING_NAME)
&& _nm_connection_get_setting_bluetooth_for_nap (connection)) {
/* for Bluetooth NAP connections, we return the bridge factory
* instead of the bluetooth factory.
*
* In a way, this is a hack. The more orthodox solution would
* be that device factories don't only announce supported setting
* types, but instead match on a full fledged NMConnection.
*
* However, our device-factories are known at compile time.
* There is no need to keep this generic. We *know* which
* factory to choose. Making this generic would not make it
* cleaner. */
if (!g_hash_table_lookup (factories_by_setting, type)) {
/* we need both the bluetooth and the bridge factory
* to make this work. */
return NULL;
}
type = NM_SETTING_BRIDGE_SETTING_NAME;
for (; list; list = g_slist_next (list)) {
factory = list->data;
klass = NM_DEVICE_FACTORY_GET_CLASS (factory);
if (!klass->match_connection || klass->match_connection (factory, connection))
return factory;
}
return g_hash_table_lookup (factories_by_setting, type);
return NULL;
}
void
@ -283,9 +273,11 @@ nm_device_factory_manager_for_each_factory (NMDeviceFactoryManagerFactoryFunc ca
if (factories_by_setting) {
g_hash_table_iter_init (&iter, factories_by_setting);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) {
if (!g_slist_find (list, factory))
list = g_slist_prepend (list, factory);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &list_iter)) {
for (; list_iter; list_iter = g_slist_next (list_iter)) {
if (!g_slist_find (list, list_iter->data))
list = g_slist_prepend (list, list_iter->data);
}
}
}
@ -303,6 +295,7 @@ _add_factory (NMDeviceFactory *factory,
{
const NMLinkType *link_types = NULL;
const char *const*setting_types = NULL;
GSList *list;
int i;
g_return_val_if_fail (factories_by_link, FALSE);
@ -313,8 +306,15 @@ _add_factory (NMDeviceFactory *factory,
g_object_set_qdata_full (G_OBJECT (factory), plugin_path_quark (), g_strdup (path), g_free);
for (i = 0; link_types && link_types[i] > NM_LINK_TYPE_UNKNOWN; i++)
g_hash_table_insert (factories_by_link, GUINT_TO_POINTER (link_types[i]), g_object_ref (factory));
for (i = 0; setting_types && setting_types[i]; i++)
g_hash_table_insert (factories_by_setting, (char *) setting_types[i], g_object_ref (factory));
for (i = 0; setting_types && setting_types[i]; i++) {
list = g_hash_table_lookup (factories_by_setting, (char *) setting_types[i]);
if (list)
list = g_slist_append (list, g_object_ref (factory));
else {
list = g_slist_append (list, g_object_ref (factory));
g_hash_table_insert (factories_by_setting, (char *) setting_types[i], list);
}
}
callback (factory, user_data);
@ -333,6 +333,12 @@ _load_internal_factory (GType factory_gtype,
_add_factory (factory, "internal", callback, user_data);
}
static void
factories_list_unref (GSList *list)
{
g_slist_free_full (list, g_object_unref);
}
void
nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc callback,
gpointer user_data)
@ -345,7 +351,7 @@ nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc call
g_return_if_fail (factories_by_setting == NULL);
factories_by_link = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
factories_by_setting = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
factories_by_setting = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) factories_list_unref);
#define _ADD_INTERNAL(get_type_fcn) \
G_STMT_START { \

View file

@ -71,6 +71,14 @@ typedef struct {
*/
void (*start) (NMDeviceFactory *factory);
/**
* match_connection:
* @connection: the #NMConnection
*
* Check if the factory supports the given connection.
*/
gboolean (*match_connection) (NMDeviceFactory *factory, NMConnection *connection);
/**
* get_connection_parent:
* @factory: the #NMDeviceFactory