diff --git a/lib/core-net/client/connect3.c b/lib/core-net/client/connect3.c index 98fff5bac..6bfd94cb9 100644 --- a/lib/core-net/client/connect3.c +++ b/lib/core-net/client/connect3.c @@ -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; } diff --git a/lib/core-net/network.c b/lib/core-net/network.c index d20a416fd..28c348e0f 100644 --- a/lib/core-net/network.c +++ b/lib/core-net/network.c @@ -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; diff --git a/lib/core-net/private-lib-core-net.h b/lib/core-net/private-lib-core-net.h index 06c69f312..33557c50f 100644 --- a/lib/core-net/private-lib-core-net.h +++ b/lib/core-net/private-lib-core-net.h @@ -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 diff --git a/lib/core-net/vhost.c b/lib/core-net/vhost.c index a5a1dfcee..ed8827e4d 100644 --- a/lib/core-net/vhost.c +++ b/lib/core-net/vhost.c @@ -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 * diff --git a/lib/event-libs/libevent/libevent.c b/lib/event-libs/libevent/libevent.c index a4fe99dca..1ae0acc66 100644 --- a/lib/event-libs/libevent/libevent.c +++ b/lib/event-libs/libevent/libevent.c @@ -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; diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c index 9ddb108c1..8c1f74cae 100644 --- a/lib/roles/http/server/server.c +++ b/lib/roles/http/server/server.c @@ -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 * diff --git a/lib/tls/tls-network.c b/lib/tls/tls-network.c index 644ed7e9d..0698e1ab5 100644 --- a/lib/tls/tls-network.c +++ b/lib/tls/tls-network.c @@ -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 */ diff --git a/lib/tls/tls.c b/lib/tls/tls.c index e85cc84ef..c714fa509 100644 --- a/lib/tls/tls.c +++ b/lib/tls/tls.c @@ -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); } }