Newer
Older
/*
* libwebsockets - small server side websockets and web server implementation
*
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
#ifndef LWS_BUILD_HASH
#define LWS_BUILD_HASH "unknown-build-hash"
#endif
static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
/**
* lws_get_library_version: get version and git hash library built from
*
* returns a const char * to a string like "1.1 178d78c"
* representing the library version followed by the git head hash it
* was built from
*/
LWS_VISIBLE const char *
lws_get_library_version(void)
{
return library_version;
}
static const char * const mount_protocols[] = {
"http://",
"https://",
"file://",
"cgi://",
">http://",
">https://",
#if defined(LWS_WITH_HTTP2)
/*
* These are the standardized defaults.
* Override what actually goes in the vhost settings in platform or user code.
* Leave these alone because they are used to determine "what is different
* from the protocol defaults".
*/
const struct http2_settings lws_h2_defaults = { {
1,
/* H2SET_HEADER_TABLE_SIZE */ 4096,
/* *** This controls how many entries in the dynamic table ***
* Allows the sender to inform the remote endpoint of the maximum
* size of the header compression table used to decode header
* blocks, in octets. The encoder can select any size equal to or
* less than this value by using signaling specific to the header
* compression format inside a header block (see [COMPRESSION]).
* The initial value is 4,096 octets.
*/
/* H2SET_ENABLE_PUSH */ 1,
/* H2SET_MAX_CONCURRENT_STREAMS */ 0x7fffffff,
/* H2SET_INITIAL_WINDOW_SIZE */ 65535,
/* H2SET_MAX_FRAME_SIZE */ 16384,
/* H2SET_MAX_HEADER_LIST_SIZE */ 0x7fffffff,
/*< This advisory setting informs a peer of the maximum size of
* header list that the sender is prepared to accept, in octets.
* The value is based on the uncompressed size of header fields,
* including the length of the name and value in octets plus an
* overhead of 32 octets for each header field.
*/
/* H2SET_RESERVED7 */ 0,
/* H2SET_ENABLE_CONNECT_PROTOCOL */ 0,
/* these are the "lws defaults"... they can be overridden in plat */
const struct http2_settings lws_h2_stock_settings = { {
1,
/* H2SET_HEADER_TABLE_SIZE */ 65536, /* ffox */
/* *** This controls how many entries in the dynamic table ***
* Allows the sender to inform the remote endpoint of the maximum
* size of the header compression table used to decode header
* blocks, in octets. The encoder can select any size equal to or
* less than this value by using signaling specific to the header
* compression format inside a header block (see [COMPRESSION]).
* The initial value is 4,096 octets.
*
* Can't pass h2spec with less than 4096 here...
*/
/* H2SET_ENABLE_PUSH */ 1,
/* H2SET_MAX_CONCURRENT_STREAMS */ 24,
/* H2SET_INITIAL_WINDOW_SIZE */ 65535,
/* H2SET_MAX_FRAME_SIZE */ 16384,
/* H2SET_MAX_HEADER_LIST_SIZE */ 4096,
/*< This advisory setting informs a peer of the maximum size of
* header list that the sender is prepared to accept, in octets.
* The value is based on the uncompressed size of header fields,
* including the length of the name and value in octets plus an
* overhead of 32 octets for each header field.
*/
/* H2SET_RESERVED7 */ 0,
/* H2SET_ENABLE_CONNECT_PROTOCOL */ 1,
lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost,
const struct lws_protocols *prot, int size)
{
int n = 0;
/* allocate the vh priv array only on demand */
if (!vhost->protocol_vh_privs) {
vhost->protocol_vh_privs = (void **)lws_zalloc(
vhost->count_protocols * sizeof(void *),
"protocol_vh_privs");
if (!vhost->protocol_vh_privs)
return NULL;
}
while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
n++;
if (n == vhost->count_protocols) {
n = 0;
while (n < vhost->count_protocols &&
strcmp(vhost->protocols[n].name, prot->name))
n++;
if (n == vhost->count_protocols)
return NULL;
}
vhost->protocol_vh_privs[n] = lws_zalloc(size, "vh priv");
return vhost->protocol_vh_privs[n];
}
LWS_VISIBLE void *
lws_protocol_vh_priv_get(struct lws_vhost *vhost,
const struct lws_protocols *prot)
if (!vhost || !vhost->protocol_vh_privs)
return NULL;
while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
n++;
if (n == vhost->count_protocols) {
n = 0;
while (n < vhost->count_protocols &&
strcmp(vhost->protocols[n].name, prot->name))
n++;
if (n == vhost->count_protocols) {
lwsl_err("%s: unknown protocol %p\n", __func__, prot);
return NULL;
}
static const struct lws_protocol_vhost_options *
lws_vhost_protocol_options(struct lws_vhost *vh, const char *name)
{
const struct lws_protocol_vhost_options *pvo = vh->pvo;
Andy Green
committed
if (!name)
return NULL;
while (pvo) {
if (!strcmp(pvo->name, name))
return pvo;
pvo = pvo->next;
}
return NULL;
}
/*
* inform every vhost that hasn't already done it, that
* his protocols are initializing
*/
lws_protocol_init(struct lws_context *context)
{
struct lws_vhost *vh = context->vhost_list;
const struct lws_protocol_vhost_options *pvo, *pvo1;
if (context->doing_protocol_init)
return 0;
context->doing_protocol_init = 1;
/* only do the protocol init once for a given vhost */
if (vh->created_vhost_protocols ||
(vh->options & LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT))
/* initialize supported protocols on this vhost */
for (n = 0; n < vh->count_protocols; n++) {
wsi.protocol = &vh->protocols[n];
pvo = lws_vhost_protocol_options(vh,
vh->protocols[n].name);
/*
* linked list of options specific to
* vh + protocol
*/
pvo1 = pvo;
pvo = pvo1->options;
while (pvo) {
vh->name,
vh->protocols[n].name,
pvo->name);
if (!strcmp(pvo->name, "default")) {
"protocol for vh %s to %s\n",
vh->name,
vh->protocols[n].name);
vh->default_protocol_index = n;
}
"protocol for vh %s to %s\n",
vh->name,
vh->protocols[n].name);
vh->raw_protocol_index = n;
}
pvo = pvo->next;
}
pvo = pvo1->options;
}
#if defined(LWS_OPENSSL_SUPPORT)
any |= !!vh->ssl_ctx;
#endif
* inform all the protocols that they are doing their
* one-time initialization if they want to.
* NOTE the wsi is all zeros except for the context, vh
* + protocol ptrs so lws_get_context(wsi) etc can work
(void *)pvo, 0)) {
lws_free(vh->protocol_vh_privs[n]);
vh->protocol_vh_privs[n] = NULL;
lwsl_err("%s: protocol %s failed init\n", __func__,
vh->protocols[n].name);
}
vh->created_vhost_protocols = 1;
next:
context->doing_protocol_init = 0;
if (!context->protocol_init_done)
lws_finalize_startup(context);
if (any)
lws_tls_check_all_cert_lifetimes(context);
LWS_VISIBLE int
lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
#ifdef LWS_WITH_CGI
struct lws_cgi_args *args;
#endif
#if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY)
char buf[512];
int n;
#endif
switch (reason) {
case LWS_CALLBACK_HTTP:
#ifndef LWS_NO_SERVER
if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL))
return -1;
if (lws_http_transaction_completed(wsi))
#endif
return -1;
break;
#if !defined(LWS_NO_SERVER)
case LWS_CALLBACK_HTTP_FILE_COMPLETION:
if (lws_http_transaction_completed(wsi))
return -1;
break;
#endif
case LWS_CALLBACK_HTTP_WRITEABLE:
#ifdef LWS_WITH_CGI
if (wsi->reason_bf & (LWS_CB_REASON_AUX_BF__CGI_HEADERS |
LWS_CB_REASON_AUX_BF__CGI)) {
n = lws_cgi_write_split_stdout_headers(wsi);
if (n < 0) {
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_HEADERS)
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__CGI;
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_CHUNK_END) {
if (!wsi->http2_substream) {
memcpy(buf + LWS_PRE, "0\x0d\x0a\x0d\x0a", 5);
lwsl_debug("writing chunk term and exiting\n");
n = lws_write(wsi, (unsigned char *)buf +
LWS_PRE, 5, LWS_WRITE_HTTP);
n = lws_write(wsi, (unsigned char *)buf +
LWS_PRE, 0,
LWS_WRITE_HTTP_FINAL);
/* always close after sending it */
return -1;
if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) {
char *px = buf + LWS_PRE;
int lenx = sizeof(buf) - LWS_PRE;
/*
* our sink is writeable and our source has something
* to read. So read a lump of source material of
* suitable size to send or what's available, whichever
* is the smaller.
*/
wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY;
return -1;
break;
}
#endif
break;
#if defined(LWS_WITH_HTTP_PROXY)
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
assert(lws_get_parent(wsi));
if (!lws_get_parent(wsi))
break;
lws_get_parent(wsi)->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY;
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
assert(lws_get_parent(wsi));
n = lws_write(lws_get_parent(wsi), (unsigned char *)in,
len, LWS_WRITE_HTTP);
if (n < 0)
return -1;
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: {
unsigned char *p, *end;
char ctype[64], ctlen = 0;
p = (unsigned char *)buf + LWS_PRE;
end = p + sizeof(buf) - LWS_PRE;
if (lws_add_http_header_status(lws_get_parent(wsi),
HTTP_STATUS_OK, &p, end))
return 1;
if (lws_add_http_header_by_token(lws_get_parent(wsi),
WSI_TOKEN_HTTP_SERVER,
(unsigned char *)"libwebsockets",
13, &p, end))
return 1;
ctlen = lws_hdr_copy(wsi, ctype, sizeof(ctype),
WSI_TOKEN_HTTP_CONTENT_TYPE);
if (ctlen > 0) {
if (lws_add_http_header_by_token(lws_get_parent(wsi),
WSI_TOKEN_HTTP_CONTENT_TYPE,
(unsigned char *)ctype, ctlen, &p, end))
return 1;
}
if (lws_finalize_http_header(lws_get_parent(wsi), &p, end))
return 1;
*p = '\0';
n = lws_write(lws_get_parent(wsi),
(unsigned char *)buf + LWS_PRE,
p - ((unsigned char *)buf + LWS_PRE),
LWS_WRITE_HTTP_HEADERS);
if (n < 0)
return -1;
break; }
#endif
#ifdef LWS_WITH_CGI
/* CGI IO events (POLLIN/OUT) appear here, our default policy is:
*
* - POST data goes on subprocess stdin
* - subprocess stdout goes on http via writeable callback
* - subprocess stderr goes to the logs
*/
case LWS_CALLBACK_CGI:
args = (struct lws_cgi_args *)in;
switch (args->ch) { /* which of stdin/out/err ? */
case LWS_STDIN:
/* TBD stdin rx flow control */
break;
case LWS_STDOUT:
/* quench POLLIN on STDOUT until MASTER got writeable */
lws_rx_flow_control(args->stdwsi[LWS_STDOUT], 0);
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI;
/* when writing to MASTER would not block */
lws_callback_on_writable(wsi);
break;
case LWS_STDERR:
n = lws_get_socket_fd(args->stdwsi[LWS_STDERR]);
if (n < 0)
break;
n = read(n, buf, sizeof(buf) - 2);
if (n > 0) {
if (buf[n - 1] != '\n')
buf[n++] = '\n';
buf[n] = '\0';
lwsl_notice("CGI-stderr: %s\n", buf);
}
break;
}
break;
case LWS_CALLBACK_CGI_TERMINATED:
lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: %d %" PRIu64 "\n",
wsi->cgi->explicitly_chunked,
(uint64_t)wsi->cgi->content_length);
if (!wsi->cgi->explicitly_chunked &&
!wsi->cgi->content_length) {
/* send terminating chunk */
wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END;
lws_callback_on_writable(wsi);
lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3);
break;
return -1;
case LWS_CALLBACK_CGI_STDIN_DATA: /* POST body for stdin */
args = (struct lws_cgi_args *)in;
args->data[args->len] = '\0';
n = lws_get_socket_fd(args->stdwsi[LWS_STDIN]);
if (n < 0)
return -1;
n = write(n, args->data, args->len);
if (n < args->len)
lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: "
"sent %d only %d went", n, args->len);
return n;
#endif
(void)si;
lwsl_notice("LWS_CALLBACK_SSL_INFO: where: 0x%x, ret: 0x%x\n",
si->where, si->ret);
default:
break;
}
return 0;
}
/* list of supported protocols and callbacks */
static const struct lws_protocols protocols_dummy[] = {
/* first protocol must always be HTTP handler */
{
"http-only", /* name */
0, /* per_session_data_size */
0, /* max frame size / rx buffer */
},
/*
* the other protocols are provided by lws plugins
*/
{ NULL, NULL, 0, 0, 0, NULL, 0} /* terminator */
};
#ifdef LWS_PLAT_OPTEE
#undef LWS_HAVE_GETENV
#endif
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), "create vhost"),
#ifdef LWS_WITH_PLUGINS
struct lws_plugin *plugin = context->plugin_list;
if (!info->protocols)
info->protocols = &protocols_dummy[0];
vh->context = context;
if (!info->vhost_name)
vh->name = "default";
else
vh->name = info->vhost_name;
if (info->options & LWS_SERVER_OPTION_ONLY_RAW)
lwsl_info("%s set to only support RAW\n", vh->name);
#if defined(LWS_WITH_HTTP2)
vh->set = context->set;
if (info->http2_settings[0])
for (n = 1; n < LWS_H2_SETTINGS_LEN; n++)
vh->set.s[n] = info->http2_settings[n];
#endif
vh->bind_iface = info->bind_iface;
#endif
for (vh->count_protocols = 0;
info->protocols[vh->count_protocols].callback;
vh->count_protocols++)
;
vh->options = info->options;
vh->user = info->user;
vh->ssl_info_event_mask = info->ssl_info_event_mask;
if (info->keepalive_timeout)
vh->keepalive_timeout = info->keepalive_timeout;
else
vh->keepalive_timeout = 5;
if (info->timeout_secs_ah_idle)
vh->timeout_secs_ah_idle = info->timeout_secs_ah_idle;
else
vh->timeout_secs_ah_idle = 10;
#ifdef LWS_OPENSSL_SUPPORT
if (info->ecdh_curve)
strncpy(vh->ecdh_curve, info->ecdh_curve, sizeof(vh->ecdh_curve) - 1);
#endif
/* carefully allocate and take a copy of cert + key paths if present */
n = 0;
if (info->ssl_cert_filepath)
n += (int)strlen(info->ssl_cert_filepath) + 1;
if (info->ssl_private_key_filepath)
n += (int)strlen(info->ssl_private_key_filepath) + 1;
if (n) {
vh->key_path = vh->alloc_cert_path = lws_malloc(n, "vh paths");
if (info->ssl_cert_filepath) {
n = (int)strlen(info->ssl_cert_filepath) + 1;
memcpy(vh->alloc_cert_path, info->ssl_cert_filepath, n);
vh->key_path += n;
}
if (info->ssl_private_key_filepath)
memcpy(vh->key_path, info->ssl_private_key_filepath,
strlen(info->ssl_private_key_filepath) + 1);
}
/*
* 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),
"vhost-specific plugin table");
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 (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
f = 0;
(void)f;
#ifdef LWS_WITH_PLUGINS
if (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++;
}
}
if (
#ifdef LWS_WITH_PLUGINS
(context->plugin_list) ||
#endif
context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
vh->same_vh_protocol_list = (struct lws **)
lws_zalloc(sizeof(struct lws *) * vh->count_protocols,
"same vh list");
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");
lwsl_info(" 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))
continue;
((struct lws_protocol_vhost_options *)pvo)->
value = (const char *)(lws_intptr_t)n;
break;
}
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) *
if (!vh->extensions)
return NULL;
memcpy((struct lws_extension *)vh->extensions, info->extensions,
sizeof(struct lws_extension) * m);
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;
vh->http_proxy_port = 0;
vh->http_proxy_address[0] = '\0';
#if defined(LWS_WITH_SOCKS5)
vh->socks_proxy_port = 0;
vh->socks_proxy_address[0] = '\0';
#endif
/* 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
}
#if defined(LWS_WITH_SOCKS5)
/* socks proxy */
if (info->socks_proxy_address) {
/* override for backwards compatibility */
if (info->socks_proxy_port)
vh->socks_proxy_port = info->socks_proxy_port;
lws_set_socks(vh, info->socks_proxy_address);
} else {
#ifdef LWS_HAVE_GETENV
p = getenv("socks_proxy");
if (p)
lws_set_socks(vh, p);
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);
lwsl_err("unable to open log filepath %s\n",
info->log_filepath);
goto bail;
}
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);
if (lws_context_init_server(info, vh)) {
lwsl_err("init server failed\n");
while (1) {
if (!(*vh1)) {
*vh1 = vh;
break;
}
vh1 = &(*vh1)->vhost_next;
};
/* for the case we are adding a vhost much later, after server init */
if (context->protocol_init_done)
bail1:
lws_vhost_destroy(vh);
return NULL;
#ifdef LWS_WITH_ACCESS_LOG
LWS_VISIBLE int
lws_init_vhost_client_ssl(const struct lws_context_creation_info *info,
struct lws_vhost *vhost)
{
struct lws_context_creation_info i;
memcpy(&i, info, sizeof(i));
i.port = CONTEXT_PORT_NO_LISTEN;
return lws_context_init_client_ssl(&i, vhost);
}
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
LWS_VISIBLE void
lws_cancel_service_pt(struct lws *wsi)
{
lws_plat_pipe_signal(wsi);
}
LWS_VISIBLE void
lws_cancel_service(struct lws_context *context)
{
struct lws_context_per_thread *pt = &context->pt[0];
short m = context->count_threads;
lwsl_notice("%s\n", __func__);
while (m--) {
if (pt->pipe_wsi)
lws_plat_pipe_signal(pt->pipe_wsi);
pt++;
}
}
int
lws_create_event_pipes(struct lws_context *context)
{
struct lws *wsi;
int n;
/*
* Create the pt event pipes... these are unique in that they are
* not bound to a vhost or protocol (both are NULL)
*/
for (n = 0; n < context->count_threads; n++) {
if (context->pt[n].pipe_wsi)
continue;
wsi = lws_zalloc(sizeof(*wsi), "event pipe wsi");
if (!wsi) {
lwsl_err("Out of mem\n");
return 1;
}
wsi->context = context;
wsi->mode = LWSCM_EVENT_PIPE;
wsi->protocol = NULL;
wsi->tsi = n;
wsi->vhost = NULL;
wsi->event_pipe = 1;
if (lws_plat_pipe_create(wsi)) {
lws_free(wsi);
continue;
}
wsi->desc.sockfd = context->pt[n].dummy_pipe_fds[0];
lwsl_debug("event pipe fd %d\n", wsi->desc.sockfd);
context->pt[n].pipe_wsi = wsi;
lws_libuv_accept(wsi, wsi->desc);
lws_libev_accept(wsi, wsi->desc);
lws_libevent_accept(wsi, wsi->desc);
if (insert_wsi_socket_into_fds(context, wsi))
return 1;
lws_change_pollfd(context->pt[n].pipe_wsi, 0, LWS_POLLIN);
context->count_wsi_allocated++;
}
return 0;
}
LWS_VISIBLE struct lws_context *
lws_create_context(struct lws_context_creation_info *info)
struct lws_context *context = NULL;
int pid_daemon = get_daemonize_pid();
#if defined(__ANDROID__)
struct rlimit rt;
#endif
lwsl_info("Initial logging level %d\n", log_level);
lwsl_info("Libwebsockets version: %s\n", library_version);
lwsl_info("Compiled with %s\n", GCC_VER);
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_IPV6))
lwsl_info("IPV6 compiled in and enabled\n");
lwsl_info("IPV6 compiled in but disabled\n");
lwsl_info("IPV6 not compiled in\n");
lwsl_info(" LWS_DEF_HEADER_LEN : %u\n", LWS_DEF_HEADER_LEN);
lwsl_info(" LWS_MAX_PROTOCOLS : %u\n", LWS_MAX_PROTOCOLS);
lwsl_info(" LWS_MAX_SMP : %u\n", LWS_MAX_SMP);
lwsl_info(" sizeof (*info) : %ld\n", (long)sizeof(*info));
lwsl_info(" LWS_WITH_STATS : on\n");