static signed char
cb_authz(struct lejp_ctx *ctx, char reason)
{
	struct acme_connection *s = (struct acme_connection *)ctx->user;

	if (reason == LEJPCB_CONSTRUCTED) {
		s->yes = 0;
		s->use = 0;
		s->chall_token[0] = '\0';
		s->is_sni_02 = 0;
	}

	if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
		return 0;

	switch (ctx->path_match - 1) {
	case JAAZ_ID_TYPE:
		break;
	case JAAZ_ID_VALUE:
		break;
	case JAAZ_STATUS:
		break;
	case JAAZ_EXPIRES:
		break;
	case JAAZ_DETAIL:
		lws_snprintf(s->detail, sizeof(s->detail), "%s", ctx->buf);
		break;
	case JAAZ_CHALLENGES_TYPE:
		if (s->is_sni_02)
			break;
		s->use = !strcmp(ctx->buf, "tls-sni-01") ||
			 !strcmp(ctx->buf, "tls-sni-02");
		s->is_sni_02 = !strcmp(ctx->buf, "tls-sni-02");
		break;
	case JAAZ_CHALLENGES_STATUS:
		lws_strncpy(s->status, ctx->buf, sizeof(s->status));
		break;
	case JAAZ_CHALLENGES_URI:
		if (s->use) {
			lws_strncpy(s->challenge_uri, ctx->buf,
				sizeof(s->challenge_uri));
			s->yes |= 2;
		}
		break;
	case JAAZ_CHALLENGES_TOKEN:
		lwsl_notice("JAAZ_CHALLENGES_TOKEN: %s %d\n", ctx->buf, s->use);
		if (s->use) {
			lws_strncpy(s->chall_token, ctx->buf,
				sizeof(s->chall_token));
			s->yes |= 1;
		}
		break;
	}

	return 0;
}
/*
 * Notice: trashes i and url
 */
