Пример #1
0
void
lws_libuv_io(struct lws *wsi, int flags)
{
	struct lws_context *context = lws_get_context(wsi);
	struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
	struct lws_io_watcher *w = &wsi->w_read;
//#if defined(WIN32) || defined(_WIN32)
//	int current_events = w->uv_watcher.events &
//			     (UV_READABLE | UV_WRITABLE);
//#else
	int current_events = w->actual_events & (UV_READABLE | UV_WRITABLE);
//#endif

	if (!LWS_LIBUV_ENABLED(context))
		return;

	// w->context is set after the loop is initialized

	if (!pt->io_loop_uv || !w->context) {
		lwsl_info("%s: no io loop yet\n", __func__);
		return;
	}

	if (!((flags & (LWS_EV_START | LWS_EV_STOP)) &&
	      (flags & (LWS_EV_READ | LWS_EV_WRITE)))) {
		lwsl_err("%s: assert: flags %d", __func__, flags);
		assert(0);
	}

	if (flags & LWS_EV_START) {
		if (flags & LWS_EV_WRITE)
			current_events |= UV_WRITABLE;

		if (flags & LWS_EV_READ)
			current_events |= UV_READABLE;

		uv_poll_start(&w->uv_watcher, current_events, lws_io_cb);
	} else {
		if (flags & LWS_EV_WRITE)
			current_events &= ~UV_WRITABLE;

		if (flags & LWS_EV_READ)
			current_events &= ~UV_READABLE;

		if (!(current_events & (UV_READABLE | UV_WRITABLE)))
			uv_poll_stop(&w->uv_watcher);
		else
			uv_poll_start(&w->uv_watcher, current_events,
				      lws_io_cb);
	}

	w->actual_events = current_events;
}
Пример #2
0
void lws_set_protocol_write_pending(struct libwebsocket_context *context,
				    struct libwebsocket *wsi,
				    enum lws_pending_protocol_send pend)
{
	lwsl_info("setting pps %d\n", pend);
	
	if (wsi->pps)
		lwsl_err("pps overwrite\n");
	wsi->pps = pend;
	libwebsocket_rx_flow_control(wsi, 0);
	libwebsocket_callback_on_writable(context, wsi);
}
Пример #3
0
static void
elops_io_uv(struct lws *wsi, int flags)
{
	struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
	struct lws_io_watcher *w = &wsi->w_read;
	int current_events = w->actual_events & (UV_READABLE | UV_WRITABLE);

	lwsl_debug("%s: %p: %d\n", __func__, wsi, flags);

	/* w->context is set after the loop is initialized */

	if (!pt->uv.io_loop || !w->context) {
		lwsl_info("%s: no io loop yet\n", __func__);
		return;
	}

	if (!((flags & (LWS_EV_START | LWS_EV_STOP)) &&
	      (flags & (LWS_EV_READ | LWS_EV_WRITE)))) {
		lwsl_err("%s: assert: flags %d", __func__, flags);
		assert(0);
	}

	if (!w->uv.pwatcher || wsi->told_event_loop_closed) {
		lwsl_err("%s: no watcher\n", __func__);

		return;
	}

	if (flags & LWS_EV_START) {
		if (flags & LWS_EV_WRITE)
			current_events |= UV_WRITABLE;

		if (flags & LWS_EV_READ)
			current_events |= UV_READABLE;

		uv_poll_start(w->uv.pwatcher, current_events, lws_io_cb);
	} else {
		if (flags & LWS_EV_WRITE)
			current_events &= ~UV_WRITABLE;

		if (flags & LWS_EV_READ)
			current_events &= ~UV_READABLE;

		if (!(current_events & (UV_READABLE | UV_WRITABLE)))
			uv_poll_stop(w->uv.pwatcher);
		else
			uv_poll_start(w->uv.pwatcher, current_events,
				      lws_io_cb);
	}

	w->actual_events = current_events;
}
Пример #4
0
void
lws_libuv_io(struct lws *wsi, int flags)
{
	struct lws_context *context = lws_get_context(wsi);
	struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
#if defined(WIN32) || defined(_WIN32)
	int current_events = wsi->w_read.uv_watcher.events &
			     (UV_READABLE | UV_WRITABLE);
#else
	int current_events = wsi->w_read.uv_watcher.io_watcher.pevents &
			     (UV_READABLE | UV_WRITABLE);
#endif
	struct lws_io_watcher *w = &wsi->w_read;

	if (!LWS_LIBUV_ENABLED(context))
		return;

	// lwsl_notice("%s: wsi: %p, flags:0x%x\n", __func__, wsi, flags);

	if (!pt->io_loop_uv) {
		lwsl_info("%s: no io loop yet\n", __func__);
		return;
	}

	if (!((flags & (LWS_EV_START | LWS_EV_STOP)) &&
	      (flags & (LWS_EV_READ | LWS_EV_WRITE)))) {
		lwsl_err("%s: assert: flags %d", __func__, flags);
		assert(0);
	}

	if (flags & LWS_EV_START) {
		if (flags & LWS_EV_WRITE)
			current_events |= UV_WRITABLE;

		if (flags & LWS_EV_READ)
			current_events |= UV_READABLE;

		uv_poll_start(&w->uv_watcher, current_events, lws_io_cb);
	} else {
		if (flags & LWS_EV_WRITE)
			current_events &= ~UV_WRITABLE;

		if (flags & LWS_EV_READ)
			current_events &= ~UV_READABLE;

		if (!(current_events & (UV_READABLE | UV_WRITABLE)))
			uv_poll_stop(&w->uv_watcher);
		else
			uv_poll_start(&w->uv_watcher, current_events,
				      lws_io_cb);
	}
}
Пример #5
0
int LWS_WARN_UNUSED_RESULT
lws_http_transaction_completed_client(struct lws *wsi)
{
	lwsl_debug("%s: wsi %p\n", __func__, wsi);
	/* if we can't go back to accept new headers, drop the connection */
	if (wsi->u.http.connection_type != HTTP_CONNECTION_KEEP_ALIVE) {
		lwsl_info("%s: %p: close connection\n", __func__, wsi);
		return 1;
	}

	/* we don't support chained client connections yet */
	return 1;
#if 0
	/* otherwise set ourselves up ready to go again */
	wsi->state = LWSS_CLIENT_HTTP_ESTABLISHED;
	wsi->mode = LWSCM_HTTP_CLIENT_ACCEPTED;
	wsi->u.http.content_length = 0;
	wsi->hdr_parsing_completed = 0;

	/* He asked for it to stay alive indefinitely */
	lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);

	/*
	 * As client, nothing new is going to come until we ask for it
	 * we can drop the ah, if any
	 */
	if (wsi->u.hdr.ah) {
		lws_header_table_force_to_detachable_state(wsi);
		lws_header_table_detach(wsi, 0);
	}

	/* If we're (re)starting on headers, need other implied init */
	wsi->u.hdr.ues = URIES_IDLE;

	lwsl_info("%s: %p: keep-alive await new transaction\n", __func__, wsi);

	return 0;
