Example #1
0
static void
lws_io_cb(uv_poll_t *watcher, int status, int revents)
{
	struct lws_io_watcher *lws_io = container_of(watcher,
					struct lws_io_watcher, uv_watcher);
	struct lws_context *context = lws_io->context;
	struct lws_pollfd eventfd;

	eventfd.fd = watcher->io_watcher.fd;
	eventfd.events = 0;
	eventfd.revents = 0;

	if (status < 0) {
		/* at this point status will be an UV error, like UV_EBADF,
		we treat all errors as LWS_POLLHUP */

		/* you might want to return; instead of servicing the fd in some cases */
		if (status == UV_EAGAIN)
			return;

		eventfd.events |= LWS_POLLHUP;
		eventfd.revents |= LWS_POLLHUP;
	} else {
		if (revents & UV_READABLE) {
			eventfd.events |= LWS_POLLIN;
			eventfd.revents |= LWS_POLLIN;
		}
		if (revents & UV_WRITABLE) {
			eventfd.events |= LWS_POLLOUT;
			eventfd.revents |= LWS_POLLOUT;
		}
	}
	lws_service_fd(context, &eventfd);
}
Example #2
0
static void
esp8266_cb_sent(void *arg)
{
	struct espconn *conn = arg;
	struct lws *wsi = conn->reverse;
	struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];

//	lwsl_err("%s: wsi %p (psc %d) wsi->position_in_fds_table=%d\n", __func__, wsi, wsi->pending_send_completion, wsi->position_in_fds_table);

	wsi->pending_send_completion--;
	if (wsi->close_is_pending_send_completion &&
	    !wsi->pending_send_completion &&
	    !lws_partial_buffered(wsi)) {
		lwsl_notice("doing delayed close\n");
		lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
	}

	if (pt->fds[wsi->position_in_fds_table].events & LWS_POLLOUT) {
		struct lws_pollfd pollfd;

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

//	        lwsl_notice("informing POLLOUT\n");

	        lws_service_fd(lws_get_context(wsi), &pollfd);
	}
}
Example #3
0
static int ws_callback_poll(struct lws_context *context, struct pollfd *pollfd)
{
	int ret;

	log_debug(3, "ws_callback_poll: %d %02X", pollfd->fd, pollfd->revents);

	ret = lws_service_fd(context, pollfd);
	if (ret < 0) {
		log_debug(3, "  => %d", ret);
	}
	return 1;
}
Example #4
0
void lws_conn::onRX(Socket *s)
{
	struct lws_pollfd pollfd;
	
	(void)s;

	pollfd.fd = this;
	pollfd.events = POLLIN;
	pollfd.revents = POLLIN;
	
	lwsl_debug("%s: lws %p\n", __func__, wsi);
	
	lws_service_fd(wsi->protocol->owning_server, &pollfd);
}
Example #5
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);

}
Example #6
0
static void
cb_1Hz(void *arg)
{
	struct lws_context *context = arg;
	struct lws_context_per_thread *pt = &context->pt[0];
	struct lws *wsi;
	struct lws_pollfd *pollfd;
	int n;

	/* Service any ah that has pending rx */
	for (n = 0; n < context->max_http_header_pool; n++)
		if (pt->ah_pool[n].rxpos != pt->ah_pool[n].rxlen) {
			wsi = pt->ah_pool[n].wsi;
			pollfd = &pt->fds[wsi->position_in_fds_table];
			if (pollfd->events & LWS_POLLIN) {
				pollfd->revents |= LWS_POLLIN;
				lws_service_fd(context, pollfd);
			}
		}

	/* handle timeouts */

	lws_service_fd(context, NULL);
}
Example #7
0
void lws_conn::serialized_writeable(struct lws *_wsi)
{
	struct lws *wsi = (struct lws *)_wsi;
	struct lws_pollfd pollfd;
	lws_conn *conn = (lws_conn *)wsi->sock;
	
	conn->awaiting_on_writeable = 0;

	pollfd.fd = wsi->sock;
	pollfd.events = POLLOUT;
	pollfd.revents = POLLOUT;

	lwsl_debug("%s: wsi %p\r\n", __func__, (void *)wsi);

	lws_service_fd(wsi->protocol->owning_server, &pollfd);
}
Example #8
0
static void
lws_io_cb(uv_poll_t *watcher, int status, int revents)
{
	struct lws_io_watcher *lws_io = lws_container_of(watcher,
					struct lws_io_watcher, uv_watcher);
	struct lws *wsi = lws_container_of(lws_io, struct lws, w_read);
	struct lws_context *context = wsi->context;
	struct lws_pollfd eventfd;

#if defined(WIN32) || defined(_WIN32)
	eventfd.fd = watcher->socket;
#else
	eventfd.fd = watcher->io_watcher.fd;
#endif
	eventfd.events = 0;
	eventfd.revents = 0;

	if (status < 0) {
		/*
		 * At this point status will be an UV error, like UV_EBADF,
		 * we treat all errors as LWS_POLLHUP
		 *
		 * You might want to return; instead of servicing the fd in
		 * some cases */
		if (status == UV_EAGAIN)
			return;

		eventfd.events |= LWS_POLLHUP;
		eventfd.revents |= LWS_POLLHUP;
	} else {
		if (revents & UV_READABLE) {
			eventfd.events |= LWS_POLLIN;
			eventfd.revents |= LWS_POLLIN;
		}
		if (revents & UV_WRITABLE) {
			eventfd.events |= LWS_POLLOUT;
			eventfd.revents |= LWS_POLLOUT;
		}
	}
	lws_service_fd(context, &eventfd);

	uv_idle_start(&context->pt[(int)wsi->tsi].uv_idle, lws_uv_idle);
}
Example #9
0
static void 
lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
	struct lws_pollfd eventfd;
	struct lws_io_watcher *lws_io = container_of(watcher, struct lws_io_watcher, watcher);
	struct lws_context *context = lws_io->context;

	if (revents & EV_ERROR)
		return;

	eventfd.fd = watcher->fd;
	eventfd.revents = EV_NONE;
	if (revents & EV_READ)
		eventfd.revents |= LWS_POLLIN;

	if (revents & EV_WRITE)
		eventfd.revents |= LWS_POLLOUT;

	lws_service_fd(context, &eventfd);
}
Example #10
0
LWS_VISIBLE int
lws_plat_change_pollfd(struct lws_context *context,
		       struct lws *wsi, struct lws_pollfd *pfd)
{
	void *p;

	//lwsl_notice("%s: %p: wsi->pift=%d, events %d\n",
	//		__func__, wsi, wsi->position_in_fds_table, pfd->events);

	if (pfd->events & LWS_POLLIN) {
		if (wsi->premature_rx) {
			lwsl_notice("replaying buffered rx: wsi %p\n", wsi);
			p = wsi->premature_rx;
			wsi->premature_rx = NULL;
			esp8266_cb_rx(wsi->desc.sockfd,
				      (char *)p + wsi->prem_rx_pos,
				      wsi->prem_rx_size - wsi->prem_rx_pos);
			wsi->prem_rx_size = 0;
			wsi->prem_rx_pos = 0;
			lws_free(p);
		}
		if (espconn_recv_unhold(wsi->desc.sockfd) < 0)
			return -1;
	} else
		if (espconn_recv_hold(wsi->desc.sockfd) < 0)
			return -1;

	if (!(pfd->events & LWS_POLLOUT))
		return 0;

	if (!wsi->pending_send_completion) {
		pfd->revents |= LWS_POLLOUT;

//		lwsl_notice("doing POLLOUT\n");
		lws_service_fd(lws_get_context(wsi), pfd);
	} //else
		//lwsl_notice("pending sc\n");

