ecore_con: add systemd socket activation.
authorCedric Bail <cedric.bail@free.fr>
Sun, 10 Mar 2013 06:49:54 +0000 (15:49 +0900)
committerCedric Bail <cedric.bail@free.fr>
Sun, 10 Mar 2013 07:00:32 +0000 (16:00 +0900)
Be careful, systemd socket activation require you to always order
server socket creation in the same order as defined in the unit file.
This means ecore_con_server_add should always been in the same order
for those of them using systemd socket activation.

ChangeLog
NEWS
configure.ac
src/lib/ecore_con/Ecore_Con.h
src/lib/ecore_con/ecore_con.c
src/lib/ecore_con/ecore_con_local.c
src/lib/ecore_con/ecore_con_private.h

index 129e551a205bc18e0483a24d4ff8b39edd3cc965..719dfc99dc681a2b54a9d91ab7b4c19fca6210f7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,7 @@
 2013-03-10  Cedric Bail
 
        * Eeze: add a dummy implementation of libmount when it is not available.
+       * Ecore_Con: add systemd socket activation support (ECORE_CON_SOCKET_ACTIVATE).
 
 2013-03-08  Igor Murzov
 
diff --git a/NEWS b/NEWS
index 08ce5debe2ef2965cf596194c4061b0912bfa5c4..2729d5c34bf38eaf6f4a6f0269fe4248d7060fd6 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -72,6 +72,7 @@ Additions:
        * Ecore_x: Add atom related with indicator type. 
     * Ecore_x: Add manual render code before deiconify
     * Eeze: Add a dummy libmount replacement for when libmount is not there.
+    * Ecore_Con: Add systemd socket activation support (ECORE_CON_SOCKET_ACTIVATE).
 
 Deprecations:
     * ecore_x:
index 79d562b4f1888c73737e41101c3452052b61c294..d43be7bed303b7d3a7c4104c1c4d9deca73f75a6 100644 (file)
@@ -1883,21 +1883,26 @@ want_ecore_con_local_sockets="yes"
 want_ecore_con_abstract_sockets="yes"
 
 if test "${have_wince}" = "yes"; then
+   want_systemd="no"
    want_curl="no"
    want_cares="no"
    want_ecore_con_local_sockets="no"
    want_ecore_con_abstract_sockets="no"
 elif test "${have_win32}" = "yes"; then
+   want_systemd="no"
    want_cares="yes"
    want_ecore_con_abstract_sockets="no"
 elif test "${have_darwin}" = "yes"; then
+   want_systemd="no"
    want_cares="no"
    want_ecore_con_abstract_sockets="no"
 elif test "${have_ps3}" = "yes"; then
+   want_systemd="no"
    want_cares="no"
    want_ecore_con_local_sockets="no"
    want_ecore_con_abstract_sockets="no"
 else
+   want_systemd="yes"
    want_cares="no"
 fi
 
@@ -1934,11 +1939,14 @@ else
    ecore_con_resolver="fork"
 fi
 
+EFL_OPTIONAL_DEPEND_PKG([ECORE_CON], [${want_systemd}], [SYSTEMD], [libsystemd-daemon])
+
 EFL_ADD_FEATURE([ECORE_CON], [curl])
 EFL_ADD_FEATURE([ECORE_CON], [cares])
 EFL_ADD_FEATURE([ECORE_CON], [local-sockets], [${want_ecore_con_local_sockets}])
 EFL_ADD_FEATURE([ECORE_CON], [abstract-sockets], [${want_ecore_con_abstract_sockets}])
 EFL_ADD_FEATURE([ECORE_CON], [resolver], [${ecore_con_resolver}])
+EFL_ADD_FEATURE([ECORE_CON], [systemd-daemon], [${want_systemd}])
 
 EFL_EVAL_PKGS([ECORE_CON])
 
index 78225a32bae14859ef397afa1a19c188bbc34522..3eec77066721d06f7481828e35984d13ed5cc3db 100644 (file)
@@ -662,7 +662,8 @@ typedef enum _Ecore_Con_Type
     * @note Only functional for clients
     * @since 1.2
     */