#endif
}
Пример #6
0
int
libwebsocket_ensure_user_space(struct libwebsocket *wsi)
{
	lwsl_info("%s: %p protocol %p\n", __func__, wsi, wsi->protocol);
	if (!wsi->protocol)
		return 1;

	/* allocate the per-connection user memory (if any) */

	if (wsi->protocol->per_session_data_size && !wsi->user_space) {
		wsi->user_space = malloc(
				  wsi->protocol->per_session_data_size);
		if (wsi->user_space  == NULL) {
			lwsl_err("Out of memory for conn user space\n");
			return 1;
		}
		memset(wsi->user_space, 0,
					 wsi->protocol->per_session_data_size);
	} else
		lwsl_info("%s: %p protocol pss %u, user_space=%d\n", __func__, wsi, wsi->protocol->per_session_data_size, wsi->user_space);
	return 0;
}
Пример #7
0
static int
lws_gate_accepts(struct lws_context *context, int on)
{
	struct lws_vhost *v = context->vhost_list;

	lwsl_info("gating accepts %d\n", on);
	context->ssl_gate_accepts = !on;
#if defined(LWS_WITH_STATS)
	context->updated = 1;
#endif

	while (v) {
		if (v->use_ssl &&  v->lserv_wsi) /* gate ability to accept incoming connections */
			if (lws_change_pollfd(v->lserv_wsi, (LWS_POLLIN) * !on,
					      (LWS_POLLIN) * on))
				lwsl_info("Unable to set accept POLLIN %d\n", on);

		v = v->vhost_next;
	}

	return 0;
}
Пример #8
0
static struct lws_urldecode_stateful *
lws_urldecode_s_create(struct lws *wsi, char *out, int out_len, void *data,
		       lws_urldecode_stateful_cb output)
{
	struct lws_urldecode_stateful *s = lws_zalloc(sizeof(*s),
						"stateful urldecode");
	char buf[200], *p;
	int m = 0;

	if (!s)
		return NULL;

	s->out = out;
	s->out_len  = out_len;
	s->output = output;
	s->pos = 0;
	s->sum = 0;
	s->mp = 0;
	s->state = US_NAME;
	s->name[0] = '\0';
	s->data = data;
	s->wsi = wsi;

	if (lws_hdr_copy(wsi, buf, sizeof(buf),
			 WSI_TOKEN_HTTP_CONTENT_TYPE) > 0) {
	/* multipart/form-data; boundary=----WebKitFormBoundarycc7YgAPEIHvgE9Bf */

		if (!strncmp(buf, "multipart/form-data", 19)) {
			s->multipart_form_data = 1;
			s->state = MT_LOOK_BOUND_IN;
			s->mp = 2;
			p = strstr(buf, "boundary=");
			if (p) {
				p += 9;
				s->mime_boundary[m++] = '\x0d';
				s->mime_boundary[m++] = '\x0a';
				s->mime_boundary[m++] = '-';
				s->mime_boundary[m++] = '-';
				while (m < (int)sizeof(s->mime_boundary) - 1 &&
				       *p && *p != ' ')
					s->mime_boundary[m++] = *p++;

				s->mime_boundary[m] = '\0';

				lwsl_info("boundary '%s'\n", s->mime_boundary);
			}
		}
	}

	return s;
}
Пример #9
0
static void
lws_uv_close_cb_sa(uv_handle_t *handle)
{
	struct lws_context *context =
			LWS_UV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(handle);
	int n;

	lwsl_info("%s: sa left %d: dyn left: %d\n", __func__,
		    context->count_event_loop_static_asset_handles,
		    context->count_wsi_allocated);

	/* any static assets left? */

	if (LWS_UV_REFCOUNT_STATIC_HANDLE_DESTROYED(handle) ||
	    context->count_wsi_allocated)
		return;

	/*
	 * That's it... all wsi were down, and now every
	 * static asset lws had a UV handle for is down.
	 *
	 * Stop the loop so we can get out of here.
	 */

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

		if (pt->uv.io_loop && !pt->event_loop_foreign)
			uv_stop(pt->uv.io_loop);
	}

	if (!context->pt[0].event_loop_foreign) {
		lwsl_info("%s: calling lws_context_destroy2\n", __func__);
		lws_context_destroy2(context);
	}

	lwsl_info("%s: all done\n", __func__);
}
Пример #10
0
static int ws_def_callback(struct libwebsocket_context *context,
						   struct libwebsocket *wsi,
						   enum libwebsocket_callback_reasons reason, void *user,
						   void *in, size_t len)
{
	switch (reason) {
		
		case LWS_CALLBACK_CLIENT_ESTABLISHED:
			lwsl_info("dumb: LWS_CALLBACK_CLIENT_ESTABLISHED\n");
			break;
			
		case LWS_CALLBACK_CLOSED:
			lwsl_notice("dumb: LWS_CALLBACK_CLOSED\n");
			wsi_cl = NULL;force_exit=1;
			break;
			
		case LWS_CALLBACK_CLIENT_RECEIVE:
			((char *)in)[len] = '\0';
			lwsl_info("rx %d '%s'\n", (int)len, (char *)in);
			break;
			
			/* because we are protocols[0] ... */
			
			case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
				if (wsi == wsi_cl) {
					lwsl_err("dumb: LWS_CALLBACK_CLIENT_CONNECTION_ERROR\n");
					wsi_cl = NULL;
				}
				break;
				
			
				
			default:
				break;
	}
	
	return 0;
}
Пример #11
0
void
lws_ssl_elaborate_error(void)
{
#if defined(LWS_WITH_MBEDTLS)
#else
	char buf[256];
	u_long err;

	while ((err = ERR_get_error()) != 0) {
		ERR_error_string_n(err, buf, sizeof(buf));
		lwsl_info("*** %s\n", buf);
	}
#endif
}
Пример #12
0
static int
esp8266_find_free_conn(struct lws_context *context)
{
	int n;

	for (n = 0; n < context->max_fds; n++)
		if (!context->connpool[n]) {
			lwsl_info(" using connpool %d\n", n);
			return n;
		}

	lwsl_err("%s: no free conns\n", __func__);

	return -1;
}
Пример #13
0
int
_libwebsocket_rx_flow_control(struct libwebsocket *wsi)
{
	struct libwebsocket_context *context = wsi->protocol->owning_server;

	/* there is no pending change */
	if (!(wsi->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE))
		return 0;

	/* stuff is still buffered, not ready to really accept new input */
	if (wsi->rxflow_buffer) {
		/* get ourselves called back to deal with stashed buffer */
		libwebsocket_callback_on_writable(context, wsi);
		return 0;
	}

	/* pending is cleared, we can change rxflow state */

	wsi->rxflow_change_to &= ~LWS_RXFLOW_PENDING_CHANGE;

	lwsl_info("rxflow: wsi %p change_to %d\n", wsi,
			      wsi->rxflow_change_to & LWS_RXFLOW_ALLOW);

	/* adjust the pollfd for this wsi */

	if (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW) {
		if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
			lwsl_info("%s: fail\n", __func__);
			return -1;
		}
	} else
		if (lws_change_pollfd(wsi, LWS_POLLIN, 0))
			return -1;

	return 0;
}
Пример #14
0
/*
 * This does not actually stop the event loop.  The reason is we have to pass
 * libuv handle closures through its event loop.  So this tries to close all
 * wsi, and set a flag; when all the wsi closures are finalized then we
 * actually stop the libuv event loops.
 */
