예제 #1
0
struct lws *
lws_client_connect_via_info2(struct lws *wsi)
{
	struct client_info_stash *stash = wsi->u.hdr.stash;

	if (!stash)
		return wsi;

	/*
	 * we're not necessarily in a position to action these right away,
	 * stash them... we only need during connect phase so u.hdr is fine
	 */
	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
				  stash->address))
		goto bail1;

	/* these only need u.hdr lifetime as well */

	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash->path))
		goto bail1;

	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, stash->host))
		goto bail1;

	if (stash->origin[0])
		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
					  stash->origin))
			goto bail1;
	/*
	 * this is a list of protocols we tell the server we're okay with
	 * stash it for later when we compare server response with it
	 */
	if (stash->protocol[0])
		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
					  stash->protocol))
			goto bail1;
	if (stash->method[0])
		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
					  stash->method))
			goto bail1;
	if (stash->iface[0])
		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,
					  stash->iface))
			goto bail1;

#if defined(LWS_WITH_SOCKS5)
	if (!wsi->vhost->socks_proxy_port)
		lws_free_set_NULL(wsi->u.hdr.stash);
#endif

	/*
	 * Check with each extension if it is able to route and proxy this
	 * connection for us.  For example, an extension like x-google-mux
	 * can handle this and then we don't need an actual socket for this
	 * connection.
	 */

	if (lws_ext_cb_all_exts(wsi->context, wsi,
				LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
				(void *)stash->address,
				wsi->c_port) > 0) {
		lwsl_client("lws_client_connect: ext handling conn\n");

		lws_set_timeout(wsi,
			PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
			        AWAITING_TIMEOUT);

		wsi->mode = LWSCM_WSCL_WAITING_EXTENSION_CONNECT;
		return wsi;
	}
	lwsl_client("lws_client_connect: direct conn\n");
	wsi->context->count_wsi_allocated++;

	return lws_client_connect_2(wsi);

bail1:
#if defined(LWS_WITH_SOCKS5)
	if (!wsi->vhost->socks_proxy_port)
		lws_free_set_NULL(wsi->u.hdr.stash);
#endif

	return NULL;
}
예제 #2
0
파일: client.c 프로젝트: 5ouya/raspC
char *
lws_generate_client_handshake(struct lws *wsi, char *pkt)
{
	char buf[128], hash[20], key_b64[40], *p = pkt;
	struct lws_context *context = wsi->context;
	int n;
#ifndef LWS_NO_EXTENSIONS
	const struct lws_extension *ext;
	int ext_count = 0;
#endif

	/*
	 * create the random key
	 */
	n = lws_get_random(context, hash, 16);
	if (n != 16) {
		lwsl_err("Unable to read from random dev %s\n",
			 SYSTEM_RANDOM_FILEPATH);
		lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
		return NULL;
	}

	lws_b64_encode_string(hash, 16, key_b64, sizeof(key_b64));

	/*
	 * 00 example client handshake
	 *
	 * GET /socket.io/websocket HTTP/1.1
	 * Upgrade: WebSocket
	 * Connection: Upgrade
	 * Host: 127.0.0.1:9999
	 * Origin: http://127.0.0.1
	 * Sec-WebSocket-Key1: 1 0 2#0W 9 89 7  92 ^
	 * Sec-WebSocket-Key2: 7 7Y 4328 B2v[8(z1
	 * Cookie: socketio=websocket
	 *
	 * (Á®Ä0¶†≥
	 *
	 * 04 example client handshake
	 *
	 * GET /chat HTTP/1.1
	 * Host: server.example.com
	 * Upgrade: websocket
	 * Connection: Upgrade
	 * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
	 * Sec-WebSocket-Origin: http://example.com
	 * Sec-WebSocket-Protocol: chat, superchat
	 * Sec-WebSocket-Version: 4
	 */

	p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a",
		     lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI));

	p += sprintf(p, "Pragma: no-cache\x0d\x0a"
			"Cache-Control: no-cache\x0d\x0a");

	p += sprintf(p, "Host: %s\x0d\x0a",
		     lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
	p += sprintf(p, "Upgrade: websocket\x0d\x0a"
			"Connection: Upgrade\x0d\x0a"
			"Sec-WebSocket-Key: ");
	strcpy(p, key_b64);
	p += strlen(key_b64);
	p += sprintf(p, "\x0d\x0a");
	if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN))
		p += sprintf(p, "Origin: http://%s\x0d\x0a",
			     lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN));

	if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS))
		p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a",
		     lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS));

	/* tell the server what extensions we could support */

	p += sprintf(p, "Sec-WebSocket-Extensions: ");