static struct lws *
lws_acme_client_connect(struct lws_context *context, struct lws_vhost *vh,
			struct lws **pwsi, struct lws_client_connect_info *i,
			char *url, const char *method)
{
	const char *prot, *p;
	char path[200], _url[256];
	struct lws *wsi;

	memset(i, 0, sizeof(*i));
	i->port = 443;
	lws_strncpy(_url, url, sizeof(_url));
	if (lws_parse_uri(_url, &prot, &i->address, &i->port, &p)) {
		lwsl_err("unable to parse uri %s\n", url);

		return NULL;
	}

	/* add back the leading / on path */
	path[0] = '/';
	lws_strncpy(path + 1, p, sizeof(path) - 1);
	i->path = path;
	i->context = context;
	i->vhost = vh;
	i->ssl_connection = 1;
	i->host = i->address;
	i->origin = i->address;
	i->method = method;
	i->pwsi = pwsi;
	i->protocol = "lws-acme-client";

	wsi = lws_client_connect_via_info(i);
	if (!wsi) {
		lws_snprintf(path, sizeof(path) - 1,
			     "Unable to connect to %s", url);
		lwsl_notice("%s: %s\n", __func__, path);
		lws_acme_report_status(vh, LWS_CUS_FAILED, path);
	}

	return wsi;
}
static signed char
cb_chac(struct lejp_ctx *ctx, char reason)
{
	struct acme_connection *s = (struct acme_connection *)ctx->user;

	if (reason == LEJPCB_CONSTRUCTED) {
		s->yes = 0;
		s->use = 0;
	}

	if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
		return 0;

	switch (ctx->path_match - 1) {
	case JCAC_TYPE:
		if (strcmp(ctx->buf, "tls-sni-01") &&
		    strcmp(ctx->buf, "tls-sni-02"))
			return 1;
		break;
	case JCAC_STATUS:
		lws_strncpy(s->status, ctx->buf, sizeof(s->status));
		break;
	case JCAC_URI:
		s->yes |= 2;
		break;
	case JCAC_TOKEN:
		lws_strncpy(s->chall_token, ctx->buf,
				sizeof(s->chall_token));
		s->yes |= 1;
		break;
	case JCAC_DETAIL:
		lws_snprintf(s->detail, sizeof(s->detail), "%s", ctx->buf);
		break;
	}

	return 0;
}
Esempio n. 4
0
int main(int argc, const char **argv)
{
	struct lws_context_creation_info info;
	struct lws_context *context;
	const char *p;
	int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
			/* for LLL_ verbosity above NOTICE to be built into lws,
			 * lws must have been configured and built with
			 * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
			/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
			/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
			/* | LLL_DEBUG */;

	signal(SIGINT, sigint_handler);

	if ((p = lws_cmdline_option(argc, argv, "-d")))
		logs = atoi(p);

	lws_set_log_level(logs, NULL);
	lwsl_user("LWS minimal raw file\n");
	if (argc < 2) {
		lwsl_user("Usage: %s <file to monitor>  "
			  " eg, /dev/ttyUSB0 or /dev/input/event0 or "
			  "/proc/self/fd/0\n", argv[0]);

		return 1;
	}

	signal(SIGINT, sigint_handler);

	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
	info.port = CONTEXT_PORT_NO_LISTEN_SERVER; /* no listen socket for demo */
	info.protocols = protocols;

	lws_strncpy(filepath, argv[1], sizeof(filepath));

	context = lws_create_context(&info);
	if (!context) {
		lwsl_err("lws init failed\n");
		return 1;
	}

	while (n >= 0 && !interrupted)
		n = lws_service(context, 1000);

	lws_context_destroy(context);

	return 0;
}
static int
file_upload_cb(void *data, const char *name, const char *filename,
	       char *buf, int len, enum lws_spa_fileupload_states state)
{
	struct pss *pss = (struct pss *)data;

	switch (state) {
	case LWS_UFS_OPEN:
		/* take a copy of the provided filename */
		lws_strncpy(pss->filename, filename, sizeof(pss->filename) - 1);
		/* remove any scary things like .. */
		lws_filename_purify_inplace(pss->filename);
		/* open a file of that name for write in the cwd */
		pss->fd = lws_open(pss->filename, O_CREAT | O_TRUNC | O_RDWR, 0600);
		if (pss->fd == LWS_INVALID_FILE) {
			lwsl_notice("Failed to open output file %s\n",
				    pss->filename);
			return 1;
		}
		break;
	case LWS_UFS_FINAL_CONTENT:
	case LWS_UFS_CONTENT:
		if (len) {
			int n;

			pss->file_length += len;

			n = write(pss->fd, buf, len);
			if (n < len) {
				lwsl_notice("Problem writing file %d\n", errno);
			}
		}
		if (state == LWS_UFS_CONTENT)
			/* wasn't the last part of the file */
			break;

		/* the file upload is completed */

		lwsl_user("%s: upload done, written %lld to %s\n", __func__,
			  pss->file_length, pss->filename);

		close(pss->fd);
		pss->fd = LWS_INVALID_FILE;
		break;
	}

	return 0;
}
Esempio n. 6
0
char* lws_ssl_get_error_string(int status, int ret, char *buf, size_t len) {
	switch (status) {
	case SSL_ERROR_NONE:
		return lws_strncpy(buf, "SSL_ERROR_NONE", len);
	case SSL_ERROR_ZERO_RETURN:
		return lws_strncpy(buf, "SSL_ERROR_ZERO_RETURN", len);
	case SSL_ERROR_WANT_READ:
		return lws_strncpy(buf, "SSL_ERROR_WANT_READ", len);
	case SSL_ERROR_WANT_WRITE:
		return lws_strncpy(buf, "SSL_ERROR_WANT_WRITE", len);
	case SSL_ERROR_WANT_CONNECT:
		return lws_strncpy(buf, "SSL_ERROR_WANT_CONNECT", len);
	case SSL_ERROR_WANT_ACCEPT:
		return lws_strncpy(buf, "SSL_ERROR_WANT_ACCEPT", len);
	case SSL_ERROR_WANT_X509_LOOKUP:
		return lws_strncpy(buf, "SSL_ERROR_WANT_X509_LOOKUP", len);
	case SSL_ERROR_SYSCALL:
		switch (ret) {
                case 0:
                        lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: EOF");
                        return buf;
                case -1:
#ifndef LWS_PLAT_OPTEE
			lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: %s",
				     strerror(errno));
#else
			lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: %d", errno);
#endif
			return buf;
                default:
                        return strncpy(buf, "SSL_ERROR_SYSCALL", len);
	}
	case SSL_ERROR_SSL:
		return "SSL_ERROR_SSL";
	default:
		return "SSL_ERROR_UNKNOWN";
	}
}
Esempio n. 7
0
int
lws_uv_plugins_init(struct lws_context *context, const char * const *d)
{
	struct lws_plugin_capability lcaps;
	struct lws_plugin *plugin;
	lws_plugin_init_func initfunc;
	int m, ret = 0;
	void *v;
	uv_dirent_t dent;
	uv_fs_t req;
	char path[256];
	uv_lib_t lib;
	int pofs = 0;

#if  defined(__MINGW32__) || !defined(WIN32)
	pofs = 3;
#endif

	lib.errmsg = NULL;
	lib.handle = NULL;

	uv_loop_init(&context->uv.loop);

	lwsl_notice("  Plugins:\n");

	while (d && *d) {

		lwsl_notice("  Scanning %s\n", *d);
		m =uv_fs_scandir(&context->uv.loop, &req, *d, 0, NULL);
		if (m < 1) {
			lwsl_err("Scandir on %s failed\n", *d);
			return 1;
		}

		while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
			if (strlen(dent.name) < 7)
				continue;

			lwsl_notice("   %s\n", dent.name);

			lws_snprintf(path, sizeof(path) - 1, "%s/%s", *d,
				     dent.name);
			if (uv_dlopen(path, &lib)) {
				uv_dlerror(&lib);
				lwsl_err("Error loading DSO: %s\n", lib.errmsg);
				uv_dlclose(&lib);
				goto bail;
			}

			/* we could open it, can we get his init function? */

#if !defined(WIN32) && !defined(__MINGW32__)
			m = lws_snprintf(path, sizeof(path) - 1, "init_%s",
				     dent.name + pofs /* snip lib... */);
			path[m - 3] = '\0'; /* snip the .so */
#else
			m = lws_snprintf(path, sizeof(path) - 1, "init_%s",
				     dent.name + pofs);
			path[m - 4] = '\0'; /* snip the .dll */
#endif
			if (uv_dlsym(&lib, path, &v)) {
				uv_dlerror(&lib);
				lwsl_err("Failed to get %s on %s: %s", path,
						dent.name, lib.errmsg);
				uv_dlclose(&lib);
				goto bail;
			}
			initfunc = (lws_plugin_init_func)v;
			lcaps.api_magic = LWS_PLUGIN_API_MAGIC;
			m = initfunc(context, &lcaps);
			if (m) {
				lwsl_err("Init %s failed %d\n", dent.name, m);
				goto skip;
			}

			plugin = lws_malloc(sizeof(*plugin), "plugin");
			if (!plugin) {
				uv_dlclose(&lib);
				lwsl_err("OOM\n");
				goto bail;
			}
			plugin->list = context->plugin_list;
			context->plugin_list = plugin;
			lws_strncpy(plugin->name, dent.name, sizeof(plugin->name));
			plugin->lib = lib;
			plugin->caps = lcaps;
			context->plugin_protocol_count += lcaps.count_protocols;
			context->plugin_extension_count += lcaps.count_extensions;

			continue;

skip:
			uv_dlclose(&lib);
		}
bail:
		uv_fs_req_cleanup(&req);
		d++;
	}

	return ret;
}
static int
callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
			void *user, void *in, size_t len)
{
	struct per_session_data__raw_test *pss =
			(struct per_session_data__raw_test *)user;
	struct per_vhost_data__raw_test *vhd =
			(struct per_vhost_data__raw_test *)
			lws_protocol_vh_priv_get(lws_get_vhost(wsi),
					lws_get_protocol(wsi));
	lws_sock_file_fd_type u;

	(void)pss;

	switch (reason) {
	case LWS_CALLBACK_PROTOCOL_INIT:
		vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
				lws_get_protocol(wsi),
				sizeof(struct per_vhost_data__raw_test));
		vhd->context = lws_get_context(wsi);
		vhd->protocol = lws_get_protocol(wsi);
		vhd->vhost = lws_get_vhost(wsi);
		{
			const struct lws_protocol_vhost_options *pvo =
					(const struct lws_protocol_vhost_options *)in;
			while (pvo) {
				if (!strcmp(pvo->name, "fifo-path"))
					lws_strncpy(vhd->fifo_path, pvo->value,
							sizeof(vhd->fifo_path));
				pvo = pvo->next;
			}
			if (vhd->fifo_path[0] == '\0') {
				lwsl_err("%s: Missing pvo \"fifo-path\", raw file fd testing disabled\n", __func__);
				break;
			}
		}
		unlink(vhd->fifo_path);
		if (mkfifo(vhd->fifo_path, 0666)) {
			lwsl_err("mkfifo failed\n");
			return 1;
		}
		vhd->fifo = lws_open(vhd->fifo_path, O_NONBLOCK | O_RDONLY);
		if (vhd->fifo == -1) {
			lwsl_err("opening fifo failed\n");
			unlink(vhd->fifo_path);
			return 1;
		}
		lwsl_notice("FIFO %s created\n", vhd->fifo_path);
		u.filefd = vhd->fifo;
		if (!lws_adopt_descriptor_vhost(vhd->vhost,
						LWS_ADOPT_RAW_FILE_DESC, u,
						"protocol-lws-raw-test",
						NULL)) {
			lwsl_err("Failed to adopt fifo descriptor\n");
			close(vhd->fifo);
			unlink(vhd->fifo_path);
			return 1;
		}
		break;

	case LWS_CALLBACK_PROTOCOL_DESTROY:
		if (!vhd)
			break;
		if (vhd->fifo >= 0) {
			close(vhd->fifo);
			unlink(vhd->fifo_path);
		}
		break;


	/*
	 * Callbacks related to Raw file descriptor testing
	 */

	case LWS_CALLBACK_RAW_ADOPT_FILE:
		lwsl_notice("LWS_CALLBACK_RAW_ADOPT_FILE\n");
		break;


	case LWS_CALLBACK_RAW_RX_FILE:
		lwsl_notice("LWS_CALLBACK_RAW_RX_FILE\n");
		{
			char buf[256];
			int n;
			
			n = read(vhd->fifo, buf, sizeof(buf) - 1);
			if (n < 0) {
				lwsl_err("FIFO read failed\n");
				return 1;
			}
			/*
			 * When nobody opened the other side of the FIFO, the FIFO fd acts well and
			 * only signals POLLIN when somebody opened and wrote to it.
			 *
			 * But if the other side of the FIFO closed it, we will see an endless
			 * POLLIN and 0 available to read.
			 *
			 * The only way to handle it is to reopen the FIFO our side and wait for a
			 * new peer.  This is a quirk of FIFOs not of LWS.
			 */
			if (n == 0) { /* peer closed - do reopen in close processing */
				vhd->zero_length_read = 1;
				return 1;
			}
			buf[n] = '\0';
			lwsl_info("read %d\n", n);
			puts(buf);
		}
		break;

	case LWS_CALLBACK_RAW_CLOSE_FILE:
		lwsl_notice("LWS_CALLBACK_RAW_CLOSE_FILE\n");
		if (vhd->zero_length_read) {
			vhd->zero_length_read = 0;
			close(vhd->fifo);
			/* the wsi that adopted the fifo file is closing... reopen the fifo and readopt */
			vhd->fifo = lws_open(vhd->fifo_path, O_NONBLOCK | O_RDONLY);
			if (vhd->fifo == -1) {
				lwsl_err("opening fifo failed\n");
				return 1;
			}
			lwsl_notice("FIFO %s reopened\n", vhd->fifo_path);
			u.filefd = vhd->fifo;
			if (!lws_adopt_descriptor_vhost(vhd->vhost, 0, u, "protocol-lws-raw-test", NULL)) {
				lwsl_err("Failed to adopt fifo descriptor\n");
				close(vhd->fifo);
				return 1;
			}
		}
		break;

	case LWS_CALLBACK_RAW_WRITEABLE_FILE:
		lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE_FILE\n");
		break;

	/*
	 * Callbacks related to Raw socket descriptor testing
	 */

	case LWS_CALLBACK_RAW_ADOPT:
		lwsl_notice("LWS_CALLBACK_RAW_ADOPT\n");
		break;

	case LWS_CALLBACK_RAW_RX:
		lwsl_notice("LWS_CALLBACK_RAW_RX %ld\n", (long)len);
		if (len > sizeof(pss->buf))
			len = sizeof(pss->buf);
		memcpy(pss->buf, in, len);
		pss->len = len;
		lws_callback_on_writable(wsi);
		break;

	case LWS_CALLBACK_RAW_CLOSE:
		lwsl_notice("LWS_CALLBACK_RAW_CLOSE\n");
		break;

	case LWS_CALLBACK_RAW_WRITEABLE:
		lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE\n");
		lws_write(wsi, pss->buf, pss->len, LWS_WRITE_HTTP);
		break;

	default:
		break;
	}

	return 0;
}
Esempio n. 9
0
File: client.c Progetto: 93i/godot
int
lws_client_interpret_server_handshake(struct lws *wsi)
{
	int n, port = 0, ssl = 0;
	int close_reason = LWS_CLOSE_STATUS_PROTOCOL_ERR;
	const char *prot, *ads = NULL, *path, *cce = NULL;
	struct allocated_headers *ah = NULL;
	struct lws *w = lws_client_wsi_effective(wsi);
	char *p, *q;
	char new_path[300];

	lws_client_stash_destroy(wsi);

	ah = wsi->http.ah;
	if (!wsi->do_ws) {
		/* we are being an http client...
		 */
#if defined(LWS_ROLE_H2)
		if (wsi->client_h2_alpn || wsi->client_h2_substream) {
			lwsl_debug("%s: %p: transitioning to h2 client\n", __func__, wsi);
			lws_role_transition(wsi, LWSIFR_CLIENT,
					    LRS_ESTABLISHED, &role_ops_h2);
		} else
#endif
		{
#if defined(LWS_ROLE_H1)
			{
			lwsl_debug("%s: %p: transitioning to h1 client\n", __func__, wsi);
			lws_role_transition(wsi, LWSIFR_CLIENT,
					    LRS_ESTABLISHED, &role_ops_h1);
			}
#else
			return -1;
#endif
		}

		wsi->http.ah = ah;
		ah->http_response = 0;
	}

	/*
	 * well, what the server sent looked reasonable for syntax.
	 * Now let's confirm it sent all the necessary headers
	 *
	 * http (non-ws) client will expect something like this
	 *
	 * HTTP/1.0.200
	 * server:.libwebsockets
	 * content-type:.text/html
	 * content-length:.17703
	 * set-cookie:.test=LWS_1456736240_336776_COOKIE;Max-Age=360000
	 */

	wsi->http.connection_type = HTTP_CONNECTION_KEEP_ALIVE;
	if (!wsi->client_h2_substream) {
		p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP);
		if (wsi->do_ws && !p) {
			lwsl_info("no URI\n");
			cce = "HS: URI missing";
			goto bail3;
		}
		if (!p) {
			p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP1_0);
			wsi->http.connection_type = HTTP_CONNECTION_CLOSE;
		}
		if (!p) {
			cce = "HS: URI missing";
			lwsl_info("no URI\n");
			goto bail3;
		}
	} else {
		p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_STATUS);
		if (!p) {
			cce = "HS: :status missing";
			lwsl_info("no status\n");
			goto bail3;
		}
	}
	n = atoi(p);
	if (ah)
		ah->http_response = n;

	if (n == 301 || n == 302 || n == 303 || n == 307 || n == 308) {
		p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_LOCATION);
		if (!p) {
			cce = "HS: Redirect code but no Location";
			goto bail3;
		}

		/* Relative reference absolute path */
		if (p[0] == '/') {
#if defined(LWS_WITH_TLS)
			ssl = wsi->tls.use_ssl & LCCSCF_USE_SSL;
#endif
			ads = lws_hdr_simple_ptr(wsi,
						 _WSI_TOKEN_CLIENT_PEER_ADDRESS);
			port = wsi->c_port;
			/* +1 as lws_client_reset expects leading / omitted */
			path = p + 1;
		}
		/* Absolute (Full) URI */
		else if (strchr(p, ':')) {
			if (lws_parse_uri(p, &prot, &ads, &port, &path)) {
				cce = "HS: URI did not parse";
				goto bail3;
			}

			if (!strcmp(prot, "wss") || !strcmp(prot, "https"))
				ssl = 1;
		}
		/* Relative reference relative path */
		else {
			/* This doesn't try to calculate an absolute path,
			 * that will be left to the server */
#if defined(LWS_WITH_TLS)
			ssl = wsi->tls.use_ssl & LCCSCF_USE_SSL;
#endif
			ads = lws_hdr_simple_ptr(wsi,
						 _WSI_TOKEN_CLIENT_PEER_ADDRESS);
			port = wsi->c_port;
			/* +1 as lws_client_reset expects leading / omitted */
			path = new_path + 1;
			lws_strncpy(new_path, lws_hdr_simple_ptr(wsi,
				   _WSI_TOKEN_CLIENT_URI), sizeof(new_path));
			q = strrchr(new_path, '/');
			if (q)
				lws_strncpy(q + 1, p, sizeof(new_path) -
							(q - new_path));
			else
				path = p;
		}

