コード例 #1
0
static void
esp8266_cb_rx(void *arg, char *data, unsigned short len)
{
	struct espconn *conn = arg;
	struct lws *wsi = conn->reverse;
	struct lws_context_per_thread *pt = &wsi->context->pt[0];
	struct lws_pollfd pollfd;
	int n = 0;

	/*
	 * if we're doing HTTP headers, and we have no ah, check if there is
	 * a free ah, if not, have to buffer it
	 */
	if (!wsi->hdr_parsing_completed && !wsi->ah) {
		for (n = 0; n < wsi->context->max_http_header_pool; n++)
			if (!pt->ah_pool[n].in_use)
				break;

		n = n == wsi->context->max_http_header_pool;
	}

	if (!(pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN) || n) {
		wsi->premature_rx = realloc(wsi->premature_rx,
					    wsi->prem_rx_size + len);
		if (!wsi->premature_rx)
			return;
		os_memcpy((char *)wsi->premature_rx + wsi->prem_rx_size, data, len);
		wsi->prem_rx_size += len;
	//	lwsl_notice("%s: wsi %p: len %d BUFFERING\n", __func__, wsi, len);

		if (n) /* we know it will fail, but we will get on the wait list */
			n = lws_header_table_attach(wsi, 0);

		(void)n;
		return;
	}

	//lwsl_err("%s: wsi %p. len %d\n", __func__, wsi, len);

        pollfd.fd = arg;
        pollfd.events = LWS_POLLIN;
        pollfd.revents = LWS_POLLIN;

        wsi->context->rxd = data;
        wsi->context->rxd_len = len;

        lws_service_fd(lws_get_context(wsi), &pollfd);

}
コード例 #2
0
LWS_VISIBLE struct lws *
lws_client_connect_via_info(struct lws_client_connect_info *i)
{
	struct lws *wsi;
	int v = SPEC_LATEST_SUPPORTED;
	const struct lws_protocols *p;

	if (i->context->requested_kill)
		return NULL;

	if (!i->context->protocol_init_done)
		lws_protocol_init(i->context);

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

	wsi->context = i->context;
	/* assert the mode and union status (hdr) clearly */
	lws_union_transition(wsi, LWSCM_HTTP_CLIENT);
	wsi->desc.sockfd = LWS_SOCK_INVALID;

	/* 1) fill up the wsi with stuff from the connect_info as far as it
	 * can go.  It's because not only is our connection async, we might
	 * not even be able to get ahold of an ah at this point.
	 */

	/* -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->pending_timeout = NO_PENDING_TIMEOUT;
	wsi->position_in_fds_table = -1;
	wsi->c_port = i->port;
	wsi->vhost = i->vhost;
	if (!wsi->vhost)
		wsi->vhost = i->context->vhost_list;

	wsi->protocol = &wsi->vhost->protocols[0];

	/* for http[s] connection, allow protocol selection by name */

	if (i->method && i->vhost && i->protocol) {
		p = lws_vhost_name_to_protocol(i->vhost, i->protocol);
		if (p)
			wsi->protocol = p;
	}

	if (wsi && !wsi->user_space && i->userdata) {
		wsi->user_space_externally_allocated = 1;
		wsi->user_space = i->userdata;
	} else
		/* if we stay in http, we can assign the user space now,
		 * otherwise do it after the protocol negotiated
		 */
		if (i->method)
			if (lws_ensure_user_space(wsi))
				goto bail;

#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

	/* 2) stash the things from connect_info that we can't process without
	 * an ah.  Because if no ah, we will go on the ah waiting list and
	 * process those things later (after the connect_info and maybe the
	 * things pointed to have gone out of scope.
	 */

	wsi->u.hdr.stash = lws_malloc(sizeof(*wsi->u.hdr.stash));
	if (!wsi->u.hdr.stash) {
		lwsl_err("%s: OOM\n", __func__);
		goto bail;
	}

	wsi->u.hdr.stash->origin[0] = '\0';
	wsi->u.hdr.stash->protocol[0] = '\0';
	wsi->u.hdr.stash->method[0] = '\0';
	wsi->u.hdr.stash->iface[0] = '\0';

	strncpy(wsi->u.hdr.stash->address, i->address,
		sizeof(wsi->u.hdr.stash->address) - 1);
	strncpy(wsi->u.hdr.stash->path, i->path,
		sizeof(wsi->u.hdr.stash->path) - 1);
	strncpy(wsi->u.hdr.stash->host, i->host,
		sizeof(wsi->u.hdr.stash->host) - 1);
	if (i->origin)
		strncpy(wsi->u.hdr.stash->origin, i->origin,
			sizeof(wsi->u.hdr.stash->origin) - 1);
	if (i->protocol)
		strncpy(wsi->u.hdr.stash->protocol, i->protocol,
			sizeof(wsi->u.hdr.stash->protocol) - 1);
	if (i->method)
		strncpy(wsi->u.hdr.stash->method, i->method,
			sizeof(wsi->u.hdr.stash->method) - 1);
	if (i->iface)
		strncpy(wsi->u.hdr.stash->iface, i->iface,
			sizeof(wsi->u.hdr.stash->iface) - 1);

	wsi->u.hdr.stash->address[sizeof(wsi->u.hdr.stash->address) - 1] = '\0';
	wsi->u.hdr.stash->path[sizeof(wsi->u.hdr.stash->path) - 1] = '\0';
	wsi->u.hdr.stash->host[sizeof(wsi->u.hdr.stash->host) - 1] = '\0';
	wsi->u.hdr.stash->origin[sizeof(wsi->u.hdr.stash->origin) - 1] = '\0';
	wsi->u.hdr.stash->protocol[sizeof(wsi->u.hdr.stash->protocol) - 1] = '\0';
	wsi->u.hdr.stash->method[sizeof(wsi->u.hdr.stash->method) - 1] = '\0';
	wsi->u.hdr.stash->iface[sizeof(wsi->u.hdr.stash->iface) - 1] = '\0';

	if (i->pwsi)
		*i->pwsi = wsi;

	/* if we went on the waiting list, no probs just return the wsi
	 * when we get the ah, now or later, he will call
	 * lws_client_connect_via_info2() below.
	 */
	if (lws_header_table_attach(wsi, 0) < 0) {
		/*
		 * if we failed here, the connection is already closed
		 * and freed.
		 */
		goto bail1;
	}

	if (i->parent_wsi) {
		lwsl_info("%s: created child %p of parent %p\n", __func__,
				wsi, i->parent_wsi);
		wsi->parent = i->parent_wsi;
		wsi->sibling_list = i->parent_wsi->child_list;
		i->parent_wsi->child_list = wsi;
	}
#ifdef LWS_WITH_HTTP_PROXY
	if (i->uri_replace_to)
		wsi->rw = lws_rewrite_create(wsi, html_parser_cb,
					     i->uri_replace_from,
					     i->uri_replace_to);
#endif

	return wsi;

bail:
	lws_free(wsi);

bail1:
	if (i->pwsi)
		*i->pwsi = NULL;

	return NULL;
}
コード例 #3
0
ファイル: server.c プロジェクト: lcsaintlee/libwebsockets
LWS_VISIBLE int
lws_server_socket_service(struct lws_context *context, struct lws *wsi,
			  struct lws_pollfd *pollfd)
{
	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
	lws_sockfd_type accept_fd = LWS_SOCK_INVALID;
	struct allocated_headers *ah;
#if LWS_POSIX
	struct sockaddr_in cli_addr;
	socklen_t clilen;
#endif
	int n, len;