#ifndef LWS_NO_EXTENSIONS
	ext = context->extensions;
	while (ext && ext->callback) {
		n = lws_ext_cb_all_exts(context, wsi,
			   LWS_EXT_CB_CHECK_OK_TO_PROPOSE_EXTENSION,
			   (char *)ext->name, 0);
		if (n) { /* an extension vetos us */
			lwsl_ext("ext %s vetoed\n", (char *)ext->name);
			ext++;
			continue;
		}
		n = context->protocols[0].callback(wsi,
			LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,
				wsi->user_space, (char *)ext->name, 0);

		/*
		 * zero return from callback means
		 * go ahead and allow the extension,
		 * it's what we get if the callback is
		 * unhandled
		 */

		if (n) {
			ext++;
			continue;
		}

		/* apply it */

		if (ext_count)
			*p++ = ',';
		p += sprintf(p, "%s", ext->client_offer);
		ext_count++;

		ext++;
	}
#endif
	p += sprintf(p, "\x0d\x0a");

	if (wsi->ietf_spec_revision)
		p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a",
			     wsi->ietf_spec_revision);

	/* give userland a chance to append, eg, cookies */

	context->protocols[0].callback(wsi, LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
				       NULL, &p, (pkt + LWS_MAX_SOCKET_IO_BUF) - p - 12);

	p += sprintf(p, "\x0d\x0a");

	/* prepare the expected server accept response */

	key_b64[39] = '\0'; /* enforce composed length below buf sizeof */
	n = sprintf(buf, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", key_b64);

	lws_SHA1((unsigned char *)buf, n, (unsigned char *)hash);

	lws_b64_encode_string(hash, 20,
			      wsi->u.hdr.ah->initial_handshake_hash_base64,
			      sizeof(wsi->u.hdr.ah->initial_handshake_hash_base64));

	return p;
}
예제 #3
0
char *
lws_generate_client_handshake(struct lws *wsi, char *pkt)
{
	char buf[128], hash[20], key_b64[40], *p = pkt;
	struct lws_context *context = wsi->context;
	const char *meth;
	int n;
#ifndef LWS_NO_EXTENSIONS
	const struct lws_extension *ext;
	int ext_count = 0;
#endif
	const char *pp = lws_hdr_simple_ptr(wsi,
				_WSI_TOKEN_CLIENT_SENT_PROTOCOLS);

	meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
	if (!meth) {
		meth = "GET";
		wsi->do_ws = 1;
	} else {
		wsi->do_ws = 0;
	}

	if (!strcmp(meth, "RAW")) {
		lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
		lwsl_notice("client transition to raw\n");

		if (pp) {
			const struct lws_protocols *pr;

			pr = lws_vhost_name_to_protocol(wsi->vhost, pp);

			if (!pr) {
				lwsl_err("protocol %s not enabled on vhost\n",
					 pp);
				return NULL;
			}

			lws_bind_protocol(wsi, pr);
		}

		if ((wsi->protocol->callback)(wsi,
				LWS_CALLBACK_RAW_ADOPT,
				wsi->user_space, NULL, 0))
			return NULL;

		lws_header_table_force_to_detachable_state(wsi);
		lws_union_transition(wsi, LWSCM_RAW);
		lws_header_table_detach(wsi, 1);

		return NULL;
	}

	if (wsi->do_ws) {
		/*
		 * create the random key
		 */
		n = lws_get_random(context, hash, 16);
		if (n != 16) {
			lwsl_err("Unable to read from random dev %s\n",
				 SYSTEM_RANDOM_FILEPATH);
			lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
			return NULL;
		}

		lws_b64_encode_string(hash, 16, key_b64, sizeof(key_b64));
	}

	/*
	 * 04 example client handshake
	 *
	 * GET /chat HTTP/1.1
	 * Host: server.example.com
	 * Upgrade: websocket
	 * Connection: Upgrade
	 * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
	 * Sec-WebSocket-Origin: http://example.com
	 * Sec-WebSocket-Protocol: chat, superchat
	 * Sec-WebSocket-Version: 4
	 */

	p += sprintf(p, "%s %s HTTP/1.1\x0d\x0a", meth,
		     lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI));

	p += sprintf(p, "Pragma: no-cache\x0d\x0a"
			"Cache-Control: no-cache\x0d\x0a");

	p += sprintf(p, "Host: %s\x0d\x0a",
		     lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));

	if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN)) {
		if (lws_check_opt(context->options, LWS_SERVER_OPTION_JUST_USE_RAW_ORIGIN))
			p += sprintf(p, "Origin: %s\x0d\x0a",
				     lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN));
		else
			p += sprintf(p, "Origin: http://%s\x0d\x0a",
				     lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN));
	}

	if (wsi->do_ws) {
		p += sprintf(p, "Upgrade: websocket\x0d\x0a"
				"Connection: Upgrade\x0d\x0a"
				"Sec-WebSocket-Key: ");
		strcpy(p, key_b64);
		p += strlen(key_b64);
		p += sprintf(p, "\x0d\x0a");
		if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS))
			p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a",
			     lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS));

		/* tell the server what extensions we could support */