	return 0;
}
Example #11
0
static void
lws_accept_cb(uv_poll_t *watcher, int status, int revents)
{
	struct lws_io_watcher *lws_io = container_of(watcher,
					struct lws_io_watcher, uv_watcher);
	struct lws_context *context = lws_io->context;
	struct lws_pollfd eventfd;

	if (status < 0)
		return;

	eventfd.fd = watcher->io_watcher.fd;
	eventfd.events = 0;
	eventfd.revents = 0;
	if (revents & UV_READABLE) {
		eventfd.events |= LWS_POLLIN;
		eventfd.revents |= LWS_POLLIN;
	}
	if (revents & UV_WRITABLE) {
		eventfd.events |= LWS_POLLOUT;
		eventfd.revents |= LWS_POLLOUT;
	}
	lws_service_fd(context, &eventfd);
}
Example #12
0
void lws_conn::onSent(Socket *s, uint16_t len)
{
	struct lws_pollfd pollfd;

	(void)s;
	(void)len;
	
	if (!awaiting_on_writeable) {
		lwsl_debug("%s: wsi %p (setting writable=1)\r\n",
			   __func__, (void *)wsi);
		writeable = 1;
		return;
	}
	
	writeable = 1;

	pollfd.fd = wsi->sock;
	pollfd.events = POLLOUT;
	pollfd.revents = POLLOUT;

	lwsl_debug("%s: wsi %p (servicing now)\r\n", __func__, (void *)wsi);
	
	lws_service_fd(wsi->protocol->owning_server, &pollfd);
}
Example #13
0
LWS_VISIBLE int
lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
{
	struct lws_context_per_thread *pt = &context->pt[tsi];
	WSANETWORKEVENTS networkevents;
	struct lws_pollfd *pfd;
	struct lws *wsi;
	unsigned int i;
	DWORD ev;
	int n, m;

	/* stay dead once we are dead */
	if (context == NULL)
		return 1;

	if (!context->service_tid_detected) {
		struct lws _lws;

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

		context->service_tid_detected = context->vhost_list->
			protocols[0].callback(&_lws, LWS_CALLBACK_GET_THREAD_ID,
					      NULL, NULL, 0);
	}
	context->service_tid = context->service_tid_detected;

	if (timeout_ms < 0)
		goto faked_service;

	for (i = 0; i < pt->fds_count; ++i) {
		pfd = &pt->fds[i];

		if (!(pfd->events & LWS_POLLOUT))
			continue;

		wsi = wsi_from_fd(context, pfd->fd);
		if (wsi->listener)
			continue;
		if (!wsi || wsi->sock_send_blocking)
			continue;
		pfd->revents = LWS_POLLOUT;
		n = lws_service_fd(context, pfd);
		if (n < 0)
			return -1;
		/* if something closed, retry this slot */
		if (n)
			i--;
	}

	/* if we know something needs service already, don't wait in poll */
	timeout_ms = lws_service_adjust_timeout(context, timeout_ms, tsi);

	ev = lws_plat_wait_event(pt, timeout_ms);

	context->service_tid = 0;

	if (ev == WSA_WAIT_TIMEOUT) {
		lws_service_fd(context, NULL);
		return 0;
	}

	if (ev == WSA_WAIT_EVENT_0) {
		WSAResetEvent(pt->events[0]);
		return 0;
	}

	if (ev < WSA_WAIT_EVENT_0 || ev > WSA_WAIT_EVENT_0 + pt->fds_count)
		return -1;

	pfd = &pt->fds[ev - WSA_WAIT_EVENT_0 - 1];

	/* eh... is one event at a time the best windows can do? */

	if (WSAEnumNetworkEvents(pfd->fd, pt->events[ev - WSA_WAIT_EVENT_0],
				 &networkevents) == SOCKET_ERROR) {
		lwsl_err("WSAEnumNetworkEvents() failed with error %d\n",
								     LWS_ERRNO);
		return -1;
	}

	pfd->revents = (short)networkevents.lNetworkEvents;

	if (pfd->revents & LWS_POLLOUT) {
		wsi = wsi_from_fd(context, pfd->fd);
		if (wsi)
			wsi->sock_send_blocking = 0;
	}

faked_service:

	/* if someone faked their LWS_POLLIN, then go through all active fds */

	if (lws_service_flag_pending(context, tsi)) {
		/* any socket with events to service? */
		for (n = 0; n < (int)pt->fds_count; n++) {
			if (!pt->fds[n].revents)
				continue;

			m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
			if (m < 0)
				return -1;
			/* if something closed, retry this slot */
			if (m)
				n--;
		}
		return 0;
	}

	if (timeout_ms < 0)
		return 0;

	/* otherwise just do the one... must be a way to improve that... */

	return lws_service_fd_tsi(context, pfd, tsi);
}
LWS_VISIBLE int
lws_plat_service(struct lws_context *context, int timeout_ms)
{
	int n;
	int m;
	char buf;
#ifdef LWS_OPENSSL_SUPPORT
	struct lws *wsi, *wsi_next;
#endif

	/* stay dead once we are dead */

	if (!context)
		return 1;

	lws_libev_run(context);

	context->service_tid = context->protocols[0].callback(NULL,
				     LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);

#ifdef LWS_OPENSSL_SUPPORT
	/* if we know we have non-network pending data, do not wait in poll */
	if (lws_ssl_anybody_has_buffered_read(context))
		timeout_ms = 0;
#endif
	n = poll(context->fds, context->fds_count, timeout_ms);
	context->service_tid = 0;

#ifdef LWS_OPENSSL_SUPPORT
	if (!lws_ssl_anybody_has_buffered_read(context) && n == 0) {
#else
	if (n == 0) /* poll timeout */ {
#endif
		lws_service_fd(context, NULL);
		return 0;
	}

	if (n < 0) {
		if (LWS_ERRNO != LWS_EINTR)
			return -1;
		return 0;
	}

#ifdef LWS_OPENSSL_SUPPORT
	/*
	 * For all guys with buffered SSL read data already saved up, if they
	 * are not flowcontrolled, fake their POLLIN status so they'll get
	 * service to use up the buffered incoming data, even though their
	 * network socket may have nothing
	 */

	wsi = context->pending_read_list;
	while (wsi) {
		wsi_next = wsi->pending_read_list_next;
		context->fds[wsi->position_in_fds_table].revents |=
			context->fds[wsi->position_in_fds_table].events & POLLIN;
		if (context->fds[wsi->position_in_fds_table].revents & POLLIN)
			/*
			 * he's going to get serviced now, take him off the
			 * list of guys with buffered SSL.  If he still has some
			 * at the end of the service, he'll get put back on the
			 * list then.
			 */
			lws_ssl_remove_wsi_from_buffered_list(wsi);

		wsi = wsi_next;
	}
#endif

	/* any socket with events to service? */

	for (n = 0; n < context->fds_count; n++) {
		if (!context->fds[n].revents)
			continue;

		if (context->fds[n].fd == context->dummy_pipe_fds[0]) {
			if (read(context->fds[n].fd, &buf, 1) != 1)
				lwsl_err("Cannot read from dummy pipe.");
			continue;
		}

		m = lws_service_fd(context, &context->fds[n]);
		if (m < 0)
			return -1;
		/* if something closed, retry this slot */
		if (m)
			n--;
	}

	return 0;
}

LWS_VISIBLE int
lws_plat_set_socket_options(struct lws_context *context, int fd)
{
	int optval = 1;
	socklen_t optlen = sizeof(optval);

#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
    defined(__OpenBSD__)
	struct protoent *tcp_proto;
#endif

	if (context->ka_time) {
		/* enable keepalive on this socket */
		optval = 1;
		if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
			       (const void *)&optval, optlen) < 0)
			return 1;

#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
        defined(__CYGWIN__) || defined(__OpenBSD__)

		/*
		 * didn't find a way to set these per-socket, need to
		 * tune kernel systemwide values
		 */
#else
		/* set the keepalive conditions we want on it too */
		optval = context->ka_time;
		if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
			       (const void *)&optval, optlen) < 0)
			return 1;

		optval = context->ka_interval;
		if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
			       (const void *)&optval, optlen) < 0)
			return 1;

		optval = context->ka_probes;
		if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
			       (const void *)&optval, optlen) < 0)
			return 1;
#endif
	}

	/* Disable Nagle */
	optval = 1;
#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \
    !defined(__OpenBSD__)
	if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0)
		return 1;
#else
	tcp_proto = getprotobyname("TCP");
	if (setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen) < 0)
		return 1;
