diff --git a/ChangeLog b/ChangeLog index 89ab88779d..af8c28a984 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +2007-09-14 Dan Williams + + Implement deferred activation support in the device class. + + * src/nm-device-interface.c + src/nm-device-interface.h + - (nm_device_interface_activate): take more arguments to support + deferred activation; callers must pass one of (connection) OR + (service_name, connection_path) + - (impl_device_activate): connection validation is punted to the device + to be able to handle deferred activation. Yes, this means errors + don't get returned from the Activate() dbus call, and yes, that + should be fixed somehow later. + + * src/nm-device.c + src/nm-device.h + - (clear_act_request): clear additional deferred activation stuff too + - (deferred_activation_timeout_cb): new function; clean up when + deferred activation times out. + - (deferred_activation_start_cb): new function; when the connection + finally becomes available, start device activation + - (nm_device_activate): attach to the right signals of the activation + request if we need to defer activation until the connection is valid + + * src/NetworkManagerPolicy.c + - (nm_policy_device_change_check): update for additional arguments + required for nm_device_interface_activate(). Pass NULL for these + though because this function already knows exactly which + NMConnection to use + 2007-09-14 Dan Williams Implement deferred activation handling in the NMActRequest class. When a diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c index 90eb1af77c..44b73dabcd 100644 --- a/src/NetworkManagerPolicy.c +++ b/src/NetworkManagerPolicy.c @@ -338,7 +338,11 @@ nm_policy_device_change_check (gpointer user_data) if (new_dev) { nm_device_interface_activate (NM_DEVICE_INTERFACE (new_dev), - connection, specific_object, FALSE); + NULL, + NULL, + connection, + specific_object, + FALSE); } } diff --git a/src/nm-device-interface.c b/src/nm-device-interface.c index 213e5c57e4..a850a4eda6 100644 --- a/src/nm-device-interface.c +++ b/src/nm-device-interface.c @@ -177,16 +177,22 @@ nm_device_interface_get_type (void) return device_interface_type; } +/* Pass _either_ connection_path or connection. Passing 'connection' is + * meant for internal use only. + */ void nm_device_interface_activate (NMDeviceInterface *device, - NMConnection *connection, - const char *specific_object, - gboolean user_requested) + const char *service_name, + const char *connection_path, + NMConnection *connection, + const char *specific_object, + gboolean user_requested) { g_return_if_fail (NM_IS_DEVICE_INTERFACE (device)); - g_return_if_fail (connection != NULL); NM_DEVICE_INTERFACE_GET_INTERFACE (device)->activate (device, + service_name, + connection_path, connection, specific_object, user_requested); @@ -199,36 +205,13 @@ impl_device_activate (NMDeviceInterface *device, const char *specific_object, GError **err) { - NMManager *manager; - NMConnection *connection; - gboolean success = FALSE; - - manager = nm_manager_get (); - if (!strcmp (service_name, NM_DBUS_SERVICE_USER_SETTINGS)) { - connection = nm_manager_get_connection_by_object_path (manager, - NM_CONNECTION_TYPE_USER, - connection_path); - } else if (!strcmp (service_name, NM_DBUS_SERVICE_USER_SETTINGS)) { - connection = nm_manager_get_connection_by_object_path (manager, - NM_CONNECTION_TYPE_SYSTEM, - connection_path); - } - - if (connection == NULL) { - g_set_error (err, - NM_DEVICE_INTERFACE_ERROR, - NM_DEVICE_INTERFACE_ERROR_UNKNOWN_CONNECTION, - "%s", - "Connection object or service unknown"); - goto out; - } - - nm_connection_dump (connection); - nm_device_interface_activate (device, connection, specific_object, TRUE); - success = TRUE; - -out: - return success; + nm_device_interface_activate (device, + service_name, + connection_path, + NULL, + specific_object, + TRUE); + return TRUE; } void diff --git a/src/nm-device-interface.h b/src/nm-device-interface.h index 95b914e7fc..f7b568fb3c 100644 --- a/src/nm-device-interface.h +++ b/src/nm-device-interface.h @@ -51,6 +51,8 @@ struct _NMDeviceInterface { /* Methods */ void (*activate) (NMDeviceInterface *device, + const char *service_name, + const char *connection_path, NMConnection *connection, const char *specific_object, gboolean user_requested); @@ -66,10 +68,12 @@ GType nm_device_interface_error_get_type (void); GType nm_device_interface_get_type (void); -void nm_device_interface_activate (NMDeviceInterface *device, - NMConnection *connection, - const char *specific_object, - gboolean user_requested); +void nm_device_interface_activate (NMDeviceInterface *device, + const char *service_name, + const char *connection_path, + NMConnection *connection, + const char *specific_object, + gboolean user_requested); void nm_device_interface_deactivate (NMDeviceInterface *device); diff --git a/src/nm-device.c b/src/nm-device.c index f5f0e1746b..eb1640d999 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -69,6 +69,8 @@ struct _NMDevicePrivate struct in6_addr ip6_address; NMActRequest * act_request; + gulong act_deferred_timeout_id; + gulong act_deferred_start_id; guint act_source_id; gulong secrets_updated_id; @@ -81,9 +83,11 @@ struct _NMDevicePrivate }; static void nm_device_activate (NMDeviceInterface *device, - NMConnection *connection, - const char *specific_object, - gboolean user_requested); + const char *service_name, + const char *connection_path, + NMConnection *connection, + const char *specific_object, + gboolean user_requested); static void nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self); static void nm_device_deactivate (NMDeviceInterface *device); @@ -121,6 +125,8 @@ nm_device_init (NMDevice * self) self->priv->ip4_address = 0; memset (&self->priv->ip6_address, 0, sizeof (struct in6_addr)); + self->priv->act_deferred_timeout_id = 0; + self->priv->act_deferred_start_id = 0; self->priv->act_source_id = 0; self->priv->system_config_data = NULL; @@ -952,9 +958,23 @@ clear_act_request (NMDevice *self) if (!priv->act_request) return; - g_signal_handler_disconnect (priv->act_request, - priv->secrets_updated_id); - priv->secrets_updated_id = 0; + if (priv->act_deferred_timeout_id) { + g_signal_handler_disconnect (priv->act_request, + priv->act_deferred_timeout_id); + priv->act_deferred_timeout_id = 0; + } + + if (priv->act_deferred_start_id) { + g_signal_handler_disconnect (priv->act_request, + priv->act_deferred_start_id); + priv->act_deferred_start_id = 0; + } + + if (priv->secrets_updated_id) { + g_signal_handler_disconnect (priv->act_request, + priv->secrets_updated_id); + priv->secrets_updated_id = 0; + } g_object_unref (priv->act_request); priv->act_request = NULL; @@ -1096,33 +1116,53 @@ connection_secrets_updated_cb (NMActRequest *req, } static void -nm_device_activate (NMDeviceInterface *device, - NMConnection *connection, - const char *specific_object, - gboolean user_requested) +deferred_activation_timeout_cb (NMActRequest *req, gpointer user_data) { - NMDevice *self = NM_DEVICE (device); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gulong id; + NMDevice *self = NM_DEVICE (user_data); + + if (nm_device_get_act_request (self) != req) + return; + + nm_info ("%s: didn't receive connection details soon enough for activation.", + nm_device_get_iface (self)); + + clear_act_request (self); + nm_device_state_changed (self, NM_DEVICE_STATE_DISCONNECTED); +} + +static gboolean +device_activation_precheck (NMDevice *self, NMConnection *connection) +{ + NMConnection *current_connection; + + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); if (!NM_DEVICE_GET_CLASS (self)->check_connection (self, connection)) /* connection is invalid */ - return; + return FALSE; - if (nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED || nm_device_is_activating (self)) { - NMConnection *current_connection; + if (nm_device_get_state (self) != NM_DEVICE_STATE_ACTIVATED) + return TRUE; - current_connection = nm_act_request_get_connection (nm_device_get_act_request (self)); + if (!nm_device_is_activating (self)) + return TRUE; - if (nm_connection_compare (connection, current_connection)) - /* Already activating or activated with the same connection */ - return; + current_connection = nm_act_request_get_connection (nm_device_get_act_request (self)); + if (nm_connection_compare (connection, current_connection)) + /* Already activating or activated with the same connection */ + return FALSE; - nm_device_deactivate (device); - } + return TRUE; +} - nm_info ("Activating device %s", nm_device_get_iface (self)); - priv->act_request = nm_act_request_new (connection, specific_object, user_requested); +static void +device_activation_go (NMDevice *self) +{ + NMDevicePrivate * priv; + gulong id; + + priv = NM_DEVICE_GET_PRIVATE (self); id = g_signal_connect (priv->act_request, "connection-secrets-updated", G_CALLBACK (connection_secrets_updated_cb), @@ -1132,6 +1172,90 @@ nm_device_activate (NMDeviceInterface *device, nm_device_activate_schedule_stage1_device_prepare (self); } +static void +deferred_activation_start_cb (NMActRequest *req, gpointer user_data) +{ + NMDevice *self = NM_DEVICE (user_data); + NMDevicePrivate * priv; + NMConnection *connection; + + if (nm_device_get_act_request (self) != req) + return; + + priv = NM_DEVICE_GET_PRIVATE (self); + g_signal_handler_disconnect (priv->act_request, + priv->act_deferred_start_id); + priv->act_deferred_start_id = 0; + + connection = nm_act_request_get_connection (req); + if (device_activation_precheck (self, connection) == FALSE) + return; + + nm_info ("%s: connection details received, will start activation.", + nm_device_get_iface (self)); + + device_activation_go (self); +} + +static void +nm_device_activate (NMDeviceInterface *device, + const char *service_name, + const char *connection_path, + NMConnection *connection, + const char *specific_object, + gboolean user_requested) +{ + NMDevice *self = NM_DEVICE (device); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + /* Only one of: + * - connection + * - service_name AND connection_path + * is valid. + */ + if (!connection) { + g_return_if_fail (service_name != NULL); + g_return_if_fail (connection_path != NULL); + } else if (connection) { + g_return_if_fail (service_name == NULL); + g_return_if_fail (connection_path == NULL); + } + + nm_info ("Activating device %s", nm_device_get_iface (self)); + if (connection) { + if (device_activation_precheck (self, connection) == FALSE) + return; + + priv->act_request = nm_act_request_new (connection, + specific_object, + user_requested); + device_activation_go (self); + } else { + gulong id; + + /* Don't have the connection quite yet, probably created by + * the client on-the-fly. Defer the activation until we have it + */ + priv->act_request = nm_act_request_new_deferred (service_name, + connection_path, + specific_object, + user_requested); + + id = g_signal_connect (priv->act_request, "deferred-activation-timeout", + G_CALLBACK (deferred_activation_timeout_cb), + self); + priv->act_deferred_timeout_id = id; + + id = g_signal_connect (priv->act_request, "deferred-activation-start", + G_CALLBACK (deferred_activation_start_cb), + self); + priv->act_deferred_start_id = id; + + nm_info ("%s: Deferring activation until connection information is " + "received.", nm_device_get_iface (self)); + } +} + /* * nm_device_is_activating *