	switch (wsi->mode) {

	case LWSCM_HTTP_SERVING:
	case LWSCM_HTTP_SERVING_ACCEPTED:
	case LWSCM_HTTP2_SERVING:

		/* handle http headers coming in */

		/* pending truncated sends have uber priority */

		if (wsi->trunc_len) {
			if (!(pollfd->revents & LWS_POLLOUT))
				break;

			if (lws_issue_raw(wsi, wsi->trunc_alloc +
					       wsi->trunc_offset,
					  wsi->trunc_len) < 0)
				goto fail;
			/*
			 * we can't afford to allow input processing to send
			 * something new, so spin around he event loop until
			 * he doesn't have any partials
			 */
			break;
		}

		/* any incoming data ready? */

		if (!(pollfd->revents & pollfd->events & LWS_POLLIN))
			goto try_pollout;

		/* these states imply we MUST have an ah attached */

		if (wsi->state == LWSS_HTTP ||
		    wsi->state == LWSS_HTTP_ISSUING_FILE ||
		    wsi->state == LWSS_HTTP_HEADERS) {
			if (!wsi->u.hdr.ah)
				/* no autoservice beacuse we will do it next */
				if (lws_header_table_attach(wsi, 0))
					goto try_pollout;

			ah = wsi->u.hdr.ah;

			lwsl_debug("%s: %p: rxpos:%d rxlen:%d\n", __func__, wsi,
				   ah->rxpos, ah->rxlen);

			/* if nothing in ah rx buffer, get some fresh rx */
			if (ah->rxpos == ah->rxlen) {
				ah->rxlen = lws_ssl_capable_read(wsi, ah->rx,
						   sizeof(ah->rx));
				ah->rxpos = 0;
				lwsl_debug("%s: wsi %p, ah->rxlen = %d\r\n",
					   __func__, wsi, ah->rxlen);
				switch (ah->rxlen) {
				case 0:
					lwsl_info("%s: read 0 len\n", __func__);
					/* lwsl_info("   state=%d\n", wsi->state); */
//					if (!wsi->hdr_parsing_completed)
//						lws_header_table_detach(wsi);
					/* fallthru */
				case LWS_SSL_CAPABLE_ERROR:
					goto fail;
				case LWS_SSL_CAPABLE_MORE_SERVICE:
					ah->rxlen = ah->rxpos = 0;
					goto try_pollout;
				}
			}
			assert(ah->rxpos != ah->rxlen && ah->rxlen);
			/* just ignore incoming if waiting for close */
			if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
				n = lws_read(wsi, ah->rx + ah->rxpos,
					     ah->rxlen - ah->rxpos);
				if (n < 0) /* we closed wsi */
					return 1;
				if (wsi->u.hdr.ah) {
					if ( wsi->u.hdr.ah->rxlen)
						 wsi->u.hdr.ah->rxpos += n;

					if (wsi->u.hdr.ah->rxpos == wsi->u.hdr.ah->rxlen &&
					    (wsi->mode != LWSCM_HTTP_SERVING &&
					     wsi->mode != LWSCM_HTTP_SERVING_ACCEPTED &&
					     wsi->mode != LWSCM_HTTP2_SERVING))
						lws_header_table_detach(wsi, 1);
				}
				break;
			}

			goto try_pollout;
		}