#endif

	/* We are nonblocking... */
	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
		return 1;

	return 0;
}
Example #15
0
LWS_VISIBLE int
lws_plat_service(struct lws_context *context, int timeout_ms)
{
	int n;
	int i;
	DWORD ev;
	WSANETWORKEVENTS networkevents;
	struct lws_pollfd *pfd;
	struct lws *wsi;

	/* stay dead once we are dead */

	if (context == NULL)
		return 1;

	context->service_tid = context->protocols[0].callback(context, NULL,
				     LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);

	for (i = 0; i < context->fds_count; ++i) {
		pfd = &context->fds[i];
		if (pfd->fd == context->listen_service_fd)
			continue;

		if (pfd->events & LWS_POLLOUT) {
			wsi = wsi_from_fd(context, pfd->fd);
			if (!wsi || wsi->sock_send_blocking)
				continue;
			pfd->revents = LWS_POLLOUT;
			n = lws_service_fd(context, pfd);
			if (n < 0)
				return -1;
			/* if something closed, retry this slot */
			if (n)
				i--;
		}
	}

	ev = WSAWaitForMultipleEvents(context->fds_count + 1,
				     context->events, FALSE, timeout_ms, FALSE);
	context->service_tid = 0;

	if (ev == WSA_WAIT_TIMEOUT) {
		lws_service_fd(context, NULL);
		return 0;
	}

	if (ev == WSA_WAIT_EVENT_0) {
		WSAResetEvent(context->events[0]);
		return 0;
	}

	if (ev < WSA_WAIT_EVENT_0 || ev > WSA_WAIT_EVENT_0 + context->fds_count)
		return -1;

	pfd = &context->fds[ev - WSA_WAIT_EVENT_0 - 1];

	if (WSAEnumNetworkEvents(pfd->fd,
			context->events[ev - WSA_WAIT_EVENT_0],
					      &networkevents) == SOCKET_ERROR) {
		lwsl_err("WSAEnumNetworkEvents() failed with error %d\n",
								     LWS_ERRNO);
		return -1;
	}

	pfd->revents = (short)networkevents.lNetworkEvents;

	if (pfd->revents & LWS_POLLOUT) {
		wsi = wsi_from_fd(context, pfd->fd);
		if (wsi)
			wsi->sock_send_blocking = FALSE;
	}

	return lws_service_fd(context, pfd);
}
Example #16
0
LWS_VISIBLE LWS_EXTERN int
_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
{
	struct lws_context_per_thread *pt;
	WSANETWORKEVENTS networkevents;
	struct lws_pollfd *pfd;
	struct lws *wsi;
	unsigned int i;
	DWORD ev;
	int n, m;

	/* stay dead once we are dead */
	if (context == NULL || !context->vhost_list)
		return 1;

	pt = &context->pt[tsi];

	if (!context->service_tid_detected) {
		struct lws _lws;

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

		context->service_tid_detected = context->vhost_list->
			protocols[0].callback(&_lws, LWS_CALLBACK_GET_THREAD_ID,
						  NULL, NULL, 0);
		context->service_tid = context->service_tid_detected;
		context->service_tid_detected = 1;
	}

	if (timeout_ms < 0)
	{
			if (lws_service_flag_pending(context, tsi)) {
			/* any socket with events to service? */
			for (n = 0; n < (int)pt->fds_count; n++) {
				if (!pt->fds[n].revents)
					continue;

				m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
				if (m < 0)
					return -1;
				/* if something closed, retry this slot */
				if (m)
					n--;
			}
		}
		return 0;
	}

	for (i = 0; i < pt->fds_count; ++i) {
		pfd = &pt->fds[i];

		if (!(pfd->events & LWS_POLLOUT))
			continue;

		wsi = wsi_from_fd(context, pfd->fd);
		if (wsi->listener)
			continue;
		if (!wsi || wsi->sock_send_blocking)
			continue;
		pfd->revents = LWS_POLLOUT;
		n = lws_service_fd(context, pfd);
		if (n < 0)
			return -1;
		/* if something closed, retry this slot */
		if (n)
			i--;

		if (wsi->trunc_len)
			WSASetEvent(pt->events[0]);
	}

	/*
	 * is there anybody with pending stuff that needs service forcing?
	 */
	if (!lws_service_adjust_timeout(context, 1, tsi)) {
		/* -1 timeout means just do forced service */
		_lws_plat_service_tsi(context, -1, pt->tid);
		/* still somebody left who wants forced service? */
		if (!lws_service_adjust_timeout(context, 1, pt->tid))
			/* yes... come back again quickly */
			timeout_ms = 0;
	}

	ev = WSAWaitForMultipleEvents( 1,  pt->events , FALSE, timeout_ms, FALSE);
	if (ev == WSA_WAIT_EVENT_0) {
		unsigned int eIdx;

		WSAResetEvent(pt->events[0]);

		for (eIdx = 0; eIdx < pt->fds_count; ++eIdx) {
			if (WSAEnumNetworkEvents(pt->fds[eIdx].fd, 0, &networkevents) == SOCKET_ERROR) {
				lwsl_err("WSAEnumNetworkEvents() failed with error %d\n", LWS_ERRNO);
				return -1;
			}

			pfd = &pt->fds[eIdx];
			pfd->revents = (short)networkevents.lNetworkEvents;

			if ((networkevents.lNetworkEvents & FD_CONNECT) &&
				 networkevents.iErrorCode[FD_CONNECT_BIT] &&
				 networkevents.iErrorCode[FD_CONNECT_BIT] != LWS_EALREADY &&
				 networkevents.iErrorCode[FD_CONNECT_BIT] != LWS_EINPROGRESS &&
				 networkevents.iErrorCode[FD_CONNECT_BIT] != LWS_EWOULDBLOCK &&
				 networkevents.iErrorCode[FD_CONNECT_BIT] != WSAEINVAL) {
				lwsl_debug("Unable to connect errno=%d\n",
					   networkevents.iErrorCode[FD_CONNECT_BIT]);
				pfd->revents |= LWS_POLLHUP;
			}

			if (pfd->revents & LWS_POLLOUT) {
				wsi = wsi_from_fd(context, pfd->fd);
				if (wsi)
					wsi->sock_send_blocking = 0;
			}
			 /* if something closed, retry this slot */
			if (pfd->revents & LWS_POLLHUP)
					--eIdx;

			if( pfd->revents != 0 ) {
				lws_service_fd_tsi(context, pfd, tsi);

			}
		}
	}

	context->service_tid = 0;

	if (ev == WSA_WAIT_TIMEOUT) {
		lws_service_fd(context, NULL);
	}
	return 0;;
}
Example #17
0
LWS_EXTERN int
_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
{
	struct lws_context_per_thread *pt;
	WSANETWORKEVENTS networkevents;
	struct lws_pollfd *pfd;
	struct lws *wsi;
	unsigned int i;
	DWORD ev;
	int n;

	/* stay dead once we are dead */
	if (context == NULL || !context->vhost_list)
		return 1;

	pt = &context->pt[tsi];

	if (!pt->service_tid_detected) {
		struct lws _lws;

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

		pt->service_tid = context->vhost_list->
			protocols[0].callback(&_lws, LWS_CALLBACK_GET_THREAD_ID,
						  NULL, NULL, 0);
		pt->service_tid_detected = 1;
	}

	if (timeout_ms < 0) {
		if (lws_service_flag_pending(context, tsi)) {
			/* any socket with events to service? */
			for (n = 0; n < (int)pt->fds_count; n++) {
				int m;
				if (!pt->fds[n].revents)
					continue;

				m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
				if (m < 0)
					return -1;
				/* if something closed, retry this slot */
				if (m)
					n--;
			}
		}
		return 0;
	}

	if (context->event_loop_ops->run_pt)
		context->event_loop_ops->run_pt(context, tsi);

	for (i = 0; i < pt->fds_count; ++i) {
		pfd = &pt->fds[i];

		if (!(pfd->events & LWS_POLLOUT))
			continue;

		wsi = wsi_from_fd(context, pfd->fd);
		if (!wsi || wsi->listener)
			continue;
		if (wsi->sock_send_blocking)
			continue;
		pfd->revents = LWS_POLLOUT;
		n = lws_service_fd(context, pfd);
		if (n < 0)
			return -1;

		/*
		 * Force WSAWaitForMultipleEvents() to check events
		 * and then return immediately.
		 */
		timeout_ms = 0;

		/* if something closed, retry this slot */
		if (n)
			i--;
	}

	/*
	 * is there anybody with pending stuff that needs service forcing?
	 */
	if (!lws_service_adjust_timeout(context, 1, tsi)) {
		/* -1 timeout means just do forced service */
		_lws_plat_service_tsi(context, -1, pt->tid);
		/* still somebody left who wants forced service? */
		if (!lws_service_adjust_timeout(context, 1, pt->tid))
			/* yes... come back again quickly */
			timeout_ms = 0;
	}

	if (timeout_ms) {
		lws_usec_t t;

		lws_pt_lock(pt, __func__);
		/* don't stay in poll wait longer than next hr timeout */
		t =  __lws_hrtimer_service(pt);

		if ((lws_usec_t)timeout_ms * 1000 > t)
			timeout_ms = (int)(t / 1000);
		lws_pt_unlock(pt);
	}

	for (n = 0; n < (int)pt->fds_count; n++)
		WSAEventSelect(pt->fds[n].fd, pt->events,
		       FD_READ | (!!(pt->fds[n].events & LWS_POLLOUT) * FD_WRITE) |
		       FD_OOB | FD_ACCEPT |
		       FD_CONNECT | FD_CLOSE | FD_QOS |
		       FD_ROUTING_INTERFACE_CHANGE |
		       FD_ADDRESS_LIST_CHANGE);

	ev = WSAWaitForMultipleEvents(1, &pt->events, FALSE, timeout_ms, FALSE);
	if (ev == WSA_WAIT_EVENT_0) {
		unsigned int eIdx;

#if defined(LWS_WITH_TLS)
		if (pt->context->tls_ops &&
		    pt->context->tls_ops->fake_POLLIN_for_buffered)
			pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
#endif

		for (eIdx = 0; eIdx < pt->fds_count; ++eIdx) {
			unsigned int err;

			if (WSAEnumNetworkEvents(pt->fds[eIdx].fd, pt->events,
					&networkevents) == SOCKET_ERROR) {
				lwsl_err("WSAEnumNetworkEvents() failed "
					 "with error %d\n", LWS_ERRNO);
				return -1;
			}

			if (!networkevents.lNetworkEvents)
				networkevents.lNetworkEvents = LWS_POLLOUT;

			pfd = &pt->fds[eIdx];
			pfd->revents = (short)networkevents.lNetworkEvents;

			err = networkevents.iErrorCode[FD_CONNECT_BIT];

			if ((networkevents.lNetworkEvents & FD_CONNECT) &&
			     err && err != LWS_EALREADY &&
			     err != LWS_EINPROGRESS && err != LWS_EWOULDBLOCK &&
			     err != WSAEINVAL) {
				lwsl_debug("Unable to connect errno=%d\n", err);
				pfd->revents |= LWS_POLLHUP;
			}

			if (pfd->revents & LWS_POLLOUT) {
				wsi = wsi_from_fd(context, pfd->fd);
				if (wsi)
					wsi->sock_send_blocking = 0;
			}
			 /* if something closed, retry this slot */
			if (pfd->revents & LWS_POLLHUP)
				--eIdx;

			if (pfd->revents) {
				recv(pfd->fd, NULL, 0, 0);
				lws_service_fd_tsi(context, pfd, tsi);
			}
		}
	} else if (ev == WSA_WAIT_TIMEOUT) {
		lws_service_fd(context, NULL);
	} else if (ev == WSA_WAIT_FAILED)
		return 0;

	return 0;
}
Example #18
0
LWS_VISIBLE LWS_EXTERN int
libwebsocket_service_fd(struct lws_context *context,
        struct lws_pollfd *pollfd)
{
    return lws_service_fd(context, pollfd);
}
Example #19
0
int main(int argc, char **argv)
{
	struct lws_context_creation_info info;
	char interface_name[128] = "";
	unsigned int ms, oldms = 0;
	const char *iface = NULL;
	char cert_path[1024];
	char key_path[1024];
 	int debug_level = 7;
	int use_ssl = 0;
	int opts = 0;
	int n = 0;
#ifndef _WIN32
	int syslog_options = LOG_PID | LOG_PERROR;
#endif
#ifndef LWS_NO_DAEMONIZE
 	int daemonize = 0;
#endif

	/*
	 * take care to zero down the info struct, he contains random garbaage
	 * from the stack otherwise
	 */
	memset(&info, 0, sizeof info);
	info.port = 7681;

	while (n >= 0) {
		n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
		if (n < 0)
			continue;
		switch (n) {
		case 'e':
			opts |= LWS_SERVER_OPTION_LIBEV;
			break;
#ifndef LWS_NO_DAEMONIZE
		case 'D':
			daemonize = 1;
			#ifndef _WIN32
			syslog_options &= ~LOG_PERROR;
			#endif
			break;
#endif
		case 'd':
			debug_level = atoi(optarg);
			break;
		case 's':
			use_ssl = 1;
			break;
		case 'a':
			opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
			break;
		case 'p':
			info.port = atoi(optarg);
			break;
		case 'i':
			strncpy(interface_name, optarg, sizeof interface_name);
			interface_name[(sizeof interface_name) - 1] = '\0';
			iface = interface_name;
			break;
		case 'c':
			close_testing = 1;
			fprintf(stderr, " Close testing mode -- closes on "
					   "client after 50 dumb increments"
					   "and suppresses lws_mirror spam\n");
			break;
		case 'r':
			resource_path = optarg;
			printf("Setting resource path to \"%s\"\n", resource_path);
			break;
		case 'h':
			fprintf(stderr, "Usage: test-server "
					"[--port=<p>] [--ssl] "
					"[-d <log bitfield>] "
					"[--resource_path <path>]\n");
			exit(1);
		}
	}

#if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
	/*
	 * normally lock path would be /var/lock/lwsts or similar, to
	 * simplify getting started without having to take care about
	 * permissions or running as root, set to /tmp/.lwsts-lock
	 */
	if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
		fprintf(stderr, "Failed to daemonize\n");
		return 1;
	}
#endif

	signal(SIGINT, sighandler);

#ifndef _WIN32
	/* we will only try to log things according to our debug_level */
	setlogmask(LOG_UPTO (LOG_DEBUG));
	openlog("lwsts", syslog_options, LOG_DAEMON);
#endif

	/* tell the library what debug level to emit and to send it to syslog */
	lws_set_log_level(debug_level, lwsl_emit_syslog);

	lwsl_notice("libwebsockets test server - "
			"(C) Copyright 2010-2015 Andy Green <*****@*****.**> - "
						    "licensed under LGPL2.1\n");

	printf("Using resource path \"%s\"\n", resource_path);
#ifdef EXTERNAL_POLL
	max_poll_elements = getdtablesize();
	pollfds = malloc(max_poll_elements * sizeof (struct lws_pollfd));
	fd_lookup = malloc(max_poll_elements * sizeof (int));
	if (pollfds == NULL || fd_lookup == NULL) {
		lwsl_err("Out of memory pollfds=%d\n", max_poll_elements);
		return -1;
	}
#endif

	info.iface = iface;
	info.protocols = protocols;
#ifndef LWS_NO_EXTENSIONS
	info.extensions = lws_get_internal_extensions();
#endif

	info.ssl_cert_filepath = NULL;
	info.ssl_private_key_filepath = NULL;

	if (use_ssl) {
		if (strlen(resource_path) > sizeof(cert_path) - 32) {
			lwsl_err("resource path too long\n");
			return -1;
		}
		sprintf(cert_path, "%s/libwebsockets-test-server.pem",
								resource_path);
		if (strlen(resource_path) > sizeof(key_path) - 32) {
			lwsl_err("resource path too long\n");
			return -1;
		}
		sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
								resource_path);

		info.ssl_cert_filepath = cert_path;
		info.ssl_private_key_filepath = key_path;
	}
	info.gid = -1;
	info.uid = -1;
	info.max_http_header_pool = 1;
	info.options = opts;

	context = lws_create_context(&info);
	if (context == NULL) {
		lwsl_err("libwebsocket init failed\n");
		return -1;
	}

	/* this shows how to override the lws file operations.  You don't need
	 * to do any of this unless you have a reason (eg, want to serve
	 * compressed files without decompressing the whole archive)
	 */
	/* stash original platform fops */
	fops_plat = *(lws_get_fops(context));
	/* override the active fops */
	lws_get_fops(context)->open = test_server_fops_open;

	n = 0;
	while (n >= 0 && !force_exit) {
		struct timeval tv;

		gettimeofday(&tv, NULL);

		/*
		 * This provokes the LWS_CALLBACK_SERVER_WRITEABLE for every
		 * live websocket connection using the DUMB_INCREMENT protocol,
		 * as soon as it can take more packets (usually immediately)
		 */

		ms = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
		if ((ms - oldms) > 50) {
			lws_callback_on_writable_all_protocol(context,
				&protocols[PROTOCOL_DUMB_INCREMENT]);
			oldms = ms;
		}

#ifdef EXTERNAL_POLL
		/*
		 * this represents an existing server's single poll action
		 * which also includes libwebsocket sockets
		 */

		n = poll(pollfds, count_pollfds, 50);
		if (n < 0)
			continue;

		if (n)
			for (n = 0; n < count_pollfds; n++)
				if (pollfds[n].revents)
					/*
					* returns immediately if the fd does not
					* match anything under libwebsockets
					* control
					*/
					if (lws_service_fd(context,
								  &pollfds[n]) < 0)
						goto done;
#else
		/*
		 * If libwebsockets sockets are all we care about,
		 * you can use this api which takes care of the poll()
		 * and looping through finding who needed service.
		 *
		 * If no socket needs service, it'll return anyway after
		 * the number of ms in the second argument.
		 */

		n = lws_service(context, 50);
#endif
	}