static void
lws_libuv_stop(struct lws_context *context)
{
	struct lws_context_per_thread *pt;
	int n, m;

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

	if (context->requested_kill) {
		lwsl_err("%s: ignoring\n", __func__);
		return;
	}

	context->requested_kill = 1;

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

	/*
	 * Phase 1: start the close of every dynamic uv handle
	 */

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

		if (pt->pipe_wsi) {
			uv_poll_stop(pt->pipe_wsi->w_read.uv.pwatcher);
			lws_destroy_event_pipe(pt->pipe_wsi);
			pt->pipe_wsi = NULL;
		}

		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,
				__func__ /* no protocol close */);
			n--;
		}
	}

	lwsl_info("%s: started closing all wsi\n", __func__);

	/* we cannot have completed... there are at least the cancel pipes */
}
Пример #15
0
struct lws *
lws_create_server_child_wsi(struct lws_vhost *vhost, struct lws *parent_wsi,
			    unsigned int sid)
{
	struct lws *wsi = lws_create_new_server_wsi(vhost);

	if (!wsi)
		return NULL;

	/* no more children allowed by parent */
	if (parent_wsi->u.http2.child_count + 1 ==
	    parent_wsi->u.http2.peer_settings.setting[
			LWS_HTTP2_SETTINGS__MAX_CONCURRENT_STREAMS])
		goto bail;
	lws_http2_init(&wsi->u.http2.peer_settings);
	lws_http2_init(&wsi->u.http2.my_settings);
	wsi->u.http2.stream_id = sid;
	wsi->u.http2.my_stream_id = sid;

	wsi->u.http2.parent_wsi = parent_wsi;
	wsi->u.http2.next_child_wsi = parent_wsi->u.http2.next_child_wsi;
	parent_wsi->u.http2.next_child_wsi = wsi;
	parent_wsi->u.http2.child_count++;

	wsi->u.http2.my_priority = 16;
	wsi->u.http2.tx_credit = 65535;

	wsi->state = LWSS_HTTP2_ESTABLISHED;
	wsi->mode = parent_wsi->mode;

	wsi->protocol = &vhost->protocols[0];
	if (lws_ensure_user_space(wsi))
		goto bail;

	lwsl_info("%s: %p new child %p, sid %d, user_space=%p\n", __func__,
		  parent_wsi, wsi, sid, wsi->user_space);

	return wsi;

bail:
	vhost->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY,
			       NULL, NULL, 0);
	lws_free(wsi);

	return NULL;
}
Пример #16
0
int
insert_wsi_socket_into_fds(struct libwebsocket_context *context,
						       struct libwebsocket *wsi)
{
	struct libwebsocket_pollargs pa = { wsi->sock, LWS_POLLIN, 0 };

