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

vhost: create multiple listen sockets per AF

On some platforms AF_INET and AF_INET6 must be listened for on separate
sockets.  Adapt the vhost server creation code to use the new support for
multiple listen sockets per vhost to create up to two listen sockets for
AF_INET and AF_INET6.

It refactors how the decision about the AF is made and propagated so
there's only one place for it.
This commit is contained in:
Andy Green 2021-06-21 10:36:36 +01:00
parent 6163c96727
commit cf2dbdc6a0
8 changed files with 276 additions and 171 deletions

View file

@ -154,7 +154,7 @@ lws_client_connect_3_connect(struct lws *wsi, const char *ads,
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
int cfail;
#endif
int m;
int m, af = 0;
/*
* If we come here with result set, we need to convert getaddrinfo
@ -247,7 +247,7 @@ lws_client_connect_3_connect(struct lws *wsi, const char *ads,
ads++;
memset(&wsi->sa46_peer, 0, sizeof(wsi->sa46_peer));
memset(&sau, 0, sizeof(sau));
sau.sun_family = AF_UNIX;
af = sau.sun_family = AF_UNIX;
strncpy(sau.sun_path, ads, sizeof(sau.sun_path));
sau.sun_path[sizeof(sau.sun_path) - 1] = '\0';
@ -324,12 +324,18 @@ ads_known:
}
#if defined(LWS_WITH_UNIX_SOCK)
if (wsi->unix_skt)
af = 0;
if (wsi->unix_skt) {
af = AF_UNIX;
wsi->desc.sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
}
else
#endif
{
af = wsi->sa46_peer.sa4.sin_family;
wsi->desc.sockfd = socket(wsi->sa46_peer.sa4.sin_family,
SOCK_STREAM, 0);
}
if (!lws_socket_is_valid(wsi->desc.sockfd)) {
lwsl_warn("Unable to open socket\n");
@ -391,7 +397,7 @@ ads_known:
if (iface && *iface) {
m = lws_socket_bind(wsi->a.vhost, wsi, wsi->desc.sockfd,
0, iface, wsi->ipv6);
0, iface, af);
if (m < 0)
goto try_next_dns_result_fds;
}

View file

@ -206,7 +206,7 @@ bail:
int
lws_socket_bind(struct lws_vhost *vhost, struct lws *wsi,
lws_sockfd_type sockfd, int port, const char *iface,
int ipv6_allowed)
int af)
{
#ifdef LWS_WITH_UNIX_SOCK
struct sockaddr_un serv_unix;
@ -218,7 +218,7 @@ lws_socket_bind(struct lws_vhost *vhost, struct lws *wsi,
#ifndef LWS_PLAT_OPTEE
socklen_t len = sizeof(struct sockaddr_storage);
#endif
int n;
int n = 0;
#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
int m;
#endif
@ -231,8 +231,9 @@ lws_socket_bind(struct lws_vhost *vhost, struct lws *wsi,
if (wsi)
psin = (struct sockaddr_storage *)&wsi->sa46_local;
switch (af) {
#if defined(LWS_WITH_UNIX_SOCK)
if (!port && LWS_UNIX_SOCK_ENABLED(vhost)) {
case AF_UNIX:
v = (struct sockaddr *)&serv_unix;
memset(&serv_unix, 0, sizeof(serv_unix));
serv_unix.sun_family = AF_UNIX;
@ -251,13 +252,13 @@ lws_socket_bind(struct lws_vhost *vhost, struct lws *wsi,
unlink(serv_unix.sun_path);
// lwsl_hexdump_notice(v, n);
} else
break;
#endif
#if defined(LWS_WITH_IPV6) && !defined(LWS_PLAT_FREERTOS)
if (ipv6_allowed && LWS_IPV6_ENABLED(vhost)) {
case AF_INET6:
v = (struct sockaddr *)&serv_addr6;
n = sizeof(struct sockaddr_in6);
memset(&serv_addr6, 0, sizeof(serv_addr6));
if (iface) {
m = interface_to_sa(vhost, iface,
@ -281,9 +282,10 @@ lws_socket_bind(struct lws_vhost *vhost, struct lws *wsi,
serv_addr6.sin6_port = (uint16_t)htons((uint16_t)port);
else
((struct sockaddr_in *)v)->sin_port = (uint16_t)htons((uint16_t)port);
} else
break;
#endif
{
case AF_INET:
v = (struct sockaddr *)&serv_addr4;
n = sizeof(serv_addr4);
memset(&serv_addr4, 0, sizeof(serv_addr4));
@ -307,7 +309,10 @@ lws_socket_bind(struct lws_vhost *vhost, struct lws *wsi,
}
#endif
serv_addr4.sin_port = htons((uint16_t)(unsigned int)port);
} /* ipv4 */
break;
default:
return -1;
} /* switch */
/* just checking for the interface extant */
if (sockfd == LWS_SOCK_INVALID)
@ -315,7 +320,7 @@ lws_socket_bind(struct lws_vhost *vhost, struct lws *wsi,
n = bind(sockfd, v, (socklen_t)n);
#ifdef LWS_WITH_UNIX_SOCK
if (n < 0 && LWS_UNIX_SOCK_ENABLED(vhost)) {
if (n < 0 && af == AF_UNIX) {
lwsl_err("ERROR on binding fd %d to \"%s\" (%d %d)\n",
sockfd, iface, n, LWS_ERRNO);
return LWS_ITOSA_NOT_EXIST;
@ -324,8 +329,8 @@ lws_socket_bind(struct lws_vhost *vhost, struct lws *wsi,
if (n < 0) {
int _lws_errno = LWS_ERRNO;
lwsl_err("ERROR on binding fd %d to port %d (%d %d)\n",
sockfd, port, n, _lws_errno);
lwsl_err("%s: ERROR on binding fd %d to port %d (%d %d)\n",
__func__, sockfd, port, n, _lws_errno);
/* if something already listening, tell caller to fail permanently */
@ -338,7 +343,7 @@ lws_socket_bind(struct lws_vhost *vhost, struct lws *wsi,
}
#if defined(LWS_WITH_UNIX_SOCK) && !defined(WIN32)
if (!port && LWS_UNIX_SOCK_ENABLED(vhost)) {
if (af == AF_UNIX) {
uid_t uid = vhost->context->uid;
gid_t gid = vhost->context->gid;

View file

@ -679,13 +679,13 @@ struct lws {
struct lws_dll2 adns; /* on adns list of guys to tell result */
lws_async_dns_cb_t adns_cb; /* callback with result */
#endif
#if defined(LWS_WITH_SERVER)
struct lws_dll2 listen_list;
#endif
#if defined(LWS_WITH_CLIENT)
struct lws_dll2 dll_cli_active_conns;
struct lws_dll2 dll2_cli_txn_queue;
struct lws_dll2_owner dll2_cli_txn_queue_owner;
#if defined(LWS_WITH_SERVER)
struct lws_dll2 listen_list;
#endif
/**< caliper is reused for tcp, tls and txn conn phases */
@ -878,6 +878,7 @@ struct lws {
uint8_t sys_tls_client_cert;
uint8_t c_pri;
#endif
uint8_t af;
#if defined(LWS_WITH_CGI) || defined(LWS_WITH_CLIENT)
char reason_bf; /* internal writeable callback reason bitfield */
#endif

View file

@ -1212,6 +1212,8 @@ __lws_vhost_destroy_pt_wsi_dieback_start(struct lws_vhost *vh)
}
#if defined(LWS_WITH_NETWORK)
/* returns nonzero if v1 and v2 can share listen sockets */
int
lws_vhost_compare_listen(struct lws_vhost *v1, struct lws_vhost *v2)
{
@ -1220,6 +1222,7 @@ lws_vhost_compare_listen(struct lws_vhost *v1, struct lws_vhost *v2)
v1->listen_port == v2->listen_port;
}
/* helper to interate every listen socket on any vhost and call cb on it */
int
lws_vhost_foreach_listen_wsi(struct lws_context *cx, void *arg,
lws_dll2_foreach_cb_t cb)
@ -1269,7 +1272,7 @@ lws_vhost_destroy1(struct lws_vhost *vh)
lws_dll2_add_tail(&vh->vh_being_destroyed_list,
&context->owner_vh_being_destroyed);
#if defined(LWS_WITH_NETWORK)
#if defined(LWS_WITH_NETWORK) && defined(LWS_WITH_SERVER)
/*
* PHASE 1: take down or reassign any listen wsi
*

View file

@ -197,7 +197,6 @@ elops_listen_init_event(struct lws_dll2 *d, void *user)
static int
elops_init_pt_event(struct lws_context *context, void *_loop, int tsi)
{
struct lws_vhost *vh = context->vhost_list;
struct event_base *loop = (struct event_base *)_loop;
struct lws_context_per_thread *pt = &context->pt[tsi];
struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
@ -338,9 +337,6 @@ static int
elops_listen_destroy_event(struct lws_dll2 *d, void *user)
{
struct lws *wsi = lws_container_of(d, struct lws, listen_list);
struct lws_context *context = (struct lws_context *)user;
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
struct lws_wsi_eventlibs_libevent *w = wsi_to_priv_event(wsi);
event_free(w->w_read.watcher);
@ -356,9 +352,6 @@ elops_destroy_pt_event(struct lws_context *context, int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
struct lws_vhost *vh = context->vhost_list;
lwsl_info("%s\n", __func__);
if (!ptpr->io_loop)
return;

View file

@ -52,73 +52,85 @@ static const char * const intermediates[] = { "private", "public" };
*/
#if defined(LWS_WITH_SERVER)
int
_lws_vhost_init_server(const struct lws_context_creation_info *info,
struct lws_vhost *vhost)
struct vh_sock_args {
const struct lws_context_creation_info *info;
struct lws_vhost *vhost;
int af;
};
static int
check_extant(struct lws_dll2 *d, void *user)
{
struct lws *wsi = lws_container_of(d, struct lws, listen_list);
struct vh_sock_args *a = (struct vh_sock_args *)user;
if (!lws_vhost_compare_listen(wsi->a.vhost, a->vhost))
return 0;
if (wsi->af != a ->af)
return 0;
lwsl_notice(" using listen skt from vhost %s\n", wsi->a.vhost->name);
return 1;
}
/*
* Creates a single listen socket of a specific AF
*/
int
_lws_vhost_init_server_af(struct vh_sock_args *a)
{
struct lws_context *cx = a->vhost->context;
struct lws_context_per_thread *pt;
int n, opt = 1, limit = 1;
lws_sockfd_type sockfd;
struct lws *wsi;
int m = 0, is;
#if defined(LWS_WITH_IPV6)
int af = 0;
int value = 1;
#endif
struct lws_vhost *vh;
struct lws *wsi;
(void)method_names;
(void)opt;
if (info) {
vhost->iface = info->iface;
vhost->listen_port = info->port;
}
lwsl_info("%s: af %d\n", __func__, (int)a->af);
/* set up our external listening socket we serve on */
if (vhost->listen_port == CONTEXT_PORT_NO_LISTEN ||
vhost->listen_port == CONTEXT_PORT_NO_LISTEN_SERVER)
if (lws_vhost_foreach_listen_wsi(a->vhost->context, a, check_extant))
return 0;
deal:
if (a->vhost->iface) {
vh = vhost->context->vhost_list;
while (vh) {
if (vh->listen_wsi.count &&
lws_vhost_compare_listen(vhost, vh)) {
lwsl_notice(" using listen skt from vhost %s\n",
vh->name);
return 0;
}
vh = vh->vhost_next;
}
if (vhost->iface) {
lwsl_err("%s\n", a->vhost->iface);
/*
* let's check before we do anything else about the disposition
* of the interface he wants to bind to...
*/
is = lws_socket_bind(vhost, NULL, LWS_SOCK_INVALID,
vhost->listen_port, vhost->iface, 1);
is = lws_socket_bind(a->vhost, NULL, LWS_SOCK_INVALID,
a->vhost->listen_port, a->vhost->iface,
a->af);
lwsl_debug("initial if check says %d\n", is);
if (is == LWS_ITOSA_BUSY)
/* treat as fatal */
return -1;
deal:
lws_start_foreach_llp(struct lws_vhost **, pv,
vhost->context->no_listener_vhost_list) {
if (is >= LWS_ITOSA_USABLE && *pv == vhost) {
cx->no_listener_vhost_list) {
if (is >= LWS_ITOSA_USABLE && *pv == a->vhost) {
/* on the list and shouldn't be: remove it */
lwsl_debug("deferred iface: removing vh %s\n",
(*pv)->name);
*pv = vhost->no_listener_vhost_list;
vhost->no_listener_vhost_list = NULL;
*pv = a->vhost->no_listener_vhost_list;
a->vhost->no_listener_vhost_list = NULL;
goto done_list;
}
if (is < LWS_ITOSA_USABLE && *pv == vhost)
if (is < LWS_ITOSA_USABLE && *pv == a->vhost)
goto done_list;
} lws_end_foreach_llp(pv, no_listener_vhost_list);
@ -128,10 +140,11 @@ deal:
/* ... but needs to be: so add it */
lwsl_debug("deferred iface: adding vh %s\n", vhost->name);
vhost->no_listener_vhost_list =
vhost->context->no_listener_vhost_list;
vhost->context->no_listener_vhost_list = vhost;
lwsl_debug("deferred iface: adding vh %s\n",
a->vhost->name);
a->vhost->no_listener_vhost_list =
cx->no_listener_vhost_list;
cx->no_listener_vhost_list = a->vhost;
}
done_list:
@ -141,88 +154,61 @@ done_list:
break;
case LWS_ITOSA_NOT_EXIST:
/* can't add it */
if (info) /* first time */
lwsl_err("VH %s: iface %s port %d DOESN'T EXIST\n",
vhost->name, vhost->iface, vhost->listen_port);
else
if (!a->info)
return -1;
return (info->options & LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND) ==
LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND?
/* first time */
lwsl_err("%s: VH %s: iface %s port %d DOESN'T EXIST\n",
__func__, a->vhost->name, a->vhost->iface,
a->vhost->listen_port);
return (a->info->options &
LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND) ==
LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND ?
-1 : 1;
case LWS_ITOSA_NOT_USABLE:
/* can't add it */
if (info) /* first time */
lwsl_err("VH %s: iface %s port %d NOT USABLE\n",
vhost->name, vhost->iface, vhost->listen_port);
else
if (!a->info) /* first time */
return -1;
return (info->options & LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND) ==
LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND?
lwsl_err("%s: VH %s: iface %s port %d NOT USABLE\n",
__func__, a->vhost->name, a->vhost->iface,
a->vhost->listen_port);
return (a->info->options &
LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND) ==
LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND ?
-1 : 1;
}
}
(void)n;
#if defined(__linux__)
#ifdef LWS_WITH_UNIX_SOCK
/*
* A Unix domain sockets cannot be bound for several times, even if we set
* the SO_REUSE* options on.
* However, fortunately, each thread is able to independently listen when
* running on a reasonably new Linux kernel. So we can safely assume
* creating just one listening socket for a multi-threaded environment won't
* fail in most cases.
* A Unix domain sockets cannot be bound multiple times, even if we
* set the SO_REUSE* options on.
*
* However on recent linux, each thread is able to independently listen.
*
* So we can assume creating just one listening socket for a multi-
* threaded environment will typically work.
*/
if (!LWS_UNIX_SOCK_ENABLED(vhost))
#endif
limit = vhost->context->count_threads;
if (a->af != AF_UNIX)
limit = cx->count_threads;
#endif
for (m = 0; m < limit; m++) {
if (lws_fi(&vhost->fic, "listenskt")) {
sockfd = LWS_SOCK_INVALID;
} else {
#ifdef LWS_WITH_UNIX_SOCK
if (LWS_UNIX_SOCK_ENABLED(vhost))
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
else {
#endif
#if defined(LWS_WITH_IPV6)
/*
* We have to assess iface if it's around, to choose
* ahead of time to create a socket with the right AF
*/
if (vhost->iface) {
uint8_t buf[16];
int q;
q = lws_parse_numeric_address(vhost->iface, buf, sizeof(buf));
if (q == 4)
af = AF_INET;
if (q == 16)
af = AF_INET6;
}
if (LWS_IPV6_ENABLED(vhost) && af != AF_INET)
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
else
#endif
sockfd = socket(AF_INET, SOCK_STREAM, 0);
#ifdef LWS_WITH_UNIX_SOCK
}
#endif
}
sockfd = lws_fi(&a->vhost->fic, "listenskt") ?
LWS_SOCK_INVALID :
socket(a->af, SOCK_STREAM, 0);
if (sockfd == LWS_SOCK_INVALID) {
lwsl_err("ERROR opening socket\n");
return 1;
}
#if !defined(LWS_PLAT_FREERTOS)
#if (defined(WIN32) || defined(_WIN32)) && defined(SO_EXCLUSIVEADDRUSE)
/*
@ -232,7 +218,7 @@ done_list:
*
* for lws, to match Linux, we default to exclusive listen
*/
if (!lws_check_opt(vhost->options,
if (!lws_check_opt(a->vhost->options,
LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE)) {
if (setsockopt(sockfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
(const void *)&opt, sizeof(opt)) < 0) {
@ -254,15 +240,17 @@ done_list:
}
#if defined(LWS_WITH_IPV6) && defined(IPV6_V6ONLY)
if (LWS_IPV6_ENABLED(vhost) &&
vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY) {
int value = (vhost->options &
LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE) ? 1 : 0;
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
(const void*)&value, sizeof(value)) < 0) {
compatible_close(sockfd);
return -1;
}
/*
* If we have an ipv6 listen socket, it only accepts ipv6.
*
* There will be a separate ipv4 listen socket if that's
* enabled.
*/
if (a->af == AF_INET6 &&
setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
(const void*)&value, sizeof(value)) < 0) {
compatible_close(sockfd);
return -1;
}
#endif
@ -271,10 +259,10 @@ done_list:
#if LWS_MAX_SMP > 1
n = 1;
#else
n = lws_check_opt(vhost->options,
n = lws_check_opt(a->vhost->options,
LWS_SERVER_OPTION_ALLOW_LISTEN_SHARE);
#endif
if (n && vhost->context->count_threads > 1)
if (n && cx->count_threads > 1)
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT,
(const void *)&opt, sizeof(opt)) < 0) {
compatible_close(sockfd);
@ -282,10 +270,12 @@ done_list:
}
#endif
#endif
lws_plat_set_socket_options(vhost, sockfd, 0);
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);
is = lws_socket_bind(vhost, NULL, sockfd, vhost->listen_port,
vhost->iface, 1);
if (is == LWS_ITOSA_BUSY) {
/* treat as fatal */
compatible_close(sockfd);
@ -301,53 +291,56 @@ done_list:
if (is < 0) {
lwsl_info("%s: lws_socket_bind says %d\n", __func__, is);
compatible_close(sockfd);
goto deal;
if (a->vhost->iface)
goto deal;
return -1;
}
/*
* Create the listen wsi and customize it
*/
lws_context_lock(vhost->context, __func__);
wsi = __lws_wsi_create_with_role(vhost->context, m, &role_ops_listen);
lws_context_unlock(vhost->context);
lws_context_lock(cx, __func__);
wsi = __lws_wsi_create_with_role(cx, m, &role_ops_listen);
lws_context_unlock(cx);
if (wsi == NULL) {
lwsl_err("Out of mem\n");
goto bail;
}
wsi->af = (uint8_t)a->af;
#ifdef LWS_WITH_UNIX_SOCK
if (!LWS_UNIX_SOCK_ENABLED(vhost))
if (!LWS_UNIX_SOCK_ENABLED(a->vhost))
#endif
{
wsi->unix_skt = 1;
vhost->listen_port = is;
a->vhost->listen_port = is;
lwsl_debug("%s: lws_socket_bind says %d\n", __func__, is);
}
wsi->desc.sockfd = sockfd;
wsi->a.protocol = vhost->protocols;
lws_vhost_bind_wsi(vhost, wsi);
wsi->a.protocol = a->vhost->protocols;
lws_vhost_bind_wsi(a->vhost, wsi);
wsi->listener = 1;
if (wsi->a.context->event_loop_ops->init_vhost_listen_wsi)
wsi->a.context->event_loop_ops->init_vhost_listen_wsi(wsi);
pt = &vhost->context->pt[m];
pt = &cx->pt[m];
lws_pt_lock(pt, __func__);
if (__insert_wsi_socket_into_fds(vhost->context, wsi)) {
if (__insert_wsi_socket_into_fds(cx, wsi)) {
lwsl_notice("inserting wsi socket into fds failed\n");
lws_pt_unlock(pt);
goto bail;
}
lws_dll2_add_tail(&wsi->listen_list, &vhost->listen_wsi);
lws_dll2_add_tail(&wsi->listen_list, &a->vhost->listen_wsi);
lws_pt_unlock(pt);
#if defined(WIN32) && defined(TCP_FASTOPEN)
if (vhost->fo_listen_queue) {
if (a->vhost->fo_listen_queue) {
int optval = 1;
if (setsockopt(wsi->desc.sockfd, IPPROTO_TCP,
TCP_FASTOPEN,
@ -359,8 +352,8 @@ done_list:
}
#else
#if defined(TCP_FASTOPEN)
if (vhost->fo_listen_queue) {
int qlen = vhost->fo_listen_queue;
if (a->vhost->fo_listen_queue) {
int qlen = a->vhost->fo_listen_queue;
if (setsockopt(wsi->desc.sockfd, SOL_TCP, TCP_FASTOPEN,
&qlen, sizeof(qlen)))
@ -378,21 +371,23 @@ done_list:
}
if (wsi)
__lws_lc_tag(&vhost->context->lcg[LWSLCG_WSI],
&wsi->lc, "listen|%s|%s|%d", vhost->name,
vhost->iface ? vhost->iface : "",
(int)vhost->listen_port);
__lws_lc_tag(&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 */
if (!lws_check_opt(vhost->context->options,
LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
if (!lws_check_opt(cx->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) {
#ifdef LWS_WITH_UNIX_SOCK
if (LWS_UNIX_SOCK_ENABLED(vhost))
lwsl_info(" Listening on \"%s\"\n", vhost->iface);
if (a->af == AF_UNIX)
lwsl_info(" Listening on \"%s\"\n", a->vhost->iface);
else
#endif
lwsl_info(" Listening on port %d\n", vhost->listen_port);
lwsl_info(" Listening on %s:%d\n",
a->vhost->iface,
a->vhost->listen_port);
}
// info->port = vhost->listen_port;
@ -404,6 +399,102 @@ bail:
return -1;
}
int
_lws_vhost_init_server(const struct lws_context_creation_info *info,
struct lws_vhost *vhost)
{
struct vh_sock_args a;
a.info = info;
a.vhost = vhost;
if (info) {
vhost->iface = info->iface;
vhost->listen_port = info->port;
}
/* set up our external listening socket we serve on */
if (vhost->listen_port == CONTEXT_PORT_NO_LISTEN ||
vhost->listen_port == CONTEXT_PORT_NO_LISTEN_SERVER)
return 0;
/*
* Let's figure out what AF(s) we want this vhost to listen on.
*
* We want AF_UNIX alone if that's what's told
*/
#if defined(LWS_WITH_UNIX_SOCK)
/*
* If unix socket, ask for that and we are done
*/
if (LWS_UNIX_SOCK_ENABLED(vhost)) {
a.af = AF_UNIX;
goto single;
}
#endif
/*
* We may support both ipv4 and ipv6, but get a numeric vhost listen
* iface that is unambiguously ipv4 or ipv6, meaning we can only listen
* for the related AF then.
*/
if (vhost->iface) {
uint8_t buf[16];
int q;
q = lws_parse_numeric_address(vhost->iface, buf, sizeof(buf));
if (q == 4) {
a.af = AF_INET;
goto single;
}
if (q == 16) {
#if defined(LWS_WITH_IPV6)
if (LWS_IPV6_ENABLED(vhost)) {
a.af = AF_INET6;
goto single;
}
#endif
lwsl_err("%s: ipv6 not supported on %s\n", __func__,
vhost->name);
return 1;
}
}
/*
* ... if we make it here, we would want to listen on AF_INET and
* AF_INET6 unless one or the other is forbidden
*/
#if defined(LWS_WITH_IPV6)
if (!(LWS_IPV6_ENABLED(vhost) &&
(vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY) &&
(vhost->options & LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE))) {
#endif
a.af = AF_INET;
if (_lws_vhost_init_server_af(&a))
return 1;
#if defined(LWS_WITH_IPV6)
}
if (LWS_IPV6_ENABLED(vhost)) {
a.af = AF_INET6;
goto single;
}
#endif
return 0;
single:
return _lws_vhost_init_server_af(&a);
}
#endif
struct lws_vhost *

View file

@ -195,7 +195,6 @@ lws_tls_cert_updated(struct lws_context *context, const char *certpath,
return 0;
}
#endif
int
lws_gate_accepts(struct lws_context *context, int on)
@ -222,6 +221,7 @@ lws_gate_accepts(struct lws_context *context, int on)
return 0;
}
#endif
/* comma-separated alpn list, like "h2,http/1.1" to openssl alpn format */

View file

@ -57,9 +57,12 @@ lws_tls_restrict_borrow(struct lws_context *context)
return 1;
}
if (++context->simultaneous_ssl == context->simultaneous_ssl_restriction)
context->simultaneous_ssl++;
#if defined(LWS_WITH_SERVER)
if (context->simultaneous_ssl == context->simultaneous_ssl_restriction)
/* that was the last allowed SSL connection */
lws_gate_accepts(context, 0);
#endif
lwsl_info("%s: %d -> %d\n", __func__,
context->simultaneous_ssl - 1,
@ -72,12 +75,15 @@ void
lws_tls_restrict_return(struct lws_context *context)
{
if (context->simultaneous_ssl_restriction) {
if (context->simultaneous_ssl-- ==
context->simultaneous_ssl_restriction)
int n = context->simultaneous_ssl--;
#if defined(LWS_WITH_SERVER)
if (n == context->simultaneous_ssl_restriction)
/* we made space and can do an accept */
lws_gate_accepts(context, 1);
lwsl_info("%s: %d -> %d\n", __func__,
context->simultaneous_ssl + 1,
#endif
lwsl_info("%s: %d -> %d\n", __func__, n,
context->simultaneous_ssl);
}
}