#ifdef EXTERNAL_POLL
done:
#endif

	lws_context_destroy(context);

	lwsl_notice("libwebsockets-test-server exited cleanly\n");

#ifndef _WIN32
	closelog();
#endif

	return 0;
}
Example #20
0
int main(int argc, char **argv)
{
	struct lws_context_creation_info info;
	struct lws_vhost *vhost;
	char interface_name[128] = "";
	unsigned int ms, oldms = 0;
	const char *iface = NULL;
	char cert_path[1024] = "";
	char key_path[1024] = "";
	char ca_path[1024] = "";
	int uid = -1, gid = -1;
	int use_ssl = 0;
	int pp_secs = 0;
	int opts = 0;
	int n = 0;
#ifndef _WIN32
/* LOG_PERROR is not POSIX standard, and may not be portable */
#ifdef __sun
	int syslog_options = LOG_PID;
#else
	int syslog_options = LOG_PID | LOG_PERROR;
#endif
#endif
#ifndef LWS_NO_DAEMONIZE
	int daemonize = 0;
#endif

	/*
	 * take care to zero down the info struct, he contains random garbaage
	 * from the stack otherwise
	 */
	memset(&info, 0, sizeof info);
	info.port = 7681;

	while (n >= 0) {
		n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:R:vu:g:P:k",
				options, NULL);
		if (n < 0)
			continue;
		switch (n) {
		case 'e':
			opts |= LWS_SERVER_OPTION_LIBEV;
			break;
#ifndef LWS_NO_DAEMONIZE
		case 'D':
			daemonize = 1;
#if !defined(_WIN32) && !defined(__sun)
			syslog_options &= ~LOG_PERROR;
#endif
			break;
#endif
		case 'u':
			uid = atoi(optarg);
			break;
		case 'g':
			gid = atoi(optarg);
			break;
		case 'd':
			debug_level = atoi(optarg);
			break;
		case 's':
			use_ssl = 1;
			break;
		case 'a':
			opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
			break;
		case 'p':
			info.port = atoi(optarg);
			break;
		case 'i':
			strncpy(interface_name, optarg, sizeof interface_name);
			interface_name[(sizeof interface_name) - 1] = '\0';
			iface = interface_name;
			break;
		case 'k':
			info.bind_iface = 1;
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
			info.caps[0] = CAP_NET_RAW;
			info.count_caps = 1;
#endif
			break;
		case 'c':
			close_testing = 1;
			fprintf(stderr, " Close testing mode -- closes on "
				"client after 50 dumb increments"
				"and suppresses lws_mirror spam\n");
			break;
		case 'r':
			resource_path = optarg;
			printf("Setting resource path to \"%s\"\n",
			       resource_path);
			break;
		case 'C':
			strncpy(cert_path, optarg, sizeof(cert_path) - 1);
			cert_path[sizeof(cert_path) - 1] = '\0';
			break;
		case 'K':
			strncpy(key_path, optarg, sizeof(key_path) - 1);
			key_path[sizeof(key_path) - 1] = '\0';
			break;
		case 'A':
			strncpy(ca_path, optarg, sizeof(ca_path) - 1);
			ca_path[sizeof(ca_path) - 1] = '\0';
			break;
		case 'P':
			pp_secs = atoi(optarg);
			lwsl_notice("Setting pingpong interval to %d\n",
				    pp_secs);
			break;
#if defined(LWS_OPENSSL_SUPPORT)
		case 'v':
			use_ssl = 1;
			opts |=
			    LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT;
			break;

#if defined(LWS_HAVE_SSL_CTX_set1_param)
		case 'R':
			strncpy(crl_path, optarg, sizeof(crl_path) - 1);
			crl_path[sizeof(crl_path) - 1] = '\0';
			break;
#endif
#endif
		case 'h':
			fprintf(stderr, "Usage: test-server "
				"[--port=<p>] [--ssl] "
				"[-d <log bitfield>] "
				"[--resource_path <path>]\n");
			exit(1);
		}
	}

#if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
	/*
	 * normally lock path would be /var/lock/lwsts or similar, to
	 * simplify getting started without having to take care about
	 * permissions or running as root, set to /tmp/.lwsts-lock
	 */
	if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
		fprintf(stderr, "Failed to daemonize\n");
		return 10;
	}
#endif

	signal(SIGINT, sighandler);

#ifndef _WIN32
	/* we will only try to log things according to our debug_level */
	setlogmask(LOG_UPTO(LOG_DEBUG));
	openlog("lwsts", syslog_options, LOG_DAEMON);
#endif

	/* tell the library what debug level to emit and to send it to syslog */
	lws_set_log_level(debug_level, lwsl_emit_syslog);

	lwsl_notice("libwebsockets test server - license LGPL2.1+SLE\n");
	lwsl_notice("(C) Copyright 2010-2016 Andy Green <*****@*****.**>\n");

	printf("Using resource path \"%s\"\n", resource_path);
#ifdef EXTERNAL_POLL
	max_poll_elements = getdtablesize();
	pollfds = malloc(max_poll_elements * sizeof(struct lws_pollfd));
	fd_lookup = malloc(max_poll_elements * sizeof(int));
	if (pollfds == NULL || fd_lookup == NULL) {
		lwsl_err("Out of memory pollfds=%d\n", max_poll_elements);
		return -1;
	}
#endif

	info.iface = iface;
	info.protocols = protocols;
	info.ssl_cert_filepath = NULL;
	info.ssl_private_key_filepath = NULL;
	info.ws_ping_pong_interval = pp_secs;

	if (use_ssl) {
		if (strlen(resource_path) > sizeof(cert_path) - 32) {
			lwsl_err("resource path too long\n");
			return -1;
		}
		if (!cert_path[0])
			sprintf(cert_path, "%s/libwebsockets-test-server.pem",
				resource_path);
		if (strlen(resource_path) > sizeof(key_path) - 32) {
			lwsl_err("resource path too long\n");
			return -1;
		}
		if (!key_path[0])
			sprintf(key_path,
				"%s/libwebsockets-test-server.key.pem",
				resource_path);

		info.ssl_cert_filepath = cert_path;
		info.ssl_private_key_filepath = key_path;
		if (ca_path[0])
			info.ssl_ca_filepath = ca_path;
	}
	info.gid = gid;
	info.uid = uid;
	info.max_http_header_pool = 16;
	info.options =
	    opts | LWS_SERVER_OPTION_VALIDATE_UTF8 |
	    LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
	    LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
	info.extensions = exts;
	info.timeout_secs = 5;
	info.ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
	    "ECDHE-RSA-AES256-GCM-SHA384:"
	    "DHE-RSA-AES256-GCM-SHA384:"
	    "ECDHE-RSA-AES256-SHA384:"
	    "HIGH:!aNULL:!eNULL:!EXPORT:"
	    "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
	    "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
	    "!DHE-RSA-AES128-SHA256:"
	    "!AES128-GCM-SHA256:"
	    "!AES128-SHA256:"
	    "!DHE-RSA-AES256-SHA256:" "!AES256-GCM-SHA384:" "!AES256-SHA256";

	if (use_ssl)
		/* redirect guys coming on http */
		info.options |= LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS;

	printf("options:%x\r\n", info.options);
	printf("before create\n");
	context = lws_create_context(&info);
	printf("end create\n");
	if (context == NULL) {
		lwsl_err("libwebsocket init failed\n");
		return -1;
	}

	printf("111111\r\n");
	vhost = lws_create_vhost(context, &info);
	if (!vhost) {
		lwsl_err("vhost creation failed\n");
		return -1;
	}
	printf("222222\r\n");
#if !defined(LWS_NO_CLIENT) && defined(LWS_OPENSSL_SUPPORT)
	lws_init_vhost_client_ssl(&info, vhost);
#endif

	/* this shows how to override the lws file operations.  You don't need
	 * to do any of this unless you have a reason (eg, want to serve
	 * compressed files without decompressing the whole archive)
	 */
	/* stash original platform fops */
	fops_plat = *(lws_get_fops(context));
	/* override the active fops */
	lws_get_fops(context)->open = test_server_fops_open;

	n = 0;
#ifdef EXTERNAL_POLL
	int ms_1sec = 0;
#endif
	while (n >= 0 && !force_exit) {
		struct timeval tv;

		gettimeofday(&tv, NULL);

		/*
		 * This provokes the LWS_CALLBACK_SERVER_WRITEABLE for every
		 * live websocket connection using the DUMB_INCREMENT protocol,
		 * as soon as it can take more packets (usually immediately)
		 */

		ms = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
		if ((ms - oldms) > 1) {
			lws_callback_on_writable_all_protocol(context,
							      &protocols
							      [PROTOCOL_DUMB_INCREMENT]);
			oldms = ms;

		}

		lws_callback_on_writable_all_protocol(context,
						      &protocols
						      [PROTOCOL_FILE_SERVER_SEND]);

#ifdef EXTERNAL_POLL
		/*
		 * this represents an existing server's single poll action
		 * which also includes libwebsocket sockets
		 */

		n = poll(pollfds, count_pollfds, 50);
		if (n < 0)
			continue;

		if (n) {
			for (n = 0; n < count_pollfds; n++)
				if (pollfds[n].revents)
					/*
					 * returns immediately if the fd does not
					 * match anything under libwebsockets
					 * control
					 */
					if (lws_service_fd(context,
							   &pollfds[n]) < 0)
						goto done;

			/* if needed, force-service wsis that may not have read all input */
			while (!lws_service_adjust_timeout(context, 1, 0)) {
				lwsl_notice("extpoll doing forced service!\n");
				lws_service_tsi(context, -1, 0);
			}
		} else {
			/* no revents, but before polling again, make lws check for any timeouts */
			if (ms - ms_1sec > 1000) {
				lwsl_notice("1 per sec\n");
				lws_service_fd(context, NULL);
				ms_1sec = ms;
			}
		}
#else
		/*
		 * If libwebsockets sockets are all we care about,
		 * you can use this api which takes care of the poll()
		 * and looping through finding who needed service.
		 *
		 * If no socket needs service, it'll return anyway after
		 * the number of ms in the second argument.
		 */

		n = lws_service(context, 5);
#endif
	}

#ifdef EXTERNAL_POLL
 done:
