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
29 int
secstream_raw(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)30 secstream_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
168 static int
secstream_connect_munge_raw(lws_ss_handle_t * h,char * buf,size_t len,struct lws_client_connect_info * i,union lws_ss_contemp * ct)169 secstream_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
179 const struct lws_protocols protocol_secstream_raw = {
180 "lws-secstream-raw",
181 secstream_raw,
182 0,
183 0,
184 0, NULL, 0
185 };
186
187 const struct ss_pcols ss_pcol_raw = {
188 "raw",
189 "",
190 &protocol_secstream_raw,
191 secstream_connect_munge_raw,
192 NULL, NULL
193 };
194