1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2019 - 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
25d4afb5ceSopenharmony_ci#include <private-lib-core.h>
26d4afb5ceSopenharmony_ci
27d4afb5ceSopenharmony_cistatic int
28d4afb5ceSopenharmony_cisecstream_ws(struct lws *wsi, enum lws_callback_reasons reason, void *user,
29d4afb5ceSopenharmony_ci	     void *in, size_t len)
30d4afb5ceSopenharmony_ci{
31d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
32d4afb5ceSopenharmony_ci	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
33d4afb5ceSopenharmony_ci#endif
34d4afb5ceSopenharmony_ci	lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
35d4afb5ceSopenharmony_ci	uint8_t buf[LWS_PRE + 1400];
36d4afb5ceSopenharmony_ci	lws_ss_state_return_t r;
37d4afb5ceSopenharmony_ci	int f = 0, f1, n;
38d4afb5ceSopenharmony_ci	size_t buflen;
39d4afb5ceSopenharmony_ci
40d4afb5ceSopenharmony_ci	switch (reason) {
41d4afb5ceSopenharmony_ci
42d4afb5ceSopenharmony_ci	/* because we are protocols[0] ... */
43d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
44d4afb5ceSopenharmony_ci		lwsl_info("%s: CLIENT_CONNECTION_ERROR: %s\n", __func__,
45d4afb5ceSopenharmony_ci			 in ? (char *)in : "(null)");
46d4afb5ceSopenharmony_ci		if (!h)
47d4afb5ceSopenharmony_ci			break;
48d4afb5ceSopenharmony_ci
49d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CONMON)
50d4afb5ceSopenharmony_ci		lws_conmon_ss_json(h);
51d4afb5ceSopenharmony_ci#endif
52d4afb5ceSopenharmony_ci
53d4afb5ceSopenharmony_ci		r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE);
54d4afb5ceSopenharmony_ci		if (r == LWSSSSRET_DESTROY_ME)
55d4afb5ceSopenharmony_ci			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
56d4afb5ceSopenharmony_ci
57d4afb5ceSopenharmony_ci		h->wsi = NULL;
58d4afb5ceSopenharmony_ci		r = lws_ss_backoff(h);
59d4afb5ceSopenharmony_ci		if (r != LWSSSSRET_OK)
60d4afb5ceSopenharmony_ci			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
61d4afb5ceSopenharmony_ci		break;
62d4afb5ceSopenharmony_ci
63d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLOSED: /* server */
64d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_CLOSED:
65d4afb5ceSopenharmony_ci		if (!h)
66d4afb5ceSopenharmony_ci			break;
67d4afb5ceSopenharmony_ci		lws_sul_cancel(&h->sul_timeout);
68d4afb5ceSopenharmony_ci
69d4afb5ceSopenharmony_ci#if defined(LWS_WITH_CONMON)
70d4afb5ceSopenharmony_ci		lws_conmon_ss_json(h);
71d4afb5ceSopenharmony_ci#endif
72d4afb5ceSopenharmony_ci
73d4afb5ceSopenharmony_ci		r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
74d4afb5ceSopenharmony_ci		if (r == LWSSSSRET_DESTROY_ME)
75d4afb5ceSopenharmony_ci			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
76d4afb5ceSopenharmony_ci
77d4afb5ceSopenharmony_ci		if (h->wsi)
78d4afb5ceSopenharmony_ci			lws_set_opaque_user_data(h->wsi, NULL);
79d4afb5ceSopenharmony_ci		h->wsi = NULL;
80d4afb5ceSopenharmony_ci
81d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
82d4afb5ceSopenharmony_ci		lws_pt_lock(pt, __func__);
83d4afb5ceSopenharmony_ci		lws_dll2_remove(&h->cli_list);
84d4afb5ceSopenharmony_ci		lws_pt_unlock(pt);
85d4afb5ceSopenharmony_ci#endif
86d4afb5ceSopenharmony_ci
87d4afb5ceSopenharmony_ci		if (reason == LWS_CALLBACK_CLIENT_CLOSED) {
88d4afb5ceSopenharmony_ci			if (h->policy &&
89d4afb5ceSopenharmony_ci			    !(h->policy->flags & LWSSSPOLF_OPPORTUNISTIC) &&
90d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
91d4afb5ceSopenharmony_ci			    !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not server */
92d4afb5ceSopenharmony_ci#endif
93d4afb5ceSopenharmony_ci			    !wsi->a.context->being_destroyed) {
94d4afb5ceSopenharmony_ci				r = lws_ss_backoff(h);
95d4afb5ceSopenharmony_ci				if (r != LWSSSSRET_OK)
96d4afb5ceSopenharmony_ci					return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
97d4afb5ceSopenharmony_ci				break;
98d4afb5ceSopenharmony_ci			}
99d4afb5ceSopenharmony_ci
100d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SERVER)
101d4afb5ceSopenharmony_ci			if (h->info.flags & LWSSSINFLAGS_ACCEPTED) {
102d4afb5ceSopenharmony_ci				/*
103d4afb5ceSopenharmony_ci				 * was an accepted client connection to
104d4afb5ceSopenharmony_ci				 * our server, so the stream is over now
105d4afb5ceSopenharmony_ci				 */
106d4afb5ceSopenharmony_ci				lws_ss_destroy(&h);
107d4afb5ceSopenharmony_ci				return 0;
108d4afb5ceSopenharmony_ci			}
109d4afb5ceSopenharmony_ci#endif
110d4afb5ceSopenharmony_ci
111d4afb5ceSopenharmony_ci		}
112d4afb5ceSopenharmony_ci		break;
113d4afb5ceSopenharmony_ci
114d4afb5ceSopenharmony_ci	case LWS_CALLBACK_ESTABLISHED:
115d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_ESTABLISHED:
116d4afb5ceSopenharmony_ci		h->retry = 0;
117d4afb5ceSopenharmony_ci		h->seqstate = SSSEQ_CONNECTED;
118d4afb5ceSopenharmony_ci		lws_sul_cancel(&h->sul);
119d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS)
120d4afb5ceSopenharmony_ci		/*
121d4afb5ceSopenharmony_ci		 * If any hanging caliper measurement, dump it, and free any tags
122d4afb5ceSopenharmony_ci		 */
123d4afb5ceSopenharmony_ci		lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
124d4afb5ceSopenharmony_ci#endif
125d4afb5ceSopenharmony_ci		r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
126d4afb5ceSopenharmony_ci		if (r != LWSSSSRET_OK)
127d4afb5ceSopenharmony_ci			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
128d4afb5ceSopenharmony_ci		break;
129d4afb5ceSopenharmony_ci
130d4afb5ceSopenharmony_ci	case LWS_CALLBACK_RECEIVE:
131d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_RECEIVE:
132d4afb5ceSopenharmony_ci		// lwsl_user("LWS_CALLBACK_CLIENT_RECEIVE: read %d\n", (int)len);
133d4afb5ceSopenharmony_ci		if (!h || !h->info.rx)
134d4afb5ceSopenharmony_ci			return 0;
135d4afb5ceSopenharmony_ci		if (lws_is_first_fragment(wsi))
136d4afb5ceSopenharmony_ci			f |= LWSSS_FLAG_SOM;
137d4afb5ceSopenharmony_ci		if (lws_is_final_fragment(wsi))
138d4afb5ceSopenharmony_ci			f |= LWSSS_FLAG_EOM;
139d4afb5ceSopenharmony_ci		// lws_frame_is_binary(wsi);
140d4afb5ceSopenharmony_ci
141d4afb5ceSopenharmony_ci		h->subseq = 1;
142d4afb5ceSopenharmony_ci
143d4afb5ceSopenharmony_ci		r = h->info.rx(ss_to_userobj(h), (const uint8_t *)in, len, f);
144d4afb5ceSopenharmony_ci		if (r != LWSSSSRET_OK)
145d4afb5ceSopenharmony_ci			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
146d4afb5ceSopenharmony_ci
147d4afb5ceSopenharmony_ci		return 0; /* don't passthru */
148d4afb5ceSopenharmony_ci
149d4afb5ceSopenharmony_ci	case LWS_CALLBACK_SERVER_WRITEABLE:
150d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLIENT_WRITEABLE:
151d4afb5ceSopenharmony_ci		// lwsl_notice("%s: %s: WRITEABLE\n", __func__, lws_ss_tag(h));
152d4afb5ceSopenharmony_ci		if (!h || !h->info.tx)
153d4afb5ceSopenharmony_ci			return 0;
154d4afb5ceSopenharmony_ci
155d4afb5ceSopenharmony_ci		if (h->seqstate != SSSEQ_CONNECTED) {
156d4afb5ceSopenharmony_ci			lwsl_warn("%s: seqstate %d\n", __func__, h->seqstate);
157d4afb5ceSopenharmony_ci			break;
158d4afb5ceSopenharmony_ci		}
159d4afb5ceSopenharmony_ci
160d4afb5ceSopenharmony_ci		buflen = sizeof(buf) - LWS_PRE;
161d4afb5ceSopenharmony_ci		r = h->info.tx(ss_to_userobj(h),  h->txord++, buf + LWS_PRE,
162d4afb5ceSopenharmony_ci				  &buflen, &f);
163d4afb5ceSopenharmony_ci		if (r == LWSSSSRET_TX_DONT_SEND)
164d4afb5ceSopenharmony_ci			return 0;
165d4afb5ceSopenharmony_ci		if (r != LWSSSSRET_OK)
166d4afb5ceSopenharmony_ci			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
167d4afb5ceSopenharmony_ci
168d4afb5ceSopenharmony_ci		f1 = lws_write_ws_flags(h->policy->u.http.u.ws.binary ?
169d4afb5ceSopenharmony_ci					   LWS_WRITE_BINARY : LWS_WRITE_TEXT,
170d4afb5ceSopenharmony_ci					!!(f & LWSSS_FLAG_SOM),
171d4afb5ceSopenharmony_ci					!!(f & LWSSS_FLAG_EOM));
172d4afb5ceSopenharmony_ci
173d4afb5ceSopenharmony_ci		n = lws_write(wsi, buf + LWS_PRE, buflen, (enum lws_write_protocol)f1);
174d4afb5ceSopenharmony_ci		if (n < (int)buflen) {
175d4afb5ceSopenharmony_ci			lwsl_info("%s: write failed %d %d\n", __func__,
176d4afb5ceSopenharmony_ci					n, (int)buflen);
177d4afb5ceSopenharmony_ci
178d4afb5ceSopenharmony_ci			return -1;
179d4afb5ceSopenharmony_ci		}
180d4afb5ceSopenharmony_ci
181d4afb5ceSopenharmony_ci		return 0;
182d4afb5ceSopenharmony_ci
183d4afb5ceSopenharmony_ci	default:
184d4afb5ceSopenharmony_ci		break;
185d4afb5ceSopenharmony_ci	}
186d4afb5ceSopenharmony_ci
187d4afb5ceSopenharmony_ci	return lws_callback_http_dummy(wsi, reason, user, in, len);
188d4afb5ceSopenharmony_ci}
189d4afb5ceSopenharmony_ci
190d4afb5ceSopenharmony_ciconst struct lws_protocols protocol_secstream_ws = {
191d4afb5ceSopenharmony_ci	"lws-secstream-ws",
192d4afb5ceSopenharmony_ci	secstream_ws,
193d4afb5ceSopenharmony_ci	0, 0, 0, NULL, 0
194d4afb5ceSopenharmony_ci};
195d4afb5ceSopenharmony_ci/*
196d4afb5ceSopenharmony_ci * Munge connect info according to protocol-specific considerations... this
197d4afb5ceSopenharmony_ci * usually means interpreting aux in a protocol-specific way and using the
198d4afb5ceSopenharmony_ci * pieces at connection setup time, eg, http url pieces.
199d4afb5ceSopenharmony_ci *
200d4afb5ceSopenharmony_ci * len bytes of buf can be used for things with scope until after the actual
201d4afb5ceSopenharmony_ci * connect.
202d4afb5ceSopenharmony_ci *
203d4afb5ceSopenharmony_ci * For ws, protocol aux is <url path>;<ws subprotocol name>
204d4afb5ceSopenharmony_ci */
205d4afb5ceSopenharmony_ci
206d4afb5ceSopenharmony_cistatic int
207d4afb5ceSopenharmony_cisecstream_connect_munge_ws(lws_ss_handle_t *h, char *buf, size_t len,
208d4afb5ceSopenharmony_ci			   struct lws_client_connect_info *i,
209d4afb5ceSopenharmony_ci			   union lws_ss_contemp *ct)
210d4afb5ceSopenharmony_ci{
211d4afb5ceSopenharmony_ci	const char *pbasis = h->policy->u.http.url;
212d4afb5ceSopenharmony_ci	size_t used_in, used_out;
213d4afb5ceSopenharmony_ci	lws_strexp_t exp;
214d4afb5ceSopenharmony_ci
215d4afb5ceSopenharmony_ci	/* i.path on entry is used to override the policy urlpath if not "" */
216d4afb5ceSopenharmony_ci
217d4afb5ceSopenharmony_ci	if (i->path[0])
218d4afb5ceSopenharmony_ci		pbasis = i->path;
219d4afb5ceSopenharmony_ci
220d4afb5ceSopenharmony_ci	if (!pbasis)
221d4afb5ceSopenharmony_ci		return 0;
222d4afb5ceSopenharmony_ci
223d4afb5ceSopenharmony_ci	if (h->policy->flags & LWSSSPOLF_HTTP_CACHE_COOKIES)
224d4afb5ceSopenharmony_ci		i->ssl_connection |= LCCSCF_CACHE_COOKIES;
225d4afb5ceSopenharmony_ci
226d4afb5ceSopenharmony_ci	if (h->policy->flags & LWSSSPOLF_PRIORITIZE_READS)
227d4afb5ceSopenharmony_ci		i->ssl_connection |= LCCSCF_PRIORITIZE_READS;
228d4afb5ceSopenharmony_ci
229d4afb5ceSopenharmony_ci	/* protocol aux is the path part ; ws subprotocol name */
230d4afb5ceSopenharmony_ci
231d4afb5ceSopenharmony_ci	i->path = buf;
232d4afb5ceSopenharmony_ci	buf[0] = '/';
233d4afb5ceSopenharmony_ci
234d4afb5ceSopenharmony_ci	lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, buf + 1, len - 1);
235d4afb5ceSopenharmony_ci
236d4afb5ceSopenharmony_ci	if (lws_strexp_expand(&exp, pbasis, strlen(pbasis),
237d4afb5ceSopenharmony_ci			      &used_in, &used_out) != LSTRX_DONE)
238d4afb5ceSopenharmony_ci		return 1;
239d4afb5ceSopenharmony_ci
240d4afb5ceSopenharmony_ci	i->protocol = h->policy->u.http.u.ws.subprotocol;
241d4afb5ceSopenharmony_ci
242d4afb5ceSopenharmony_ci	lwsl_ss_info(h, "url %s, ws subprotocol %s", buf, i->protocol);
243d4afb5ceSopenharmony_ci
244d4afb5ceSopenharmony_ci	return 0;
245d4afb5ceSopenharmony_ci}
246d4afb5ceSopenharmony_ci
247d4afb5ceSopenharmony_ciconst struct ss_pcols ss_pcol_ws = {
248d4afb5ceSopenharmony_ci	"ws",  "http/1.1",  &protocol_secstream_ws, secstream_connect_munge_ws, 0, 0
249d4afb5ceSopenharmony_ci};
250