summaryrefslogtreecommitdiff
path: root/daemon
diff options
context:
space:
mode:
authorStef Walter <stefw@gnome.org>2014-03-14 11:05:21 +0100
committerStef Walter <stefw@gnome.org>2014-03-14 11:29:25 +0100
commit61cc045d145e2211a5d4993b9f1f29f548a0177e (patch)
tree0ea5e58458309da6363107206a0e67c2a6637baa /daemon
parent90a3ae6656960b36a1d2277f336222bd49d5eece (diff)
daemon: Provide caller syncronization for quitting the daemon
Quit control messages are a bit strange because the daemon will quit shortly afterwards. There are three syncronization issues here. 1. We need the response to be written right away, because if we wait for the main loop it might not be written. 2. Callers may want to wait for the daemon to exit, so keep the socket open until we do. 3. Prevent additional connections on the control socket.
Diffstat (limited to 'daemon')
-rw-r--r--daemon/control/gkd-control-client.c5
-rw-r--r--daemon/control/gkd-control-server.c42
-rw-r--r--daemon/control/gkd-control.h3
-rw-r--r--daemon/gkd-main.c2
4 files changed, 39 insertions, 13 deletions
diff --git a/daemon/control/gkd-control-client.c b/daemon/control/gkd-control-client.c
index e7446179..ecfdc5ca 100644
--- a/daemon/control/gkd-control-client.c
+++ b/daemon/control/gkd-control-client.c
@@ -181,6 +181,11 @@ control_chat (const gchar *directory,
return FALSE;
ret = control_write (sock, buffer) && control_read (sock, buffer);
+
+ if (flags & GKD_CONTROL_WAIT_FOR_CLOSE) {
+ while (read (sock, &path, sizeof (path)) < 0);
+ }
+
close (sock);
return ret;
}
diff --git a/daemon/control/gkd-control-server.c b/daemon/control/gkd-control-server.c
index 5a81eb49..65a1b042 100644
--- a/daemon/control/gkd-control-server.c
+++ b/daemon/control/gkd-control-server.c
@@ -48,6 +48,8 @@ typedef struct _ControlData {
EGG_SECURE_DECLARE (control_server);
+static gchar *control_path;
+
/* -----------------------------------------------------------------------------------
* CONTROL SERVER
*/
@@ -242,11 +244,24 @@ control_process (EggBuffer *req, GIOChannel *channel)
g_return_if_fail (!egg_buffer_has_error (&cdata->buffer));
egg_buffer_set_uint32 (&cdata->buffer, 0, cdata->buffer.len);
- /* Can't send response in main loop, send here */
+ /*
+ * Quit messages are a bit strange because the daemon will quit.
+ * There are three syncronization issues here.
+ * 1. We need the response to be written right away, because if
+ * we wait for the main loop it might not be written.
+ * 2. Callers may want to wait for the daemon to exit, so keep the
+ * socket open until we do.
+ * 3. Prevent additional connections on the control socket (done via
+ * gkd_control_stop()).
+ */
if (op == GKD_CONTROL_OP_QUIT) {
if (write (g_io_channel_unix_get_fd (channel),
cdata->buffer.buf, cdata->buffer.len) != cdata->buffer.len)
g_message ("couldn't write response to close control request");
+ if (res == GKD_CONTROL_RESULT_OK) {
+ egg_cleanup_register ((GDestroyNotify)g_io_channel_unref,
+ g_io_channel_ref (channel));
+ }
control_data_free (cdata);
/* Any other response, send in the main loop */
@@ -373,12 +388,14 @@ control_accept (GIOChannel *channel, GIOCondition cond, gpointer callback_data)
return TRUE;
}
-static void
-control_cleanup_channel (gpointer user_data)
+void
+gkd_control_stop (void)
{
- gchar *path = user_data;
- unlink (path);
- g_free (path);
+ if (control_path) {
+ unlink (control_path);
+ g_free (control_path);
+ control_path = NULL;
+ }
}
gboolean
@@ -386,13 +403,12 @@ gkd_control_listen (void)
{
struct sockaddr_un addr;
GIOChannel *channel;
- gchar *path;
int sock;
- path = g_strdup_printf ("%s/control", gkd_util_get_master_directory ());
- egg_cleanup_register (control_cleanup_channel, path);
+ control_path = g_strdup_printf ("%s/control", gkd_util_get_master_directory ());
+ egg_cleanup_register ((GDestroyNotify)gkd_control_stop, NULL);
- unlink (path);
+ unlink (control_path);
sock = socket (AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
@@ -402,15 +418,15 @@ gkd_control_listen (void)
memset (&addr, 0, sizeof (addr));
addr.sun_family = AF_UNIX;
- g_strlcpy (addr.sun_path, path, sizeof (addr.sun_path));
+ g_strlcpy (addr.sun_path, control_path, sizeof (addr.sun_path));
if (bind (sock, (struct sockaddr*) &addr, sizeof (addr)) < 0) {
- g_warning ("couldn't bind to control socket: %s: %s", path, g_strerror (errno));
+ g_warning ("couldn't bind to control socket: %s: %s", control_path, g_strerror (errno));
close (sock);
return FALSE;
}
if (listen (sock, 128) < 0) {
- g_warning ("couldn't listen on control socket: %s: %s", path, g_strerror (errno));
+ g_warning ("couldn't listen on control socket: %s: %s", control_path, g_strerror (errno));
close (sock);
return FALSE;
}
diff --git a/daemon/control/gkd-control.h b/daemon/control/gkd-control.h
index c6d31aa7..53af2c6e 100644
--- a/daemon/control/gkd-control.h
+++ b/daemon/control/gkd-control.h
@@ -25,10 +25,13 @@
typedef enum {
GKD_CONTROL_QUIET_IF_NO_PEER = 1 << 0,
+ GKD_CONTROL_WAIT_FOR_CLOSE = 1 << 1,
} GkdControlFlags;
gboolean gkd_control_listen (void);
+void gkd_control_stop (void);
+
gchar** gkd_control_initialize (const gchar *directory,
const gchar *components,
const gchar **env);
diff --git a/daemon/gkd-main.c b/daemon/gkd-main.c
index 5c5381c7..2bcfc045 100644
--- a/daemon/gkd-main.c
+++ b/daemon/gkd-main.c
@@ -399,6 +399,8 @@ dump_diagnostics (void)
void
gkd_main_quit (void)
{
+ /* Always stop accepting control connections immediately */
+ gkd_control_stop ();
g_main_loop_quit (loop);
}