#endif

	lws_context_destroy(context);

	lwsl_notice("libwebsockets-test-server exited cleanly\n");

#ifndef _WIN32
	closelog();
#endif

	return 0;
}
struct lws *
lws_client_connect_2(struct lws *wsi)
{
#ifdef LWS_USE_IPV6
    struct sockaddr_in6 server_addr6;
    struct sockaddr_in6 client_addr6;
    struct addrinfo hints, *result;
#endif
    struct lws_context *context = wsi->context;
    struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
    struct sockaddr_in server_addr4;
    struct sockaddr_in client_addr4;
    struct lws_pollfd pfd;
    struct sockaddr *v;
    int n, plen = 0;
    const char *ads;

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

    /* proxy? */

    if (context->http_proxy_port) {
        plen = sprintf((char *)pt->serv_buf,
                       "CONNECT %s:%u HTTP/1.0\x0d\x0a"
                       "User-agent: libwebsockets\x0d\x0a",
                       lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
                       wsi->u.hdr.ah->c_port);

        if (context->proxy_basic_auth_token[0])
            plen += sprintf((char *)pt->serv_buf + plen,
                            "Proxy-authorization: basic %s\x0d\x0a",
                            context->proxy_basic_auth_token);

        plen += sprintf((char *)pt->serv_buf + plen, "\x0d\x0a");
        ads = context->http_proxy_address;

#ifdef LWS_USE_IPV6
        if (LWS_IPV6_ENABLED(context)) {
            memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
            server_addr6.sin6_port = htons(context->http_proxy_port);
        } else
#endif
            server_addr4.sin_port = htons(context->http_proxy_port);

    } else {
        ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
#ifdef LWS_USE_IPV6
        if (LWS_IPV6_ENABLED(context)) {
            memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
            server_addr6.sin6_port = htons(wsi->u.hdr.ah->c_port);
        } else
#endif
            server_addr4.sin_port = htons(wsi->u.hdr.ah->c_port);
    }

    /*
     * prepare the actual connection (to the proxy, if any)
     */
    lwsl_client("%s: address %s\n", __func__, ads);

#ifdef LWS_USE_IPV6
    if (LWS_IPV6_ENABLED(context)) {
        memset(&hints, 0, sizeof(struct addrinfo));
#if !defined(__ANDROID__)
        hints.ai_family = AF_INET6;
        hints.ai_flags = AI_V4MAPPED;
#endif
        n = getaddrinfo(ads, NULL, &hints, &result);
        if (n) {
#ifdef _WIN32
            lwsl_err("getaddrinfo: %ls\n", gai_strerrorW(n));
#else
            lwsl_err("getaddrinfo: %s\n", gai_strerror(n));
#endif
            goto oom4;
        }

        server_addr6.sin6_family = AF_INET6;
        switch (result->ai_family) {
#if defined(__ANDROID__)
        case AF_INET:
            /* map IPv4 to IPv6 */
            bzero((char *)&server_addr6.sin6_addr,
                  sizeof(struct in6_addr));
            server_addr6.sin6_addr.s6_addr[10] = 0xff;
            server_addr6.sin6_addr.s6_addr[11] = 0xff;
            memcpy(&server_addr6.sin6_addr.s6_addr[12],
                   &((struct sockaddr_in *)result->ai_addr)->sin_addr,
                   sizeof(struct in_addr));
            break;
#endif
        case AF_INET6:
            memcpy(&server_addr6.sin6_addr,
                   &((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
                   sizeof(struct in6_addr));
            break;
        default:
            lwsl_err("Unknown address family\n");
            freeaddrinfo(result);
            goto oom4;
        }

        freeaddrinfo(result);
    } else
#endif
    {
        struct addrinfo ai, *res, *result;
        void *p = NULL;

        memset (&ai, 0, sizeof ai);
        ai.ai_family = PF_UNSPEC;
        ai.ai_socktype = SOCK_STREAM;
        ai.ai_flags = AI_CANONNAME;

        if (getaddrinfo(ads, NULL, &ai, &result))
            goto oom4;

        res = result;
        while (!p && res) {
            switch (res->ai_family) {
            case AF_INET:
                p = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
                break;
            }

            res = res->ai_next;
        }

        if (!p) {
            freeaddrinfo(result);
            goto oom4;
        }

        server_addr4.sin_family = AF_INET;
        server_addr4.sin_addr = *((struct in_addr *)p);
        bzero(&server_addr4.sin_zero, 8);
        freeaddrinfo(result);
    }

    if (!lws_socket_is_valid(wsi->sock)) {

#ifdef LWS_USE_IPV6
        if (LWS_IPV6_ENABLED(context))
            wsi->sock = socket(AF_INET6, SOCK_STREAM, 0);
        else
#endif
            wsi->sock = socket(AF_INET, SOCK_STREAM, 0);

        if (!lws_socket_is_valid(wsi->sock)) {
            lwsl_warn("Unable to open socket\n");
            goto oom4;
        }

        if (lws_plat_set_socket_options(context, wsi->sock)) {
            lwsl_err("Failed to set wsi socket options\n");
            compatible_close(wsi->sock);
            goto oom4;
        }

        wsi->mode = LWSCM_WSCL_WAITING_CONNECT;

        lws_libev_accept(wsi, wsi->sock);
        if (insert_wsi_socket_into_fds(context, wsi)) {
            compatible_close(wsi->sock);
            goto oom4;
        }

        /*
         * past here, we can't simply free the structs as error
         * handling as oom4 does.  We have to run the whole close flow.
         */

        lws_set_timeout(wsi,
                        PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
                        AWAITING_TIMEOUT);
#ifdef LWS_USE_IPV6
        if (LWS_IPV6_ENABLED(context)) {
            v = (struct sockaddr *)&client_addr6;
            n = sizeof(client_addr6);
            bzero((char *)v, n);
            client_addr6.sin6_family = AF_INET6;
        } else
#endif
        {
            v = (struct sockaddr *)&client_addr4;
            n = sizeof(client_addr4);
            bzero((char *)v, n);
            client_addr4.sin_family = AF_INET;
        }

        if (context->iface) {
            if (interface_to_sa(context, context->iface,
                                (struct sockaddr_in *)v, n) < 0) {
                lwsl_err("Unable to find interface %s\n",
                         context->iface);
                goto failed;
            }

            if (bind(wsi->sock, v, n) < 0) {
                lwsl_err("Error binding to interface %s",
                         context->iface);
                goto failed;
            }
        }
    }

#ifdef LWS_USE_IPV6
    if (LWS_IPV6_ENABLED(context)) {
        v = (struct sockaddr *)&server_addr6;
        n = sizeof(struct sockaddr_in6);
    } else
#endif
    {
        v = (struct sockaddr *)&server_addr4;
        n = sizeof(struct sockaddr);
    }

    if (connect(wsi->sock, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
        if (LWS_ERRNO == LWS_EALREADY ||
                LWS_ERRNO == LWS_EINPROGRESS ||
                LWS_ERRNO == LWS_EWOULDBLOCK
#ifdef _WIN32
                || LWS_ERRNO == WSAEINVAL
#endif
           ) {
            lwsl_client("nonblocking connect retry\n");

            /*
             * must do specifically a POLLOUT poll to hear
             * about the connect completion
             */
            if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
                goto failed;
            lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE);

            return wsi;
        }

        if (LWS_ERRNO != LWS_EISCONN) {
            lwsl_debug("Connect failed errno=%d\n", LWS_ERRNO);
            goto failed;
        }
    }

    lwsl_client("connected\n");

    /* we are connected to server, or proxy */

    if (context->http_proxy_port) {

        /*
         * OK from now on we talk via the proxy, so connect to that
         *
         * (will overwrite existing pointer,
         * leaving old string/frag there but unreferenced)
         */
        if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
                                  context->http_proxy_address))
            goto failed;
        wsi->u.hdr.ah->c_port = context->http_proxy_port;

        n = send(wsi->sock, (char *)pt->serv_buf, plen,
                 MSG_NOSIGNAL);
        if (n < 0) {
            lwsl_debug("ERROR writing to proxy socket\n");
            goto failed;
        }

        lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
                        AWAITING_TIMEOUT);

        wsi->mode = LWSCM_WSCL_WAITING_PROXY_REPLY;

        return wsi;
    }

    /*
     * provoke service to issue the handshake directly
     * we need to do it this way because in the proxy case, this is the
     * next state and executed only if and when we get a good proxy
     * response inside the state machine... but notice in SSL case this
     * may not have sent anything yet with 0 return, and won't until some
     * many retries from main loop.  To stop that becoming endless,
     * cover with a timeout.
     */

    lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
                    AWAITING_TIMEOUT);

    wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
    pfd.fd = wsi->sock;
    pfd.revents = LWS_POLLIN;

    n = lws_service_fd(context, &pfd);
    if (n < 0)
        goto failed;
    if (n) /* returns 1 on failure after closing wsi */
        return NULL;

    return wsi;

oom4:
    lws_free_header_table(wsi);
    lws_free(wsi);

    return NULL;

failed:
    lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);

    return NULL;
}
Example #22
0
struct lws *
lws_client_connect_2(struct lws *wsi)
{
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
	struct lws_context *context = wsi->context;
	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
	const char *adsin;
	struct lws *wsi_piggyback = NULL;
	struct lws_pollfd pfd;
	ssize_t plen = 0;
#endif
	struct addrinfo *result;
#if defined(LWS_WITH_UNIX_SOCK)
	struct sockaddr_un sau;
	char unix_skt = 0;
#endif
	const char *ads;
	sockaddr46 sa46;
	const struct sockaddr *psa;
	int n, port;
	const char *cce = "", *iface;
	const char *meth = NULL;
#ifdef LWS_WITH_IPV6
	char ipv6only = lws_check_opt(wsi->vhost->options,
			LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY |
			LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);

#if defined(__ANDROID__)
	ipv6only = 0;
#endif
#endif

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

#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
	if (!wsi->http.ah) {
		cce = "ah was NULL at cc2";
		lwsl_err("%s\n", cce);
		goto oom4;
	}

	/* we can only piggyback GET or POST */

	meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
	if (meth && strcmp(meth, "GET") && strcmp(meth, "POST"))
		goto create_new_conn;

	/* we only pipeline connections that said it was okay */

	if (!wsi->client_pipeline)
		goto create_new_conn;

	/*
	 * let's take a look first and see if there are any already-active
	 * client connections we can piggy-back on.
	 */

	adsin = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);

	lws_vhost_lock(wsi->vhost); /* ----------------------------------- { */

	lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1,
				   wsi->vhost->dll_active_client_conns.next) {
		struct lws *w = lws_container_of(d, struct lws,
						 dll_active_client_conns);

		lwsl_debug("%s: check %s %s %d %d\n", __func__, adsin,
			   w->client_hostname_copy, wsi->c_port, w->c_port);

		if (w != wsi && w->client_hostname_copy &&
		    !strcmp(adsin, w->client_hostname_copy) &&
#if defined(LWS_WITH_TLS)
		    (wsi->tls.use_ssl & LCCSCF_USE_SSL) ==
		     (w->tls.use_ssl & LCCSCF_USE_SSL) &&
#endif
		    wsi->c_port == w->c_port) {

			/* someone else is already connected to the right guy */

			/* do we know for a fact pipelining won't fly? */
			if (w->keepalive_rejected) {
				lwsl_info("defeating pipelining due to no "
					    "keepalive on server\n");
				lws_vhost_unlock(wsi->vhost); /* } ---------- */
				goto create_new_conn;
			}
#if defined (LWS_WITH_HTTP2)
			/*
			 * h2: in usable state already: just use it without
			 *     going through the queue
			 */
			if (w->client_h2_alpn &&
			    (lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS ||
			     lwsi_state(w) == LRS_ESTABLISHED)) {

				lwsl_info("%s: just join h2 directly\n",
						__func__);

				wsi->client_h2_alpn = 1;
				lws_wsi_h2_adopt(w, wsi);
				lws_vhost_unlock(wsi->vhost); /* } ---------- */

				return wsi;
			}
#endif

			lwsl_info("applying %p to txn queue on %p (wsistate 0x%x)\n",
				wsi, w, w->wsistate);
			/*
			 * ...let's add ourselves to his transaction queue...
			 * we are adding ourselves at the HEAD
			 */
			lws_dll_lws_add_front(&wsi->dll_client_transaction_queue,
				&w->dll_client_transaction_queue_head);

			/*
			 * h1: pipeline our headers out on him,
			 * and wait for our turn at client transaction_complete
			 * to take over parsing the rx.
			 */

			wsi_piggyback = w;

			lws_vhost_unlock(wsi->vhost); /* } ---------- */
			goto send_hs;
		}

	} lws_end_foreach_dll_safe(d, d1);

	lws_vhost_unlock(wsi->vhost); /* } ---------------------------------- */