		len = lws_ssl_capable_read(wsi, pt->serv_buf,
					   LWS_MAX_SOCKET_IO_BUF);
		lwsl_debug("%s: wsi %p read %d\r\n", __func__, wsi, len);
		switch (len) {
		case 0:
			lwsl_info("%s: read 0 len\n", __func__);
			/* lwsl_info("   state=%d\n", wsi->state); */
//			if (!wsi->hdr_parsing_completed)
//				lws_header_table_detach(wsi);
			/* fallthru */
		case LWS_SSL_CAPABLE_ERROR:
			goto fail;
		case LWS_SSL_CAPABLE_MORE_SERVICE:
			goto try_pollout;
		}

		/* just ignore incoming if waiting for close */
		if (wsi->state != LWSS_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
			/*
			 * hm this may want to send
			 * (via HTTP callback for example)
			 */
			n = lws_read(wsi, pt->serv_buf, len);
			if (n < 0) /* we closed wsi */
				return 1;
			/* hum he may have used up the
			 * writability above */
			break;
		}

try_pollout:
		/* this handles POLLOUT for http serving fragments */

		if (!(pollfd->revents & LWS_POLLOUT))
			break;

		/* one shot */
		if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
			lwsl_notice("%s a\n", __func__);
			goto fail;
		}

		if (!wsi->hdr_parsing_completed)
			break;

		if (wsi->state != LWSS_HTTP_ISSUING_FILE) {
			n = user_callback_handle_rxflow(wsi->protocol->callback,
					wsi, LWS_CALLBACK_HTTP_WRITEABLE,
					wsi->user_space, NULL, 0);
			if (n < 0) {
				lwsl_info("writeable_fail\n");
				goto fail;
			}
			break;
		}

		/* >0 == completion, <0 == error */
		n = lws_serve_http_file_fragment(wsi);
		if (n < 0 || (n > 0 && lws_http_transaction_completed(wsi))) {
			lwsl_info("completed\n");
			goto fail;
		}
		break;

	case LWSCM_SERVER_LISTENER:

