diff options
author | Thomas Haller <thaller@redhat.com> | 2018-05-25 12:41:21 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2018-05-25 12:41:21 +0200 |
commit | dbedce8674350d73bdc98dfb569d4dd33bc95ad8 (patch) | |
tree | 161a4808ff362f9f9943a6043a1b8e543ed039f4 | |
parent | 3fd9bf9d7d9fc0290fd25f709b60a3a8f5c7e334 (diff) | |
parent | eaf36db68bd4bdc1b626d672079dd241b4eea53e (diff) | |
download | NetworkManager-dbedce8674350d73bdc98dfb569d4dd33bc95ad8.tar.gz |
ppp: merge branch 'th/ppp-stop'
https://github.com/NetworkManager/NetworkManager/pull/113
-rw-r--r-- | src/NetworkManagerUtils.c | 89 | ||||
-rw-r--r-- | src/NetworkManagerUtils.h | 31 | ||||
-rw-r--r-- | src/devices/adsl/nm-device-adsl.c | 2 | ||||
-rw-r--r-- | src/devices/nm-device-ethernet.c | 2 | ||||
-rw-r--r-- | src/devices/nm-device-ppp.c | 2 | ||||
-rw-r--r-- | src/devices/wwan/nm-modem.c | 61 | ||||
-rw-r--r-- | src/ppp/nm-ppp-manager-call.c | 34 | ||||
-rw-r--r-- | src/ppp/nm-ppp-manager-call.h | 14 | ||||
-rw-r--r-- | src/ppp/nm-ppp-manager.c | 300 | ||||
-rw-r--r-- | src/ppp/nm-ppp-manager.h | 7 | ||||
-rw-r--r-- | src/ppp/nm-ppp-plugin-api.h | 14 |
11 files changed, 352 insertions, 204 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 78e1ac19c3..a3bd601359 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -23,6 +23,8 @@ #include "NetworkManagerUtils.h" +#include "nm-utils/nm-c-list.h" + #include "nm-common-macros.h" #include "nm-utils.h" #include "nm-setting-connection.h" @@ -907,3 +909,90 @@ nm_match_spec_device_by_pllink (const NMPlatformLink *pllink, return no_match_value; } +/*****************************************************************************/ + +struct _NMShutdownWaitObjHandle { + CList lst; + GObject *watched_obj; + const char *msg_reason; +}; + +static CList _shutdown_waitobj_lst_head; + +static void +_shutdown_waitobj_unregister (NMShutdownWaitObjHandle *handle) +{ + c_list_unlink_stale (&handle->lst); + g_slice_free (NMShutdownWaitObjHandle, handle); + + /* FIXME(shutdown): check whether the object list is empty, and + * signal shutdown-complete */ +} + +static void +_shutdown_waitobj_cb (gpointer user_data, + GObject *where_the_object_was) +{ + NMShutdownWaitObjHandle *handle = user_data; + + nm_assert (handle); + nm_assert (handle->watched_obj == where_the_object_was); + _shutdown_waitobj_unregister (handle); +} + +/** + * _nm_shutdown_wait_obj_register: + * @watched_obj: the object to watch. Takes a weak reference on the object + * to be notified when it gets destroyed. + * @msg_reason: a reason message, for debugging and logging purposes. It + * must be a static string. Or at least, be alive at least as long as + * @watched_obj. So, theoretically, if you need a dynamic @msg_reason, + * you could attach it to @watched_obj's user-data. + * + * Keep track of @watched_obj until it gets destroyed. During shutdown, + * we wait until all watched objects are destroyed. This is useful, if + * this object still conducts some asynchronous action, which needs to + * complete before NetworkManager is allowed to terminate. We re-use + * the reference-counter of @watched_obj as signal, that the object + * is still used. + * + * FIXME(shutdown): proper shutdown is not yet implemented, and registering + * an object (currently) has no effect. + * + * Returns: a handle to unregister the object. The caller may choose to ignore + * the handle, in which case, the object will be automatically unregistered, + * once it gets destroyed. + */ +NMShutdownWaitObjHandle * +_nm_shutdown_wait_obj_register (GObject *watched_obj, + const char *msg_reason) +{ + NMShutdownWaitObjHandle *handle; + + g_return_val_if_fail (G_IS_OBJECT (watched_obj), NULL); + + if (G_UNLIKELY (!_shutdown_waitobj_lst_head.next)) + c_list_init (&_shutdown_waitobj_lst_head); + + handle = g_slice_new (NMShutdownWaitObjHandle); + handle->watched_obj = watched_obj; + /* we don't clone the string. We require the caller to use pass a static message. + * If he really cannot do that, he should attach the string to the watched_obj + * as user-data. */ + handle->msg_reason = msg_reason; + c_list_link_tail (&_shutdown_waitobj_lst_head, &handle->lst); + g_object_weak_ref (watched_obj, _shutdown_waitobj_cb, handle); + return handle; +} + +void +nm_shutdown_wait_obj_unregister (NMShutdownWaitObjHandle *handle) +{ + g_return_if_fail (handle); + + nm_assert (G_IS_OBJECT (handle->watched_obj)); + nm_assert (nm_c_list_contains_entry (&_shutdown_waitobj_lst_head, handle, lst)); + + g_object_weak_unref (handle->watched_obj, _shutdown_waitobj_cb, handle); + _shutdown_waitobj_unregister (handle); +} diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 13bdb67e85..b26d08bdce 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -53,6 +53,37 @@ int nm_match_spec_device_by_pllink (const NMPlatformLink *pllink, const GSList *specs, int no_match_value); + +/*****************************************************************************/ + +/* during shutdown, there are two relevant timeouts. One is + * NM_SHUTDOWN_TIMEOUT_MS which is plenty of time, that we give for all + * actions to complete. Of course, during shutdown components should hurry + * to cleanup. + * + * When we initiate shutdown, we should start killing child processes + * with SIGTERM. If they don't complete within NM_SHUTDOWN_TIMEOUT_MS, we send + * SIGKILL. + * + * After NM_SHUTDOWN_TIMEOUT_MS, NetworkManager will however not yet terminate right + * away. It iterates the mainloop for another NM_SHUTDOWN_TIMEOUT_MS_EXTRA. This + * should give time to reap the child process (after SIGKILL). + * + * So, the maxiumum time we should wait before sending SIGKILL should be at most + * NM_SHUTDOWN_TIMEOUT_MS. + */ +#define NM_SHUTDOWN_TIMEOUT_MS 1500 +#define NM_SHUTDOWN_TIMEOUT_MS_WATCHDOG 500 + +typedef struct _NMShutdownWaitObjHandle NMShutdownWaitObjHandle; + +NMShutdownWaitObjHandle *_nm_shutdown_wait_obj_register (GObject *watched_obj, + const char *msg_reason); + +#define nm_shutdown_wait_obj_register(watched_obj, msg_reason) _nm_shutdown_wait_obj_register((watched_obj), (""msg_reason"")) + +void nm_shutdown_wait_obj_unregister (NMShutdownWaitObjHandle *handle); + /*****************************************************************************/ #endif /* __NETWORKMANAGER_UTILS_H__ */ diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index 5fcc823a20..1450a8369d 100644 --- a/src/devices/adsl/nm-device-adsl.c +++ b/src/devices/adsl/nm-device-adsl.c @@ -525,7 +525,7 @@ adsl_cleanup (NMDeviceAdsl *self) if (priv->ppp_manager) { g_signal_handlers_disconnect_by_func (priv->ppp_manager, G_CALLBACK (ppp_state_changed), self); g_signal_handlers_disconnect_by_func (priv->ppp_manager, G_CALLBACK (ppp_ip4_config), self); - nm_ppp_manager_stop_sync (priv->ppp_manager); + nm_ppp_manager_stop (priv->ppp_manager, NULL, NULL); g_clear_object (&priv->ppp_manager); } diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 43d137aab2..6c5e33e4cc 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -1343,7 +1343,7 @@ deactivate (NMDevice *device) nm_clear_g_source (&priv->pppoe_wait_id); if (priv->ppp_manager) { - nm_ppp_manager_stop_sync (priv->ppp_manager); + nm_ppp_manager_stop (priv->ppp_manager, NULL, NULL); g_clear_object (&priv->ppp_manager); } diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c index 94df0caed2..a6abb228a6 100644 --- a/src/devices/nm-device-ppp.c +++ b/src/devices/nm-device-ppp.c @@ -239,7 +239,7 @@ deactivate (NMDevice *device) NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE (self); if (priv->ppp_manager) { - nm_ppp_manager_stop_sync (priv->ppp_manager); + nm_ppp_manager_stop (priv->ppp_manager, NULL, NULL); g_clear_object (&priv->ppp_manager); } } diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index c49b1aac6a..fbe99cc30e 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -1131,7 +1131,7 @@ deactivate_cleanup (NMModem *self, NMDevice *device) if (priv->ppp_manager) { g_signal_handlers_disconnect_by_data (priv->ppp_manager, self); - nm_ppp_manager_stop_sync (priv->ppp_manager); + nm_ppp_manager_stop (priv->ppp_manager, NULL, NULL); g_clear_object (&priv->ppp_manager); } @@ -1177,11 +1177,19 @@ typedef struct { GSimpleAsyncResult *result; DeactivateContextStep step; NMPPPManager *ppp_manager; + NMPPPManagerStopHandle *ppp_stop_handle; + gulong ppp_stop_cancellable_id; } DeactivateContext; static void deactivate_context_complete (DeactivateContext *ctx) { + if (ctx->ppp_stop_handle) + nm_ppp_manager_stop_cancel (ctx->ppp_stop_handle); + + nm_assert (!ctx->ppp_stop_handle); + nm_assert (ctx->ppp_stop_cancellable_id == 0); + if (ctx->ppp_manager) g_object_unref (ctx->ppp_manager); if (ctx->cancellable) @@ -1223,26 +1231,37 @@ disconnect_ready (NMModem *self, static void ppp_manager_stop_ready (NMPPPManager *ppp_manager, - GAsyncResult *res, - DeactivateContext *ctx) + NMPPPManagerStopHandle *handle, + gboolean was_cancelled, + gpointer user_data) { - NMModem *self = ctx->self; - GError *error = NULL; + DeactivateContext *ctx = user_data; - if (!nm_ppp_manager_stop_finish (ppp_manager, res, &error)) { - _LOGW ("cannot stop PPP manager: %s", - error->message); - g_simple_async_result_take_error (ctx->result, error); - deactivate_context_complete (ctx); - return; + nm_assert (ctx->ppp_stop_handle == handle); + ctx->ppp_stop_handle = NULL; + + if (ctx->ppp_stop_cancellable_id) { + g_cancellable_disconnect (ctx->cancellable, + nm_steal_int (&ctx->ppp_stop_cancellable_id)); } - /* Go on */ + if (was_cancelled) + return; + ctx->step++; deactivate_step (ctx); } static void +ppp_manager_stop_cancelled (GCancellable *cancellable, + gpointer user_data) +{ + DeactivateContext *ctx = user_data; + + nm_ppp_manager_stop_cancel (ctx->ppp_stop_handle); +} + +static void deactivate_step (DeactivateContext *ctx) { NMModem *self = ctx->self; @@ -1271,10 +1290,16 @@ deactivate_step (DeactivateContext *ctx) case DEACTIVATE_CONTEXT_STEP_PPP_MANAGER_STOP: /* If we have a PPP manager, stop it */ if (ctx->ppp_manager) { - nm_ppp_manager_stop_async (ctx->ppp_manager, - ctx->cancellable, - (GAsyncReadyCallback) ppp_manager_stop_ready, - ctx); + nm_assert (!ctx->ppp_stop_handle); + if (ctx->cancellable) { + ctx->ppp_stop_cancellable_id = g_cancellable_connect (ctx->cancellable, + G_CALLBACK (ppp_manager_stop_cancelled), + ctx, + NULL); + } + ctx->ppp_stop_handle = nm_ppp_manager_stop (ctx->ppp_manager, + ppp_manager_stop_ready, + ctx); return; } ctx->step++; @@ -1313,7 +1338,9 @@ nm_modem_deactivate_async (NMModem *self, callback, user_data, nm_modem_deactivate_async); - ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + /* FIXME(shutdown): we always require a cancellable, otherwise we cannot + * do a coordinated shutdown. */ + ctx->cancellable = nm_g_object_ref (cancellable); /* Start */ ctx->step = DEACTIVATE_CONTEXT_STEP_FIRST; diff --git a/src/ppp/nm-ppp-manager-call.c b/src/ppp/nm-ppp-manager-call.c index ed70f68790..3d6fee49a0 100644 --- a/src/ppp/nm-ppp-manager-call.c +++ b/src/ppp/nm-ppp-manager-call.c @@ -82,9 +82,8 @@ nm_ppp_manager_create (const char *iface, GError **error) nm_assert (ops); nm_assert (ops->create); nm_assert (ops->start); - nm_assert (ops->stop_async); - nm_assert (ops->stop_finish); - nm_assert (ops->stop_sync); + nm_assert (ops->stop); + nm_assert (ops->stop_cancel); ppp_ops = ops; @@ -125,32 +124,21 @@ nm_ppp_manager_start (NMPPPManager *self, return ppp_ops->start (self, req, ppp_name, timeout_secs, baud_override, err); } -void -nm_ppp_manager_stop_async (NMPPPManager *self, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +NMPPPManagerStopHandle * +nm_ppp_manager_stop (NMPPPManager *self, + NMPPPManagerStopCallback callback, + gpointer user_data) { - g_return_if_fail (ppp_ops); + g_return_val_if_fail (ppp_ops, NULL); - ppp_ops->stop_async (self, cancellable, callback, user_data); -} - -gboolean -nm_ppp_manager_stop_finish (NMPPPManager *self, - GAsyncResult *res, - GError **error) -{ - g_return_val_if_fail (ppp_ops, FALSE); - - return ppp_ops->stop_finish (self, res, error); + return ppp_ops->stop (self, callback, user_data); } void -nm_ppp_manager_stop_sync (NMPPPManager *self) +nm_ppp_manager_stop_cancel (NMPPPManagerStopHandle *handle) { g_return_if_fail (ppp_ops); + g_return_if_fail (handle); - ppp_ops->stop_sync (self); + ppp_ops->stop_cancel (handle); } - diff --git a/src/ppp/nm-ppp-manager-call.h b/src/ppp/nm-ppp-manager-call.h index 2258ae08f7..daf8a82e68 100644 --- a/src/ppp/nm-ppp-manager-call.h +++ b/src/ppp/nm-ppp-manager-call.h @@ -38,13 +38,11 @@ gboolean nm_ppp_manager_start (NMPPPManager *self, guint32 timeout_secs, guint baud_override, GError **error); -void nm_ppp_manager_stop_async (NMPPPManager *self, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean nm_ppp_manager_stop_finish (NMPPPManager *self, - GAsyncResult *res, - GError **error); -void nm_ppp_manager_stop_sync (NMPPPManager *self); + +NMPPPManagerStopHandle *nm_ppp_manager_stop (NMPPPManager *self, + NMPPPManagerStopCallback callback, + gpointer user_data); + +void nm_ppp_manager_stop_cancel (NMPPPManagerStopHandle *handle); #endif /* __NM_PPP_MANAGER_CALL_H__ */ diff --git a/src/ppp/nm-ppp-manager.c b/src/ppp/nm-ppp-manager.c index 7d1eb4089d..fc658bec93 100644 --- a/src/ppp/nm-ppp-manager.c +++ b/src/ppp/nm-ppp-manager.c @@ -134,8 +134,11 @@ G_DEFINE_TYPE (NMPPPManager, nm_ppp_manager, NM_TYPE_DBUS_OBJECT) /*****************************************************************************/ -static void _ppp_cleanup (NMPPPManager *manager); -static void _ppp_kill (NMPPPManager *manager); +static void _ppp_cleanup (NMPPPManager *self); + +static NMPPPManagerStopHandle *_ppp_manager_stop (NMPPPManager *self, + NMPPPManagerStopCallback callback, + gpointer user_data); /*****************************************************************************/ @@ -173,8 +176,8 @@ _ppp_manager_set_route_parameters (NMPPPManager *self, static gboolean monitor_cb (gpointer user_data) { - NMPPPManager *manager = NM_PPP_MANAGER (user_data); - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); + NMPPPManager *self = NM_PPP_MANAGER (user_data); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); const char *ifname; ifname = nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex); @@ -190,7 +193,7 @@ monitor_cb (gpointer user_data) if (errno != ENODEV) _LOGW ("could not read ppp stats: %s", strerror (errno)); } else { - g_signal_emit (manager, signals[STATS], 0, + g_signal_emit (self, signals[STATS], 0, (guint) stats.p.ppp_ibytes, (guint) stats.p.ppp_obytes); } @@ -200,9 +203,9 @@ monitor_cb (gpointer user_data) } static void -monitor_stats (NMPPPManager *manager) +monitor_stats (NMPPPManager *self) { - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); /* already monitoring */ if (priv->monitor_fd >= 0) @@ -213,7 +216,7 @@ monitor_stats (NMPPPManager *manager) g_warn_if_fail (priv->monitor_id == 0); if (priv->monitor_id) g_source_remove (priv->monitor_id); - priv->monitor_id = g_timeout_add_seconds (5, monitor_cb, manager); + priv->monitor_id = g_timeout_add_seconds (5, monitor_cb, self); } else _LOGW ("could not monitor PPP stats: %s", strerror (errno)); } @@ -351,8 +354,8 @@ impl_ppp_manager_need_secrets (NMDBusObject *obj, GDBusMethodInvocation *invocation, GVariant *parameters) { - NMPPPManager *manager = NM_PPP_MANAGER (obj); - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); + NMPPPManager *self = NM_PPP_MANAGER (obj); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); NMConnection *applied_connection; const char *username = NULL; const char *password = NULL; @@ -371,7 +374,7 @@ impl_ppp_manager_need_secrets (NMDBusObject *obj, if (extract_details_from_connection (applied_connection, NULL, &username, &password, &error)) { /* Send existing secrets to the PPP plugin */ priv->pending_secrets_context = invocation; - ppp_secrets_cb (priv->act_req, priv->secrets_id, NULL, NULL, manager); + ppp_secrets_cb (priv->act_req, priv->secrets_id, NULL, NULL, self); } else { _LOGW ("%s", error->message); g_dbus_method_invocation_take_error (priv->pending_secrets_context, error); @@ -393,7 +396,7 @@ impl_ppp_manager_need_secrets (NMDBusObject *obj, flags, hints ? g_ptr_array_index (hints, 0) : NULL, ppp_secrets_cb, - manager); + self); g_object_set_qdata (G_OBJECT (applied_connection), ppp_manager_secret_tries_quark (), GUINT_TO_POINTER (++tries)); priv->pending_secrets_context = invocation; @@ -410,11 +413,11 @@ impl_ppp_manager_set_state (NMDBusObject *obj, GDBusMethodInvocation *invocation, GVariant *parameters) { - NMPPPManager *manager = NM_PPP_MANAGER (obj); + NMPPPManager *self = NM_PPP_MANAGER (obj); guint32 state; g_variant_get (parameters, "(u)", &state); - g_signal_emit (manager, signals[STATE_CHANGED], 0, (guint) state); + g_signal_emit (self, signals[STATE_CHANGED], 0, (guint) state); g_dbus_method_invocation_return_value (invocation, NULL); } @@ -427,8 +430,8 @@ impl_ppp_manager_set_ifindex (NMDBusObject *obj, GDBusMethodInvocation *invocation, GVariant *parameters) { - NMPPPManager *manager = NM_PPP_MANAGER (obj); - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); + NMPPPManager *self = NM_PPP_MANAGER (obj); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); const NMPlatformLink *plink = NULL; nm_auto_nmpobj const NMPObject *obj_keep_alive = NULL; gint32 ifindex; @@ -459,7 +462,7 @@ impl_ppp_manager_set_ifindex (NMDBusObject *obj, obj_keep_alive = nmp_object_ref (NMP_OBJECT_UP_CAST (plink)); - g_signal_emit (manager, signals[IFINDEX_SET], 0, ifindex, plink->name); + g_signal_emit (self, signals[IFINDEX_SET], 0, ifindex, plink->name); g_dbus_method_invocation_return_value (invocation, NULL); } @@ -498,8 +501,8 @@ impl_ppp_manager_set_ip4_config (NMDBusObject *obj, GDBusMethodInvocation *invocation, GVariant *parameters) { - NMPPPManager *manager = NM_PPP_MANAGER (obj); - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); + NMPPPManager *self = NM_PPP_MANAGER (obj); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); gs_unref_object NMIP4Config *config = NULL; NMPlatformIP4Address address; guint32 u32, mtu; @@ -512,7 +515,7 @@ impl_ppp_manager_set_ip4_config (NMDBusObject *obj, nm_clear_g_source (&priv->ppp_timeout_handler); - if (!set_ip_config_common (manager, config_dict, &mtu)) + if (!set_ip_config_common (self, config_dict, &mtu)) goto out; config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), priv->ifindex); @@ -564,7 +567,7 @@ impl_ppp_manager_set_ip4_config (NMDBusObject *obj, } /* Push the IP4 config up to the device */ - g_signal_emit (manager, signals[IP4_CONFIG], 0, config); + g_signal_emit (self, signals[IP4_CONFIG], 0, config); out: g_dbus_method_invocation_return_value (invocation, NULL); @@ -608,8 +611,8 @@ impl_ppp_manager_set_ip6_config (NMDBusObject *obj, GDBusMethodInvocation *invocation, GVariant *parameters) { - NMPPPManager *manager = NM_PPP_MANAGER (obj); - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); + NMPPPManager *self = NM_PPP_MANAGER (obj); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); gs_unref_object NMIP6Config *config = NULL; NMPlatformIP6Address addr; struct in6_addr a; @@ -623,7 +626,7 @@ impl_ppp_manager_set_ip6_config (NMDBusObject *obj, nm_clear_g_source (&priv->ppp_timeout_handler); - if (!set_ip_config_common (manager, config_dict, NULL)) + if (!set_ip_config_common (self, config_dict, NULL)) goto out; config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET), priv->ifindex); @@ -651,7 +654,7 @@ impl_ppp_manager_set_ip6_config (NMDBusObject *obj, nm_ip6_config_add_address (config, &addr); /* Push the IPv6 config and interface identifier up to the device */ - g_signal_emit (manager, signals[IP6_CONFIG], 0, &iid, config); + g_signal_emit (self, signals[IP6_CONFIG], 0, &iid, config); } else _LOGE ("invalid IPv6 address received!"); @@ -744,8 +747,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (pppd_exit_code_to_str, int, static void ppp_watch_cb (GPid pid, int status, gpointer user_data) { - NMPPPManager *manager = NM_PPP_MANAGER (user_data); - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); + NMPPPManager *self = NM_PPP_MANAGER (user_data); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); int err; const long long lpid = (long long) pid; @@ -770,20 +773,19 @@ ppp_watch_cb (GPid pid, int status, gpointer user_data) priv->pid = 0; priv->ppp_watch_id = 0; - _ppp_cleanup (manager); - g_signal_emit (manager, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_DEAD); + _ppp_cleanup (self); + g_signal_emit (self, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_DEAD); } static gboolean pppd_timed_out (gpointer data) { - NMPPPManager *manager = NM_PPP_MANAGER (data); + NMPPPManager *self = NM_PPP_MANAGER (data); _LOGW ("pppd timed out or didn't initialize our dbus module"); - _ppp_cleanup (manager); - _ppp_kill (manager); + _ppp_manager_stop (self, NULL, NULL); - g_signal_emit (manager, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_DEAD); + g_signal_emit (self, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_DEAD); return FALSE; } @@ -1008,7 +1010,7 @@ pppoe_fill_defaults (NMSettingPpp *setting) } static gboolean -_ppp_manager_start (NMPPPManager *manager, +_ppp_manager_start (NMPPPManager *self, NMActRequest *req, const char *ppp_name, guint32 timeout_secs, @@ -1028,10 +1030,10 @@ _ppp_manager_start (NMPPPManager *manager, gboolean ip6_enabled = FALSE; gboolean ip4_enabled = FALSE; - g_return_val_if_fail (NM_IS_PPP_MANAGER (manager), FALSE); + g_return_val_if_fail (NM_IS_PPP_MANAGER (self), FALSE); g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); - priv = NM_PPP_MANAGER_GET_PRIVATE (manager); + priv = NM_PPP_MANAGER_GET_PRIVATE (self); #if !WITH_PPP /* PPP support disabled */ @@ -1042,7 +1044,7 @@ _ppp_manager_start (NMPPPManager *manager, return FALSE; #endif - nm_dbus_object_export (NM_DBUS_OBJECT (manager)); + nm_dbus_object_export (NM_DBUS_OBJECT (self)); priv->pid = 0; @@ -1077,7 +1079,7 @@ _ppp_manager_start (NMPPPManager *manager, ip6_method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); ip6_enabled = g_strcmp0 (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0; - ppp_cmd = create_pppd_cmd_line (manager, + ppp_cmd = create_pppd_cmd_line (self, s_ppp, pppoe_setting, adsl_setting, @@ -1107,8 +1109,8 @@ _ppp_manager_start (NMPPPManager *manager, _LOGI ("pppd started with pid %lld", (long long) priv->pid); - priv->ppp_watch_id = g_child_watch_add (priv->pid, (GChildWatchFunc) ppp_watch_cb, manager); - priv->ppp_timeout_handler = g_timeout_add_seconds (timeout_secs, pppd_timed_out, manager); + priv->ppp_watch_id = g_child_watch_add (priv->pid, (GChildWatchFunc) ppp_watch_cb, self); + priv->ppp_timeout_handler = g_timeout_add_seconds (timeout_secs, pppd_timed_out, self); priv->act_req = g_object_ref (req); out: @@ -1116,42 +1118,27 @@ out: nm_cmd_line_destroy (ppp_cmd); if (priv->pid <= 0) - nm_dbus_object_unexport (NM_DBUS_OBJECT (manager)); + nm_dbus_object_unexport (NM_DBUS_OBJECT (self)); return priv->pid > 0; } static void -_ppp_kill (NMPPPManager *manager) +_ppp_cleanup (NMPPPManager *self) { NMPPPManagerPrivate *priv; - g_return_if_fail (NM_IS_PPP_MANAGER (manager)); - - priv = NM_PPP_MANAGER_GET_PRIVATE (manager); - - if (priv->pid) { - nm_utils_kill_child_async (priv->pid, SIGTERM, LOGD_PPP, "pppd", 2000, NULL, NULL); - priv->pid = 0; - } -} - -static void -_ppp_cleanup (NMPPPManager *manager) -{ - NMPPPManagerPrivate *priv; - - g_return_if_fail (NM_IS_PPP_MANAGER (manager)); + g_return_if_fail (NM_IS_PPP_MANAGER (self)); - priv = NM_PPP_MANAGER_GET_PRIVATE (manager); + priv = NM_PPP_MANAGER_GET_PRIVATE (self); - cancel_get_secrets (manager); + cancel_get_secrets (self); nm_clear_g_source (&priv->monitor_id); if (priv->monitor_fd >= 0) { /* Get the stats one last time */ - monitor_cb (manager); + monitor_cb (self); nm_close (priv->monitor_fd); priv->monitor_fd = -1; } @@ -1162,108 +1149,133 @@ _ppp_cleanup (NMPPPManager *manager) /*****************************************************************************/ -typedef struct { - NMPPPManager *manager; - GSimpleAsyncResult *result; - GCancellable *cancellable; -} StopContext; +struct _NMPPPManagerStopHandle { + NMPPPManager *self; + NMPPPManagerStopCallback callback; + gpointer user_data; + + /* this object delays shutdown, because we still need to wait until + * pppd process terminated. */ + GObject *shutdown_waitobj; + + guint idle_id; +}; static void -stop_context_complete (StopContext *ctx) +_stop_handle_complete (NMPPPManagerStopHandle *handle, gboolean was_cancelled) { - if (ctx->cancellable) - g_object_unref (ctx->cancellable); - g_simple_async_result_complete_in_idle (ctx->result); - g_object_unref (ctx->result); - g_object_unref (ctx->manager); - g_slice_free (StopContext, ctx); -} + gs_unref_object NMPPPManager *self = NULL; + NMPPPManagerStopCallback callback; -static gboolean -stop_context_complete_if_cancelled (StopContext *ctx) -{ - GError *error = NULL; + self = g_steal_pointer (&handle->self); + if (!self) + return; - if (g_cancellable_set_error_if_cancelled (ctx->cancellable, &error)) { - g_simple_async_result_take_error (ctx->result, error); - stop_context_complete (ctx); - return TRUE; - } - return FALSE; + if (!handle->callback) + return; + + callback = handle->callback; + handle->callback = NULL; + callback (self, handle, was_cancelled, handle->user_data); } -static gboolean -_ppp_manager_stop_finish (NMPPPManager *manager, - GAsyncResult *res, - GError **error) +static void +_stop_handle_destroy (NMPPPManagerStopHandle *handle, gboolean was_cancelled) { - return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); + _stop_handle_complete (handle, was_cancelled); + nm_clear_g_source (&handle->idle_id); + g_clear_object (&handle->shutdown_waitobj); + g_slice_free (NMPPPManagerStopHandle, handle); } static void -kill_child_ready (pid_t pid, - gboolean success, - int child_status, - StopContext *ctx) +_stop_child_cb (pid_t pid, + gboolean success, + int child_status, + gpointer user_data) { - if (stop_context_complete_if_cancelled (ctx)) - return; - stop_context_complete (ctx); + _stop_handle_destroy (user_data, FALSE); } -static void -_ppp_manager_stop_async (NMPPPManager *manager, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +static gboolean +_stop_idle_cb (gpointer user_data) { - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); - StopContext *ctx; + NMPPPManagerStopHandle *handle = user_data; - nm_dbus_object_unexport (NM_DBUS_OBJECT (manager)); + handle->idle_id = 0; + _stop_handle_destroy (handle, FALSE); + return G_SOURCE_REMOVE; +} - ctx = g_slice_new0 (StopContext); - ctx->manager = g_object_ref (manager); - ctx->result = g_simple_async_result_new (G_OBJECT (manager), - callback, - user_data, - _ppp_manager_stop_async); +static NMPPPManagerStopHandle * +_ppp_manager_stop (NMPPPManager *self, + NMPPPManagerStopCallback callback, + gpointer user_data) +{ + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); + NMDBusObject *dbus = NM_DBUS_OBJECT (self); + NMPPPManagerStopHandle *handle; - /* Setup cancellable */ - ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - if (stop_context_complete_if_cancelled (ctx)) - return; + if (nm_dbus_object_is_exported (dbus)) + nm_dbus_object_unexport (dbus); - /* Cleanup internals */ - _ppp_cleanup (manager); + _ppp_cleanup (self); + + if ( !priv->pid + && !callback) { + /* nothing to do further... + * + * In this case, we return a %NULL handle. The caller cannot cancel this + * event, but clearly he is not waiting for a callback anyway. */ + return NULL; + } + + handle = g_slice_new0 (NMPPPManagerStopHandle); + handle->self = g_object_ref (self); + handle->callback = callback; + handle->user_data = user_data; - /* If no pppd running, we're done */ if (!priv->pid) { - stop_context_complete (ctx); - return; + /* No PID. There is nothing to kill, however, invoke the callback in + * an idle handler. + * + * Note that we don't register nm_shutdown_wait_obj_register(). + * In order for shutdown to work properly, the caller must always + * explicitly cancel the action to go down. With the idle-handler, + * cancelling the handle completes the request. */ + handle->idle_id = g_idle_add (_stop_idle_cb, handle); + return handle; } - /* No cancellable operation, so just wait until it returns always */ - nm_utils_kill_child_async (priv->pid, - SIGTERM, - LOGD_PPP, - "pppd", - 2000, - (NMUtilsKillChildAsyncCb) kill_child_ready, - ctx); - priv->pid = 0; + /* we really want to kill the process and delay shutdown of NetworkManager + * until the process terminated. We do that, by registering an object + * that delays shutdown. */ + handle->shutdown_waitobj = g_object_new (G_TYPE_OBJECT, NULL); + nm_shutdown_wait_obj_register (handle->shutdown_waitobj, "ppp-manager-wait-kill-pppd"); + nm_utils_kill_child_async (nm_steal_int (&priv->pid), + SIGTERM, LOGD_PPP, "pppd", + NM_SHUTDOWN_TIMEOUT_MS, + _stop_child_cb, handle); + + return handle; } static void -_ppp_manager_stop_sync (NMPPPManager *manager) +_ppp_manager_stop_cancel (NMPPPManagerStopHandle *handle) { - NMDBusObject *dbus = NM_DBUS_OBJECT (manager); + g_return_if_fail (handle); + g_return_if_fail (NM_IS_PPP_MANAGER (handle->self)); - if (nm_dbus_object_is_exported (dbus)) - nm_dbus_object_unexport (dbus); + if (handle->idle_id) { + /* we can complete this fake handle right away. */ + _stop_handle_destroy (handle, TRUE); + return; + } - _ppp_cleanup (manager); - _ppp_kill (manager); + /* a real handle. Only invoke the callback (synchronously). This marks + * the handle as handled, but it keeps shutdown_waitobj around, until + * nm_utils_kill_child_async() returns. */ + _stop_handle_complete (handle, TRUE); } /*****************************************************************************/ @@ -1304,9 +1316,9 @@ set_property (GObject *object, guint prop_id, /*****************************************************************************/ static void -nm_ppp_manager_init (NMPPPManager *manager) +nm_ppp_manager_init (NMPPPManager *self) { - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); priv->ifindex = -1; priv->monitor_fd = -1; @@ -1330,14 +1342,13 @@ static void dispose (GObject *object) { NMPPPManager *self = (NMPPPManager *) object; - NMDBusObject *dbus = NM_DBUS_OBJECT (self); NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); - if (nm_dbus_object_is_exported (dbus)) - nm_dbus_object_unexport (dbus); - - _ppp_cleanup (self); - _ppp_kill (self); + /* we expect the user to first stop the manager. As fallback, + * still stop. */ + g_warn_if_fail (!priv->pid); + g_warn_if_fail (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (self))); + _ppp_manager_stop (self, NULL, NULL); g_clear_object (&priv->act_req); @@ -1483,7 +1494,6 @@ NMPPPOps ppp_ops = { .create = _ppp_manager_new, .set_route_parameters = _ppp_manager_set_route_parameters, .start = _ppp_manager_start, - .stop_async = _ppp_manager_stop_async, - .stop_finish = _ppp_manager_stop_finish, - .stop_sync = _ppp_manager_stop_sync, + .stop = _ppp_manager_stop, + .stop_cancel = _ppp_manager_stop_cancel, }; diff --git a/src/ppp/nm-ppp-manager.h b/src/ppp/nm-ppp-manager.h index 5457726e96..ec0ca46e71 100644 --- a/src/ppp/nm-ppp-manager.h +++ b/src/ppp/nm-ppp-manager.h @@ -32,4 +32,11 @@ typedef struct _NMPPPManager NMPPPManager; +typedef struct _NMPPPManagerStopHandle NMPPPManagerStopHandle; + +typedef void (*NMPPPManagerStopCallback) (NMPPPManager *manager, + NMPPPManagerStopHandle *handle, + gboolean was_cancelled, + gpointer user_data); + #endif /* __NM_PPP_MANAGER_H__ */ diff --git a/src/ppp/nm-ppp-plugin-api.h b/src/ppp/nm-ppp-plugin-api.h index bb53690c63..558de2c2c2 100644 --- a/src/ppp/nm-ppp-plugin-api.h +++ b/src/ppp/nm-ppp-plugin-api.h @@ -21,6 +21,8 @@ #ifndef __NM_PPP_PLUGIN_API_H__ #define __NM_PPP_PLUGIN_API_H__ +#include "nm-ppp-manager.h" + typedef const struct { NMPPPManager *(*create) (const char *iface); @@ -37,16 +39,12 @@ typedef const struct { guint baud_override, GError **err); - void (*stop_async) (NMPPPManager *manager, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); + NMPPPManagerStopHandle *(*stop) (NMPPPManager *manager, + NMPPPManagerStopCallback callback, + gpointer user_data); - gboolean (*stop_finish) (NMPPPManager *manager, - GAsyncResult *res, - GError **error); + void (*stop_cancel) (NMPPPManagerStopHandle *handle); - void (*stop_sync) (NMPPPManager *manager); } NMPPPOps; #endif /* __NM_PPP_PLUGIN_API_H__ */ |