#ifndef LWS_NO_EXTENSIONS
		ext = wsi->vhost->extensions;
		while (ext && ext->callback) {
			n = lws_ext_cb_all_exts(context, wsi,
				   LWS_EXT_CB_CHECK_OK_TO_PROPOSE_EXTENSION,
				   (char *)ext->name, 0);
			if (n) { /* an extension vetos us */
				lwsl_ext("ext %s vetoed\n", (char *)ext->name);
				ext++;
				continue;
			}
			n = wsi->vhost->protocols[0].callback(wsi,
				LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,
					wsi->user_space, (char *)ext->name, 0);

			/*
			 * zero return from callback means
			 * go ahead and allow the extension,
			 * it's what we get if the callback is
			 * unhandled
			 */

			if (n) {
				ext++;
				continue;
			}

			/* apply it */

			if (ext_count)
				*p++ = ',';
			else
				p += sprintf(p, "Sec-WebSocket-Extensions: ");
			p += sprintf(p, "%s", ext->client_offer);
			ext_count++;

			ext++;
		}
		if (ext_count)
			p += sprintf(p, "\x0d\x0a");
#endif

		if (wsi->ietf_spec_revision)
			p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a",
				     wsi->ietf_spec_revision);

		/* prepare the expected server accept response */

		key_b64[39] = '\0'; /* enforce composed length below buf sizeof */
		n = sprintf(buf, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", key_b64);

		lws_SHA1((unsigned char *)buf, n, (unsigned char *)hash);

		lws_b64_encode_string(hash, 20,
				      wsi->u.hdr.ah->initial_handshake_hash_base64,
				      sizeof(wsi->u.hdr.ah->initial_handshake_hash_base64));
	}

	/* give userland a chance to append, eg, cookies */

	wsi->protocol->callback(wsi, LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
				wsi->user_space, &p, (pkt + context->pt_serv_buf_size) - p - 12);

	p += sprintf(p, "\x0d\x0a");

	return p;
}
예제 #4
0
LWS_VISIBLE struct lws *
lws_client_connect_via_info(struct lws_client_connect_info *i)
{
    struct lws *wsi;
    int v = SPEC_LATEST_SUPPORTED;

    wsi = lws_zalloc(sizeof(struct lws));
    if (wsi == NULL)
        goto bail;

    wsi->context = i->context;
    wsi->sock = LWS_SOCK_INVALID;

    /* -1 means just use latest supported */

    if (i->ietf_version_or_minus_one != -1 && i->ietf_version_or_minus_one)
        v = i->ietf_version_or_minus_one;

    wsi->ietf_spec_revision = v;
    wsi->user_space = NULL;
    wsi->state = LWSS_CLIENT_UNCONNECTED;
    wsi->protocol = NULL;
    wsi->pending_timeout = NO_PENDING_TIMEOUT;

#ifdef LWS_OPENSSL_SUPPORT
    wsi->use_ssl = i->ssl_connection;
#else
    if (i->ssl_connection) {
        lwsl_err("libwebsockets not configured for ssl\n");
        goto bail;
    }
#endif

    if (lws_allocate_header_table(wsi))
        goto bail;

    /*
     * we're not necessarily in a position to action these right away,
     * stash them... we only need during connect phase so u.hdr is fine
     */
    wsi->u.hdr.ah->c_port = i->port;
    if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, i->address))
        goto bail1;

    /* these only need u.hdr lifetime as well */

    if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, i->path))
        goto bail1;

    if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, i->host))
        goto bail1;

    if (i->origin)
        if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN, i->origin))
            goto bail1;
    /*
     * this is a list of protocols we tell the server we're okay with
     * stash it for later when we compare server response with it
     */
    if (i->protocol)
        if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
                                  i->protocol))
            goto bail1;

    wsi->protocol = &i->context->protocols[0];
    if (wsi && !wsi->user_space && i->userdata) {
        wsi->user_space_externally_allocated = 1;
        wsi->user_space = i->userdata;
    }

    /*
     * Check with each extension if it is able to route and proxy this
     * connection for us.  For example, an extension like x-google-mux
     * can handle this and then we don't need an actual socket for this
     * connection.
     */

    if (lws_ext_cb_all_exts(i->context, wsi,
                            LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
                            (void *)i->address, i->port) > 0) {
        lwsl_client("lws_client_connect: ext handling conn\n");

        lws_set_timeout(wsi,
                        PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
                        AWAITING_TIMEOUT);

        wsi->mode = LWSCM_WSCL_WAITING_EXTENSION_CONNECT;
        return wsi;
    }
    lwsl_client("lws_client_connect: direct conn\n");

    return lws_client_connect_2(wsi);

bail1:
    lws_free_header_table(wsi);