create_new_conn:
#endif

	/*
	 * clients who will create their own fresh connection keep a copy of
	 * the hostname they originally connected to, in case other connections
	 * want to use it too
	 */

	if (!wsi->client_hostname_copy)
		wsi->client_hostname_copy =
			lws_strdup(lws_hdr_simple_ptr(wsi,
					_WSI_TOKEN_CLIENT_PEER_ADDRESS));

	/*
	 * If we made our own connection, and we're doing a method that can take
	 * a pipeline, we are an "active client connection".
	 *
	 * Add ourselves to the vhost list of those so that others can
	 * piggyback on our transaction queue
	 */

	if (meth && (!strcmp(meth, "GET") || !strcmp(meth, "POST")) &&
	    lws_dll_is_null(&wsi->dll_client_transaction_queue) &&
	    lws_dll_is_null(&wsi->dll_active_client_conns)) {
		lws_vhost_lock(wsi->vhost);
		/* caution... we will have to unpick this on oom4 path */
		lws_dll_lws_add_front(&wsi->dll_active_client_conns,
				      &wsi->vhost->dll_active_client_conns);
		lws_vhost_unlock(wsi->vhost);
	}

	/*
	 * unix socket destination?
	 */

	ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
#if defined(LWS_WITH_UNIX_SOCK)
	if (*ads == '+') {
		ads++;
		memset(&sau, 0, sizeof(sau));
		sau.sun_family = AF_UNIX;
		strncpy(sau.sun_path, ads, sizeof(sau.sun_path));
		sau.sun_path[sizeof(sau.sun_path) - 1] = '\0';

		lwsl_info("%s: Unix skt: %s\n", __func__, ads);

		if (sau.sun_path[0] == '@')
			sau.sun_path[0] = '\0';

		unix_skt = 1;
		goto ads_known;
	}
#endif

	/*
	 * start off allowing ipv6 on connection if vhost allows it
	 */
	wsi->ipv6 = LWS_IPV6_ENABLED(wsi->vhost);

#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)

	/* Decide what it is we need to connect to:
	 *
	 * Priority 1: connect to http proxy */

	if (wsi->vhost->http.http_proxy_port) {
		plen = sprintf((char *)pt->serv_buf,
			"CONNECT %s:%u HTTP/1.0\x0d\x0a"
			"User-agent: libwebsockets\x0d\x0a",
			lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
			wsi->c_port);

		if (wsi->vhost->proxy_basic_auth_token[0])
			plen += sprintf((char *)pt->serv_buf + plen,
					"Proxy-authorization: basic %s\x0d\x0a",
					wsi->vhost->proxy_basic_auth_token);

		plen += sprintf((char *)pt->serv_buf + plen, "\x0d\x0a");
		ads = wsi->vhost->http.http_proxy_address;
		port = wsi->vhost->http.http_proxy_port;
#else
		if (0) {
#endif

#if defined(LWS_WITH_SOCKS5)

	/* Priority 2: Connect to SOCK5 Proxy */

	} else if (wsi->vhost->socks_proxy_port) {
		socks_generate_msg(wsi, SOCKS_MSG_GREETING, &plen);
		lwsl_client("Sending SOCKS Greeting\n");
		ads = wsi->vhost->socks_proxy_address;
		port = wsi->vhost->socks_proxy_port;
#endif
	} else {

		/* Priority 3: Connect directly */

		ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
		port = wsi->c_port;
	}

	/*
	 * prepare the actual connection
	 * to whatever we decided to connect to
	 */

       lwsl_info("%s: %p: address %s\n", __func__, wsi, ads);

       n = lws_getaddrinfo46(wsi, ads, &result);

#ifdef LWS_WITH_IPV6
	if (wsi->ipv6) {
		struct sockaddr_in6 *sa6;

		if (n || !result) {
			/* lws_getaddrinfo46 failed, there is no usable result */
			lwsl_notice("%s: lws_getaddrinfo46 failed %d\n",
					__func__, n);
			cce = "ipv6 lws_getaddrinfo46 failed";
			goto oom4;
		}

		sa6 = ((struct sockaddr_in6 *)result->ai_addr);

		memset(&sa46, 0, sizeof(sa46));

		sa46.sa6.sin6_family = AF_INET6;
		switch (result->ai_family) {
		case AF_INET:
			if (ipv6only)
				break;
			/* map IPv4 to IPv6 */
			bzero((char *)&sa46.sa6.sin6_addr,
						sizeof(sa46.sa6.sin6_addr));
			sa46.sa6.sin6_addr.s6_addr[10] = 0xff;
			sa46.sa6.sin6_addr.s6_addr[11] = 0xff;
			memcpy(&sa46.sa6.sin6_addr.s6_addr[12],
				&((struct sockaddr_in *)result->ai_addr)->sin_addr,
							sizeof(struct in_addr));
			lwsl_notice("uplevelling AF_INET to AF_INET6\n");
			break;

		case AF_INET6:
			memcpy(&sa46.sa6.sin6_addr, &sa6->sin6_addr,
						sizeof(struct in6_addr));
			sa46.sa6.sin6_scope_id = sa6->sin6_scope_id;
			sa46.sa6.sin6_flowinfo = sa6->sin6_flowinfo;
			break;
		default:
			lwsl_err("Unknown address family\n");
			freeaddrinfo(result);
			cce = "unknown address family";
			goto oom4;
		}
	} else
#endif /* use ipv6 */

	/* use ipv4 */
	{
		void *p = NULL;

		if (!n) {
			struct addrinfo *res = result;

			/* pick the first AF_INET (IPv4) result */

			while (!p && res) {
				switch (res->ai_family) {
				case AF_INET:
					p = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
					break;
				}

				res = res->ai_next;
			}
#if defined(LWS_FALLBACK_GETHOSTBYNAME)
		} else if (n == EAI_SYSTEM) {
			struct hostent *host;

			lwsl_info("getaddrinfo (ipv4) failed, trying gethostbyname\n");
			host = gethostbyname(ads);
			if (host) {
				p = host->h_addr;
			} else {
				lwsl_err("gethostbyname failed\n");
				cce = "gethostbyname (ipv4) failed";
				goto oom4;
			}
#endif
		} else {
			lwsl_err("getaddrinfo failed: %d\n", n);
			cce = "getaddrinfo failed";
			goto oom4;
		}

		if (!p) {
			if (result)
				freeaddrinfo(result);
			lwsl_err("Couldn't identify address\n");
			cce = "unable to lookup address";
			goto oom4;
		}

		sa46.sa4.sin_family = AF_INET;
		sa46.sa4.sin_addr = *((struct in_addr *)p);
		bzero(&sa46.sa4.sin_zero, 8);
	}

	if (result)
		freeaddrinfo(result);

#if defined(LWS_WITH_UNIX_SOCK)
ads_known:
#endif

	/* now we decided on ipv4 or ipv6, set the port */

	if (!lws_socket_is_valid(wsi->desc.sockfd)) {

		if (wsi->context->event_loop_ops->check_client_connect_ok &&
		    wsi->context->event_loop_ops->check_client_connect_ok(wsi)) {
			cce = "waiting for event loop watcher to close";
			goto oom4;
		}

#if defined(LWS_WITH_UNIX_SOCK)
		if (unix_skt) {
			wsi->unix_skt = 1;
			wsi->desc.sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
		} else
#endif
		{

#ifdef LWS_WITH_IPV6
		if (wsi->ipv6)
			wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
		else
#endif
			wsi->desc.sockfd = socket(AF_INET, SOCK_STREAM, 0);
		}

		if (!lws_socket_is_valid(wsi->desc.sockfd)) {
			lwsl_warn("Unable to open socket\n");
			cce = "unable to open socket";
			goto oom4;
		}

		if (lws_plat_set_socket_options(wsi->vhost, wsi->desc.sockfd,
#if defined(LWS_WITH_UNIX_SOCK)
						unix_skt)) {
#else
						0)) {
#endif
			lwsl_err("Failed to set wsi socket options\n");
			compatible_close(wsi->desc.sockfd);
			cce = "set socket opts failed";
			goto oom4;
		}

		lwsi_set_state(wsi, LRS_WAITING_CONNECT);

		if (wsi->context->event_loop_ops->accept)
			if (wsi->context->event_loop_ops->accept(wsi)) {
				compatible_close(wsi->desc.sockfd);
				cce = "event loop accept failed";
				goto oom4;
			}

		if (__insert_wsi_socket_into_fds(wsi->context, wsi)) {
			compatible_close(wsi->desc.sockfd);
			cce = "insert wsi failed";
			goto oom4;
		}

		lws_change_pollfd(wsi, 0, LWS_POLLIN);

		/*
		 * past here, we can't simply free the structs as error
		 * handling as oom4 does.  We have to run the whole close flow.
		 */

		if (!wsi->protocol)
			wsi->protocol = &wsi->vhost->protocols[0];

		wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
					wsi->user_space, NULL, 0);

		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
				AWAITING_TIMEOUT);

		iface = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);

		if (iface) {
			n = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0, iface);
			if (n < 0) {
				cce = "unable to bind socket";
				goto failed;
			}
		}
	}

#if defined(LWS_WITH_UNIX_SOCK)
	if (unix_skt) {
		psa = (const struct sockaddr *)&sau;
		n = sizeof(sau);
	} else
