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:
parent
41d7306eb4
commit
3207da067e
6 changed files with 159 additions and 23 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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)
|
||||
|
|
83
lib/plat/unix/unix-systemd.c
Normal file
83
lib/plat/unix/unix-systemd.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue