1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

vhost: allow fd adoption

This commit is contained in:
Andy Green 2024-01-02 07:15:12 +00:00
parent 41d7306eb4
commit 3207da067e
6 changed files with 159 additions and 23 deletions

View file

@ -662,6 +662,8 @@ CHECK_C_SOURCE_COMPILES("#include <inttypes.h>\nvoid main(void) { while(1) ; } v
CHECK_C_SOURCE_COMPILES("#include <sys/resource.h>\nvoid main(void) { while(1) ; } void xxexit(void){}" LWS_HAVE_SYS_RESOURCE_H)
CHECK_C_SOURCE_COMPILES("#include <linux/ipv6.h>\nvoid main(void) { while(1) ; } void xxexit(void){}" LWS_HAVE_LINUX_IPV6_H)
CHECK_C_SOURCE_COMPILES("#include <net/ethernet.h>\nvoid main(void) { while(1) ; } void xxexit(void){}" LWS_HAVE_NET_ETHERNET_H)
CHECK_C_SOURCE_COMPILES("#include <systemd/sd-daemon.h>\nvoid main(void) { while(1) ; } void xxexit(void){}" LWS_HAVE_SYSTEMD_H)
if (LWS_EXT_PTHREAD_INCLUDE_DIR)

View file

@ -242,6 +242,7 @@
#cmakedefine LWS_WITH_SYS_METRICS
#cmakedefine LWS_WITH_SYS_NTPCLIENT
#cmakedefine LWS_WITH_SYS_STATE
#cmakedefine LWS_HAVE_SYSTEMD_H
#cmakedefine LWS_WITHOUT_TEST_SERVER
#cmakedefine LWS_WITHOUT_TESTAPPS
#cmakedefine LWS_WITH_THREADPOOL

View file

@ -959,6 +959,14 @@ struct lws_context_creation_info {
* selected default loglevel can then be cleanly overridden using -d 1039 etc
* commandline switch */
lws_sockfd_type vh_listen_sockfd;
/**< VHOST: 0 for normal vhost listen socket fd creation, if any.
* Nonzero to force the selection of an already-existing fd for the
* vhost's listen socket, which is already prepared. This is intended
* for an external process having chosen the fd, which cannot then be
* zero.
*/
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibility
*
@ -1253,6 +1261,20 @@ lws_context_default_loop_run_destroy(struct lws_context *cx);
LWS_VISIBLE LWS_EXTERN int
lws_cmdline_passfail(int argc, const char **argv, int actual);
/**
* lws_systemd_inherited_fd() - prepare vhost creation info for systemd exported fd if any
*
* \param index: 0+ index of exported fd
* \param info: info struct to be prepared with related info, if any
*
* Returns 0 and points info to the related fd, aligning the other information
* to the type of fd and port it is bound to, or returns nonzero if no such
* inherited fd.
*/
LWS_VISIBLE LWS_EXTERN int
lws_systemd_inherited_fd(unsigned int index,
struct lws_context_creation_info *info);
/**
* lws_context_is_being_destroyed() - find out if context is being destroyed
*

View file

@ -63,6 +63,12 @@ if (LWS_WITH_NETWORK)
list(APPEND SOURCES plat/unix/unix-resolv.c)
endif()
endif()
if (LWS_HAVE_SYSTEMD_H)
list(APPEND SOURCES
plat/unix/unix-systemd.c
)
list(APPEND LIB_LIST_AT_END systemd)
endif()
endif()
if (LWS_WITH_PLUGINS_API)

View file

@ -0,0 +1,83 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2024 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#include <sys/socket.h>
#include <systemd/sd-daemon.h>
#include "private-lib-core.h"
int
lws_systemd_inherited_fd(unsigned int index,
struct lws_context_creation_info *info)
{
unsigned int inherited = (unsigned int)sd_listen_fds(0);
if (index >= inherited)
return -1;
info->vh_listen_sockfd = (int)(SD_LISTEN_FDS_START + index);
if (sd_is_socket_unix(info->vh_listen_sockfd, 0, 0, NULL, 0))
info->options |= LWS_SERVER_OPTION_UNIX_SOCK;
if (sd_is_socket_inet(info->vh_listen_sockfd, AF_UNSPEC, 0, 1, 0)) {
struct sockaddr_storage addr;
socklen_t addrlen = sizeof(addr);
if (getsockname(info->vh_listen_sockfd,
(struct sockaddr *)&addr, &addrlen)) {
lwsl_err("%s: getsockname failed for fd %d\n",
__func__, info->vh_listen_sockfd);
return -1;
}
switch (((struct sockaddr *)&addr)->sa_family) {
case AF_INET:
info->port = ntohs(((struct sockaddr_in *)&addr)->sin_port);
lwsl_info("%s: inet socket %d\n", __func__, info->port);
break;
case AF_INET6:
info->port = ntohs(((struct sockaddr_in6 *)&addr)->sin6_port);
lwsl_info("%s: inet6 socket %d\n", __func__, info->port);
break;
}
if (sd_is_socket_inet(info->vh_listen_sockfd, AF_INET6, 0, 1, 0))
info->options |= LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY |
LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE;
if (sd_is_socket_inet(info->vh_listen_sockfd, AF_INET, 0, 1, 0)) {
info->options &= (uint64_t)~(LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY |
LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);
info->options |= LWS_SERVER_OPTION_DISABLE_IPV6;
}
}
return 0;
}

View file

@ -72,6 +72,10 @@ check_extant(struct lws_dll2 *d, void *user)
if (wsi->af != a ->af)
return 0;
if (a->info && a->info->vh_listen_sockfd &&
wsi->desc.sockfd != a->info->vh_listen_sockfd)
return 0;
lwsl_notice(" using listen skt from vhost %s\n", wsi->a.vhost->name);
return 1;
@ -107,7 +111,7 @@ deal:
if (!san--)
return -1;
if (a->vhost->iface) {
if (a->vhost->iface && (!a->info || !a->info->vh_listen_sockfd)) {
/*
* let's check before we do anything else about the disposition
@ -183,6 +187,11 @@ done_list:
LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND ?
-1 : 1;
}
} else {
if (a->info && a->info->vh_listen_sockfd) {
a->vhost->iface = "inherited";
a->vhost->listen_port = a->info->port;
}
}
(void)n;
@ -202,7 +211,10 @@ done_list:
for (m = 0; m < limit; m++) {
sockfd = lws_fi(&a->vhost->fic, "listenskt") ?
if (a->info && a->info->vh_listen_sockfd)
sockfd = dup(a->info->vh_listen_sockfd);
else
sockfd = lws_fi(&a->vhost->fic, "listenskt") ?
LWS_SOCK_INVALID :
socket(a->af, SOCK_STREAM, 0);
@ -248,9 +260,11 @@ done_list:
* There will be a separate ipv4 listen socket if that's
* enabled.
*/
if (a->af == AF_INET6 &&
if (a->af == AF_INET6 && (!a->info || !a->info->vh_listen_sockfd) &&
setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
(const void*)&value, sizeof(value)) < 0) {
lwsl_err("ipv6 only failed\n");
compatible_close(sockfd);
return -1;
}
@ -267,6 +281,7 @@ done_list:
if (n || cx->count_threads > 1) /* ... also implied by threads > 1 */
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
(const void *)&opt, sizeof(opt)) < 0) {
lwsl_err("reuseport failed\n");
compatible_close(sockfd);
return -1;
}
@ -274,28 +289,30 @@ done_list:
#endif
lws_plat_set_socket_options(a->vhost, sockfd, 0);
is = lws_socket_bind(a->vhost, NULL, sockfd,
a->vhost->listen_port,
a->vhost->iface, a->af);
if (!a->info || !a->info->vh_listen_sockfd) {
is = lws_socket_bind(a->vhost, NULL, sockfd,
a->vhost->listen_port,
a->vhost->iface, a->af);
if (is == LWS_ITOSA_BUSY) {
/* treat as fatal */
compatible_close(sockfd);
if (is == LWS_ITOSA_BUSY) {
/* treat as fatal */
compatible_close(sockfd);
return -1;
}
return -1;
}
/*
* There is a race where the network device may come up and then
* go away and fail here. So correctly handle unexpected failure
* here despite we earlier confirmed it.
*/
if (is < 0) {
lwsl_info("%s: lws_socket_bind says %d\n", __func__, is);
compatible_close(sockfd);
if (a->vhost->iface)
goto deal;
return -1;
/*
* There is a race where the network device may come up and then
* go away and fail here. So correctly handle unexpected failure
* here despite we earlier confirmed it.
*/
if (is < 0) {
lwsl_info("%s: lws_socket_bind says %d\n", __func__, is);
compatible_close(sockfd);
if (a->vhost->iface)
goto deal;
return -1;
}
}
/*
@ -373,13 +390,17 @@ done_list:
goto bail;
}
if (wsi)
if (wsi) {
if (a->info && a->info->vh_listen_sockfd)
a->vhost->listen_port = a->info->port;
__lws_lc_tag(a->vhost->context,
&a->vhost->context->lcg[LWSLCG_WSI],
&wsi->lc, "listen|%s|%s|%d",
a->vhost->name,
a->vhost->iface ? a->vhost->iface : "",
(int)a->vhost->listen_port);
}
} /* for each thread able to independently listen */
@ -399,6 +420,7 @@ done_list:
return 0;
bail:
lwsl_err("%s: bailing\n", __func__);
compatible_close(sockfd);
return -1;