#if defined(LWS_WITH_TLS)
		if ((wsi->tls.use_ssl & LCCSCF_USE_SSL) && !ssl) {
			cce = "HS: Redirect attempted SSL downgrade";
			goto bail3;
		}
#endif

		if (!lws_client_reset(&wsi, ssl, ads, port, path, ads)) {
			/* there are two ways to fail out with NULL return...
			 * simple, early problem where the wsi is intact, or
			 * we went through with the reconnect attempt and the
			 * wsi is already closed.  In the latter case, the wsi
			 * has beet set to NULL additionally.
			 */
			lwsl_err("Redirect failed\n");
			cce = "HS: Redirect failed";
			if (wsi)
				goto bail3;

			return 1;
		}
		return 0;
	}

	if (!wsi->do_ws) {

		/* if h1 KA is allowed, enable the queued pipeline guys */

		if (!wsi->client_h2_alpn && !wsi->client_h2_substream && w == wsi) { /* ie, coming to this for the first time */
			if (wsi->http.connection_type == HTTP_CONNECTION_KEEP_ALIVE)
				wsi->keepalive_active = 1;
			else {
				/*
				 * Ugh... now the main http connection has seen
				 * both sides, we learn the server doesn't
				 * support keepalive.
				 *
				 * That means any guys queued on us are going
				 * to have to be restarted from connect2 with
				 * their own connections.
				 */

				/*
				 * stick around telling any new guys they can't
				 * pipeline to this server
				 */
				wsi->keepalive_rejected = 1;

				lws_vhost_lock(wsi->vhost);
				lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1,
							   wsi->dll_client_transaction_queue_head.next) {
					struct lws *ww = lws_container_of(d, struct lws,
								  dll_client_transaction_queue);

					/* remove him from our queue */
					lws_dll_lws_remove(&ww->dll_client_transaction_queue);
					/* give up on pipelining */
					ww->client_pipeline = 0;

					/* go back to "trying to connect" state */
					lws_role_transition(ww, LWSIFR_CLIENT,
							    LRS_UNCONNECTED,
#if defined(LWS_ROLE_H1)
							    &role_ops_h1);
#else
#if defined (LWS_ROLE_H2)
							    &role_ops_h2);
#else
							    &role_ops_raw);
#endif
#endif
					ww->user_space = NULL;
				} lws_end_foreach_dll_safe(d, d1);
				lws_vhost_unlock(wsi->vhost);
			}
		}