-   ECORE_CON_NO_PROXY = (1 << 8)
+   ECORE_CON_NO_PROXY = (1 << 8),
+   ECORE_CON_SOCKET_ACTIVATE = (1 << 9) 
 } Ecore_Con_Type;
 
 /**
index eac019edc362c10e234f99602190717399960ac4..b4da4578f62003f3d9d101b22efdb8fa2acf8c7e 100644 (file)
 #include <arpa/inet.h>
 #include <sys/un.h>
 
+#ifdef HAVE_SYSTEMD
+# include <systemd/sd-daemon.h>
+#endif
+
 #ifdef HAVE_WS2TCPIP_H
 # include <ws2tcpip.h>
 #endif
@@ -88,6 +92,10 @@ static void _ecore_con_lookup_done(void           *data,
 
 static const char * _ecore_con_pretty_ip(struct sockaddr *client_addr);
 
+#ifdef HAVE_SYSTEMD
+int sd_fd_index = 0;
+int sd_fd_max = 0;
+#endif
 
 void
 _ecore_con_client_kill(Ecore_Con_Client *cl)
@@ -158,7 +166,6 @@ ecore_con_init(void)
 #ifdef HAVE_EVIL
    if (!evil_init())
      return --_ecore_con_init_count;
-
 #endif
 
    if (!ecore_init())
@@ -197,6 +204,10 @@ ecore_con_init(void)
    ecore_con_ssl_init();
    ecore_con_info_init();
 
+#ifdef HAVE_SYSTEMD
+   sd_fd_max = sd_listen_fds(0);
+#endif
+
    return _ecore_con_init_count;
 }
 
@@ -1425,6 +1436,45 @@ _ecore_con_cb_tcp_listen(void           *data,
         goto error;
      }
 
+#ifdef HAVE_SYSTEMD
+   if (svr->type & ECORE_CON_SOCKET_ACTIVATE && sd_fd_index < sd_fd_max)
+     {
+        if (sd_is_socket_inet(SD_LISTEN_FDS_START + sd_fd_index,
+                             net_info->info.ai_family,
+                             net_info->info.ai_socktype,
+                             1,
+                             svr->port) <= 0)
+         {
+            ERR("Your systemd unit seems to provide fd in the wrong order for Socket activation.");
+            goto error;
+         }
+
+       svr->fd = SD_LISTEN_FDS_START + sd_fd_index++;
+
+       /* I am wondering if that's really going to work as the bind is already done */
+       if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
+
+       lin.l_onoff = 1;
+       lin.l_linger = 0;
+       if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin,
+                      sizeof(struct linger)) < 0)
+         goto error;                                                    
+
+       if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_NODELAY)
+         {
+            int flag = 1;
+
+            if (setsockopt(svr->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag,
+                           sizeof(int)) < 0)
+              {
+                goto error;
+              }
+         }
+
+       goto fd_ready;
+     }
+#endif
+
    svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype,
                     net_info->info.ai_protocol);
    if (svr->fd < 0) goto error;
@@ -1439,7 +1489,7 @@ _ecore_con_cb_tcp_listen(void           *data,
 
    if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_REMOTE_NODELAY)
      {
-        int flag = 1;
+       int flag = 1;
 
         if (setsockopt(svr->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag,
                        sizeof(int)) < 0)
@@ -1453,8 +1503,11 @@ _ecore_con_cb_tcp_listen(void           *data,
 
    if (listen(svr->fd, 4096) < 0) goto error;
 
+#ifdef HAVE_SYSTEMD
+ fd_ready:
+#endif
    svr->fd_handler = ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
-                                               _ecore_con_svr_tcp_handler, svr, NULL, NULL);
+                                              _ecore_con_svr_tcp_handler, svr, NULL, NULL);
    if (!svr->fd_handler)
      {
         memerr = "Memory allocation failure";
@@ -1492,7 +1545,27 @@ _ecore_con_cb_udp_listen(void           *data,
         svr->delete_me = EINA_TRUE;
         goto error;
      }
+#ifdef HAVE_SYSTEMD
+   if (svr->type & ECORE_CON_SOCKET_ACTIVATE && sd_fd_index < sd_fd_max)
+     {
+        if (sd_is_socket_inet(SD_LISTEN_FDS_START + sd_fd_index,
+                             net_info->info.ai_family,
+                             net_info->info.ai_socktype,
+                             -1,
+                             svr->port) <= 0)
+         {
+            ERR("Your systemd unit seems to provide fd in the wrong order for Socket activation.");
+            goto error;
+         }
+       svr->fd = SD_LISTEN_FDS_START + sd_fd_index++;
+
+       if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on)) != 0)
+         goto error;
+       if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error;
 
+       goto fd_ready;
+     }
+#endif
    svr->fd = socket(net_info->info.ai_family, net_info->info.ai_socktype,
                     net_info->info.ai_protocol);
    if (svr->fd < 0) goto error;