bail:
    lws_free(wsi);

    return NULL;
}
예제 #5
0
LWS_VISIBLE struct lws_context *
lws_create_context(struct lws_context_creation_info *info)
{
	struct lws_context *context = NULL;
	struct lws wsi;
#ifndef LWS_NO_DAEMONIZE
	int pid_daemon = get_daemonize_pid();
#endif
	char *p;
	int n;

	lwsl_notice("Initial logging level %d\n", log_level);

	lwsl_notice("Libwebsockets version: %s\n", library_version);
#if LWS_POSIX
#ifdef LWS_USE_IPV6
	if (!(info->options & LWS_SERVER_OPTION_DISABLE_IPV6))
		lwsl_notice("IPV6 compiled in and enabled\n");
	else
		lwsl_notice("IPV6 compiled in but disabled\n");
#else
	lwsl_notice("IPV6 not compiled in\n");
#endif
	lws_feature_status_libev(info);
#endif
	lwsl_info(" LWS_MAX_HEADER_LEN: %u\n", LWS_MAX_HEADER_LEN);
	lwsl_info(" LWS_MAX_PROTOCOLS: %u\n", LWS_MAX_PROTOCOLS);

	lwsl_info(" SPEC_LATEST_SUPPORTED: %u\n", SPEC_LATEST_SUPPORTED);
	lwsl_info(" AWAITING_TIMEOUT: %u\n", AWAITING_TIMEOUT);
	lwsl_info(" sizeof (*info): %u\n", sizeof(*info));
#if LWS_POSIX
	lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
	lwsl_info(" LWS_MAX_ZLIB_CONN_BUFFER: %u\n", LWS_MAX_ZLIB_CONN_BUFFER);
#endif
	if (lws_plat_context_early_init())
		return NULL;

	context = lws_zalloc(sizeof(struct lws_context));
	if (!context) {
		lwsl_err("No memory for websocket context\n");
		return NULL;
	}
#ifndef LWS_NO_DAEMONIZE
	if (pid_daemon) {
		context->started_with_parent = pid_daemon;
		lwsl_notice(" Started with daemon pid %d\n", pid_daemon);
	}
#endif
	context->lserv_seen = 0;
	context->protocols = info->protocols;
	context->token_limits = info->token_limits;
	context->listen_port = info->port;
	context->http_proxy_port = 0;
	context->http_proxy_address[0] = '\0';
	context->options = info->options;
	context->iface = info->iface;
	context->ka_time = info->ka_time;
	context->ka_interval = info->ka_interval;
	context->ka_probes = info->ka_probes;

	memset(&wsi, 0, sizeof(wsi));
	wsi.context = context;

	if (!info->ka_interval && info->ka_time > 0) {
		lwsl_err("info->ka_interval can't be 0 if ka_time used\n");
		return NULL;
	}

#ifdef LWS_USE_LIBEV
	/* (Issue #264) In order to *avoid breaking backwards compatibility*, we
	 * enable libev mediated SIGINT handling with a default handler of
	 * lws_sigint_cb. The handler can be overridden or disabled
	 * by invoking lws_sigint_cfg after creating the context, but
	 * before invoking lws_initloop:
	 */
	context->use_ev_sigint = 1;
	context->lws_ev_sigint_cb = &lws_sigint_cb;
#endif /* LWS_USE_LIBEV */

	lwsl_info(" mem: context:         %5u bytes\n", sizeof(struct lws_context));

	/*
	 * allocate and initialize the pool of
	 * allocated_header structs + data
	 */
	if (info->max_http_header_data)
		context->max_http_header_data = info->max_http_header_data;
	else
		context->max_http_header_data = LWS_MAX_HEADER_LEN;
	if (info->max_http_header_pool)
		context->max_http_header_pool = info->max_http_header_pool;
	else
		context->max_http_header_pool = LWS_MAX_HEADER_POOL;

	context->http_header_data = lws_malloc(context->max_http_header_data *
					       context->max_http_header_pool);
	if (!context->http_header_data)
		goto bail;
	context->ah_pool = lws_zalloc(sizeof(struct allocated_headers) *
				      context->max_http_header_pool);
	if (!context->ah_pool)
		goto bail;

	for (n = 0; n < context->max_http_header_pool; n++)
		context->ah_pool[n].data = (char *)context->http_header_data +
			(n * context->max_http_header_data);

	/* this is per context */
	lwsl_info(" mem: http hdr rsvd:   %5u bytes ((%u + %u) x %u)\n",
		    (context->max_http_header_data + sizeof(struct allocated_headers)) *
		    context->max_http_header_pool,
		    context->max_http_header_data, sizeof(struct allocated_headers),
		    context->max_http_header_pool);

	context->max_fds = getdtablesize();

	context->fds = lws_zalloc(sizeof(struct lws_pollfd) * context->max_fds);
	if (context->fds == NULL) {
		lwsl_err("OOM allocating %d fds\n", context->max_fds);
		goto bail;
	}

	lwsl_info(" mem: pollfd map:      %5u\n",
		    sizeof(struct lws_pollfd) * context->max_fds);

	if (lws_plat_init(context, info))
		goto bail;

	lws_context_init_extensions(info, context);

	context->user_space = info->user;

	lwsl_notice(" mem: per-conn:        %5u bytes + protocol rx buf\n",
		    sizeof(struct lws));

	strcpy(context->canonical_hostname, "unknown");
	lws_server_get_canonical_hostname(context, info);

	/* 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)
			context->http_proxy_port = info->http_proxy_port;
		lws_set_proxy(context, info->http_proxy_address);
	} else {
#ifdef LWS_HAVE_GETENV
		p = getenv("http_proxy");
		if (p)
			lws_set_proxy(context, p);
#endif
	}

	if (lws_context_init_server_ssl(info, context))
		goto bail;

	if (lws_context_init_client_ssl(info, context))
		goto bail;

	if (lws_context_init_server(info, context))
		goto bail;

	/*
	 * drop any root privs for this process
	 * to listen on port < 1023 we would have needed root, but now we are
	 * listening, we don't want the power for anything else
	 */
	lws_plat_drop_app_privileges(info);

	/* initialize supported protocols */

	for (context->count_protocols = 0;
	     info->protocols[context->count_protocols].callback;
	     context->count_protocols++)
		/*
		 * 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 pointer
		 * so lws_get_context(wsi) can work in the callback.
		 */
		info->protocols[context->count_protocols].callback(&wsi,
				LWS_CALLBACK_PROTOCOL_INIT, NULL, NULL, 0);

	/*
	 * give all extensions a chance to create any per-context
	 * allocations they need
	 */
	if (info->port != CONTEXT_PORT_NO_LISTEN) {
		if (lws_ext_cb_all_exts(context, NULL,
			LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT, NULL, 0) < 0)
			goto bail;
	} else
		if (lws_ext_cb_all_exts(context, NULL,
			LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT, NULL, 0) < 0)
			goto bail;

	return context;

bail:
	lws_context_destroy(context);
	return NULL;
}
예제 #6
0
/**
 * lws_context_destroy() - Destroy the websocket context
 * @context:	Websocket context
 *
 *	This function closes any active connections and then frees the
 *	context.  After calling this, any further use of the context is
 *	undefined.
 */
