[network-manager-openvpn/th/handle-child-process-bgo761299] fixup! service: fix handling child processes and their cleanup
- From: Thomas Haller <thaller src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [network-manager-openvpn/th/handle-child-process-bgo761299] fixup! service: fix handling child processes and their cleanup
- Date: Sun, 31 Jan 2016 13:09:39 +0000 (UTC)
commit f24327eb3c2594095c27c78c01af34fb43fdf533
Author: Thomas Haller <thaller redhat com>
Date: Sun Jan 31 13:56:57 2016 +0100
fixup! service: fix handling child processes and their cleanup
src/nm-openvpn-service.c | 226 ++++++++++++++++++++++++++++------------------
1 files changed, 136 insertions(+), 90 deletions(-)
---
diff --git a/src/nm-openvpn-service.c b/src/nm-openvpn-service.c
index dbca720..7569982 100644
--- a/src/nm-openvpn-service.c
+++ b/src/nm-openvpn-service.c
@@ -59,6 +59,10 @@
static gboolean debug = FALSE;
static GMainLoop *loop = NULL;
+static struct {
+ GSList *pids_pending_list;
+} gl/*obal*/;
+
#define NM_OPENVPN_HELPER_PATH LIBEXECDIR"/nm-openvpn-service-openvpn-helper"
G_DEFINE_TYPE (NMOpenvpnPlugin, nm_openvpn_plugin, NM_TYPE_VPN_SERVICE_PLUGIN)
@@ -84,7 +88,6 @@ typedef struct {
NMOpenvpnPluginIOData *io_data;
gboolean interactive;
char *mgt_path;
- GSList *pids_pending_list;
} NMOpenvpnPluginPrivate;
typedef struct {
@@ -99,6 +102,7 @@ typedef struct {
GPid pid;
guint watch_id;
guint kill_id;
+ NMOpenvpnPlugin *plugin;
} PidsPendingData;
static ValidProperty valid_properties[] = {
@@ -157,23 +161,125 @@ static ValidProperty valid_secrets[] = {
/*****************************************************************************/
static void
-pids_pending_data_free (PidsPendingData *data)
+pids_pending_data_free (PidsPendingData *pid_data)
{
- nm_clear_g_source (&data->watch_id);
- nm_clear_g_source (&data->kill_id);
- g_slice_free (PidsPendingData, data);
+ nm_clear_g_source (&pid_data->watch_id);
+ nm_clear_g_source (&pid_data->kill_id);
+ if (pid_data->plugin)
+ g_object_remove_weak_pointer ((GObject *) pid_data->plugin, (gpointer *) &pid_data->plugin);
+ g_slice_free (PidsPendingData, pid_data);
}
static PidsPendingData *
-pids_pending_get (GSList *pids_pending_list, GPid pid)
+pids_pending_get (GPid pid)
{
- for (; pids_pending_list; pids_pending_list = pids_pending_list->next) {
- if (((PidsPendingData *) pids_pending_list->data)->pid == pid)
- return pids_pending_list->data;
+ GSList *iter;
+
+ for (iter = gl.pids_pending_list; iter; iter = iter->next) {
+ if (((PidsPendingData *) iter->data)->pid == pid)
+ return iter->data;
}
g_return_val_if_reached (NULL);
}
+static void openvpn_child_terminated (NMOpenvpnPlugin *plugin, GPid pid, gint status);
+
+static void
+pids_pending_child_watch_cb (GPid pid, gint status, gpointer user_data)
+{
+ PidsPendingData *pid_data = user_data;
+ NMOpenvpnPlugin *plugin;
+
+ if (WIFEXITED (status)) {
+ int exit_status;
+
+ exit_status = WEXITSTATUS (status);
+ if (exit_status != 0)
+ g_warning ("openvpn[%ld] exited with error code %d", (long) pid, exit_status);
+ else
+ g_message ("openvpn[%ld] exited with success", (long) pid);
+ }
+ else if (WIFSTOPPED (status))
+ g_warning ("openvpn[%ld] stopped unexpectedly with signal %d", (long) pid, WSTOPSIG (status));
+ else if (WIFSIGNALED (status))
+ g_warning ("openvpn[%ld] died with signal %d", (long) pid, WTERMSIG (status));
+ else
+ g_warning ("openvpn[%ld] died from an unnatural cause", (long) pid);
+
+ g_return_if_fail (pid_data);
+ g_return_if_fail (pid_data->pid == pid);
+ g_return_if_fail (pid_data == pids_pending_get (pid));
+
+ plugin = pid_data->plugin;
+
+ pid_data->watch_id = 0;
+ gl.pids_pending_list = g_slist_remove (gl.pids_pending_list , pid_data);
+ pids_pending_data_free (pid_data);
+
+ if (plugin)
+ openvpn_child_terminated (plugin, pid, status);
+}
+
+static void
+pids_pending_add (NMOpenvpnPlugin *plugin, GPid pid)
+{
+ PidsPendingData *pid_data;
+
+ g_return_if_fail (NM_IS_OPENVPN_PLUGIN (plugin));
+ g_return_if_fail (pid > 0);
+
+ g_message ("openvpn[%ld] started", (long) pid);
+
+ pid_data = g_slice_new (PidsPendingData);
+ pid_data->pid = pid;
+ pid_data->kill_id = 0;
+ pid_data->watch_id = g_child_watch_add (pid, pids_pending_child_watch_cb, pid_data);
+ pid_data->plugin = plugin;
+ g_object_add_weak_pointer ((GObject *) plugin, (gpointer *) &pid_data->plugin);
+
+ gl.pids_pending_list = g_slist_prepend (gl.pids_pending_list, pid_data);
+}
+
+static gboolean
+pids_pending_ensure_killed (gpointer user_data)
+{
+ PidsPendingData *pid_data = user_data;
+
+ g_return_val_if_fail (pid_data && pid_data == pids_pending_get (pid_data->pid), FALSE);
+
+ g_message ("openvpn[%ld]: send SIGKILL", (long) pid_data->pid);
+
+ pid_data->kill_id = 0;
+ kill (pid_data->pid, SIGKILL);
+ return FALSE;
+}
+
+static void
+pids_pending_send_sigterm (GPid pid)
+{
+ PidsPendingData *pid_data;
+
+ pid_data = pids_pending_get (pid);
+ g_return_if_fail (pid_data);
+
+ g_message ("openvpn[%ld]: send SIGTERM", (long) pid);
+
+ kill (pid, SIGTERM);
+ pid_data->kill_id = g_timeout_add (2000, pids_pending_ensure_killed, pid_data);
+}
+
+static void
+pids_pending_wait_for_processes (GMainLoop *main_loop)
+{
+ if (gl.pids_pending_list) {
+ g_message ("wait for %u openvpn processes to terminate...", g_slist_length
(gl.pids_pending_list));
+
+ do {
+ g_main_context_iteration (g_main_loop_get_context (main_loop), TRUE);
+ } while (gl.pids_pending_list);
+ }
+}
+
/*****************************************************************************/
static gboolean
@@ -512,7 +618,7 @@ handle_auth (NMOpenvpnPluginIOData *io_data,
}
static gboolean
-handle_management_socket (NMVpnServicePlugin *plugin,
+handle_management_socket (NMOpenvpnPlugin *plugin,
GIOChannel *source,
GIOCondition condition,
NMVpnPluginFailure *out_failure)
@@ -554,7 +660,7 @@ handle_management_socket (NMVpnServicePlugin *plugin,
g_message ("Requesting new secrets: '%s' (%s)", message,
joined);
g_free (joined);
}
- nm_vpn_service_plugin_secrets_required (plugin, message, (const char
**) hints);
+ nm_vpn_service_plugin_secrets_required ((NMVpnServicePlugin *)
plugin, message, (const char **) hints);
} else {
/* Interactive not allowed, can't ask for more secrets */
g_warning ("More secrets required but cannot ask interactively");
@@ -608,11 +714,11 @@ out:
static gboolean
nm_openvpn_socket_data_cb (GIOChannel *source, GIOCondition condition, gpointer user_data)
{
- NMVpnServicePlugin *plugin = NM_VPN_SERVICE_PLUGIN (user_data);
+ NMOpenvpnPlugin *plugin = NM_OPENVPN_PLUGIN (user_data);
NMVpnPluginFailure failure = NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED;
if (!handle_management_socket (plugin, source, condition, &failure)) {
- nm_vpn_service_plugin_failure (plugin, failure);
+ nm_vpn_service_plugin_failure ((NMVpnServicePlugin *) plugin, failure);
return FALSE;
}
@@ -673,37 +779,15 @@ nm_openvpn_schedule_connect_timer (NMOpenvpnPlugin *plugin)
}
static void
-openvpn_watch_cb (GPid pid, gint status, gpointer user_data)
+openvpn_child_terminated (NMOpenvpnPlugin *plugin, GPid pid, gint status)
{
- NMVpnServicePlugin *plugin = NM_VPN_SERVICE_PLUGIN (user_data);
- NMOpenvpnPluginPrivate *priv = NM_OPENVPN_PLUGIN_GET_PRIVATE (plugin);
+ NMOpenvpnPluginPrivate *priv;
NMVpnPluginFailure failure = NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED;
- guint error = 0;
gboolean good_exit = FALSE;
- PidsPendingData *pid_data = NULL;
- if (WIFEXITED (status)) {
- error = WEXITSTATUS (status);
- if (error != 0)
- g_warning ("openvpn[%ld] exited with error code %d", (long) pid, error);
- else
- g_message ("openvpn[%ld] exited with success", (long) pid);
- }
- else if (WIFSTOPPED (status))
- g_warning ("openvpn[%ld] stopped unexpectedly with signal %d", (long) pid, WSTOPSIG (status));
- else if (WIFSIGNALED (status))
- g_warning ("openvpn[%ld] died with signal %d", (long) pid, WTERMSIG (status));
- else
- g_warning ("openvpn[%ld] died from an unnatural cause", (long) pid);
-
- pid_data = pids_pending_get (priv->pids_pending_list, pid);
- if (!pid_data)
- g_return_if_reached ();
- priv->pids_pending_list = g_slist_remove (priv->pids_pending_list , pid_data);
-
- pid_data->watch_id = 0;
- pids_pending_data_free (pid_data);
+ g_return_if_fail (NM_IS_OPENVPN_PLUGIN (plugin));
+ priv = NM_OPENVPN_PLUGIN_GET_PRIVATE (plugin);
/* Reap child if needed. */
if (priv->pid != pid) {
/* the dead child is not the currently active process. Nothing to do, we just
@@ -714,7 +798,7 @@ openvpn_watch_cb (GPid pid, gint status, gpointer user_data)
priv->pid = 0;
/* OpenVPN doesn't supply useful exit codes :( */
- if (error == 0)
+ if (WIFEXITED (status) && WEXITSTATUS (status) == 0)
good_exit = TRUE;
/* Try to get the last bits of data from openvpn */
@@ -731,9 +815,9 @@ openvpn_watch_cb (GPid pid, gint status, gpointer user_data)
}
if (good_exit)
- nm_vpn_service_plugin_disconnect (plugin, NULL);
+ nm_vpn_service_plugin_disconnect ((NMVpnServicePlugin *) plugin, NULL);
else
- nm_vpn_service_plugin_failure (plugin, failure);
+ nm_vpn_service_plugin_failure ((NMVpnServicePlugin *) plugin, failure);
}
static gboolean
@@ -982,7 +1066,6 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
const char *defport, *proto_tcp;
const char *nm_openvpn_user, *nm_openvpn_group, *nm_openvpn_chroot;
gchar *bus_name;
- PidsPendingData *pid_data;
/* Find openvpn */
openvpn_binary = nm_find_openvpn ();
@@ -1494,14 +1577,7 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
}
free_openvpn_args (args);
- g_message ("openvpn[%ld] started", (long) pid);
-
- pid_data = g_slice_new (PidsPendingData);
- pid_data->pid = pid;
- pid_data->kill_id = 0;
- pid_data->watch_id = g_child_watch_add (pid, openvpn_watch_cb, plugin);
-
- priv->pids_pending_list = g_slist_prepend (priv->pids_pending_list, pid_data);
+ pids_pending_add (plugin, pid);
g_warn_if_fail (!priv->pid);
priv->pid = pid;
@@ -1580,18 +1656,6 @@ check_need_secrets (NMSettingVpn *s_vpn, gboolean *need_secrets)
}
static gboolean
-ensure_killed (gpointer user_data)
-{
- PidsPendingData *pid_data = user_data;
-
- g_message ("openvpn[%ld]: send SIGKILL", (long) pid_data->pid);
-
- pid_data->kill_id = 0;
- kill (pid_data->pid, SIGKILL);
- return FALSE;
-}
-
-static gboolean
real_disconnect (NMVpnServicePlugin *plugin,
GError **err)
{
@@ -1600,18 +1664,8 @@ real_disconnect (NMVpnServicePlugin *plugin,
g_clear_pointer (&priv->mgt_path, g_free);
if (priv->pid) {
- PidsPendingData *pid_data;
- GPid pid = priv->pid;
-
+ pids_pending_send_sigterm (priv->pid);
priv->pid = 0;
-
- pid_data = pids_pending_get (priv->pids_pending_list, pid);
- g_return_val_if_fail (pid_data, TRUE);
-
- g_message ("openvpn[%ld]: send SIGTERM", (long) pid);
-
- kill (pid, SIGTERM);
- pid_data->kill_id = g_timeout_add (2000, ensure_killed, pid_data);
}
return TRUE;
@@ -1787,18 +1841,11 @@ dispose (GObject *object)
{
NMOpenvpnPluginPrivate *priv = NM_OPENVPN_PLUGIN_GET_PRIVATE (object);
- while (priv->pids_pending_list) {
- PidsPendingData *pid_data = priv->pids_pending_list->data;
-
- priv->pids_pending_list = g_slist_delete_link (priv->pids_pending_list,
priv->pids_pending_list);
+ nm_clear_g_source (&priv->connect_timer);
- if (priv->pid == pid_data->pid) {
- kill (priv->pid, SIGTERM);
- priv->pid = 0;
- g_usleep (1);
- }
- kill (priv->pid, SIGKILL);
- pids_pending_data_free (pid_data);
+ if (priv->pid) {
+ pids_pending_send_sigterm (priv->pid);
+ priv->pid = 0;
}
G_OBJECT_CLASS (nm_openvpn_plugin_parent_class)->dispose (object);
@@ -1836,10 +1883,7 @@ plugin_state_changed (NMOpenvpnPlugin *plugin,
case NM_VPN_SERVICE_STATE_STOPPING:
case NM_VPN_SERVICE_STATE_STOPPED:
/* Cleanup on failure */
- if (priv->connect_timer) {
- g_source_remove (priv->connect_timer);
- priv->connect_timer = 0;
- }
+ nm_clear_g_source (&priv->connect_timer);
nm_openvpn_disconnect_management_socket (plugin);
break;
default:
@@ -1961,9 +2005,11 @@ main (int argc, char *argv[])
setup_signals ();
g_main_loop_run (loop);
+ g_object_unref (plugin);
+
+ pids_pending_wait_for_processes (loop);
g_main_loop_unref (loop);
- g_object_unref (plugin);
exit (EXIT_SUCCESS);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]