#ifdef LWS_WITH_HTTP_PROXY
		wsi->http.perform_rewrite = 0;
		if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
			if (!strncmp(lws_hdr_simple_ptr(wsi,
						WSI_TOKEN_HTTP_CONTENT_TYPE),
						"text/html", 9))
				wsi->http.perform_rewrite = 1;
		}
#endif

		/* allocate the per-connection user memory (if any) */
		if (lws_ensure_user_space(wsi)) {
			lwsl_err("Problem allocating wsi user mem\n");
			cce = "HS: OOM";
			goto bail2;
		}

		/* he may choose to send us stuff in chunked transfer-coding */
		wsi->chunked = 0;
		wsi->chunk_remaining = 0; /* ie, next thing is chunk size */
		if (lws_hdr_total_length(wsi,
					WSI_TOKEN_HTTP_TRANSFER_ENCODING)) {
			wsi->chunked = !strcmp(lws_hdr_simple_ptr(wsi,
					       WSI_TOKEN_HTTP_TRANSFER_ENCODING),
						"chunked");
			/* first thing is hex, after payload there is crlf */
			wsi->chunk_parser = ELCP_HEX;
		}

		if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
			wsi->http.rx_content_length =
					atoll(lws_hdr_simple_ptr(wsi,
						WSI_TOKEN_HTTP_CONTENT_LENGTH));
			lwsl_info("%s: incoming content length %llu\n",
				    __func__, (unsigned long long)
					    wsi->http.rx_content_length);
			wsi->http.rx_content_remain =
					wsi->http.rx_content_length;
		} else /* can't do 1.1 without a content length or chunked */
			if (!wsi->chunked)
				wsi->http.connection_type =
							HTTP_CONNECTION_CLOSE;

		/*
		 * we seem to be good to go, give client last chance to check
		 * headers and OK it
		 */
		if (wsi->protocol->callback(wsi,
				LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
					    wsi->user_space, NULL, 0)) {

			cce = "HS: disallowed by client filter";
			goto bail2;
		}

		/* clear his proxy connection timeout */
		lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);

		wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;

		/* call him back to inform him he is up */
		if (wsi->protocol->callback(wsi,
					    LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,
					    wsi->user_space, NULL, 0)) {
			cce = "HS: disallowed at ESTABLISHED";
			goto bail3;
		}

		/*
		 * for pipelining, master needs to keep his ah... guys who
		 * queued on him can drop it now though.
		 */

		if (w != wsi)
			/* free up parsing allocations for queued guy */
			lws_header_table_detach(w, 0);

		lwsl_info("%s: client connection up\n", __func__);

		return 0;
	}

