1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2020 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci *
24d4afb5ceSopenharmony_ci * C++ classes for Secure Streams
25d4afb5ceSopenharmony_ci */
26d4afb5ceSopenharmony_ci
27d4afb5ceSopenharmony_ci#include <libwebsockets.hxx>
28d4afb5ceSopenharmony_ci
29d4afb5ceSopenharmony_cistatic const char *pcols[] = {
30d4afb5ceSopenharmony_ci	"http://",	/* LWSSSP_H1 */
31d4afb5ceSopenharmony_ci	"https://",
32d4afb5ceSopenharmony_ci	"h2://",	/* LWSSSP_H2 */
33d4afb5ceSopenharmony_ci	"h2s://",
34d4afb5ceSopenharmony_ci	"ws://",	/* LWSSSP_WS */
35d4afb5ceSopenharmony_ci	"wss://",
36d4afb5ceSopenharmony_ci	"mqtt://",	/* LWSSSP_MQTT */
37d4afb5ceSopenharmony_ci	"mqtts://",
38d4afb5ceSopenharmony_ci	"raw://",	/* LWSSSP_RAW */
39d4afb5ceSopenharmony_ci	"raws://",
40d4afb5ceSopenharmony_ci};
41d4afb5ceSopenharmony_ci
42d4afb5ceSopenharmony_cistatic const uint8_t pcols_len[] = {
43d4afb5ceSopenharmony_ci	7, 8, 5, 6, 5, 6, 7, 8, 6, 7
44d4afb5ceSopenharmony_ci};
45d4afb5ceSopenharmony_ci
46d4afb5ceSopenharmony_cistatic const uint16_t pcols_port[] = {
47d4afb5ceSopenharmony_ci	80, 443, 443, 443, 80, 443, 1883, 8883, 80, 443
48d4afb5ceSopenharmony_ci};
49d4afb5ceSopenharmony_ci
50d4afb5ceSopenharmony_cilss::lss(lws_ctx_t _ctx, std::string _uri, lsscomp_t _comp, bool _psh,
51d4afb5ceSopenharmony_ci	 lws_sscb_rx rx, lws_sscb_tx tx, lws_sscb_state state)
52d4afb5ceSopenharmony_ci{
53d4afb5ceSopenharmony_ci	const char *p, *urlpath;
54d4afb5ceSopenharmony_ci	lws_ss_info_t ssi;
55d4afb5ceSopenharmony_ci	int n, port;
56d4afb5ceSopenharmony_ci
57d4afb5ceSopenharmony_ci	memset(&ssi, 0, sizeof(ssi));
58d4afb5ceSopenharmony_ci	memset(&pol, 0, sizeof(pol));
59d4afb5ceSopenharmony_ci
60d4afb5ceSopenharmony_ci	ctx		= _ctx;
61d4afb5ceSopenharmony_ci	comp		= _comp;
62d4afb5ceSopenharmony_ci	comp_done	= 0;
63d4afb5ceSopenharmony_ci	rxlen		= 0;
64d4afb5ceSopenharmony_ci
65d4afb5ceSopenharmony_ci	/*
66d4afb5ceSopenharmony_ci	 * We have a common stub userdata, our "real" userdata is in the
67d4afb5ceSopenharmony_ci	 * derived class members.   The Opaque user pointer points to the
68d4afb5ceSopenharmony_ci	 * lss itself.
69d4afb5ceSopenharmony_ci	 */
70d4afb5ceSopenharmony_ci
71d4afb5ceSopenharmony_ci	ssi.handle_offset	    = offsetof(lssPriv, lssPriv::m_ss);
72d4afb5ceSopenharmony_ci	ssi.opaque_user_data_offset = offsetof(lssPriv, lssPriv::m_plss);
73d4afb5ceSopenharmony_ci
74d4afb5ceSopenharmony_ci	ssi.user_alloc	= sizeof(lssPriv);
75d4afb5ceSopenharmony_ci	ssi.rx		= rx;
76d4afb5ceSopenharmony_ci	ssi.tx		= tx;
77d4afb5ceSopenharmony_ci	ssi.state	= state;
78d4afb5ceSopenharmony_ci	ssi.policy	= &pol; /* we will provide our own policy */
79d4afb5ceSopenharmony_ci
80d4afb5ceSopenharmony_ci	/*
81d4afb5ceSopenharmony_ci	 * _uri is like "https://warmcat.com:443/index.html"... we need to
82d4afb5ceSopenharmony_ci	 * deconstruct it into its policy implications
83d4afb5ceSopenharmony_ci	 */
84d4afb5ceSopenharmony_ci
85d4afb5ceSopenharmony_ci	uri = strdup(_uri.c_str());
86d4afb5ceSopenharmony_ci
87d4afb5ceSopenharmony_ci	for (n = 0; n < LWS_ARRAY_SIZE(pcols); n++)
88d4afb5ceSopenharmony_ci		if (!strncmp(uri, pcols[n], pcols_len[n]))
89d4afb5ceSopenharmony_ci			break;
90d4afb5ceSopenharmony_ci
91d4afb5ceSopenharmony_ci	if (n == LWS_ARRAY_SIZE(pcols))
92d4afb5ceSopenharmony_ci		throw lssException("unknown uri protocol://");
93d4afb5ceSopenharmony_ci
94d4afb5ceSopenharmony_ci	pol.protocol = n >> 1;
95d4afb5ceSopenharmony_ci	if (n & 1)
96d4afb5ceSopenharmony_ci		pol.flags |= LWSSSPOLF_TLS;
97d4afb5ceSopenharmony_ci
98d4afb5ceSopenharmony_ci	n = pcols_port[n];
99d4afb5ceSopenharmony_ci
100d4afb5ceSopenharmony_ci	if (lws_parse_uri(uri, &p, &pol.endpoint, &n, &urlpath))
101d4afb5ceSopenharmony_ci		throw lssException("unable to parse uri://");
102d4afb5ceSopenharmony_ci
103d4afb5ceSopenharmony_ci	pol.port = (uint16_t)n;
104d4afb5ceSopenharmony_ci
105d4afb5ceSopenharmony_ci	if (pol.protocol <= LWSSSP_WS) {
106d4afb5ceSopenharmony_ci		pol.u.http.url = urlpath;
107d4afb5ceSopenharmony_ci
108d4afb5ceSopenharmony_ci		/*
109d4afb5ceSopenharmony_ci		 * These are workarounds for common h2 server noncompliances
110d4afb5ceSopenharmony_ci		 */
111d4afb5ceSopenharmony_ci
112d4afb5ceSopenharmony_ci		pol.flags |= LWSSSPOLF_QUIRK_NGHTTP2_END_STREAM |
113d4afb5ceSopenharmony_ci			     LWSSSPOLF_H2_QUIRK_OVERFLOWS_TXCR |
114d4afb5ceSopenharmony_ci			     LWSSSPOLF_H2_QUIRK_UNCLEAN_HPACK_STATE;
115d4afb5ceSopenharmony_ci
116d4afb5ceSopenharmony_ci		if (pol.protocol < LWSSSP_WS)
117d4afb5ceSopenharmony_ci			pol.u.http.method = _psh ? "POST" : "GET";
118d4afb5ceSopenharmony_ci	}
119d4afb5ceSopenharmony_ci
120d4afb5ceSopenharmony_ci	us_start = lws_now_usecs();
121d4afb5ceSopenharmony_ci
122d4afb5ceSopenharmony_ci	if (lws_ss_create(ctx, 0, &ssi, (void *)this, &m_ss, NULL, NULL))
123d4afb5ceSopenharmony_ci		goto blow;
124d4afb5ceSopenharmony_ci
125d4afb5ceSopenharmony_ci	if (pol.protocol <= LWSSSP_WS)
126d4afb5ceSopenharmony_ci		lws_ss_client_connect(m_ss);
127d4afb5ceSopenharmony_ci
128d4afb5ceSopenharmony_ci	return;
129d4afb5ceSopenharmony_ci
130d4afb5ceSopenharmony_ciblow:
131d4afb5ceSopenharmony_ci	if (uri)
132d4afb5ceSopenharmony_ci		free(uri);
133d4afb5ceSopenharmony_ci	throw lssException("ss creation failed");
134d4afb5ceSopenharmony_ci}
135d4afb5ceSopenharmony_ci
136d4afb5ceSopenharmony_cilss::~lss()
137d4afb5ceSopenharmony_ci{
138d4afb5ceSopenharmony_ci	if (uri)
139d4afb5ceSopenharmony_ci		free(uri);
140d4afb5ceSopenharmony_ci	if (m_ss)
141d4afb5ceSopenharmony_ci		lws_ss_destroy(&m_ss);
142d4afb5ceSopenharmony_ci}
143d4afb5ceSopenharmony_ci
144d4afb5ceSopenharmony_ciint lss::call_completion(lws_ss_constate_t state)
145d4afb5ceSopenharmony_ci{
146d4afb5ceSopenharmony_ci	if (comp_done)
147d4afb5ceSopenharmony_ci		return 0;
148d4afb5ceSopenharmony_ci	if (!comp)
149d4afb5ceSopenharmony_ci		return 0;
150d4afb5ceSopenharmony_ci
151d4afb5ceSopenharmony_ci	comp_done = 1;
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci	return comp(this, state, NULL);
154d4afb5ceSopenharmony_ci}
155