#if LWS_POSIX
		/* pollin means a client has connected to us then */

		do {
			if (!(pollfd->revents & LWS_POLLIN) || !(pollfd->events & LWS_POLLIN))
				break;

			/* listen socket got an unencrypted connection... */

			clilen = sizeof(cli_addr);
			lws_latency_pre(context, wsi);
			accept_fd  = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
					    &clilen);
			lws_latency(context, wsi, "listener accept", accept_fd,
				    accept_fd >= 0);
			if (accept_fd < 0) {
				if (LWS_ERRNO == LWS_EAGAIN ||
				    LWS_ERRNO == LWS_EWOULDBLOCK) {
					lwsl_err("accept asks to try again\n");
					break;
				}
				lwsl_err("ERROR on accept: %s\n", strerror(LWS_ERRNO));
				break;
			}

			lws_plat_set_socket_options(wsi->vhost, accept_fd);

			lwsl_debug("accepted new conn  port %u on fd=%d\n",
					  ntohs(cli_addr.sin_port), accept_fd);

#else
			/* not very beautiful... */
			accept_fd = (lws_sockfd_type)pollfd;
#endif
			/*
			 * look at who we connected to and give user code a chance
			 * to reject based on client IP.  There's no protocol selected
			 * yet so we issue this to protocols[0]
			 */
			if ((wsi->vhost->protocols[0].callback)(wsi,
					LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
					NULL, (void *)(long)accept_fd, 0)) {
				lwsl_debug("Callback denied network connection\n");
				compatible_close(accept_fd);
				break;
			}

			if (!lws_adopt_socket_vhost(wsi->vhost, accept_fd))
				/* already closed cleanly as necessary */
				return 1;

#if LWS_POSIX
		} while (pt->fds_count < context->fd_limit_per_thread - 1 &&
			 lws_poll_listen_fd(&pt->fds[wsi->position_in_fds_table]) > 0);
#endif
		return 0;

	default:
		break;
	}

	if (!lws_server_socket_service_ssl(wsi, accept_fd))
		return 0;