#if defined(LWS_ROLE_WS)
	switch (lws_client_ws_upgrade(wsi, &cce)) {
	case 2:
		goto bail2;
	case 3:
		goto bail3;
	}

	return 0;
#endif

bail3:
	close_reason = LWS_CLOSE_STATUS_NOSTATUS;

bail2:
	if (wsi->protocol) {
		n = 0;
		if (cce)
			n = (int)strlen(cce);
		wsi->protocol->callback(wsi,
				LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
				wsi->user_space, (void *)cce,
				(unsigned int)n);
	}
	wsi->already_did_cce = 1;

	lwsl_info("closing connection due to bail2 connection error\n");

	/* closing will free up his parsing allocations */
	lws_close_free_wsi(wsi, close_reason, "c hs interp");

	return 1;
}
Esempio n. 10
0
void socks_generate_msg(struct lws *wsi, enum socks_msg_type type,
			ssize_t *msg_len)
{
	struct lws_context *context = wsi->context;
	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
	ssize_t len = 0, n, passwd_len;
	short net_num;
	char *p;

	switch (type) {
	case SOCKS_MSG_GREETING:
		/* socks version, version 5 only */
		pt->serv_buf[len++] = SOCKS_VERSION_5;
		/* number of methods */
		pt->serv_buf[len++] = 2;
		/* username password method */
		pt->serv_buf[len++] = SOCKS_AUTH_USERNAME_PASSWORD;
		/* no authentication method */
		pt->serv_buf[len++] = SOCKS_AUTH_NO_AUTH;
		break;

	case SOCKS_MSG_USERNAME_PASSWORD:
		n = strlen(wsi->vhost->socks_user);
		passwd_len = strlen(wsi->vhost->socks_password);

		/* the subnegotiation version */
		pt->serv_buf[len++] = SOCKS_SUBNEGOTIATION_VERSION_1;
		/* length of the user name */
		pt->serv_buf[len++] = n;
		/* user name */
		lws_strncpy((char *)&pt->serv_buf[len], wsi->vhost->socks_user,
			context->pt_serv_buf_size - len + 1);
		len += n;
		/* length of the password */
		pt->serv_buf[len++] = passwd_len;
		/* password */
		lws_strncpy((char *)&pt->serv_buf[len], wsi->vhost->socks_password,
			context->pt_serv_buf_size - len + 1);
		len += passwd_len;
		break;

	case SOCKS_MSG_CONNECT:
		p = (char*)&net_num;

		/* socks version */
		pt->serv_buf[len++] = SOCKS_VERSION_5;
		/* socks command */
		pt->serv_buf[len++] = SOCKS_COMMAND_CONNECT;
		/* reserved */
		pt->serv_buf[len++] = 0;
		/* address type */
		pt->serv_buf[len++] = SOCKS_ATYP_DOMAINNAME;
		/* skip length, we fill it in at the end */
		n = len++;

		/* the address we tell SOCKS proxy to connect to */
		lws_strncpy((char *)&(pt->serv_buf[len]), wsi->stash->address,
			context->pt_serv_buf_size - len + 1);
		len += strlen(wsi->stash->address);
		net_num = htons(wsi->c_port);

		/* the port we tell SOCKS proxy to connect to */
		pt->serv_buf[len++] = p[0];
		pt->serv_buf[len++] = p[1];

		/* the length of the address, excluding port */
		pt->serv_buf[n] = strlen(wsi->stash->address);
		break;
		
	default:
		return;
	}

	*msg_len = len;
}
Esempio n. 11
0
/**
 * lws_client_reset() - retarget a connected wsi to start over with a new connection (ie, redirect)
 *			this only works if still in HTTP, ie, not upgraded yet
 * wsi:		connection to reset
 * address:	network address of the new server
 * port:	port to connect to
 * path:	uri path to connect to on the new server
 * host:	host header to send to the new server
 */