#endif

	{
#ifdef LWS_WITH_IPV6
		if (wsi->ipv6) {
			sa46.sa6.sin6_port = htons(port);
			n = sizeof(struct sockaddr_in6);
			psa = (const struct sockaddr *)&sa46;
		} else
#endif
		{
			sa46.sa4.sin_port = htons(port);
			n = sizeof(struct sockaddr);
			psa = (const struct sockaddr *)&sa46;
		}
	}

	if (connect(wsi->desc.sockfd, (const struct sockaddr *)psa, n) == -1 ||
	    LWS_ERRNO == LWS_EISCONN) {
		if (LWS_ERRNO == LWS_EALREADY ||
		    LWS_ERRNO == LWS_EINPROGRESS ||
		    LWS_ERRNO == LWS_EWOULDBLOCK
#ifdef _WIN32
			|| LWS_ERRNO == WSAEINVAL
#endif
		) {
			lwsl_client("nonblocking connect retry (errno = %d)\n",
				    LWS_ERRNO);

			if (lws_plat_check_connection_error(wsi)) {
				cce = "socket connect failed";
				goto failed;
			}

			/*
			 * must do specifically a POLLOUT poll to hear
			 * about the connect completion
			 */
			if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
				cce = "POLLOUT set failed";
				goto failed;
			}

			return wsi;
		}

		if (LWS_ERRNO != LWS_EISCONN) {
			lwsl_notice("Connect failed errno=%d\n", LWS_ERRNO);
			cce = "connect failed";
			goto failed;
		}
	}

	lwsl_client("connected\n");

#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
	/* we are connected to server, or proxy */

	/* http proxy */
	if (wsi->vhost->http.http_proxy_port) {

		/*
		 * OK from now on we talk via the proxy, so connect to that
		 *
		 * (will overwrite existing pointer,
		 * leaving old string/frag there but unreferenced)
		 */
		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
					  wsi->vhost->http.http_proxy_address))
			goto failed;
		wsi->c_port = wsi->vhost->http.http_proxy_port;

		n = send(wsi->desc.sockfd, (char *)pt->serv_buf, (int)plen,
			 MSG_NOSIGNAL);
		if (n < 0) {
			lwsl_debug("ERROR writing to proxy socket\n");
			cce = "proxy write failed";
			goto failed;
		}

		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
				AWAITING_TIMEOUT);

		lwsi_set_state(wsi, LRS_WAITING_PROXY_REPLY);

		return wsi;
	}
#endif
#if defined(LWS_WITH_SOCKS5)
	/* socks proxy */
	else if (wsi->vhost->socks_proxy_port) {
		n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
			 MSG_NOSIGNAL);
		if (n < 0) {
			lwsl_debug("ERROR writing socks greeting\n");
			cce = "socks write failed";
			goto failed;
		}

		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,
				AWAITING_TIMEOUT);

		lwsi_set_state(wsi, LRS_WAITING_SOCKS_GREETING_REPLY);

		return wsi;
	}
#endif
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
send_hs:

	if (wsi_piggyback &&
	    !lws_dll_is_null(&wsi->dll_client_transaction_queue)) {
		/*
		 * We are pipelining on an already-established connection...
		 * we can skip tls establishment.
		 */

		lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);

		/*
		 * we can't send our headers directly, because they have to
		 * be sent when the parent is writeable.  The parent will check
		 * for anybody on his client transaction queue that is in
		 * LRS_H1C_ISSUE_HANDSHAKE2, and let them write.
		 *
		 * If we are trying to do this too early, before the master
		 * connection has written his own headers, then it will just
		 * wait in the queue until it's possible to send them.
		 */
		lws_callback_on_writable(wsi_piggyback);
		lwsl_info("%s: wsi %p: waiting to send headers (parent state %x)\n",
			    __func__, wsi, lwsi_state(wsi_piggyback));
	} else {
		lwsl_info("%s: wsi %p: client creating own connection\n",
			    __func__, wsi);

		/* we are making our own connection */
		lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE);

		/*
		 * provoke service to issue the handshake directly.
		 *
		 * we need to do it this way because in the proxy case, this is
		 * the next state and executed only if and when we get a good
		 * proxy response inside the state machine... but notice in
		 * SSL case this may not have sent anything yet with 0 return,
		 * and won't until many retries from main loop.  To stop that
		 * becoming endless, cover with a timeout.
		 */

		lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
				AWAITING_TIMEOUT);

		pfd.fd = wsi->desc.sockfd;
		pfd.events = LWS_POLLIN;
		pfd.revents = LWS_POLLIN;

		n = lws_service_fd(context, &pfd);
		if (n < 0) {
			cce = "first service failed";
			goto failed;
		}
		if (n) /* returns 1 on failure after closing wsi */
			return NULL;
	}
#endif
	return wsi;

oom4:
	if (lwsi_role_client(wsi) /* && lwsi_state_est(wsi) */) {
		wsi->protocol->callback(wsi,
			LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
			wsi->user_space, (void *)cce, strlen(cce));
		wsi->already_did_cce = 1;
	}
	/* take care that we might be inserted in fds already */
	if (wsi->position_in_fds_table != LWS_NO_FDS_POS)
		goto failed1;

	/*
	 * We can't be an active client connection any more, if we thought
	 * that was what we were going to be doing.  It should be if we are
	 * failing by oom4 path, we are still called by
	 * lws_client_connect_via_info() and will be returning NULL to that,
	 * so nobody else should have had a chance to queue on us.
	 */
	{
		struct lws_vhost *vhost = wsi->vhost;

		lws_vhost_lock(vhost);
		__lws_free_wsi(wsi);
		lws_vhost_unlock(vhost);
	}

	return NULL;

failed:
	wsi->protocol->callback(wsi,
		LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
		wsi->user_space, (void *)cce, strlen(cce));
	wsi->already_did_cce = 1;
failed1:
	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "client_connect2");

	return NULL;
}
Example #23
0
struct lws *
lws_client_connect_2(struct lws *wsi)
{
	sockaddr46 sa46;
	struct addrinfo *result;
	struct lws_context *context = wsi->context;
	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
	struct lws_pollfd pfd;
	const char *cce = "", *iface;
	int n, port;
	ssize_t plen = 0;
	const char *ads;
#ifdef LWS_USE_IPV6
	char ipv6only = lws_check_opt(wsi->vhost->options,
			LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY |
			LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE);

#if defined(__ANDROID__)
	ipv6only = 0;
#endif
#endif

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

	if (!wsi->u.hdr.ah) {
		cce = "ah was NULL at cc2";
		lwsl_err("%s\n", cce);
		goto oom4;
	}

	/*
	 * start off allowing ipv6 on connection if vhost allows it
	 */
	wsi->ipv6 = LWS_IPV6_ENABLED(wsi->vhost);

	/* Decide what it is we need to connect to:
	 *
	 * Priority 1: connect to http proxy */

	if (wsi->vhost->http_proxy_port) {
		plen = sprintf((char *)pt->serv_buf,
			"CONNECT %s:%u HTTP/1.0\x0d\x0a"
			"User-agent: libwebsockets\x0d\x0a",
			lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
			wsi->c_port);

		if (wsi->vhost->proxy_basic_auth_token[0])
			plen += sprintf((char *)pt->serv_buf + plen,
					"Proxy-authorization: basic %s\x0d\x0a",
					wsi->vhost->proxy_basic_auth_token);

		plen += sprintf((char *)pt->serv_buf + plen, "\x0d\x0a");
		ads = wsi->vhost->http_proxy_address;
		port = wsi->vhost->http_proxy_port;

#if defined(LWS_WITH_SOCKS5)

	/* Priority 2: Connect to SOCK5 Proxy */

	} else if (wsi->vhost->socks_proxy_port) {
		socks_generate_msg(wsi, SOCKS_MSG_GREETING, &plen);
		lwsl_client("Sending SOCKS Greeting\n");
		ads = wsi->vhost->socks_proxy_address;
		port = wsi->vhost->socks_proxy_port;
#endif
	} else {

		/* Priority 3: Connect directly */

		ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
		port = wsi->c_port;
	}

	/*
	 * prepare the actual connection
	 * to whatever we decided to connect to
	 */

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

       n = lws_getaddrinfo46(wsi, ads, &result);

#ifdef LWS_USE_IPV6
	if (wsi->ipv6) {

		if (n) {
			/* lws_getaddrinfo46 failed, there is no usable result */
			lwsl_notice("%s: lws_getaddrinfo46 failed %d\n",
					__func__, n);
			cce = "ipv6 lws_getaddrinfo46 failed";
			goto oom4;
		}

		memset(&sa46, 0, sizeof(sa46));

		sa46.sa6.sin6_family = AF_INET6;
		switch (result->ai_family) {
		case AF_INET:
			if (ipv6only)
				break;
			/* map IPv4 to IPv6 */
			bzero((char *)&sa46.sa6.sin6_addr,
						sizeof(sa46.sa6.sin6_addr));
			sa46.sa6.sin6_addr.s6_addr[10] = 0xff;
			sa46.sa6.sin6_addr.s6_addr[11] = 0xff;
			memcpy(&sa46.sa6.sin6_addr.s6_addr[12],
				&((struct sockaddr_in *)result->ai_addr)->sin_addr,
							sizeof(struct in_addr));
			lwsl_notice("uplevelling AF_INET to AF_INET6\n");
			break;

		case AF_INET6:
			memcpy(&sa46.sa6.sin6_addr,
			  &((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
						sizeof(struct in6_addr));
			sa46.sa6.sin6_scope_id = ((struct sockaddr_in6 *)result->ai_addr)->sin6_scope_id;
			sa46.sa6.sin6_flowinfo = ((struct sockaddr_in6 *)result->ai_addr)->sin6_flowinfo;
			break;
		default:
			lwsl_err("Unknown address family\n");
			freeaddrinfo(result);
			cce = "unknown address family";
			goto oom4;
		}
	} else
#endif /* use ipv6 */

	/* use ipv4 */
	{
		void *p = NULL;

		if (!n) {
			struct addrinfo *res = result;

			/* pick the first AF_INET (IPv4) result */

			while (!p && res) {
				switch (res->ai_family) {
				case AF_INET:
					p = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
					break;
				}

				res = res->ai_next;
			}
#if defined(LWS_FALLBACK_GETHOSTBYNAME)
		} else if (n == EAI_SYSTEM) {
			struct hostent *host;

			lwsl_info("getaddrinfo (ipv4) failed, trying gethostbyname\n");
			host = gethostbyname(ads);
			if (host) {
				p = host->h_addr;
			} else {
				lwsl_err("gethostbyname failed\n");
				cce = "gethostbyname (ipv4) failed";
				goto oom4;
			}
#endif
		} else {
			lwsl_err("getaddrinfo failed\n");
			cce = "getaddrinfo failed";
			goto oom4;
		}

		if (!p) {
			if (result)
				freeaddrinfo(result);
			lwsl_err("Couldn't identify address\n");
			cce = "unable to lookup address";
			goto oom4;
		}

		sa46.sa4.sin_family = AF_INET;
		sa46.sa4.sin_addr = *((struct in_addr *)p);
		bzero(&sa46.sa4.sin_zero, 8);
	}

	if (result)
		freeaddrinfo(result);

	/* now we decided on ipv4 or ipv6, set the port */

	if (!lws_socket_is_valid(wsi->desc.sockfd)) {

#if defined(LWS_USE_LIBUV)
		if (LWS_LIBUV_ENABLED(context))
			if (lws_libuv_check_watcher_active(wsi)) {
				lwsl_warn("Waiting for libuv watcher to close\n");
				cce = "waiting for libuv watcher to close";
				goto oom4;
			}
#endif

#ifdef LWS_USE_IPV6
		if (wsi->ipv6)
			wsi->desc.sockfd = socket(AF_INET6, SOCK_STREAM, 0);
		else
#endif
			wsi->desc.sockfd = socket(AF_INET, SOCK_STREAM, 0);

		if (!lws_socket_is_valid(wsi->desc.sockfd)) {
			lwsl_warn("Unable to open socket\n");
			cce = "unable to open socket";
			goto oom4;
		}

		if (lws_plat_set_socket_options(wsi->vhost, wsi->desc.sockfd)) {
			lwsl_err("Failed to set wsi socket options\n");
			compatible_close(wsi->desc.sockfd);
			cce = "set socket opts failed";
			goto oom4;
		}

		wsi->mode = LWSCM_WSCL_WAITING_CONNECT;

		lws_libev_accept(wsi, wsi->desc);
		lws_libuv_accept(wsi, wsi->desc);
		lws_libevent_accept(wsi, wsi->desc);

		if (insert_wsi_socket_into_fds(context, wsi)) {
			compatible_close(wsi->desc.sockfd);
			cce = "insert wsi failed";
			goto oom4;
		}

		lws_change_pollfd(wsi, 0, LWS_POLLIN);

		/*
		 * past here, we can't simply free the structs as error
		 * handling as oom4 does.  We have to run the whole close flow.
		 */

		if (!wsi->protocol)
			wsi->protocol = &wsi->vhost->protocols[0];

		wsi->protocol->callback(wsi, LWS_CALLBACK_WSI_CREATE,
					wsi->user_space, NULL, 0);

		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
				AWAITING_TIMEOUT);

		iface = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);

		if (iface) {
			n = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0, iface);
			if (n < 0) {
				cce = "unable to bind socket";
				goto failed;
			}
		}
	}