LWS_VISIBLE void
lws_context_destroy(struct lws_context *context)
{
	const struct lws_protocols *protocol = NULL;
	struct lws wsi;
	int n;

	lwsl_notice("%s\n", __func__);

	if (!context)
		return;

	memset(&wsi, 0, sizeof(wsi));
	wsi.context = context;

#ifdef LWS_LATENCY
	if (context->worst_latency_info[0])
		lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
#endif

	for (n = 0; n < context->fds_count; n++) {
		struct lws *wsi = wsi_from_fd(context, context->fds[n].fd);
		if (!wsi)
			continue;
		lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY
				/* no protocol close */);
		n--;
	}

	/*
	 * give all extensions a chance to clean up any per-context
	 * allocations they might have made
	 */

	n = lws_ext_cb_all_exts(context, NULL,
			LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, NULL, 0);

	n = lws_ext_cb_all_exts(context, NULL,
			LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, NULL, 0);

	/*
	 * inform all the protocols that they are done and will have no more
	 * callbacks
	 */
	protocol = context->protocols;
	if (protocol) {
		while (protocol->callback) {
			protocol->callback(&wsi,
					   LWS_CALLBACK_PROTOCOL_DESTROY,
					   NULL, NULL, 0);
			protocol++;
		}
	}
#ifdef LWS_USE_LIBEV
	ev_io_stop(context->io_loop, &context->w_accept.watcher);
	if(context->use_ev_sigint)
		ev_signal_stop(context->io_loop, &context->w_sigint.watcher);