	if (context->fds_count >= context->max_fds) {
		lwsl_err("Too many fds (%d)\n", context->max_fds);
		return 1;
	}

	if (wsi->sock >= context->max_fds) {
		lwsl_err("Socket fd %d is too high (%d)\n",
						wsi->sock, context->max_fds);
		return 1;
	}

	assert(wsi);
	assert(wsi->sock >= 0);

	lwsl_info("insert_wsi_socket_into_fds: wsi=%p, sock=%d, fds pos=%d\n",
					    wsi, wsi->sock, context->fds_count);

	context->protocols[0].callback(context, wsi,
		LWS_CALLBACK_LOCK_POLL,
		wsi->user_space, (void *) &pa, 0);

	context->lws_lookup[wsi->sock] = wsi;
	wsi->position_in_fds_table = context->fds_count;
	context->fds[context->fds_count].fd = wsi->sock;
	context->fds[context->fds_count].events = LWS_POLLIN;
	
	lws_plat_insert_socket_into_fds(context, wsi);

	/* external POLL support via protocol 0 */
	context->protocols[0].callback(context, wsi,
		LWS_CALLBACK_ADD_POLL_FD,
		wsi->user_space, (void *) &pa, 0);

	context->protocols[0].callback(context, wsi,
		LWS_CALLBACK_UNLOCK_POLL,
		wsi->user_space, (void *)&pa, 0);

	return 0;
}
Пример #17
0
static int
lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)
{
	struct lws_context *context;
	struct lws_vhost *vhost, *vh;
	const char *servername;
	int port;

	if (!ssl)
		return SSL_TLSEXT_ERR_NOACK;

	context = (struct lws_context *)SSL_CTX_get_ex_data(
					SSL_get_SSL_CTX(ssl),
					openssl_SSL_CTX_private_data_index);

	/*
	 * We can only get ssl accepted connections by using a vhost's ssl_ctx
	 * find out which listening one took us and only match vhosts on the
	 * same port.
	 */
	vh = context->vhost_list;
	while (vh) {
		if (vh->ssl_ctx == SSL_get_SSL_CTX(ssl))
			break;
		vh = vh->vhost_next;
	}

	assert(vh); /* we cannot get an ssl without using a vhost ssl_ctx */
	port = vh->listen_port;

	servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);

	if (servername) {
		vhost = lws_select_vhost(context, port, servername);
		if (vhost) {
			lwsl_info("SNI: Found: %s\n", servername);
			SSL_set_SSL_CTX(ssl, vhost->ssl_ctx);
			return SSL_TLSEXT_ERR_OK;
		}
		lwsl_err("SNI: Unknown ServerName: %s\n", servername);
	}

	return SSL_TLSEXT_ERR_OK;
}
Пример #18
0
void
lws_libuv_io(struct lws *wsi, int flags)
{
	struct lws_context *context = lws_get_context(wsi);
	struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
	int current_events = wsi->w_read.uv_watcher.io_watcher.pevents &
			     (UV_READABLE | UV_WRITABLE);
	struct lws_io_watcher *w = &wsi->w_read;

	if (!LWS_LIBUV_ENABLED(context))
		return;

	lwsl_debug("%s: wsi: %p, flags:%d\n", __func__, wsi, flags);

	if (!pt->io_loop_uv) {
		lwsl_info("%s: no io loop yet\n", __func__);
		return;
	}

	assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
	       (flags & (LWS_EV_READ | LWS_EV_WRITE)));

	if (flags & LWS_EV_START) {
		if (flags & LWS_EV_WRITE)
			current_events |= UV_WRITABLE;

		if (flags & LWS_EV_READ)
			current_events |= UV_READABLE;

		uv_poll_start(&w->uv_watcher, current_events, lws_accept_cb);
	} else {
		if (flags & LWS_EV_WRITE)
			current_events &= ~UV_WRITABLE;

		if (flags & LWS_EV_READ)
			current_events &= ~UV_READABLE;

		if (!(current_events & (UV_READABLE | UV_WRITABLE)))
			uv_poll_stop(&w->uv_watcher);
		else
			uv_poll_start(&w->uv_watcher, current_events,
				      lws_accept_cb);
	}
}
Пример #19
0
int
lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, int ebuf_len)
{
	int n;
	X509 *peer = SSL_get_peer_certificate(wsi->tls.ssl);
	struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
	char *sb = (char *)&pt->serv_buf[0];

	if (!peer) {
		lwsl_info("peer did not provide cert\n");

		return -1;
	}
	lwsl_info("peer provided cert\n");

	n = SSL_get_verify_result(wsi->tls.ssl);
	lws_latency(wsi->context, wsi,
			"SSL_get_verify_result LWS_CONNMODE..HANDSHAKE", n, n > 0);

        lwsl_debug("get_verify says %d\n", n);

	if (n == X509_V_OK)
		return 0;

	if (n == X509_V_ERR_HOSTNAME_MISMATCH &&
	    (wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
		lwsl_info("accepting certificate for invalid hostname\n");
		return 0;
	}

	if (n == X509_V_ERR_INVALID_CA &&
	    (wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED)) {
		lwsl_info("accepting certificate from untrusted CA\n");
		return 0;
	}

	if ((n == X509_V_ERR_CERT_NOT_YET_VALID ||
	     n == X509_V_ERR_CERT_HAS_EXPIRED) &&
	     (wsi->tls.use_ssl & LCCSCF_ALLOW_EXPIRED)) {
		lwsl_info("accepting expired or not yet valid certificate\n");

		return 0;
	}
	lws_snprintf(ebuf, ebuf_len,
		"server's cert didn't look good, X509_V_ERR = %d: %s\n",
		 n, ERR_error_string(n, sb));
	lwsl_info("%s\n", ebuf);
	lws_ssl_elaborate_error();

	return -1;
}
Пример #20
0
int lws_add_http_header_content_length(struct lws *wsi,
				       lws_filepos_t content_length,
				       unsigned char **p, unsigned char *end)
{
	char b[24];
	int n;

	n = sprintf(b, "%llu", (unsigned long long)content_length);
	if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
					 (unsigned char *)b, n, p, end))
		return 1;
	wsi->http.tx_content_length = content_length;
	wsi->http.tx_content_remain = content_length;

	lwsl_info("%s: wsi %p: tx_content_length/remain %llu\n", __func__,
			wsi, (unsigned long long)content_length);

	return 0;
}
Пример #21
0
static void
elops_destroy_pt_uv(struct lws_context *context, int tsi)
{
	struct lws_context_per_thread *pt = &context->pt[tsi];
	int m, ns;

	lwsl_info("%s: %d\n", __func__, tsi);

	if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
		return;

	if (!pt->uv.io_loop)
		return;

	if (pt->event_loop_destroy_processing_done)
		return;

	pt->event_loop_destroy_processing_done = 1;

	if (!pt->event_loop_foreign) {
		uv_signal_stop(&pt->w_sigint.uv.watcher);

		ns = LWS_ARRAY_SIZE(sigs);
		if (lws_check_opt(context->options,
				  LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN))
			ns = 2;

		for (m = 0; m < ns; m++) {
			uv_signal_stop(&pt->uv.signals[m]);
			uv_close((uv_handle_t *)&pt->uv.signals[m],
				 lws_uv_close_cb_sa);
		}
	} else
		lwsl_debug("%s: not closing pt signals\n", __func__);

	uv_timer_stop(&pt->uv.timeout_watcher);
	uv_close((uv_handle_t *)&pt->uv.timeout_watcher, lws_uv_close_cb_sa);
	uv_timer_stop(&pt->uv.hrtimer);
	uv_close((uv_handle_t *)&pt->uv.hrtimer, lws_uv_close_cb_sa);

	uv_idle_stop(&pt->uv.idle);
	uv_close((uv_handle_t *)&pt->uv.idle, lws_uv_close_cb_sa);
}
Пример #22
0
int
lws_context_init_ssl_library(struct lws_context_creation_info *info)
{
#ifdef USE_WOLFSSL
#ifdef USE_OLD_CYASSL
	lwsl_info(" Compiled with CyaSSL support\n");
#else
	lwsl_info(" Compiled with wolfSSL support\n");
#endif
#else
#if defined(LWS_WITH_BORINGSSL)
	lwsl_info(" Compiled with BoringSSL support\n");
#else
#if defined(LWS_WITH_MBEDTLS)
	lwsl_info(" Compiled with MbedTLS support\n");
#else
	lwsl_info(" Compiled with OpenSSL support\n");
#endif
#endif
#endif
	if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
		lwsl_info(" SSL disabled: no LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT\n");
		return 0;
	}

	/* basic openssl init */

	lwsl_info("Doing SSL library init\n");