#ifdef LWS_USE_IPV6
	if (wsi->ipv6) {
		sa46.sa6.sin6_port = htons(port);
		n = sizeof(struct sockaddr_in6);
	} else
#endif
	{
		sa46.sa4.sin_port = htons(port);
		n = sizeof(struct sockaddr);
	}

	if (connect(wsi->desc.sockfd, (const struct sockaddr *)&sa46, n) == -1 ||
	    LWS_ERRNO == LWS_EISCONN) {
		if (LWS_ERRNO == LWS_EALREADY ||
		    LWS_ERRNO == LWS_EINPROGRESS ||
		    LWS_ERRNO == LWS_EWOULDBLOCK
#ifdef _WIN32
			|| LWS_ERRNO == WSAEINVAL
#endif
		) {
			lwsl_client("nonblocking connect retry (errno = %d)\n",
				    LWS_ERRNO);

			if (lws_plat_check_connection_error(wsi)) {
				cce = "socket connect failed";
				goto failed;
			}

			/*
			 * must do specifically a POLLOUT poll to hear
			 * about the connect completion
			 */
			if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
				cce = "POLLOUT set failed";
				goto failed;
			}

			return wsi;
		}

		if (LWS_ERRNO != LWS_EISCONN) {
			lwsl_notice("Connect failed errno=%d\n", LWS_ERRNO);
			cce = "connect failed";
			goto failed;
		}
	}

	lwsl_client("connected\n");

	/* we are connected to server, or proxy */

	/* http proxy */
	if (wsi->vhost->http_proxy_port) {

		/*
		 * OK from now on we talk via the proxy, so connect to that
		 *
		 * (will overwrite existing pointer,
		 * leaving old string/frag there but unreferenced)
		 */
		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
					  wsi->vhost->http_proxy_address))
			goto failed;
		wsi->c_port = wsi->vhost->http_proxy_port;

		n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
			 MSG_NOSIGNAL);
		if (n < 0) {
			lwsl_debug("ERROR writing to proxy socket\n");
			cce = "proxy write failed";
			goto failed;
		}

		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
				AWAITING_TIMEOUT);

		wsi->mode = LWSCM_WSCL_WAITING_PROXY_REPLY;

		return wsi;
	}
#if defined(LWS_WITH_SOCKS5)
	/* socks proxy */
	else if (wsi->vhost->socks_proxy_port) {
		n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
			 MSG_NOSIGNAL);
		if (n < 0) {
			lwsl_debug("ERROR writing socks greeting\n");
			cce = "socks write failed";
			goto failed;
		}

		lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,
				AWAITING_TIMEOUT);

		wsi->mode = LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY;

		return wsi;
	}
#endif

	/*
	 * provoke service to issue the handshake directly
	 * we need to do it this way because in the proxy case, this is the
	 * next state and executed only if and when we get a good proxy
	 * response inside the state machine... but notice in SSL case this
	 * may not have sent anything yet with 0 return, and won't until some
	 * many retries from main loop.  To stop that becoming endless,
	 * cover with a timeout.
	 */

	lws_set_timeout(wsi, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE,
			AWAITING_TIMEOUT);

	wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE;
	pfd.fd = wsi->desc.sockfd;
	pfd.events = LWS_POLLIN;
	pfd.revents = LWS_POLLIN;

	n = lws_service_fd(context, &pfd);
	if (n < 0) {
		cce = "first service failed";
		goto failed;
	}
	if (n) /* returns 1 on failure after closing wsi */
		return NULL;

	return wsi;

oom4:
	/* we're closing, losing some rx is OK */
	lws_header_table_force_to_detachable_state(wsi);

	if (wsi->mode == LWSCM_HTTP_CLIENT ||
	    wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED ||
	    wsi->mode == LWSCM_WSCL_WAITING_CONNECT) {
		wsi->vhost->protocols[0].callback(wsi,
			LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
			wsi->user_space, (void *)cce, strlen(cce));
		wsi->already_did_cce = 1;
	}
	/* take care that we might be inserted in fds already */
	if (wsi->position_in_fds_table != -1)
		goto failed1;
	lws_remove_from_timeout_list(wsi);
	lws_header_table_detach(wsi, 0);
	lws_free(wsi);

	return NULL;

failed:
	wsi->vhost->protocols[0].callback(wsi,
		LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
		wsi->user_space, (void *)cce, strlen(cce));
	wsi->already_did_cce = 1;
failed1:
	lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);

	return NULL;
}
Example #24
0
int openServer() {
    pthread_t pthread_mirror, pthread_service[32];
    struct lws_context_creation_info info;
    unsigned int ms, oldms = 0;
    const char *iface = NULL;
    char interface_name[128] = "";
    char certificationPath[1024];
    char keyPath[1024];
    char resourcePath[1024];
    int threads = 1;
    int useSSL = 0;
    int opts = 0;
    int n = 0;
    void *retval;

#ifndef LWS_NO_DAEMONIZE
    int daemonize = 0;
#endif
    
    /*
     * take care to zero down the info struct, he contains random garbaage
     * from the stack otherwise
     */
    memset(&info, 0, sizeof info);
    info.port = PORT;

    pthread_mutex_init(&lock_established_conns, NULL);
    signal(SIGINT, sighandler);
    
    /* tell the library what debug level to emit and to send it to syslog */
    lws_set_log_level(DEBUG_LEVEL, lwsl_emit_syslog);

    /* Get resource path */
    if (getcwd(resourcePath, sizeof(resourcePath)) != NULL) {
        fprintf(stdout, "Current working dir: %s\n", resourcePath);
    } 
    else {
        perror("getcwd() error");
        return -1;
    }
    strcat(resourcePath, RESOURCE_PATH);
    RESOURCE_PATH = resourcePath;
    printf("Using resource path \"%s\"\n", RESOURCE_PATH);
    
#ifdef EXTERNAL_POLL
    max_poll_elements = getdtablesize();
    pollfds = malloc(max_poll_elements * sizeof (struct lws_pollfd));
    fd_lookup = malloc(max_poll_elements * sizeof (int));
    if (pollfds == NULL || fd_lookup == NULL) {
        lwsl_err("Out of memory pollfds=%d\n", max_poll_elements);
        return -1;
    }
#endif
    
    info.iface = iface;
    info.protocols = protocols;
    info.extensions = exts;
    info.ssl_cert_filepath = NULL;
    info.ssl_private_key_filepath = NULL;
    
    if (useSSL) {
        if (strlen(RESOURCE_PATH) > sizeof(certificationPath) - 32) {
            lwsl_err("resource path too long\n");
            return -1;
        }
        sprintf(certificationPath, "%s/libwebsockets-test-server.pem", RESOURCE_PATH);
        if (strlen(RESOURCE_PATH) > sizeof(keyPath) - 32) {
            lwsl_err("resource path too long\n");
            return -1;
        }
        sprintf(keyPath, "%s/libwebsockets-test-server.key.pem", RESOURCE_PATH);
        info.ssl_cert_filepath = certificationPath;
        info.ssl_private_key_filepath = keyPath;
    }

    info.gid = -1;
    info.uid = -1;
    info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8;
    info.max_http_header_pool = 1;
    context = lws_create_context(&info);
    if (context == NULL) {
        lwsl_err("Server failed to initialize!\n");
        return -1;
    }
    
    /* start the dumb increment thread */
    n = pthread_create(&pthread_mirror, NULL, thread_lws_mirror, 0);
    if (n) {
        lwsl_err("Unable to create dumb thread\n");
        goto done;
    }

    /* stash original platform fops */
    fops_plat = *(lws_get_fops(context));

    /* override the active fops */
    lws_get_fops(context)->open = test_server_fops_open;
    
    n = 0;
    while (n >= 0 && !force_exit) {
        struct timeval tv;
        gettimeofday(&tv, NULL);
#ifdef EXTERNAL_POLL
        printf("ifdef EXTERNAL POLL");
        /*
         * this represents an existing server's single poll action
         * which also includes libwebsocket sockets
         */
        n = poll(pollfds, count_pollfds, 50);
        if (n < 0) continue;
        if (n)
            for (n = 0; n < count_pollfds; n++)
                if (pollfds[n].revents)
                /*
                 * returns immediately if the fd does not
                 * match anything under libwebsockets
                 * control
                 */
                    if (lws_service_fd(context, &pollfds[n]) < 0)
                        goto done;
#else
        /*
         * If libwebsockets sockets are all we care about,
         * you can use this api which takes care of the poll()
         * and looping through finding who needed service.
         *
         * If no socket needs service, it'll return anyway after
         * the number of ms in the second argument.
         */
        n = lws_service(context, 50);
#endif
    }
done:
    lws_context_destroy(context);
    pthread_mutex_destroy(&lock_established_conns);
    lwsl_notice("Server exited cleanly\n");
    return 0;
}