int lws_context_init_server(struct lws_context_creation_info *info, struct lws_vhost *vhost) { #ifdef LWS_POSIX int n, opt = 1, limit = 1; #endif lws_sockfd_type sockfd; struct lws_vhost *vh; struct lws *wsi; int m = 0; /* set up our external listening socket we serve on */ if (info->port == CONTEXT_PORT_NO_LISTEN) return 0; vh = vhost->context->vhost_list; while (vh) { if (vh->listen_port == info->port) { if ((!info->iface && !vh->iface) || (info->iface && vh->iface && !strcmp(info->iface, vh->iface))) { vhost->listen_port = info->port; vhost->iface = info->iface; lwsl_notice(" using listen skt from vhost %s\n", vh->name); return 0; } } vh = vh->vhost_next; } #if LWS_POSIX #if defined(__linux__) limit = vhost->context->count_threads; #endif for (m = 0; m < limit; m++) { #ifdef LWS_USE_UNIX_SOCK if (LWS_UNIX_SOCK_ENABLED(vhost)) sockfd = socket(AF_UNIX, SOCK_STREAM, 0); else #endif #ifdef LWS_USE_IPV6 if (LWS_IPV6_ENABLED(context)) sockfd = socket(AF_INET6, SOCK_STREAM, 0); else #endif sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { #else sockfd = mbed3_create_tcp_stream_socket(); if (!lws_sockfd_valid(sockfd)) { #endif lwsl_err("ERROR opening socket\n"); return 1; } #if LWS_POSIX /* * allow us to restart even if old sockets in TIME_WAIT */ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt)) < 0) { compatible_close(sockfd); return 1; } #if defined(__linux__) && defined(SO_REUSEPORT) && LWS_MAX_SMP > 1 if (vhost->context->count_threads > 1) if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const void *)&opt, sizeof(opt)) < 0) { compatible_close(sockfd); return 1; } #endif #endif lws_plat_set_socket_options(vhost, sockfd); #if LWS_POSIX n = lws_socket_bind(vhost, sockfd, info->port, info->iface); if (n < 0) goto bail; info->port = n; #endif vhost->listen_port = info->port; vhost->iface = info->iface; wsi = lws_zalloc(sizeof(struct lws)); if (wsi == NULL) { lwsl_err("Out of mem\n"); goto bail; } wsi->context = vhost->context; wsi->sock = sockfd; wsi->mode = LWSCM_SERVER_LISTENER; wsi->protocol = vhost->protocols; wsi->tsi = m; wsi->vhost = vhost; wsi->listener = 1; vhost->context->pt[m].wsi_listening = wsi; if (insert_wsi_socket_into_fds(vhost->context, wsi)) goto bail; vhost->context->count_wsi_allocated++; vhost->lserv_wsi = wsi; #if LWS_POSIX listen(wsi->sock, LWS_SOMAXCONN); } /* for each thread able to independently lister */ #else mbed3_tcp_stream_bind(wsi->sock, info->port, wsi); #endif if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS)) { #ifdef LWS_USE_UNIX_SOCK if (LWS_UNIX_SOCK_ENABLED(vhost)) lwsl_notice(" Listening on \"%s\"\n", info->iface); else #endif lwsl_notice(" Listening on port %d\n", info->port); } return 0; bail: compatible_close(sockfd); return 1; } int _lws_server_listen_accept_flow_control(struct lws *twsi, int on) { struct lws_context_per_thread *pt = &twsi->context->pt[(int)twsi->tsi]; struct lws *wsi = pt->wsi_listening; int n; if (!wsi || twsi->context->being_destroyed) return 0; lwsl_debug("%s: Thr %d: LISTEN wsi %p: state %d\n", __func__, twsi->tsi, (void *)wsi, on); if (on) n = lws_change_pollfd(wsi, 0, LWS_POLLIN); else n = lws_change_pollfd(wsi, LWS_POLLIN, 0); return n; } struct lws_vhost * lws_select_vhost(struct lws_context *context, int port, const char *servername) { struct lws_vhost *vhost = context->vhost_list; while (vhost) { if (port == vhost->listen_port && !strcmp(vhost->name, servername)) { lwsl_info("SNI: Found: %s\n", servername); return vhost; } vhost = vhost->vhost_next; } return NULL; } static const char * get_mimetype(const char *file) { int n = strlen(file); if (n < 5) return NULL; if (!strcmp(&file[n - 4], ".ico")) return "image/x-icon"; if (!strcmp(&file[n - 4], ".gif")) return "image/gif"; if (!strcmp(&file[n - 3], ".js")) return "text/javascript"; if (!strcmp(&file[n - 4], ".png")) return "image/png"; if (!strcmp(&file[n - 4], ".jpg")) return "image/jpeg"; if (!strcmp(&file[n - 5], ".html")) return "text/html"; if (!strcmp(&file[n - 4], ".css")) return "text/css"; if (!strcmp(&file[n - 4], ".ttf")) return "application/x-font-ttf"; return NULL; }
LWS_VISIBLE struct lws_vhost * lws_create_vhost(struct lws_context *context, struct lws_context_creation_info *info) { struct lws_vhost *vh = lws_zalloc(sizeof(*vh)), **vh1 = &context->vhost_list; const struct lws_http_mount *mounts; const struct lws_protocol_vhost_options *pvo; #ifdef LWS_WITH_PLUGINS struct lws_plugin *plugin = context->plugin_list; struct lws_protocols *lwsp; int m, f = !info->pvo; #endif #ifdef LWS_HAVE_GETENV char *p; #endif int n; if (!vh) return NULL; if (!info->protocols) info->protocols = &protocols_dummy[0]; vh->context = context; if (!info->vhost_name) vh->name = "default"; else vh->name = info->vhost_name; vh->iface = info->iface; for (vh->count_protocols = 0; info->protocols[vh->count_protocols].callback; vh->count_protocols++) ; vh->options = info->options; vh->pvo = info->pvo; vh->headers = info->headers; if (info->keepalive_timeout) vh->keepalive_timeout = info->keepalive_timeout; else vh->keepalive_timeout = 5; #ifdef LWS_WITH_PLUGINS if (plugin) { /* * give the vhost a unified list of protocols including the * ones that came from plugins */ lwsp = lws_zalloc(sizeof(struct lws_protocols) * (vh->count_protocols + context->plugin_protocol_count + 1)); if (!lwsp) return NULL; m = vh->count_protocols; memcpy(lwsp, info->protocols, sizeof(struct lws_protocols) * m); /* for compatibility, all protocols enabled on vhost if only * the default vhost exists. Otherwise only vhosts who ask * for a protocol get it enabled. */ if (info->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS) f = 0; while (plugin) { for (n = 0; n < plugin->caps.count_protocols; n++) { /* * for compatibility's sake, no pvo implies * allow all protocols */ if (f || lws_vhost_protocol_options(vh, plugin->caps.protocols[n].name)) { memcpy(&lwsp[m], &plugin->caps.protocols[n], sizeof(struct lws_protocols)); m++; vh->count_protocols++; } } plugin = plugin->list; } vh->protocols = lwsp; } else #endif vh->protocols = info->protocols; vh->same_vh_protocol_list = (struct lws **) lws_zalloc(sizeof(struct lws *) * vh->count_protocols); vh->mount_list = info->mounts; #ifdef LWS_USE_UNIX_SOCK if (LWS_UNIX_SOCK_ENABLED(context)) { lwsl_notice("Creating Vhost '%s' path \"%s\", %d protocols\n", vh->name, info->iface, vh->count_protocols); } else #endif lwsl_notice("Creating Vhost '%s' port %d, %d protocols, IPv6 %s\n", vh->name, info->port, vh->count_protocols, LWS_IPV6_ENABLED(vh) ? "on" : "off"); mounts = info->mounts; while (mounts) { lwsl_notice(" mounting %s%s to %s\n", mount_protocols[mounts->origin_protocol], mounts->origin, mounts->mountpoint); /* convert interpreter protocol names to pointers */ pvo = mounts->interpret; while (pvo) { for (n = 0; n < vh->count_protocols; n++) if (!strcmp(pvo->value, vh->protocols[n].name)) { ((struct lws_protocol_vhost_options *)pvo)->value = (const char *)(long)n; break; } if (n == vh->count_protocols) lwsl_err("ignoring unknown interpret protocol %s\n", pvo->value); pvo = pvo->next; } mounts = mounts->mount_next; } #ifndef LWS_NO_EXTENSIONS #ifdef LWS_WITH_PLUGINS if (context->plugin_extension_count) { m = 0; while (info->extensions && info->extensions[m].callback) m++; /* * give the vhost a unified list of extensions including the * ones that came from plugins */ vh->extensions = lws_zalloc(sizeof(struct lws_extension) * (m + context->plugin_extension_count + 1)); if (!vh->extensions) return NULL; memcpy((struct lws_extension *)vh->extensions, info->extensions, sizeof(struct lws_extension) * m); plugin = context->plugin_list; while (plugin) { memcpy((struct lws_extension *)&vh->extensions[m], plugin->caps.extensions, sizeof(struct lws_extension) * plugin->caps.count_extensions); m += plugin->caps.count_extensions; plugin = plugin->list; } } else #endif vh->extensions = info->extensions; #endif vh->listen_port = info->port; #if !defined(LWS_WITH_ESP8266) vh->http_proxy_port = 0; vh->http_proxy_address[0] = '\0'; /* either use proxy from info, or try get it from env var */ if (info->http_proxy_address) { /* override for backwards compatibility */ if (info->http_proxy_port) vh->http_proxy_port = info->http_proxy_port; lws_set_proxy(vh, info->http_proxy_address); } else { #ifdef LWS_HAVE_GETENV p = getenv("http_proxy"); if (p) lws_set_proxy(vh, p); #endif } #endif vh->ka_time = info->ka_time; vh->ka_interval = info->ka_interval; vh->ka_probes = info->ka_probes; if (vh->options & LWS_SERVER_OPTION_STS) lwsl_notice(" STS enabled\n"); #ifdef LWS_WITH_ACCESS_LOG if (info->log_filepath) { vh->log_fd = open(info->log_filepath, O_CREAT | O_APPEND | O_RDWR, 0600); if (vh->log_fd == (int)LWS_INVALID_FILE) { lwsl_err("unable to open log filepath %s\n", info->log_filepath); goto bail; } #ifndef WIN32 if (context->uid != -1) if (chown(info->log_filepath, context->uid, context->gid) == -1) lwsl_err("unable to chown log file %s\n", info->log_filepath); #endif } else vh->log_fd = (int)LWS_INVALID_FILE; #endif if (lws_context_init_server_ssl(info, vh)) goto bail; if (lws_context_init_client_ssl(info, vh)) goto bail; if (lws_context_init_server(info, vh)) goto bail; while (1) { if (!(*vh1)) { *vh1 = vh; break; } vh1 = &(*vh1)->vhost_next; }; return vh; bail: lws_free(vh); return NULL; }