From d971465937c971beb2886ad59827005f69546247 Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Sat, 26 Mar 2016 19:37:10 +0000 Subject: [PATCH v3 3/4] Allow network processes to be made with a pre-allocated fd. * src/process.c (connect_network_socket): Allow a pre-allocated socket descriptor to be used if passed to Emacs, avoiding the call to socket() and bind(). (Fmake_network_process): Allow users to pass in :use-systemd-socket on the parameter plist to use a socket descriptor that has been passed to Emacs from systemd. (wait_reading_process_output): Call socket() & bind() every time. (syms_of_process): New symbol ":use-passed-socket". * doc/lispref/processes.texi (Network Processes): Document new `make-network-process' option ':use-systemd-socket'. --- doc/lispref/processes.texi | 6 ++++++ src/process.c | 36 +++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi index 8d3df55..1d43c25 100644 --- a/doc/lispref/processes.texi +++ b/doc/lispref/processes.texi @@ -2367,6 +2367,12 @@ automatically for the given @var{host} and @var{service}. ignored. @code{ipv4} and @code{ipv6} specify to use IPv4 and IPv6, respectively. +@item :use-systemd-socket @var{use-systemd-socket} +If @var{use-systemd-socket} is non-@code{nil} and Emacs was passed a +network socket by systemd, use that socket instead of allocating one. +This is used by the Emacs server code to allow on-demand socket +activation. + @item :local @var{local-address} For a server process, @var{local-address} is the address to listen on. It overrides @var{family}, @var{host} and @var{service}, so you diff --git a/src/process.c b/src/process.c index 198e7de..28d2631 100644 --- a/src/process.c +++ b/src/process.c @@ -3075,7 +3075,8 @@ finish_after_tls_connection (Lisp_Object proc) #endif static void -connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses) +connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses, + Lisp_Object use_systemd_socket_p) { ptrdiff_t count = SPECPDL_INDEX (); ptrdiff_t count1; @@ -3089,6 +3090,16 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses) struct Lisp_Process *p = XPROCESS (proc); Lisp_Object contact = p->childp; int optbits = 0; + int systemd_socket_descriptor = 0; + +#ifdef HAVE_SYSTEMD + if (!NILP (use_systemd_socket_p)) + { + extern int systemd_socket; + systemd_socket_descriptor = systemd_socket; + } +#endif /* HAVE_SYSTEMD */ + /* Do this in case we never enter the while-loop below. */ count1 = SPECPDL_INDEX (); @@ -3109,7 +3120,11 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses) sa = xmalloc (addrlen); conv_lisp_to_sockaddr (family, ip_address, sa, addrlen); - s = socket (family, p->socktype | SOCK_CLOEXEC, p->ai_protocol); + if (systemd_socket_descriptor) + s = systemd_socket_descriptor; + else + s = socket (family, p->socktype | SOCK_CLOEXEC, p->ai_protocol); + if (s < 0) { xerrno = errno; @@ -3168,8 +3183,11 @@ connect_network_socket (Lisp_Object proc, Lisp_Object ip_addresses) report_file_error ("Cannot set reuse option on server socket", Qnil); } - if (bind (s, sa, addrlen)) - report_file_error ("Cannot bind server socket", Qnil); + /* If we are passed a socket descriptor from systemd, it is + already bound. */ + if (!systemd_socket_descriptor) + if (bind (s, sa, addrlen)) + report_file_error ("Cannot bind server socket", Qnil); #ifdef HAVE_GETSOCKNAME if (p->port == 0) @@ -3534,6 +3552,8 @@ The following network options can be specified for this connection: (this is allowed by default for a server process). :bindtodevice NAME -- bind to interface NAME. Using this may require special privileges on some systems. +:use-systemd-socket BOOL -- Use any pre-allocated sockets that have + been passed to Emacs by systemd. Consult the relevant system programmer's manual pages for more information on using these options. @@ -3578,7 +3598,7 @@ usage: (make-network-process &rest ARGS) */) EMACS_INT port = 0; Lisp_Object tem; Lisp_Object name, buffer, host, service, address; - Lisp_Object filter, sentinel; + Lisp_Object filter, sentinel, use_systemd_socket_p; Lisp_Object ip_addresses = Qnil; int socktype; int family = -1; @@ -3618,6 +3638,7 @@ usage: (make-network-process &rest ARGS) */) buffer = Fplist_get (contact, QCbuffer); filter = Fplist_get (contact, QCfilter); sentinel = Fplist_get (contact, QCsentinel); + use_systemd_socket_p = Fplist_get (contact, QCuse_systemd_socket); CHECK_STRING (name); @@ -3914,7 +3935,7 @@ usage: (make-network-process &rest ARGS) */) } #endif - connect_network_socket (proc, ip_addresses); + connect_network_socket (proc, ip_addresses, use_systemd_socket_p); return proc; } @@ -4848,7 +4869,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, { Lisp_Object ip_addresses = check_for_dns (aproc); if (!NILP (ip_addresses) && !EQ (ip_addresses, Qt)) - connect_network_socket (aproc, ip_addresses); + connect_network_socket (aproc, ip_addresses, Qnil); else retry_for_async = true; } @@ -7837,6 +7858,7 @@ syms_of_process (void) DEFSYM (QCserver, ":server"); DEFSYM (QCnowait, ":nowait"); DEFSYM (QCsentinel, ":sentinel"); + DEFSYM (QCuse_systemd_socket, ":use-systemd-socket"); DEFSYM (QCtls_parameters, ":tls-parameters"); DEFSYM (Qnsm_verify_connection, "nsm-verify-connection"); DEFSYM (QClog, ":log"); -- 2.7.4