#if !defined(LWS_WITH_MBEDTLS)
	SSL_library_init();
	OpenSSL_add_all_algorithms();
	SSL_load_error_strings();

	openssl_websocket_private_data_index =
		SSL_get_ex_new_index(0, "lws", NULL, NULL, NULL);

	openssl_SSL_CTX_private_data_index = SSL_CTX_get_ex_new_index(0,
			NULL, NULL, NULL, NULL);
#endif

	return 0;
}
Пример #23
0
static void
esp8266_cb_disconnected(void *arg)
{
	struct espconn *conn = arg;
	struct lws *wsi = conn->reverse;
	int n;

	lwsl_notice("%s: %p\n", __func__, wsi);

	for (n = 0; n < hacky_context->max_fds; n++)
		if (hacky_context->connpool[n] == arg) {
			hacky_context->connpool[n] = NULL;
			lwsl_info(" freed connpool %d\n", n);
		}

	if (wsi) {
		conn->reverse = NULL;
		lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
		lwsl_notice("closed ok\n");
	}
}
Пример #24
0
static int
lws_calllback_as_writeable(struct libwebsocket_context *context,
		   struct libwebsocket *wsi)
{
	int n;

	switch (wsi->mode) {
	case LWS_CONNMODE_WS_CLIENT:
		n = LWS_CALLBACK_CLIENT_WRITEABLE;
		break;
	case LWS_CONNMODE_WS_SERVING:
		n = LWS_CALLBACK_SERVER_WRITEABLE;
		break;
	default:
		n = LWS_CALLBACK_HTTP_WRITEABLE;
		break;
	}
	lwsl_info("%s: %p (user=%p)\n", __func__, wsi, wsi->user_space);
	return user_callback_handle_rxflow(wsi->protocol->callback, context,
			wsi, (enum libwebsocket_callback_reasons) n,
						      wsi->user_space, NULL, 0);
}
Пример #25
0
struct lws *
lws_create_server_child_wsi(struct lws_context *context, struct lws *parent_wsi,
			    unsigned int sid)
{
	struct lws *wsi = lws_create_new_server_wsi(context);
	
	if (!wsi)
		return NULL;
	
	/* no more children allowed by parent */
	if (parent_wsi->u.http2.child_count + 1 ==
	    parent_wsi->u.http2.peer_settings.setting[
			LWS_HTTP2_SETTINGS__MAX_CONCURRENT_STREAMS])
		return NULL;
	
	lws_http2_init(&wsi->u.http2.peer_settings);
	lws_http2_init(&wsi->u.http2.my_settings);
	wsi->u.http2.stream_id = sid;
	wsi->u.http2.my_stream_id = sid;

	wsi->u.http2.parent_wsi = parent_wsi;
	wsi->u.http2.next_child_wsi = parent_wsi->u.http2.next_child_wsi;
	parent_wsi->u.http2.next_child_wsi = wsi;
	parent_wsi->u.http2.child_count++;
	
	wsi->u.http2.my_priority = 16;
	wsi->u.http2.tx_credit = 65535;
	
	wsi->state = WSI_STATE_HTTP2_ESTABLISHED;
	wsi->mode = parent_wsi->mode;
	
	wsi->protocol = &context->protocols[0];
	lws_ensure_user_space(wsi);

	lwsl_info("%s: %p new child %p, sid %d, user_space=%p\n", __func__,
		  parent_wsi, wsi, sid, wsi->user_space);
	
	return wsi;
}
Пример #26
0
void
lws_context_init_alpn(struct lws_vhost *vhost)
{
#if defined(LWS_WITH_MBEDTLS) || (defined(OPENSSL_VERSION_NUMBER) && \
				  OPENSSL_VERSION_NUMBER >= 0x10002000L)
	const char *alpn_comma = vhost->context->tls.alpn_default;

	if (vhost->tls.alpn)
		alpn_comma = vhost->tls.alpn;

	lwsl_info(" Server '%s' advertising ALPN: %s\n",
		    vhost->name, alpn_comma);
	vhost->tls.alpn_ctx.len = lws_alpn_comma_to_openssl(alpn_comma,
					vhost->tls.alpn_ctx.data,
					sizeof(vhost->tls.alpn_ctx.data) - 1);

	SSL_CTX_set_alpn_select_cb(vhost->tls.ssl_ctx, alpn_cb, &vhost->tls.alpn_ctx);
