diff --git a/include/neatvnc.h b/include/neatvnc.h index 7a414b9..7a15233 100644 --- a/include/neatvnc.h +++ b/include/neatvnc.h @@ -54,6 +54,7 @@ typedef void (*nvnc_cut_text_fn)(struct nvnc*, const char* text, uint32_t len); extern const char nvnc_version[]; struct nvnc* nvnc_open(const char* addr, uint16_t port); +struct nvnc* nvnc_open_unix(const char *addr); void nvnc_close(struct nvnc* self); void nvnc_add_display(struct nvnc*, struct nvnc_display*); diff --git a/src/server.c b/src/server.c index 22d94c5..d90f5b5 100644 --- a/src/server.c +++ b/src/server.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #ifdef ENABLE_TLS @@ -69,6 +70,11 @@ struct fb_update_work { struct nvnc_fb* fb; }; +enum addrtype { + ADDRTYPE_TCP, + ADDRTYPE_UNIX, +}; + int schedule_client_update_fb(struct nvnc_client* client, struct pixman_region16* damage); static int send_desktop_resize(struct nvnc_client* client, struct nvnc_fb* fb); @@ -1009,7 +1015,7 @@ accept_failure: free(client); } -static int bind_address(const char* name, int port) +static int bind_address_tcp(const char* name, int port) { struct addrinfo hints = { .ai_socktype = SOCK_STREAM, @@ -1048,6 +1054,43 @@ failure: return fd; } +static int bind_address_unix(const char* name) +{ + struct sockaddr_un addr = { + .sun_family = AF_UNIX, + }; + + if (strlen(name) >= sizeof(addr.sun_path)) { + errno = ENAMETOOLONG; + return -1; + } + strcpy(addr.sun_path, name); + + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + return -1; + + if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) != 0) { + close(fd); + return -1; + } + + return fd; +} + +static int bind_address(const char* name, uint16_t port, enum addrtype type) +{ + switch (type) { + case ADDRTYPE_TCP: + return bind_address_tcp(name, port); + case ADDRTYPE_UNIX: + return bind_address_unix(name); + } + + log_error("unknown socket address type"); + abort(); +} + static bool nvnc__is_damaged(struct nvnc* self) { struct nvnc_client* client; @@ -1081,8 +1124,7 @@ static void on_main_dispatch(void* aml_obj) process_fb_update_requests(client); } -EXPORT -struct nvnc* nvnc_open(const char* address, uint16_t port) +static struct nvnc* open_common(const char* address, uint16_t port, enum addrtype type) { aml_require_workers(aml_get_default(), -1); @@ -1094,16 +1136,16 @@ struct nvnc* nvnc_open(const char* address, uint16_t port) LIST_INIT(&self->clients); - self->fd = bind_address(address, port); + self->fd = bind_address(address, port, type); if (self->fd < 0) - goto failure; + goto bind_failure; if (listen(self->fd, 16) < 0) - goto failure; + goto listen_failure; self->poll_handle = aml_handler_new(self->fd, on_connection, self, NULL); if (!self->poll_handle) - goto failure; + goto handle_failure; if (aml_start(aml_get_default(), self->poll_handle) < 0) goto poll_start_failure; @@ -1123,11 +1165,42 @@ new_idle_failure: aml_stop(aml_get_default(), self->poll_handle); poll_start_failure: aml_unref(self->poll_handle); -failure: +handle_failure: +listen_failure: close(self->fd); + if (type == ADDRTYPE_UNIX) { + unlink(address); + } +bind_failure: + free(self); + return NULL; } +EXPORT +struct nvnc* nvnc_open(const char* address, uint16_t port) +{ + return open_common(address, port, ADDRTYPE_TCP); +} + +EXPORT +struct nvnc* nvnc_open_unix(const char* address) +{ + return open_common(address, 0, ADDRTYPE_UNIX); +} + +static void unlink_fd_path(int fd) +{ + struct sockaddr_un addr; + socklen_t addr_len = sizeof(addr); + + if (getsockname(fd, (struct sockaddr*)&addr, &addr_len) == 0) { + if (addr.sun_family == AF_UNIX) { + unlink(addr.sun_path); + } + } +} + EXPORT void nvnc_close(struct nvnc* self) { @@ -1142,6 +1215,7 @@ void nvnc_close(struct nvnc* self) aml_stop(aml_get_default(), self->dispatch_handler); aml_stop(aml_get_default(), self->poll_handle); + unlink_fd_path(self->fd); close(self->fd); #ifdef ENABLE_TLS