LWS_VISIBLE struct lws *
lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
		 const char *path, const char *host)
{
	char origin[300] = "", protocol[300] = "", method[32] = "",
	     iface[16] = "", alpn[32] = "", *p;
	struct lws *wsi = *pwsi;

	if (wsi->redirects == 3) {
		lwsl_err("%s: Too many redirects\n", __func__);
		return NULL;
	}
	wsi->redirects++;

	p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN);
	if (p)
		lws_strncpy(origin, p, sizeof(origin));

	p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
	if (p)
		lws_strncpy(protocol, p, sizeof(protocol));

	p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
	if (p)
		lws_strncpy(method, p, sizeof(method));

	p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE);
	if (p)
		lws_strncpy(iface, p, sizeof(iface));

	p = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ALPN);
	if (p)
		lws_strncpy(alpn, p, sizeof(alpn));

	lwsl_info("redirect ads='%s', port=%d, path='%s', ssl = %d\n",
		   address, port, path, ssl);

	/* close the connection by hand */

#if defined(LWS_WITH_TLS)
	lws_ssl_close(wsi);
#endif

	__remove_wsi_socket_from_fds(wsi);

	if (wsi->context->event_loop_ops->close_handle_manually)
		wsi->context->event_loop_ops->close_handle_manually(wsi);
	else
		compatible_close(wsi->desc.sockfd);

#if defined(LWS_WITH_TLS)
	wsi->tls.use_ssl = ssl;
#else
	if (ssl) {
		lwsl_err("%s: not configured for ssl\n", __func__);
		return NULL;
	}