@@ -1532,6 +1605,9 @@ _ecore_con_cb_udp_listen(void           *data,
    if (bind(svr->fd, net_info->info.ai_addr, net_info->info.ai_addrlen) < 0)
      goto error;
 
+#ifdef HAVE_SYSTEMD
+ fd_ready:
+#endif
    svr->fd_handler =
      ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
                                _ecore_con_svr_udp_handler, svr, NULL, NULL);
index 2ca00d0529f440d22f0c8eef12b081922a02df85..fc2063aa3b4e4308c902f8d2e4f4c94230bd9797 100644 (file)
 #include <sys/socket.h>
 #include <sys/un.h>
 
+#ifdef HAVE_SYSTEMD
+# include <systemd/sd-daemon.h>
+#endif
+
 #ifdef HAVE_WS2TCPIP_H
 # include <ws2tcpip.h>
 #endif
@@ -186,6 +190,7 @@ ecore_con_local_listen(
    struct stat st;
    mode_t mask;
    int socket_unix_len;
+   Eina_Bool abstract_socket;
 
    mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
 
@@ -249,25 +254,10 @@ ecore_con_local_listen(
 
    pmode = umask(mask);
 start:
-   svr->fd = socket(AF_UNIX, SOCK_STREAM, 0);
-   if (svr->fd < 0)
-     goto error_umask;
-
-   if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0)
-     goto error_umask;
-
-   if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0)
-     goto error_umask;
-
-   lin.l_onoff = 1;
-   lin.l_linger = 0;
-   if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin,
-                  sizeof(struct linger)) < 0)
-     goto error_umask;
-
    socket_unix.sun_family = AF_UNIX;
    if ((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_ABSTRACT)
      {
+        abstract_socket = EINA_TRUE;
 #ifdef HAVE_ABSTRACT_SOCKETS
         /* . is a placeholder */
         snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s",
@@ -283,10 +273,54 @@ start:
      }
    else
      {
+        abstract_socket = EINA_FALSE;
         strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
         socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
      }
 
+#ifdef HAVE_SYSTEMD
+   if (svr->type & ECORE_CON_SOCKET_ACTIVATE && sd_fd_index < sd_fd_max)
+     {
+        if (sd_is_socket_unix(SD_LISTEN_FDS_START + sd_fd_index,
+                             SOCK_STREAM, 1,
+                             socket_unix.sun_path,
+                             abstract_socket ? socket_unix_len : 0) <= 0)
+         {
+            ERR("Your systemd unit seems to provide fd in the wrong order for Socket activation.");
+            goto error_umask;
+         }
+       svr->fd = SD_LISTEN_FDS_START + sd_fd_index++;
+
+       if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0)
+         goto error_umask;
+
+       lin.l_onoff = 1;
+       lin.l_linger = 0;
+       if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin,
+                      sizeof(struct linger)) < 0)
+         goto error_umask;
+
+       goto fd_ready;
+     }
+#else
+   (void) abstract_socket;
+#endif
+   svr->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+   if (svr->fd < 0)
+     goto error_umask;
+
+   if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0)
+     goto error_umask;
+
+   if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0)
+     goto error_umask;
+
+   lin.l_onoff = 1;
+   lin.l_linger = 0;
+   if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, (const void *)&lin,
+                  sizeof(struct linger)) < 0)
+     goto error_umask;
+
    if (bind(svr->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0)
      {
         if ((((svr->type & ECORE_CON_TYPE) == ECORE_CON_LOCAL_USER) ||
@@ -302,6 +336,9 @@ start:
    if (listen(svr->fd, 4096) < 0)
      goto error_umask;
 
+#ifdef HAVE_SYSTEMD
+ fd_ready:
+#endif
    svr->path = strdup(buf);
    if (!svr->path)
      goto error_umask;
index 2c988d88f2a01d6f7d2a705f3cfda41f4997937d..bdd7d961d63b096239217a4a988b8dff7a4ff33f 100644 (file)
@@ -270,6 +270,11 @@ struct Ecore_Con_Socks_v5
    unsigned int plen;
 };
 
+#ifdef HAVE_SYSTEMD
+extern int sd_fd_index;
+extern int sd_fd_max;
+#endif
+
 extern Ecore_Con_Socks *_ecore_con_proxy_once;
 extern Ecore_Con_Socks *_ecore_con_proxy_global;
 void ecore_con_socks_init(void);