#endif /* LWS_USE_LIBEV */

	lws_plat_context_early_destroy(context);
	lws_ssl_context_destroy(context);
	if (context->fds)
		lws_free(context->fds);
	if (context->ah_pool)
		lws_free(context->ah_pool);
	if (context->http_header_data)
		lws_free(context->http_header_data);

	lws_plat_context_late_destroy(context);

	lws_free(context);
}
예제 #7
0
LWS_VISIBLE void
lws_context_destroy(struct lws_context *context)
{
	const struct lws_protocols *protocol = NULL;
	struct lws_context_per_thread *pt;
	struct lws_vhost *vh = NULL, *vh1;
	struct lws wsi;
	int n, m;

	lwsl_notice("%s\n", __func__);

	if (!context)
		return;

	m = context->count_threads;
	context->being_destroyed = 1;

	memset(&wsi, 0, sizeof(wsi));
	wsi.context = context;

#ifdef LWS_LATENCY
	if (context->worst_latency_info[0])
		lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
#endif

	while (m--) {
		pt = &context->pt[m];

		for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
			struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
			if (!wsi)
				continue;

			lws_close_free_wsi(wsi,
				LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY
				/* no protocol close */);
			n--;
		}
		lws_pt_mutex_destroy(pt);
	}
	/*
	 * give all extensions a chance to clean up any per-context
	 * allocations they might have made
	 */

	n = lws_ext_cb_all_exts(context, NULL,
				LWS_EXT_CB_SERVER_CONTEXT_DESTRUCT, NULL, 0);

	n = lws_ext_cb_all_exts(context, NULL,
				LWS_EXT_CB_CLIENT_CONTEXT_DESTRUCT, NULL, 0);

	/*
	 * inform all the protocols that they are done and will have no more
	 * callbacks.
	 *
	 * We can't free things until after the event loop shuts down.
	 */
	if (context->protocol_init_done)
		vh = context->vhost_list;
	while (vh) {
		wsi.vhost = vh;
		protocol = vh->protocols;
		if (protocol) {
			n = 0;
			while (n < vh->count_protocols) {
				wsi.protocol = protocol;
				protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
						   NULL, NULL, 0);
				protocol++;
				n++;
			}
		}

		vh = vh->vhost_next;
	}

	for (n = 0; n < context->count_threads; n++) {
		pt = &context->pt[n];

		lws_libev_destroyloop(context, n);
		lws_libuv_destroyloop(context, n);

		lws_free_set_NULL(context->pt[n].serv_buf);
		if (pt->ah_pool)
			lws_free(pt->ah_pool);
		if (pt->http_header_data)
			lws_free(pt->http_header_data);
	}
	lws_plat_context_early_destroy(context);
	lws_ssl_context_destroy(context);

	if (context->pt[0].fds)
		lws_free_set_NULL(context->pt[0].fds);

	/* free all the vhost allocations */

	vh = context->vhost_list;
	while (vh) {
		protocol = vh->protocols;
		if (protocol) {
			n = 0;
			while (n < vh->count_protocols) {
				if (vh->protocol_vh_privs &&
				    vh->protocol_vh_privs[n]) {
					lws_free(vh->protocol_vh_privs[n]);
					vh->protocol_vh_privs[n] = NULL;
				}
				protocol++;
				n++;
			}
		}
		if (vh->protocol_vh_privs)
			lws_free(vh->protocol_vh_privs);
		lws_ssl_SSL_CTX_destroy(vh);
		lws_free(vh->same_vh_protocol_list);
#ifdef LWS_WITH_PLUGINS
		if (context->plugin_list)
			lws_free((void *)vh->protocols);
#ifndef LWS_NO_EXTENSIONS
		if (context->plugin_extension_count)
			lws_free((void *)vh->extensions);
#endif
#endif
#ifdef LWS_WITH_ACCESS_LOG
		if (vh->log_fd != (int)LWS_INVALID_FILE)
			close(vh->log_fd);
#endif

		vh1 = vh->vhost_next;
		lws_free(vh);
		vh = vh1;
	}

	lws_plat_context_late_destroy(context);

	lws_free(context);
}
예제 #8
0
LWS_VISIBLE struct lws_context *
lws_create_context(struct lws_context_creation_info *info)
{
	struct lws_context *context = NULL;
#ifndef LWS_NO_DAEMONIZE
	int pid_daemon = get_daemonize_pid();
#endif
	int n, m;
#if defined(__ANDROID__)
	struct rlimit rt;
#endif

	lwsl_notice("Initial logging level %d\n", log_level);
	lwsl_notice("Libwebsockets version: %s\n", library_version);
#if LWS_POSIX
#ifdef LWS_USE_IPV6
	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_IPV6))
		lwsl_notice("IPV6 compiled in and enabled\n");
	else
		lwsl_notice("IPV6 compiled in but disabled\n");
#else
	lwsl_notice("IPV6 not compiled in\n");
#endif
	lws_feature_status_libev(info);
	lws_feature_status_libuv(info);
#endif
	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(" SPEC_LATEST_SUPPORTED : %u\n", SPEC_LATEST_SUPPORTED);
	lwsl_info(" sizeof (*info)        : %u\n", sizeof(*info));
#if LWS_POSIX
	lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
#endif
	if (lws_plat_context_early_init())
		return NULL;

	context = lws_zalloc(sizeof(struct lws_context));
	if (!context) {
		lwsl_err("No memory for websocket context\n");
		return NULL;
	}
	if (info->pt_serv_buf_size)
		context->pt_serv_buf_size = info->pt_serv_buf_size;
	else
		context->pt_serv_buf_size = 4096;

	context->reject_service_keywords = info->reject_service_keywords;

	context->time_up = time(NULL);
