Skip to content

Commit

Permalink
main: Allow starting server from a bound socket fd
Browse files Browse the repository at this point in the history
Instead of having wayvnc/neatvnc create a socket and listen() on it,
allow listening on an already bound socket file descriptor with the
--external-listener-fd=FD option. This may be used to support any kind of
connection-based socket that isn't explicitly supported by wayvnc in an option,
such as ones using the AF_VSOCK address family, or support cases where wayvnc
is being activated by systemd (via a .socket unit) or a super-server like
inetd.
  • Loading branch information
layercak3 committed Jun 12, 2024
1 parent 14d5d54 commit 25cb597
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 3 deletions.
39 changes: 36 additions & 3 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ enum socket_type {
SOCKET_TYPE_TCP = 0,
SOCKET_TYPE_UNIX,
SOCKET_TYPE_WEBSOCKET,
SOCKET_TYPE_FROM_FD,
};

struct wayvnc {
Expand Down Expand Up @@ -885,7 +886,7 @@ static char* get_cfg_path(const struct cfg* cfg, char* dst, const char* src)
}

static int init_nvnc(struct wayvnc* self, const char* addr, uint16_t port,
enum socket_type socket_type)
int fd, enum socket_type socket_type)
{
switch (socket_type) {
case SOCKET_TYPE_TCP:
Expand All @@ -897,15 +898,20 @@ static int init_nvnc(struct wayvnc* self, const char* addr, uint16_t port,
case SOCKET_TYPE_WEBSOCKET:
self->nvnc = nvnc_open_websocket(addr, port);
break;
case SOCKET_TYPE_FROM_FD:
self->nvnc = nvnc_open_from_fd(fd);
break;
default:
abort();
}
if (!self->nvnc) {
nvnc_log(NVNC_LOG_ERROR, "Failed to bind to address. Add -Ldebug to the argument list for more info.");
nvnc_log(NVNC_LOG_ERROR, "Failed to listen on socket or bind to its address. Add -Ldebug to the argument list for more info.");
return -1;
}
if (socket_type == SOCKET_TYPE_UNIX)
nvnc_log(NVNC_LOG_INFO, "Listening for connections on %s", addr);
else if (socket_type == SOCKET_TYPE_FROM_FD)
nvnc_log(NVNC_LOG_INFO, "Listening for connections on fd %d", fd);
else
nvnc_log(NVNC_LOG_INFO, "Listening for connections on %s:%d", addr, port);

Expand Down Expand Up @@ -1705,6 +1711,7 @@ int main(int argc, char* argv[])

const char* address = NULL;
int port = 0;
int external_listener_fd = -1;
bool use_unix_socket = false;
bool use_websocket = false;
bool start_detached = false;
Expand Down Expand Up @@ -1754,6 +1761,9 @@ int main(int argc, char* argv[])
"Show performance counters." },
{ 'u', "unix-socket", NULL,
"Create unix domain socket." },
{ 'x', "external-listener-fd", "<fd>",
"Listen on a bound socket at <fd> instead of binding to an address.",
.default_ = "-1" },
{ 'd', "disable-input", NULL,
"Disable all remote input." },
{ 'D', "detached", NULL,
Expand Down Expand Up @@ -1796,6 +1806,7 @@ int main(int argc, char* argv[])
show_performance = !!option_parser_get_value(&option_parser, "performance");
use_unix_socket = !!option_parser_get_value(&option_parser, "unix-socket");
use_websocket = !!option_parser_get_value(&option_parser, "websocket");
external_listener_fd = atoi(option_parser_get_value(&option_parser, "external-listener-fd"));
disable_input = !!option_parser_get_value(&option_parser, "disable-input");
log_level = option_parser_get_value(&option_parser, "verbose")
? NVNC_LOG_INFO : NVNC_LOG_WARNING;
Expand Down Expand Up @@ -1831,6 +1842,16 @@ int main(int argc, char* argv[])
return 1;
}

if (external_listener_fd >= 0 && use_unix_socket) {
nvnc_log(NVNC_LOG_ERROR, "external-listener-fd and unix-socket are conflicting options");
return 1;
}

if (external_listener_fd >= 0 && use_websocket) {
nvnc_log(NVNC_LOG_ERROR, "external-listener-fd and websocket are conflicting options");
return 1;
}

if (use_transient_seat && disable_input) {
nvnc_log(NVNC_LOG_ERROR, "transient-seat and disable-input are conflicting options");
return 1;
Expand Down Expand Up @@ -1862,6 +1883,16 @@ int main(int argc, char* argv[])
if (!port) port = self.cfg.port;
}

if (external_listener_fd >= 0 && address) {
nvnc_log(NVNC_LOG_ERROR, "external-listener-fd and address are conflicting options");
return 1;
}

if (external_listener_fd >= 0 && port) {
nvnc_log(NVNC_LOG_ERROR, "external-listener-fd and port are conflicting options");
return 1;
}

if (!address) address = DEFAULT_ADDRESS;
if (!port) port = DEFAULT_PORT;

Expand Down Expand Up @@ -1928,6 +1959,8 @@ int main(int argc, char* argv[])
socket_type = SOCKET_TYPE_UNIX;
else if (use_websocket)
socket_type = SOCKET_TYPE_WEBSOCKET;
else if (external_listener_fd >= 0)
socket_type = SOCKET_TYPE_FROM_FD;

if (!start_detached) {
if (self.screencopy.manager)
Expand Down Expand Up @@ -1961,7 +1994,7 @@ int main(int argc, char* argv[])
if (!self.ctl)
goto ctl_server_failure;

if (init_nvnc(&self, address, port, socket_type) < 0)
if (init_nvnc(&self, address, port, external_listener_fd, socket_type) < 0)
goto nvnc_failure;

if (self.display)
Expand Down
5 changes: 5 additions & 0 deletions wayvnc.scd
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ wayvnc - A VNC server for wlroots based Wayland compositors.
*-w, --websocket*
Create a websocket.

*-x, --external-listener-fd=<fd>*
Have the VNC server listen on an already bound socket at this file
descriptor which should be inherited from wayvnc's parent process.
This is incompatible with all other server socket-related options.

*-L, --log-level*
Set log level. The levels are: error, warning, info, debug, trace and
quiet.
Expand Down

0 comments on commit 25cb597

Please sign in to comment.