#else
	lwsl_err(
		" HTTP2 / ALPN configured but not supported by OpenSSL 0x%lx\n",
		    OPENSSL_VERSION_NUMBER);
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
}
Пример #27
0
static int
stream_close(struct lws *wsi)
{
	char buf[LWS_PRE + 6], *out = buf + LWS_PRE;

	if (wsi->http.did_stream_close)
		return 0;

	wsi->http.did_stream_close = 1;

	if (wsi->http2_substream) {
		if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0,
			      LWS_WRITE_HTTP_FINAL) < 0) {
			lwsl_info("%s: COMPL_CLIENT_HTTP: h2 fin wr failed\n",
				  __func__);

			return -1;
		}
	} else {
		*out++ = '0';
		*out++ = '\x0d';
		*out++ = '\x0a';
		*out++ = '\x0d';
		*out++ = '\x0a';

		if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 5,
			      LWS_WRITE_HTTP_FINAL) < 0) {
			lwsl_err("%s: COMPL_CLIENT_HTTP: "
				 "h2 final write failed\n", __func__);

			return -1;
		}
	}

	return 0;
}
Пример #28
0
int lws_http2_frame_write(struct lws *wsi, int type, int flags,
			  unsigned int sid, unsigned int len, unsigned char *buf)
{
	struct lws *wsi_eff = lws_http2_get_network_wsi(wsi);
	unsigned char *p = &buf[-LWS_HTTP2_FRAME_HEADER_LENGTH];
	int n;

	*p++ = len >> 16;
	*p++ = len >> 8;
	*p++ = len;
	*p++ = type;
	*p++ = flags;
	*p++ = sid >> 24;
	*p++ = sid >> 16;
	*p++ = sid >> 8;
	*p++ = sid;

	lwsl_info("%s: %p (eff %p). type %d, flags 0x%x, sid=%d, len=%d\n",
		  __func__, wsi, wsi_eff, type, flags, sid, len,
		  wsi->u.http2.tx_credit);

	if (type == LWS_HTTP2_FRAME_TYPE_DATA) {
		if (wsi->u.http2.tx_credit < len)
			lwsl_err("%s: %p: sending payload len %d"
				 " but tx_credit only %d!\n", len,
				 wsi->u.http2.tx_credit);
		wsi->u.http2.tx_credit -= len;
	}

	n = lws_issue_raw(wsi_eff, &buf[-LWS_HTTP2_FRAME_HEADER_LENGTH],
			  len + LWS_HTTP2_FRAME_HEADER_LENGTH);
	if (n >= LWS_HTTP2_FRAME_HEADER_LENGTH)
		return n - LWS_HTTP2_FRAME_HEADER_LENGTH;

	return n;
}
Пример #29
0
static int
lwsws_get_config(void *user, const char *f, const char * const *paths,
		 int count_paths, lejp_callback cb)
{
	unsigned char buf[128];
	struct lejp_ctx ctx;
	int n, m, fd;

	fd = open(f, O_RDONLY);
	if (fd < 0) {
		lwsl_err("Cannot open %s\n", f);
		return 2;
	}
	lwsl_info("%s: %s\n", __func__, f);
	lejp_construct(&ctx, cb, user, paths, count_paths);

	do {
		n = read(fd, buf, sizeof(buf));
		if (!n)
			break;

		m = (int)(signed char)lejp_parse(&ctx, buf, n);
	} while (m == LEJP_CONTINUE);

	close(fd);
	n = ctx.line;
	lejp_destruct(&ctx);

	if (m < 0) {
		lwsl_err("%s(%u): parsing error %d: %s\n", f, n, m,
			 parser_errs[-m]);
		return 2;
	}

	return 0;
}
Пример #30
0
int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
		  void *in, size_t len)
{
	struct per_session_data__http *pss =
			(struct per_session_data__http *)user;
	unsigned char buffer[4096 + LWS_PRE];
	unsigned long amount, file_len, sent;
	char leaf_path[1024];
	const char *mimetype;
	char *other_headers;
	unsigned char *end;
	struct timeval tv;
	unsigned char *p;
	char buf[256];
	char b64[64];
	int n, m;

#ifdef EXTERNAL_POLL
	struct lws_pollargs *pa = (struct lws_pollargs *)in;
#endif

	switch (reason) {
	case LWS_CALLBACK_HTTP:

		if (debug_level & LLL_INFO) {
			dump_handshake_info(wsi);

			/* dump the individual URI Arg parameters */
			n = 0;
			while (lws_hdr_copy_fragment(wsi, buf, sizeof(buf),
						     WSI_TOKEN_HTTP_URI_ARGS, n) > 0) {
				lwsl_notice("URI Arg %d: %s\n", ++n, buf);
			}
		}

		{
			char name[100], rip[50];
			lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name,
					       sizeof(name), rip, sizeof(rip));
			sprintf(buf, "%s (%s)", name, rip);
			lwsl_notice("HTTP connect from %s\n", buf);
		}

		if (len < 1) {
			lws_return_http_status(wsi,
						HTTP_STATUS_BAD_REQUEST, NULL);
			goto try_to_reuse;
		}

		/* this example server has no concept of directories */
		if (strchr((const char *)in + 1, '/')) {
			lws_return_http_status(wsi, HTTP_STATUS_FORBIDDEN, NULL);
			goto try_to_reuse;
		}

		/* if a legal POST URL, let it continue and accept data */
		if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
			return 0;

		/* check for the "send a big file by hand" example case */

		if (!strcmp((const char *)in, "/leaf.jpg")) {
			if (strlen(resource_path) > sizeof(leaf_path) - 10)
				return -1;
			sprintf(leaf_path, "%s/leaf.jpg", resource_path);

			/* well, let's demonstrate how to send the hard way */

			p = buffer + LWS_PRE;
			end = p + sizeof(buffer) - LWS_PRE;

			pss->fd = lws_plat_file_open(wsi, leaf_path, &file_len,
						     LWS_O_RDONLY);

			if (pss->fd == LWS_INVALID_FILE) {
				lwsl_err("faild to open file %s\n", leaf_path);
				return -1;
			}

			/*
			 * we will send a big jpeg file, but it could be
			 * anything.  Set the Content-Type: appropriately
			 * so the browser knows what to do with it.
			 *
			 * Notice we use the APIs to build the header, which
			 * will do the right thing for HTTP 1/1.1 and HTTP2
			 * depending on what connection it happens to be working
			 * on
			 */
			if (lws_add_http_header_status(wsi, 200, &p, end))
				return 1;
			if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
				    	(unsigned char *)"libwebsockets",
					13, &p, end))
				return 1;
			if (lws_add_http_header_by_token(wsi,
					WSI_TOKEN_HTTP_CONTENT_TYPE,
				    	(unsigned char *)"image/jpeg",
					10, &p, end))
				return 1;
			if (lws_add_http_header_content_length(wsi,
							       file_len, &p,
							       end))
				return 1;
			if (lws_finalize_http_header(wsi, &p, end))
				return 1;

			/*
			 * send the http headers...
			 * this won't block since it's the first payload sent
			 * on the connection since it was established
			 * (too small for partial)
			 *
			 * Notice they are sent using LWS_WRITE_HTTP_HEADERS
			 * which also means you can't send body too in one step,
			 * this is mandated by changes in HTTP2
			 */

			*p = '\0';
			lwsl_info("%s\n", buffer + LWS_PRE);

			n = lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE),
				      LWS_WRITE_HTTP_HEADERS);
			if (n < 0) {
				lws_plat_file_close(wsi, pss->fd);
				return -1;
			}
			/*
			 * book us a LWS_CALLBACK_HTTP_WRITEABLE callback
			 */
			lws_callback_on_writable(wsi);
			break;
		}

		/* if not, send a file the easy way */
		strcpy(buf, resource_path);
		if (strcmp(in, "/")) {
			if (*((const char *)in) != '/')
				strcat(buf, "/");
			strncat(buf, in, sizeof(buf) - strlen(resource_path));
		} else /* default file to serve */
			strcat(buf, "/test.html");
		buf[sizeof(buf) - 1] = '\0';

		/* refuse to serve files we don't understand */
		mimetype = get_mimetype(buf);
		if (!mimetype) {
			lwsl_err("Unknown mimetype for %s\n", buf);
			lws_return_http_status(wsi,
				      HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL);
			return -1;
		}

		/* demonstrates how to set a cookie on / */

		other_headers = leaf_path;
		p = (unsigned char *)leaf_path;
		if (!strcmp((const char *)in, "/") &&
			   !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) {
			/* this isn't very unguessable but it'll do for us */
			gettimeofday(&tv, NULL);
			n = sprintf(b64, "test=LWS_%u_%u_COOKIE;Max-Age=360000",
				(unsigned int)tv.tv_sec,
				(unsigned int)tv.tv_usec);

			if (lws_add_http_header_by_name(wsi,
				(unsigned char *)"set-cookie:",
				(unsigned char *)b64, n, &p,
				(unsigned char *)leaf_path + sizeof(leaf_path)))
				return 1;
		}
		if (lws_is_ssl(wsi) && lws_add_http_header_by_name(wsi,
						(unsigned char *)
						"Strict-Transport-Security:",
						(unsigned char *)
						"max-age=15768000 ; "
						"includeSubDomains", 36, &p,
						(unsigned char *)leaf_path +
							sizeof(leaf_path)))
			return 1;
		n = (char *)p - leaf_path;

		n = lws_serve_http_file(wsi, buf, mimetype, other_headers, n);
		if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
			return -1; /* error or can't reuse connection: close the socket */

		/*
		 * notice that the sending of the file completes asynchronously,
		 * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
		 * it's done
		 */
		break;

	case LWS_CALLBACK_HTTP_BODY:
		strncpy(buf, in, 20);
		buf[20] = '\0';
		if (len < 20)
			buf[len] = '\0';

		lwsl_notice("LWS_CALLBACK_HTTP_BODY: %s... len %d\n",
				(const char *)buf, (int)len);

		break;

	case LWS_CALLBACK_HTTP_BODY_COMPLETION:
		lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n");
		/* the whole of the sent body arrived, close or reuse the connection */
		lws_return_http_status(wsi, HTTP_STATUS_OK, NULL);
		goto try_to_reuse;

	case LWS_CALLBACK_HTTP_FILE_COMPLETION:
		goto try_to_reuse;

	case LWS_CALLBACK_HTTP_WRITEABLE:
		lwsl_info("LWS_CALLBACK_HTTP_WRITEABLE\n");

		if (pss->fd == LWS_INVALID_FILE)
			goto try_to_reuse;

		/*
		 * we can send more of whatever it is we were sending
		 */
		sent = 0;
		do {
			/* we'd like the send this much */
			n = sizeof(buffer) - LWS_PRE;

			/* but if the peer told us he wants less, we can adapt */
			m = lws_get_peer_write_allowance(wsi);

			/* -1 means not using a protocol that has this info */
			if (m == 0)
				/* right now, peer can't handle anything */
				goto later;

			if (m != -1 && m < n)
				/* he couldn't handle that much */
				n = m;

			n = lws_plat_file_read(wsi, pss->fd,
					       &amount, buffer + LWS_PRE, n);
			/* problem reading, close conn */
			if (n < 0) {
				lwsl_err("problem reading file\n");
				goto bail;
			}
			n = (int)amount;
			/* sent it all, close conn */
			if (n == 0)
				goto penultimate;
			/*
			 * To support HTTP2, must take care about preamble space
			 *
			 * identification of when we send the last payload frame
			 * is handled by the library itself if you sent a
			 * content-length header
			 */
			m = lws_write(wsi, buffer + LWS_PRE, n, LWS_WRITE_HTTP);
			if (m < 0) {
				lwsl_err("write failed\n");
				/* write failed, close conn */
				goto bail;
			}
			if (m) /* while still active, extend timeout */
				lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, 5);
			sent += m;

		} while (!lws_send_pipe_choked(wsi) && (sent < 1024 * 1024));