#endif

	wsi->desc.sockfd = LWS_SOCK_INVALID;
	lwsi_set_state(wsi, LRS_UNCONNECTED);
	wsi->protocol = NULL;
	wsi->pending_timeout = NO_PENDING_TIMEOUT;
	wsi->c_port = port;
	wsi->hdr_parsing_completed = 0;
	_lws_header_table_reset(wsi->http.ah);

	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
		return NULL;

	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
		return NULL;

	if (origin[0])
		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
					  origin))
			return NULL;
	if (protocol[0])
		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
					  protocol))
			return NULL;
	if (method[0])
		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_METHOD,
					  method))
			return NULL;

	if (iface[0])
		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_IFACE,
					  iface))
			return NULL;
	if (alpn[0])
		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ALPN,
					  alpn))
			return NULL;

	origin[0] = '/';
	strncpy(&origin[1], path, sizeof(origin) - 2);
	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, origin))
		return NULL;

	*pwsi = lws_client_connect_2(wsi);

	return *pwsi;
}
Esempio n. 12
0
int
lws_client_ws_upgrade(struct lws *wsi, const char **cce)
{
	struct lws_context *context = wsi->context;
	struct lws_tokenize ts;
	int n, len, okay = 0;
	lws_tokenize_elem e;
	char *p, buf[64];
	const char *pc;
#if !defined(LWS_WITHOUT_EXTENSIONS)
	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
	char *sb = (char *)&pt->serv_buf[0];
	const struct lws_ext_options *opts;
	const struct lws_extension *ext;
	char ext_name[128];
	const char *c, *a;
	int more = 1;
	char ignore;
#endif

	if (wsi->client_h2_substream) {/* !!! client ws-over-h2 not there yet */
		lwsl_warn("%s: client ws-over-h2 upgrade not supported yet\n",
			  __func__);
		*cce = "HS: h2 / ws upgrade unsupported";
		goto bail3;
	}

	if (wsi->http.ah->http_response == 401) {
		lwsl_warn(
		       "lws_client_handshake: got bad HTTP response '%d'\n",
		       wsi->http.ah->http_response);
		*cce = "HS: ws upgrade unauthorized";
		goto bail3;
	}

	if (wsi->http.ah->http_response != 101) {
		lwsl_warn(
		       "lws_client_handshake: got bad HTTP response '%d'\n",
		       wsi->http.ah->http_response);
		*cce = "HS: ws upgrade response not 101";
		goto bail3;
	}

	if (lws_hdr_total_length(wsi, WSI_TOKEN_ACCEPT) == 0) {
		lwsl_info("no ACCEPT\n");
		*cce = "HS: ACCEPT missing";
		goto bail3;
	}

	p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE);
	if (!p) {
		lwsl_info("no UPGRADE\n");
		*cce = "HS: UPGRADE missing";
		goto bail3;
	}
	strtolower(p);
	if (strcmp(p, "websocket")) {
		lwsl_warn(
		      "lws_client_handshake: got bad Upgrade header '%s'\n", p);
		*cce = "HS: Upgrade to something other than websocket";
		goto bail3;
	}

	/* connection: must have "upgrade" */

	lws_tokenize_init(&ts, buf, LWS_TOKENIZE_F_COMMA_SEP_LIST |
				    LWS_TOKENIZE_F_MINUS_NONTERM);
	ts.len = lws_hdr_copy(wsi, buf, sizeof(buf) - 1, WSI_TOKEN_CONNECTION);
	if (ts.len <= 0) /* won't fit, or absent */
		goto bad_conn_format;

	do {
		e = lws_tokenize(&ts);
		switch (e) {
		case LWS_TOKZE_TOKEN:
			if (!strncasecmp(ts.token, "upgrade", ts.token_len))
				e = LWS_TOKZE_ENDED;
			break;

		case LWS_TOKZE_DELIMITER:
			break;

		default: /* includes ENDED found by the tokenizer itself */
bad_conn_format:
			lwsl_info("%s: malfored connection '%s'\n",
				  __func__, buf);
			*cce = "HS: UPGRADE malformed";
			goto bail3;
		}
	} while (e > 0);

	pc = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
	if (!pc) {
		lwsl_parser("lws_client_int_s_hs: no protocol list\n");
	} else
		lwsl_parser("lws_client_int_s_hs: protocol list '%s'\n", pc);

	/*
	 * confirm the protocol the server wants to talk was in the list
	 * of protocols we offered
	 */

	len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);
	if (!len) {
		lwsl_info("%s: WSI_TOKEN_PROTOCOL is null\n", __func__);
		/*
		 * no protocol name to work from, if we don't already have one
		 * default to first protocol
		 */

		if (wsi->protocol) {
			p = (char *)wsi->protocol->name;
			goto identify_protocol;
		}

		/* no choice but to use the default protocol */

		n = 0;
		wsi->protocol = &wsi->vhost->protocols[0];
		goto check_extensions;
	}

	p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL);
	len = (int)strlen(p);

	while (pc && *pc && !okay) {
		if (!strncmp(pc, p, len) &&
		    (pc[len] == ',' || pc[len] == '\0')) {
			okay = 1;
			continue;
		}
		while (*pc && *pc++ != ',')
			;
		while (*pc == ' ')
			pc++;
	}

	if (!okay) {
		lwsl_info("%s: got bad protocol %s\n", __func__, p);
		*cce = "HS: PROTOCOL malformed";
		goto bail2;
	}

identify_protocol:

#if defined(LWS_WITH_HTTP_PROXY)
	lws_strncpy(wsi->ws->actual_protocol, p,
		    sizeof(wsi->ws->actual_protocol));
#endif

	/*
	 * identify the selected protocol struct and set it
	 */
	n = 0;
	/* keep client connection pre-bound protocol */
	if (!lwsi_role_client(wsi))
		wsi->protocol = NULL;

	while (wsi->vhost->protocols[n].callback) {
		if (!wsi->protocol &&
		    strcmp(p, wsi->vhost->protocols[n].name) == 0) {
			wsi->protocol = &wsi->vhost->protocols[n];
			break;
		}
		n++;
	}

	if (!wsi->vhost->protocols[n].callback) { /* no match */
		/* if server, that's already fatal */
		if (!lwsi_role_client(wsi)) {
			lwsl_info("%s: fail protocol %s\n", __func__, p);
			*cce = "HS: Cannot match protocol";
			goto bail2;
		}

		/* for client, find the index of our pre-bound protocol */

		n = 0;
		while (wsi->vhost->protocols[n].callback) {
			if (wsi->protocol && strcmp(wsi->protocol->name,
				   wsi->vhost->protocols[n].name) == 0) {
				wsi->protocol = &wsi->vhost->protocols[n];
				break;
			}
			n++;
		}

		if (!wsi->vhost->protocols[n].callback) {
			if (wsi->protocol)
				lwsl_err("Failed to match protocol %s\n",
						wsi->protocol->name);
			else
				lwsl_err("No protocol on client\n");
			goto bail2;
		}
	}

	lwsl_debug("Selected protocol %s\n", wsi->protocol->name);

check_extensions:
	/*
	 * stitch protocol choice into the vh protocol linked list
	 * We always insert ourselves at the start of the list
	 *
	 * X <-> B
	 * X <-> pAn <-> pB
	 */

	lws_same_vh_protocol_insert(wsi, n);