#ifndef LWS_NO_DAEMONIZE
	if (pid_daemon) {
		context->started_with_parent = pid_daemon;
		lwsl_notice(" Started with daemon pid %d\n", pid_daemon);
	}
#endif
#if defined(__ANDROID__)
		n = getrlimit ( RLIMIT_NOFILE,&rt);
		if (-1 == n) {
			lwsl_err("Get RLIMIT_NOFILE failed!\n");
			return NULL;
		}
		context->max_fds = rt.rlim_cur;
#else
		context->max_fds = getdtablesize();
#endif

	if (info->count_threads)
		context->count_threads = info->count_threads;
	else
		context->count_threads = 1;

	if (context->count_threads > LWS_MAX_SMP)
		context->count_threads = LWS_MAX_SMP;

	context->token_limits = info->token_limits;

	context->options = info->options;

	if (info->timeout_secs)
		context->timeout_secs = info->timeout_secs;
	else
		context->timeout_secs = AWAITING_TIMEOUT;

	context->ws_ping_pong_interval = info->ws_ping_pong_interval;

	lwsl_info(" default timeout (secs): %u\n", context->timeout_secs);

	if (info->max_http_header_data)
		context->max_http_header_data = info->max_http_header_data;
	else
		if (info->max_http_header_data2)
			context->max_http_header_data =
					info->max_http_header_data2;
		else
			context->max_http_header_data = LWS_DEF_HEADER_LEN;
	if (info->max_http_header_pool)
		context->max_http_header_pool = info->max_http_header_pool;
	else
		context->max_http_header_pool = LWS_DEF_HEADER_POOL;

	/*
	 * Allocate the per-thread storage for scratchpad buffers,
	 * and header data pool
	 */
	for (n = 0; n < context->count_threads; n++) {
		context->pt[n].serv_buf = lws_zalloc(context->pt_serv_buf_size);
		if (!context->pt[n].serv_buf) {
			lwsl_err("OOM\n");
			return NULL;
		}

#ifdef LWS_USE_LIBUV
		context->pt[n].context = context;
#endif
		context->pt[n].tid = n;
		context->pt[n].http_header_data = lws_malloc(context->max_http_header_data *
						       context->max_http_header_pool);
		if (!context->pt[n].http_header_data)
			goto bail;

		context->pt[n].ah_pool = lws_zalloc(sizeof(struct allocated_headers) *
					      context->max_http_header_pool);
		for (m = 0; m < context->max_http_header_pool; m++)
			context->pt[n].ah_pool[m].data =
				(char *)context->pt[n].http_header_data +
				(m * context->max_http_header_data);
		if (!context->pt[n].ah_pool)
			goto bail;

		lws_pt_mutex_init(&context->pt[n]);
	}

	if (info->fd_limit_per_thread)
		context->fd_limit_per_thread = info->fd_limit_per_thread;
	else
		context->fd_limit_per_thread = context->max_fds /
					       context->count_threads;

	lwsl_notice(" Threads: %d each %d fds\n", context->count_threads,
		    context->fd_limit_per_thread);

	memset(&wsi, 0, sizeof(wsi));
	wsi.context = context;

	if (!info->ka_interval && info->ka_time > 0) {
		lwsl_err("info->ka_interval can't be 0 if ka_time used\n");
		return NULL;
	}

#ifdef LWS_USE_LIBEV
	/* (Issue #264) In order to *avoid breaking backwards compatibility*, we
	 * enable libev mediated SIGINT handling with a default handler of
	 * lws_sigint_cb. The handler can be overridden or disabled
	 * by invoking lws_sigint_cfg after creating the context, but
	 * before invoking lws_initloop:
	 */
	context->use_ev_sigint = 1;
	context->lws_ev_sigint_cb = &lws_ev_sigint_cb;
#endif /* LWS_USE_LIBEV */
#ifdef LWS_USE_LIBUV
	/* (Issue #264) In order to *avoid breaking backwards compatibility*, we
	 * enable libev mediated SIGINT handling with a default handler of
	 * lws_sigint_cb. The handler can be overridden or disabled
	 * by invoking lws_sigint_cfg after creating the context, but
	 * before invoking lws_initloop:
	 */
	context->use_ev_sigint = 1;
	context->lws_uv_sigint_cb = &lws_uv_sigint_cb;
