diff --git a/CMakeLists.txt b/CMakeLists.txt index 12367ec..8e1839c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ find_package(GnuTLS) find_package(Threads) find_package(X11) find_package(OpenSSL) +find_package(PkgConfig) find_library(LIBGCRYPT_LIBRARIES gcrypt) # Check whether the version of libjpeg we found was libjpeg-turbo and print a @@ -102,6 +103,17 @@ if(PNG_FOUND) endif(PNG_FOUND) option(LIBVNCSERVER_ALLOW24BPP "Allow 24 bpp" ON) +pkg_check_modules(SYSTEMD "libsystemd") +if(SYSTEMD_FOUND) + option(LIBVNCSERVER_WITH_SYSTEMD "Build with systemd socket activation support" ON) +endif(SYSTEMD_FOUND) + +if(LIBVNCSERVER_WITH_SYSTEMD) + add_definitions(-DLIBVNCSERVER_WITH_SYSTEMD) + include_directories(${SYSTEMD_INCLUDE_DIRS}) + set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} ${SYSTEMD_LIBRARIES}) +endif(LIBVNCSERVER_WITH_SYSTEMD) + if(GNUTLS_FOUND) set(LIBVNCSERVER_WITH_CLIENT_TLS 1) option(LIBVNCSERVER_WITH_WEBSOCKETS "Build with websockets support (gnutls)" ON) diff --git a/configure.ac b/configure.ac index 9651809..0b58743 100644 --- a/configure.ac +++ b/configure.ac @@ -68,6 +68,9 @@ if test ! -z "$with_ffmpeg"; then fi AM_CONDITIONAL(HAVE_MP3LAME, test "$HAVE_MP3LAME" = "true") +PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd], [with_systemd=1], [with_systemd=0]) +AM_CONDITIONAL([WITH_SYSTEMD], [test $with_systemd -eq 1]) + # Seem to need this dummy here to induce the 'checking for egrep... grep -E', etc. # before it seemed to be inside the with_jpeg conditional. AC_CHECK_HEADER(thenonexistentheader.h, HAVE_THENONEXISTENTHEADER_H="true") diff --git a/libvncserver/Makefile.am b/libvncserver/Makefile.am index 2f23e31..e25784b 100644 --- a/libvncserver/Makefile.am +++ b/libvncserver/Makefile.am @@ -59,6 +59,12 @@ LIB_SRCS = main.c rfbserver.c rfbregion.c auth.c sockets.c $(WEBSOCKETSSRCS) \ libvncserver_la_SOURCES=$(LIB_SRCS) libvncserver_la_LIBADD=$(WEBSOCKETSSSLLIBS) +if WITH_SYSTEMD +AM_CPPFLAGS += -DLIBVNCSERVER_WITH_SYSTEMD +libvncserver_la_CFLAGS = $(LIBSYSTEMD_CFLAGS) +libvncserver_la_LIBADD += $(LIBSYSTEMD_LIBS) +endif + lib_LTLIBRARIES=libvncserver.la libvncserver_la_LDFLAGS = -version-info 1:0:0 diff --git a/libvncserver/sockets.c b/libvncserver/sockets.c index 51e86eb..d4822f4 100644 --- a/libvncserver/sockets.c +++ b/libvncserver/sockets.c @@ -77,6 +77,10 @@ #include "rfbssl.h" #endif +#ifdef LIBVNCSERVER_WITH_SYSTEMD +#include +#endif + #if defined(__linux__) && defined(NEED_TIMEVAL) struct timeval { @@ -122,6 +126,54 @@ int deny_severity=LOG_WARNING; int rfbMaxClientWait = 20000; /* time (ms) after which we decide client has gone away - needed to stop us hanging */ +static rfbBool +rfbNewConnectionFromSock(rfbScreenInfoPtr rfbScreen, int sock) +{ + const int one = 1; +#ifdef LIBVNCSERVER_IPv6 + struct sockaddr_storage addr; +#else + struct sockaddr_in addr; +#endif + socklen_t addrlen = sizeof(addr); + + getpeername(sock, (struct sockaddr *)&addr, &addrlen); + + if(!rfbSetNonBlocking(sock)) { + rfbLogPerror("rfbCheckFds: setnonblock"); + closesocket(sock); + return FALSE; + } + + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + (char *)&one, sizeof(one)) < 0) { + rfbLogPerror("rfbCheckFds: setsockopt failed: can't set TCP_NODELAY flag, non TCP socket?"); + } + +#ifdef USE_LIBWRAP + if(!hosts_ctl("vnc",STRING_UNKNOWN,inet_ntoa(addr.sin_addr), + STRING_UNKNOWN)) { + rfbLog("Rejected connection from client %s\n", + inet_ntoa(addr.sin_addr)); + closesocket(sock); + return FALSE; + } +#endif + +#ifdef LIBVNCSERVER_IPv6 + char host[1024]; + if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) { + rfbLogPerror("rfbProcessNewConnection: error in getnameinfo"); + } + rfbLog("Got connection from client %s\n", host); +#else + rfbLog("Got connection from client %s\n", inet_ntoa(addr.sin_addr)); +#endif + + rfbNewClient(rfbScreen,sock); + return TRUE; +} + /* * rfbInitSockets sets up the TCP and UDP sockets to listen for RFB * connections. It does nothing if called again. @@ -138,6 +190,20 @@ rfbInitSockets(rfbScreenInfoPtr rfbScreen) rfbScreen->socketState = RFB_SOCKET_READY; +#ifdef LIBVNCSERVER_WITH_SYSTEMD + if (sd_listen_fds(0) == 1) + { + int sock = SD_LISTEN_FDS_START + 0; + if (sd_is_socket(sock, AF_UNSPEC, 0, 0)) + rfbNewConnectionFromSock(rfbScreen, sock); + else if (sd_is_socket(sock, AF_UNSPEC, 0, 1)) + rfbProcessNewConnection(rfbScreen); + return; + } + else + rfbLog("Unable to establish connection with systemd socket\n"); +#endif + if (rfbScreen->inetdSock != -1) { const int one = 1; @@ -411,14 +477,7 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec) rfbBool rfbProcessNewConnection(rfbScreenInfoPtr rfbScreen) { - const int one = 1; int sock = -1; -#ifdef LIBVNCSERVER_IPv6 - struct sockaddr_storage addr; -#else - struct sockaddr_in addr; -#endif - socklen_t addrlen = sizeof(addr); fd_set listen_fds; int chosen_listen_sock = -1; @@ -439,47 +498,12 @@ rfbProcessNewConnection(rfbScreenInfoPtr rfbScreen) if (rfbScreen->listen6Sock >= 0 && FD_ISSET(rfbScreen->listen6Sock, &listen_fds)) chosen_listen_sock = rfbScreen->listen6Sock; - if ((sock = accept(chosen_listen_sock, - (struct sockaddr *)&addr, &addrlen)) < 0) { + if ((sock = accept(chosen_listen_sock, NULL, NULL)) < 0) { rfbLogPerror("rfbCheckFds: accept"); return FALSE; } - if(!rfbSetNonBlocking(sock)) { - closesocket(sock); - return FALSE; - } - - if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, - (char *)&one, sizeof(one)) < 0) { - rfbLogPerror("rfbCheckFds: setsockopt failed: can't set TCP_NODELAY flag, non TCP socket?"); - } - -#ifdef USE_LIBWRAP - if(!hosts_ctl("vnc",STRING_UNKNOWN,inet_ntoa(addr.sin_addr), - STRING_UNKNOWN)) { - rfbLog("Rejected connection from client %s\n", - inet_ntoa(addr.sin_addr)); - closesocket(sock); - return FALSE; - } -#endif - -#ifdef LIBVNCSERVER_IPv6 - { - char host[1024]; - if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) { - rfbLogPerror("rfbProcessNewConnection: error in getnameinfo"); - } - rfbLog("Got connection from client %s\n", host); - } -#else - rfbLog("Got connection from client %s\n", inet_ntoa(addr.sin_addr)); -#endif - - rfbNewClient(rfbScreen,sock); - - return TRUE; + return rfbNewConnectionFromSock(rfbScreen, sock); }