#if !defined(LWS_WITHOUT_EXTENSIONS)
	/* instantiate the accepted extensions */

	if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS)) {
		lwsl_ext("no client extensions allowed by server\n");
		goto check_accept;
	}

	/*
	 * break down the list of server accepted extensions
	 * and go through matching them or identifying bogons
	 */

	if (lws_hdr_copy(wsi, sb, context->pt_serv_buf_size,
			 WSI_TOKEN_EXTENSIONS) < 0) {
		lwsl_warn("ext list from server failed to copy\n");
		*cce = "HS: EXT: list too big";
		goto bail2;
	}

	c = sb;
	n = 0;
	ignore = 0;
	a = NULL;
	while (more) {

		if (*c && (*c != ',' && *c != '\t')) {
			if (*c == ';') {
				ignore = 1;
				if (!a)
					a = c + 1;
			}
			if (ignore || *c == ' ') {
				c++;
				continue;
			}

			ext_name[n] = *c++;
			if (n < (int)sizeof(ext_name) - 1)
				n++;
			continue;
		}
		ext_name[n] = '\0';
		ignore = 0;
		if (!*c)
			more = 0;
		else {
			c++;
			if (!n)
				continue;
		}

		/* check we actually support it */

		lwsl_notice("checking client ext %s\n", ext_name);

		n = 0;
		ext = wsi->vhost->ws.extensions;
		while (ext && ext->callback) {
			if (strcmp(ext_name, ext->name)) {
				ext++;
				continue;
			}

			n = 1;
			lwsl_notice("instantiating client ext %s\n", ext_name);

			/* instantiate the extension on this conn */

			wsi->ws->active_extensions[wsi->ws->count_act_ext] = ext;

			/* allow him to construct his ext instance */

			if (ext->callback(lws_get_context(wsi), ext, wsi,
				   LWS_EXT_CB_CLIENT_CONSTRUCT,
				   (void *)&wsi->ws->act_ext_user[
				                        wsi->ws->count_act_ext],
				   (void *)&opts, 0)) {
				lwsl_info(" ext %s failed construction\n",
					  ext_name);
				ext++;
				continue;
			}

			/*
			 * allow the user code to override ext defaults if it
			 * wants to
			 */
			ext_name[0] = '\0';
			if (user_callback_handle_rxflow(wsi->protocol->callback,
					wsi, LWS_CALLBACK_WS_EXT_DEFAULTS,
					(char *)ext->name, ext_name,
					sizeof(ext_name))) {
				*cce = "HS: EXT: failed setting defaults";
				goto bail2;
			}

			if (ext_name[0] &&
			    lws_ext_parse_options(ext, wsi,
					          wsi->ws->act_ext_user[
						        wsi->ws->count_act_ext],
					          opts, ext_name,
						  (int)strlen(ext_name))) {
				lwsl_err("%s: unable to parse user defaults '%s'",
					 __func__, ext_name);
				*cce = "HS: EXT: failed parsing defaults";
				goto bail2;
			}

			/*
			 * give the extension the server options
			 */
			if (a && lws_ext_parse_options(ext, wsi,
					wsi->ws->act_ext_user[
					                wsi->ws->count_act_ext],
					opts, a, lws_ptr_diff(c, a))) {
				lwsl_err("%s: unable to parse remote def '%s'",
					 __func__, a);
				*cce = "HS: EXT: failed parsing options";
				goto bail2;
			}

			if (ext->callback(lws_get_context(wsi), ext, wsi,
					LWS_EXT_CB_OPTION_CONFIRM,
				      wsi->ws->act_ext_user[wsi->ws->count_act_ext],
				      NULL, 0)) {
				lwsl_err("%s: ext %s rejects server options %s",
					 __func__, ext->name, a);
				*cce = "HS: EXT: Rejects server options";
				goto bail2;
			}

			wsi->ws->count_act_ext++;

			ext++;
		}

		if (n == 0) {
			lwsl_warn("Unknown ext '%s'!\n", ext_name);
			*cce = "HS: EXT: unknown ext";
			goto bail2;
		}

		a = NULL;
		n = 0;
	}

check_accept:
#endif

	/*
	 * Confirm his accept token is the one we precomputed
	 */

	p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_ACCEPT);
	if (strcmp(p, wsi->http.ah->initial_handshake_hash_base64)) {
		lwsl_warn("lws_client_int_s_hs: accept '%s' wrong vs '%s'\n", p,
				  wsi->http.ah->initial_handshake_hash_base64);
		*cce = "HS: Accept hash wrong";
		goto bail2;
	}

	/* allocate the per-connection user memory (if any) */
	if (lws_ensure_user_space(wsi)) {
		lwsl_err("Problem allocating wsi user mem\n");
		*cce = "HS: OOM";
		goto bail2;
	}

	/*
	 * we seem to be good to go, give client last chance to check
	 * headers and OK it
	 */
	if (wsi->protocol->callback(wsi,
				    LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
				    wsi->user_space, NULL, 0)) {
		*cce = "HS: Rejected by filter cb";
		goto bail2;
	}

	/* clear his proxy connection timeout */
	lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);

	/* free up his parsing allocations */
	lws_header_table_detach(wsi, 0);

	lws_role_transition(wsi, LWSIFR_CLIENT, LRS_ESTABLISHED,
			    &role_ops_ws);
	lws_restart_ws_ping_pong_timer(wsi);

	wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;

	/*
	 * create the frame buffer for this connection according to the
	 * size mentioned in the protocol definition.  If 0 there, then
	 * use a big default for compatibility
	 */
	n = (int)wsi->protocol->rx_buffer_size;
	if (!n)
		n = context->pt_serv_buf_size;
	n += LWS_PRE;
	wsi->ws->rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */,
				"client frame buffer");
	if (!wsi->ws->rx_ubuf) {
		lwsl_err("Out of Mem allocating rx buffer %d\n", n);
		*cce = "HS: OOM";
		goto bail2;
	}
	wsi->ws->rx_ubuf_alloc = n;
	lwsl_info("Allocating client RX buffer %d\n", n);

#if !defined(LWS_WITH_ESP32)
	if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF,
		       (const char *)&n, sizeof n)) {
		lwsl_warn("Failed to set SNDBUF to %d", n);
		*cce = "HS: SO_SNDBUF failed";
		goto bail3;
	}
#endif

	lwsl_debug("handshake OK for protocol %s\n", wsi->protocol->name);

	/* call him back to inform him he is up */

	if (wsi->protocol->callback(wsi, LWS_CALLBACK_CLIENT_ESTABLISHED,
				    wsi->user_space, NULL, 0)) {
		*cce = "HS: Rejected at CLIENT_ESTABLISHED";
		goto bail3;
	}

	return 0;

bail3:
	return 3;

bail2:
	return 2;
}