#endif

	lwsl_info(" mem: context:         %5u bytes (%d ctx + (%d thr x %d))\n",
		  sizeof(struct lws_context) +
		  (context->count_threads * context->pt_serv_buf_size),
		  sizeof(struct lws_context),
		  context->count_threads,
		  context->pt_serv_buf_size);

	lwsl_info(" mem: http hdr rsvd:   %5u bytes (%u thr x (%u + %u) x %u))\n",
		    (context->max_http_header_data +
		     sizeof(struct allocated_headers)) *
		    context->max_http_header_pool * context->count_threads,
		    context->count_threads,
		    context->max_http_header_data,
		    sizeof(struct allocated_headers),
		    context->max_http_header_pool);
	n = sizeof(struct lws_pollfd) * context->count_threads *
	    context->fd_limit_per_thread;
	context->pt[0].fds = lws_zalloc(n);
	if (context->pt[0].fds == NULL) {
		lwsl_err("OOM allocating %d fds\n", context->max_fds);
		goto bail;
	}
	lwsl_info(" mem: pollfd map:      %5u\n", n);

	if (info->server_string) {
		context->server_string = info->server_string;
		context->server_string_len = (short)
				strlen(context->server_string);
	} else {
		context->server_string = "libwebsockets";
		context->server_string_len = 13;
	}

#if LWS_MAX_SMP > 1
	/* each thread serves his own chunk of fds */
	for (n = 1; n < (int)info->count_threads; n++)
		context->pt[n].fds = context->pt[n - 1].fds +
				     context->fd_limit_per_thread;
#endif

	if (lws_plat_init(context, info))
		goto bail;

	lws_context_init_ssl_library(info);

	context->user_space = info->user;

	/*
	 * if he's not saying he'll make his own vhosts later then act
	 * compatibly and make a default vhost using the data in the info
	 */
	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
		if (!lws_create_vhost(context, info)) {
			lwsl_err("Failed to create default vhost\n");
			return NULL;
		}

	lws_context_init_extensions(info, context);

	lwsl_notice(" mem: per-conn:        %5u bytes + protocol rx buf\n",
		    sizeof(struct lws));

	strcpy(context->canonical_hostname, "unknown");
	lws_server_get_canonical_hostname(context, info);

	context->uid = info->uid;
	context->gid = info->gid;

	/*
	 * drop any root privs for this process
	 * to listen on port < 1023 we would have needed root, but now we are
	 * listening, we don't want the power for anything else
	 */
	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
		lws_plat_drop_app_privileges(info);

	/*
	 * give all extensions a chance to create any per-context
	 * allocations they need
	 */
	if (info->port != CONTEXT_PORT_NO_LISTEN) {
		if (lws_ext_cb_all_exts(context, NULL,
			LWS_EXT_CB_SERVER_CONTEXT_CONSTRUCT, NULL, 0) < 0)
			goto bail;
	} else
		if (lws_ext_cb_all_exts(context, NULL,
			LWS_EXT_CB_CLIENT_CONTEXT_CONSTRUCT, NULL, 0) < 0)
			goto bail;

	return context;

bail:
	lws_context_destroy(context);
	return NULL;
}
예제 #9
0
/**
 * lws_context_destroy() - Destroy the websocket context
 * @context:	Websocket context
 *
 *	This function closes any active connections and then frees the
 *	context.  After calling this, any further use of the context is
 *	undefined.
 */
LWS_VISIBLE void
lws_context_destroy(struct lws_context *context)
{
	const struct lws_protocols *protocol = NULL;
	struct lws_context_per_thread *pt;
	struct lws wsi;
	int n, m;

	lwsl_notice("%s\n", __func__);

	if (!context)
		return;

	m = context->count_threads;
	context->being_destroyed = 1;

	memset(&wsi, 0, sizeof(wsi));
	wsi.context = context;

#ifdef LWS_LATENCY
	if (context->worst_latency_info[0])
		lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
#endif

	while (m--) {
		pt = &context->pt[m];

		for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
			struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
			if (!wsi)
				continue;

			lws_close_free_wsi(wsi,
				LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY
				/* no protocol close */);
			n--;
		}
	}
	/*
	 * give all extensions a chance to clean up any per-context
	 * allocations they might have made
	 */

	n = lws_ext_cb_all_exts(context, NULL,
				LWS_EXT_CB_SERVER_CONTEXT_DESTRUCT, NULL, 0);

	n = lws_ext_cb_all_exts(context, NULL,
				LWS_EXT_CB_CLIENT_CONTEXT_DESTRUCT, NULL, 0);

	/*
	 * inform all the protocols that they are done and will have no more
	 * callbacks
	 */
	protocol = context->protocols;
	if (protocol)
		while (protocol->callback) {
			protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
					   NULL, NULL, 0);
			protocol++;
		}

	for (n = 0; n < context->count_threads; n++) {
		pt = &context->pt[n];

		lws_libev_destroyloop(context, n);
		lws_libuv_destroyloop(context, n);

		lws_free_set_NULL(context->pt[n].serv_buf);
		if (pt->ah_pool)
			lws_free(pt->ah_pool);
		if (pt->http_header_data)
			lws_free(pt->http_header_data);
	}
	lws_plat_context_early_destroy(context);
	lws_ssl_context_destroy(context);
	if (context->pt[0].fds)
		lws_free_set_NULL(context->pt[0].fds);

	lws_plat_context_late_destroy(context);

	lws_free(context);
}