fail:
	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);

	return 1;
}
コード例 #4
0
ファイル: server.c プロジェクト: lcsaintlee/libwebsockets
LWS_VISIBLE LWS_EXTERN struct lws *
lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
			 const char *readbuf, size_t len)
{
	struct lws *wsi = lws_adopt_socket(context, accept_fd);
	struct lws_context_per_thread *pt;
	struct allocated_headers *ah;
	struct lws_pollfd *pfd;

	if (!wsi)
		return NULL;

	if (!readbuf)
		return wsi;

	if (len > sizeof(ah->rx)) {
		lwsl_err("%s: rx in too big\n", __func__);
		goto bail;
	}
	/*
	 * we can't process the initial read data until we can attach an ah.
	 *
	 * if one is available, get it and place the data in his ah rxbuf...
	 * wsi with ah that have pending rxbuf get auto-POLLIN service.
	 *
	 * no autoservice because we didn't get a chance to attach the
	 * readbuf data to wsi or ah yet, and we will do it next if we get
	 * the ah.
	 */
	if (!lws_header_table_attach(wsi, 0)) {
		ah = wsi->u.hdr.ah;
		memcpy(ah->rx, readbuf, len);
		ah->rxpos = 0;
		ah->rxlen = len;

		lwsl_notice("%s: calling service on readbuf ah\n", __func__);
		pt = &context->pt[(int)wsi->tsi];

		/* unlike a normal connect, we have the headers already
		 * (or the first part of them anyway).
		 * libuv won't come back and service us without a network
		 * event, so we need to do the header service right here.
		 */
		pfd = &pt->fds[wsi->position_in_fds_table];
		pfd->revents |= LWS_POLLIN;
		lwsl_err("%s: calling service\n", __func__);
		if (lws_service_fd_tsi(context, pfd, wsi->tsi))
			/* service closed us */
			return NULL;

		return wsi;
	}
	lwsl_err("%s: deferring handling ah\n", __func__);
	/*
	 * hum if no ah came, we are on the wait list and must defer
	 * dealing with this until the ah arrives.
	 *
	 * later successful lws_header_table_attach() will apply the
	 * below to the rx buffer (via lws_header_table_reset()).
	 */
	wsi->u.hdr.preamble_rx = lws_malloc(len);
	memcpy(wsi->u.hdr.preamble_rx, readbuf, len);
	wsi->u.hdr.preamble_rx_len = len;

	return wsi;

bail:
	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);

	return NULL;
}
コード例 #5
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;
	wsi->position_in_fds_table = -1;

#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_header_table_attach(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");

	wsi->context->count_wsi_allocated++;

	return lws_client_connect_2(wsi);

bail1:
	/* we're closing, losing some rx is OK */
	wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
	lws_header_table_detach(wsi);
bail:
	lws_free(wsi);

	return NULL;
}
コード例 #6
0
ファイル: server.c プロジェクト: Fooway/libwebsockets
static struct lws *
lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
{
	struct lws_context *context = vh->context;
	struct lws *new_wsi = lws_create_new_server_wsi(vh);

	if (!new_wsi) {
		compatible_close(accept_fd);
		return NULL;
	}

	lwsl_info("%s: new wsi %p, sockfd %d\n", __func__, new_wsi, accept_fd);

	new_wsi->sock = accept_fd;

	/* the transport is accepted... give him time to negotiate */
	lws_set_timeout(new_wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
			context->timeout_secs);

#if LWS_POSIX == 0
	mbed3_tcp_stream_accept(accept_fd, new_wsi);
#endif

	/*
	 * A new connection was accepted. Give the user a chance to
	 * set properties of the newly created wsi. There's no protocol
	 * selected yet so we issue this to protocols[0]
	 */
	if ((context->vhost_list->protocols[0].callback)(new_wsi,
	     LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0)) {
		compatible_close(new_wsi->sock);
		lws_free(new_wsi);
		return NULL;
	}

	lws_libev_accept(new_wsi, new_wsi->sock);
	lws_libuv_accept(new_wsi, new_wsi->sock);

	if (!LWS_SSL_ENABLED(new_wsi->vhost)) {
		if (insert_wsi_socket_into_fds(context, new_wsi)) {
			lwsl_err("%s: fail inserting socket\n", __func__);
			goto fail;
		}
	} else {
		new_wsi->mode = LWSCM_SSL_INIT;
		if (lws_server_socket_service_ssl(new_wsi, accept_fd)) {
			lwsl_err("%s: fail ssl negotiation\n", __func__);
			goto fail;
		}
	}

	if (!lws_header_table_attach(new_wsi, 0))
		lwsl_debug("Attached ah immediately\n");

	return new_wsi;

fail:
	lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS);

	return NULL;
}