1/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 *
24 * This is the glue that wires up raw-socket to Secure Streams.
25 */
26
27#include <private-lib-core.h>
28
29int
30secstream_raw(struct lws *wsi, enum lws_callback_reasons reason, void *user,
31	      void *in, size_t len)
32{
33#if defined(LWS_WITH_SERVER)
34	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
35#endif
36	lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi);
37	uint8_t buf[LWS_PRE + 1520], *p = &buf[LWS_PRE],
38		*end = &buf[sizeof(buf) - 1];
39	lws_ss_state_return_t r;
40	size_t buflen;
41	int f = 0;
42
43	switch (reason) {
44
45	case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
46		assert(h);
47		assert(h->policy);
48		lwsl_info("%s: %s, %s CLIENT_CONNECTION_ERROR: %s\n", __func__,
49			  lws_ss_tag(h), h->policy->streamtype, in ? (char *)in : "(null)");
50
51#if defined(LWS_WITH_CONMON)
52		lws_conmon_ss_json(h);
53#endif
54
55		r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE);
56		if (r == LWSSSSRET_DESTROY_ME)
57			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
58		h->wsi = NULL;
59		r = lws_ss_backoff(h);
60		if (r != LWSSSSRET_OK)
61			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
62		break;
63
64	case LWS_CALLBACK_RAW_CLOSE:
65		if (!h)
66			break;
67		lws_sul_cancel(&h->sul_timeout);
68
69#if defined(LWS_WITH_CONMON)
70		lws_conmon_ss_json(h);
71#endif
72
73		lwsl_info("%s: %s, %s RAW_CLOSE\n", __func__, lws_ss_tag(h),
74			  h->policy ? h->policy->streamtype : "no policy");
75		h->wsi = NULL;
76#if defined(LWS_WITH_SERVER)
77		lws_pt_lock(pt, __func__);
78		lws_dll2_remove(&h->cli_list);
79		lws_pt_unlock(pt);
80#endif
81
82		/* wsi is going down anyway */
83		r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
84		if (r == LWSSSSRET_DESTROY_ME)
85			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
86
87		if (h->policy && !(h->policy->flags & LWSSSPOLF_OPPORTUNISTIC) &&
88#if defined(LWS_WITH_SERVER)
89			    !(h->info.flags & LWSSSINFLAGS_ACCEPTED) && /* not server */
90#endif
91		    !h->txn_ok && !wsi->a.context->being_destroyed) {
92			r = lws_ss_backoff(h);
93			if (r != LWSSSSRET_OK)
94				return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
95			break;
96		}
97
98		break;
99
100	case LWS_CALLBACK_RAW_CONNECTED:
101		lwsl_info("%s: RAW_CONNECTED\n", __func__);
102
103		h->retry = 0;
104		h->seqstate = SSSEQ_CONNECTED;
105		lws_sul_cancel(&h->sul);
106#if defined(LWS_WITH_SYS_METRICS)
107		/*
108		 * If any hanging caliper measurement, dump it, and free any tags
109		 */
110		lws_metrics_caliper_report_hist(h->cal_txn, (struct lws *)NULL);
111#endif
112		r = lws_ss_event_helper(h, LWSSSCS_CONNECTED);
113		if (r != LWSSSSRET_OK)
114			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
115
116		lws_validity_confirmed(wsi);
117		break;
118
119	case LWS_CALLBACK_RAW_ADOPT:
120		lwsl_info("%s: RAW_ADOPT\n", __func__);
121		break;
122
123	/* chunks of chunked content, with header removed */
124	case LWS_CALLBACK_RAW_RX:
125		if (!h || !h->info.rx)
126			return 0;
127
128		r = h->info.rx(ss_to_userobj(h), (const uint8_t *)in, len, 0);
129		if (r != LWSSSSRET_OK)
130			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
131
132		return 0; /* don't passthru */
133
134	case LWS_CALLBACK_RAW_WRITEABLE:
135		lwsl_info("%s: RAW_WRITEABLE\n", __func__);
136		if (!h || !h->info.tx)
137			return 0;
138
139		buflen = lws_ptr_diff_size_t(end, p);
140		r = h->info.tx(ss_to_userobj(h),  h->txord++, p, &buflen, &f);
141		if (r == LWSSSSRET_TX_DONT_SEND)
142			return 0;
143		if (r < 0)
144			return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h);
145
146		/*
147		 * flags are ignored with raw, there are no protocol payload
148		 * boundaries, just an arbitrarily-fragmented bytestream
149		 */
150
151		p += buflen;
152		if (lws_write(wsi, buf + LWS_PRE, lws_ptr_diff_size_t(p, buf + LWS_PRE),
153			 LWS_WRITE_HTTP) != lws_ptr_diff(p, buf + LWS_PRE)) {
154			lwsl_err("%s: write failed\n", __func__);
155			return -1;
156		}
157
158		lws_set_timeout(wsi, 0, 0);
159		break;
160
161	default:
162		break;
163	}
164
165	return 0;
166}
167
168static int
169secstream_connect_munge_raw(lws_ss_handle_t *h, char *buf, size_t len,
170			   struct lws_client_connect_info *i,
171			   union lws_ss_contemp *ct)
172{
173	i->method = "RAW";
174
175	return 0;
176}
177
178
179const struct lws_protocols protocol_secstream_raw = {
180	"lws-secstream-raw",
181	secstream_raw,
182	0,
183	0,
184	0, NULL, 0
185};
186
187const struct ss_pcols ss_pcol_raw = {
188	"raw",
189	"",
190	&protocol_secstream_raw,
191	secstream_connect_munge_raw,
192	NULL, NULL
193};
194