]> source.dussan.org Git - tigervnc.git/commitdiff
x0vncserver: Add support for systemd socket activation 1716/head
authorMike Looijmans <mike.looijmans@topic.nl>
Fri, 12 Jan 2024 08:24:48 +0000 (09:24 +0100)
committerMike Looijmans <mike.looijmans@topic.nl>
Fri, 12 Jan 2024 15:03:20 +0000 (16:03 +0100)
systemd can pass in sockets as file descriptors 3 and beyond. Allows
the server to use socket activation.

When triggered by systemd, no other listening sockets (e.g. rfbport) will
be activated.

Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
CMakeLists.txt
unix/x0vncserver/CMakeLists.txt
unix/x0vncserver/x0vncserver.cxx
unix/x0vncserver/x0vncserver.man

index e8d8d85d43d6cc42a7de9d9aa62983d5087e1317..6028fadfa5d7cb051e7264bf930db0d110a52d13 100644 (file)
@@ -301,6 +301,9 @@ if(UNIX AND NOT APPLE)
   endif()
 endif()
 
+# check for systemd support (socket activation)
+pkg_check_modules(LIBSYSTEMD libsystemd)
+
 # Generate config.h and make sure the source finds it
 configure_file(config.h.in config.h)
 add_definitions(-DHAVE_CONFIG_H)
index 31da51183ab5641f460584638fa37a3b15bc0c9c..08b346f1a6f149cb5ffc039cb36797eff0a74ed3 100644 (file)
@@ -21,6 +21,12 @@ target_include_directories(x0vncserver PUBLIC ${CMAKE_SOURCE_DIR}/unix)
 target_include_directories(x0vncserver PUBLIC ${CMAKE_SOURCE_DIR}/common)
 target_link_libraries(x0vncserver tx rfb network rdr unixcommon)
 
+# systemd support (socket activation)
+if (LIBSYSTEMD_FOUND)
+  add_definitions(-DHAVE_SYSTEMD_H)
+  target_link_libraries(x0vncserver ${LIBSYSTEMD_LIBRARIES})
+endif()
+
 if(X11_FOUND AND X11_XTest_LIB)
   add_definitions(-DHAVE_XTEST)
   target_link_libraries(x0vncserver ${X11_XTest_LIB})
index f87eb61e4a571fbcf1fb18e693e1114b1d7f2f56..5e9a7a570c979c1b756cd0426baf69446bac3b94 100644 (file)
@@ -38,6 +38,9 @@
 #include <rfb/Timer.h>
 #include <network/TcpSocket.h>
 #include <network/UnixSocket.h>
+#ifdef HAVE_SYSTEMD_H
+#  include <systemd/sd-daemon.h>
+#endif
 
 #include <signal.h>
 #include <X11/X.h>
@@ -113,6 +116,25 @@ static void CleanupSignalHandler(int /*sig*/)
   caughtSignal = true;
 }
 
+#ifdef HAVE_SYSTEMD_H
+static int createSystemdListeners(std::list<SocketListener*> *listeners)
+{
+  int count = sd_listen_fds(0);
+
+  for (int i = 0; i < count; ++i) {
+      /* systemd sockets start at FD 3 */
+      listeners->push_back(new TcpListener(3 + i));
+  }
+
+  return count;
+}
+#else
+static int createSystemdListeners(std::list<SocketListener*> *)
+{
+  return 0;
+}
+#endif
+
 
 class FileTcpFilter : public TcpFilter
 {
@@ -300,35 +322,40 @@ int main(int argc, char** argv)
 
     VNCServerST server(desktopName, &desktop);
 
-    if (rfbunixpath.getValueStr()[0] != '\0') {
-      listeners.push_back(new network::UnixListener(rfbunixpath, rfbunixmode));
-      vlog.info("Listening on %s (mode %04o)", (const char*)rfbunixpath, (int)rfbunixmode);
-    }
-
-    if ((int)rfbport != -1) {
-      std::list<network::SocketListener*> tcp_listeners;
-      const char *addr = interface;
-
-      if (strcasecmp(addr, "all") == 0)
-        addr = 0;
-      if (localhostOnly)
-        createLocalTcpListeners(&tcp_listeners, (int)rfbport);
-      else
-        createTcpListeners(&tcp_listeners, addr, (int)rfbport);
-
-      if (!tcp_listeners.empty()) {
-        listeners.splice (listeners.end(), tcp_listeners);
-        vlog.info("Listening for VNC connections on %s interface(s), port %d",
-                  localhostOnly ? "local" : (const char*)interface,
-                  (int)rfbport);
+    if (createSystemdListeners(&listeners)) {
+      // When systemd is in charge of listeners, do not listen to anything else
+      vlog.info("Listening on systemd sockets");
+    } else {
+      if (rfbunixpath.getValueStr()[0] != '\0') {
+        listeners.push_back(new network::UnixListener(rfbunixpath, rfbunixmode));
+        vlog.info("Listening on %s (mode %04o)", (const char*)rfbunixpath, (int)rfbunixmode);
       }
 
-      FileTcpFilter fileTcpFilter(hostsFile);
-      if (strlen(hostsFile) != 0)
-        for (std::list<SocketListener*>::iterator i = listeners.begin();
-             i != listeners.end();
-             i++)
-          (*i)->setFilter(&fileTcpFilter);
+      if ((int)rfbport != -1) {
+        std::list<network::SocketListener*> tcp_listeners;
+        const char *addr = interface;
+
+        if (strcasecmp(addr, "all") == 0)
+          addr = 0;
+        if (localhostOnly)
+          createLocalTcpListeners(&tcp_listeners, (int)rfbport);
+        else
+          createTcpListeners(&tcp_listeners, addr, (int)rfbport);
+
+        if (!tcp_listeners.empty()) {
+          listeners.splice (listeners.end(), tcp_listeners);
+          vlog.info("Listening for VNC connections on %s interface(s), port %d",
+                    localhostOnly ? "local" : (const char*)interface,
+                    (int)rfbport);
+        }
+
+        FileTcpFilter fileTcpFilter(hostsFile);
+        if (strlen(hostsFile) != 0)
+          for (std::list<SocketListener*>::iterator i = listeners.begin();
+               i != listeners.end();
+               i++)
+            (*i)->setFilter(&fileTcpFilter);
+      }
     }
 
     if (listeners.empty()) {
index 359538656fb0e070d79a37393e4310e34e0537ee..0ba195ad0fc667824a2b7a0b66753e31b06cce4f 100644 (file)
@@ -61,7 +61,7 @@ DISPLAY environment variable.
 Specifies the TCP port on which x0vncserver listens for connections from
 viewers (the protocol used in VNC is called RFB - "remote framebuffer").
 The default port is 5900. Specify \fB-1\fP to disable listening on a TCP
-port.
+port. Ignored when activated by a systemd socket.
 .
 .TP
 .B \-UseIPv4
@@ -74,7 +74,7 @@ Use IPv6 for incoming and outgoing connections. Default is on.
 .TP
 .B \-rfbunixpath \fIpath\fP
 Specifies the path of a Unix domain socket on which x0vncserver listens for
-connections from viewers.
+connections from viewers. Ignored when activated by a systemd socket.
 .
 .TP
 .B \-rfbunixmode \fImode\fP