later:
		lws_callback_on_writable(wsi);
		break;
penultimate:
		lws_plat_file_close(wsi, pss->fd);
		pss->fd = LWS_INVALID_FILE;
		goto try_to_reuse;

bail:
		lws_plat_file_close(wsi, pss->fd);

		return -1;

	/*
	 * callback for confirming to continue with client IP appear in
	 * protocol 0 callback since no websocket protocol has been agreed
	 * yet.  You can just ignore this if you won't filter on client IP
	 * since the default uhandled callback return is 0 meaning let the
	 * connection continue.
	 */
	case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:

		/* if we returned non-zero from here, we kill the connection */
		break;

	/*
	 * callbacks for managing the external poll() array appear in
	 * protocol 0 callback
	 */

	case LWS_CALLBACK_LOCK_POLL:
		/*
		 * lock mutex to protect pollfd state
		 * called before any other POLL related callback
		 * if protecting wsi lifecycle change, len == 1
		 */
		test_server_lock(len);
		break;

	case LWS_CALLBACK_UNLOCK_POLL:
		/*
		 * unlock mutex to protect pollfd state when
		 * called after any other POLL related callback
		 * if protecting wsi lifecycle change, len == 1
		 */
		test_server_unlock(len);
		break;

#ifdef EXTERNAL_POLL
	case LWS_CALLBACK_ADD_POLL_FD:

		if (count_pollfds >= max_poll_elements) {
			lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n");
			return 1;
		}

		fd_lookup[pa->fd] = count_pollfds;
		pollfds[count_pollfds].fd = pa->fd;
		pollfds[count_pollfds].events = pa->events;
		pollfds[count_pollfds++].revents = 0;
		break;

	case LWS_CALLBACK_DEL_POLL_FD:
		if (!--count_pollfds)
			break;
		m = fd_lookup[pa->fd];
		/* have the last guy take up the vacant slot */
		pollfds[m] = pollfds[count_pollfds];
		fd_lookup[pollfds[count_pollfds].fd] = m;
		break;

	case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
	        pollfds[fd_lookup[pa->fd]].events = pa->events;
		break;
#endif

	case LWS_CALLBACK_GET_THREAD_ID:
		/*
		 * if you will call "lws_callback_on_writable"
		 * from a different thread, return the caller thread ID
		 * here so lws can use this information to work out if it
		 * should signal the poll() loop to exit and restart early
		 */

		/* return pthread_getthreadid_np(); */

		break;

	default:
		break;
	}

	return 0;

	/* if we're on HTTP1.1 or 2.0, will keep the idle connection alive */
try_to_reuse:
	if (lws_http_transaction_completed(wsi))
		return -1;

	return 0;
}