Skip to content

Commit

Permalink
main: Implement multi-address listening
Browse files Browse the repository at this point in the history
  • Loading branch information
any1 committed Nov 23, 2024
1 parent 8dd07b7 commit 122d7e2
Showing 1 changed file with 138 additions and 30 deletions.
168 changes: 138 additions & 30 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -894,12 +894,87 @@ static char* get_cfg_path(const struct cfg* cfg, char* dst, const char* src)
return dst;
}

static int init_nvnc(struct wayvnc* self, const char* addr, uint16_t port,
enum socket_type socket_type)
static bool is_prefix(const char* prefix, const char* str)
{
self->nvnc = nvnc_new();
if (!self->nvnc)
return -1;
return strncmp(str, prefix, strlen(prefix)) == 0;
}

static int count_colons_in_string(const char* str)
{
int n = 0;
for (int i = 0; str[i]; ++i)
if (str[i] == ':')
++n;
return n;
}

static char* parse_address_prefix(char* addr, enum socket_type* socket_type)
{
if (is_prefix("tcp:", addr)) {
*socket_type = SOCKET_TYPE_TCP;
addr += 4;
} else if (is_prefix("unix:", addr)) {
*socket_type = SOCKET_TYPE_UNIX;
addr += 5;
} else if (is_prefix("ws:", addr)) {
*socket_type = SOCKET_TYPE_WEBSOCKET;
addr += 3;
} else if (is_prefix("fd:", addr)) {
*socket_type = SOCKET_TYPE_FROM_FD;
addr += 3;
}
return addr;
}

static char* parse_address_port(char* addr, uint16_t* port)
{
// IPv6 addresses with port need to look like: [::]:5900
if (addr[0] == '[') {
char* end = strchr(addr, ']');
if (!end)
return addr;

*end++ = '\0';

if (*end == ':')
*port = atoi(end + 1);

return addr + 1;
}

if (count_colons_in_string(addr) > 1) {
// This is most likely IPv6, so let's leave it alone
return addr;
}

char* p = NULL;
p = strrchr(addr, ':');
if (!p)
return addr;

*p++ = '\0';

*port = atoi(p);

return addr;
}

static int add_listening_address(struct wayvnc* self, const char* address,
uint16_t port, enum socket_type socket_type)
{
char buffer[256];
char* addr = buffer;
strlcpy(buffer, address, sizeof(buffer));

addr = parse_address_prefix(addr, &socket_type);

if (socket_type == SOCKET_TYPE_TCP ||
socket_type == SOCKET_TYPE_WEBSOCKET) {
uint16_t parsed_port = 0;
addr = parse_address_port(addr, &parsed_port);
if (parsed_port)
port = parsed_port;
}

int rc = -1;
switch (socket_type) {
Expand All @@ -922,6 +997,7 @@ static int init_nvnc(struct wayvnc* self, const char* addr, uint16_t port,
default:
abort();
}

if (rc < 0) {
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;
Expand All @@ -935,6 +1011,15 @@ static int init_nvnc(struct wayvnc* self, const char* addr, uint16_t port,
nvnc_log(NVNC_LOG_INFO, "Listening for connections on %s:%d",
addr, port);

return 0;
}

static int init_nvnc(struct wayvnc* self)
{
self->nvnc = nvnc_new();
if (!self->nvnc)
return -1;

self->nvnc_display = nvnc_display_new(0, 0);
if (!self->nvnc_display)
goto display_failure;
Expand Down Expand Up @@ -1903,11 +1988,9 @@ int main(int argc, char* argv[])

static const struct wv_option opts[] = {
{ .positional = "address",
.help = "The IP address or unix socket path to listen on.",
.default_ = DEFAULT_ADDRESS},
{ .positional = "port",
.help = "The TCP port to listen on.",
.default_ = XSTR(DEFAULT_PORT)},
.help = "An address to listen on.",
.default_ = "localhost",
.is_repeating = true },
{ 'C', "config", "<path>",
"Select a config file." },
{ 'd', "disable-input", NULL,
Expand Down Expand Up @@ -2003,13 +2086,6 @@ int main(int argc, char* argv[])

nvnc_set_log_level(log_level);

// Only check for explicitly-set values here (defaults applied below)
address = option_parser_get_value_no_default(&option_parser, "address");
const char* port_str = option_parser_get_value_no_default(&option_parser,
"port");
if (port_str)
port = atoi(port_str);

if (seat_name && disable_input) {
nvnc_log(NVNC_LOG_ERROR, "seat and disable-input are conflicting options");
return 1;
Expand Down Expand Up @@ -2048,14 +2124,6 @@ int main(int argc, char* argv[])
if (check_cfg_sanity(&self.cfg) < 0)
return 1;

if (cfg_rc == 0) {
if (!address) address = self.cfg.address;
if (!port) port = self.cfg.port;
}

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

self.disable_input = disable_input;
self.use_transient_seat = use_transient_seat;

Expand Down Expand Up @@ -2109,13 +2177,13 @@ int main(int argc, char* argv[])
if (aml_unstable_abi_version != AML_UNSTABLE_API)
nvnc_log(NVNC_LOG_PANIC, "libaml is incompatible with this build of wayvnc!");

enum socket_type socket_type = SOCKET_TYPE_TCP;
enum socket_type default_socket_type = SOCKET_TYPE_TCP;
if (use_unix_socket)
socket_type = SOCKET_TYPE_UNIX;
default_socket_type = SOCKET_TYPE_UNIX;
else if (use_websocket)
socket_type = SOCKET_TYPE_WEBSOCKET;
default_socket_type = SOCKET_TYPE_WEBSOCKET;
else if (use_external_fd)
socket_type = SOCKET_TYPE_FROM_FD;
default_socket_type = SOCKET_TYPE_FROM_FD;

if (!start_detached && !configure_screencopy(&self))
goto screencopy_failure;
Expand All @@ -2140,9 +2208,49 @@ 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) < 0)
goto nvnc_failure;

address = option_parser_get_value_with_offset(&option_parser,
"address", 0);

// If the second address argument is a number, we will assume it to be a
// port for historical reasons.
const char* port_str = option_parser_get_value_with_offset(
&option_parser, "address", 1);
if (port_str) {
char* endptr;
port = strtoul(port_str, &endptr, 0);
if (!port_str[0] || endptr[0])
port = 0;
}

if (port) {
if (add_listening_address(&self, address, port,
default_socket_type) < 0)
goto nvnc_failure;
} else if (!option_parser_get_value_with_offset(&option_parser,
"address", 0)) {
address = self.cfg.address ? self.cfg.address : DEFAULT_ADDRESS;
port = self.cfg.port ? self.cfg.port : DEFAULT_PORT;

if (add_listening_address(&self, address, port,
default_socket_type))
goto nvnc_failure;
} else {
for (int i = 0;; ++i) {
const char* address;
address = option_parser_get_value_with_offset(
&option_parser, "address", i);
if (!address)
break;

if (add_listening_address(&self, address, DEFAULT_PORT,
default_socket_type) < 0)
goto nvnc_failure;
}
}

if (self.display)
wl_display_dispatch_pending(self.display);

Expand Down

0 comments on commit 122d7e2

Please sign in to comment.