1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #include "websocket.h"
33
34 #include "../util/io.h"
35 #include "../util/pblock.h"
36 #include "../util/util.h"
37 #include "../util/strbuf.h"
38 #include <cx/string.h>
39
40 #define WS_BUFFER_LEN 2048
41
42 NSAPI_PUBLIC int http_handle_websocket(Session *sn, Request *rq, WebSocket *websocket) {
43 char *connection = pblock_findkeyval(pb_key_connection, rq->headers);
44 char *upgrade = pblock_findval(
"upgrade", rq->headers);
45 char *origin = pblock_findval(
"origin", rq->headers);
46 char *wskey = pblock_findval(
"sec-websocket-key", rq->headers);
47 char *wsprot = pblock_findval(
"sec-websocket-protocol", rq->headers);
48 char *wsv = pblock_findval(
"sec-websocket-version", rq->headers);
49
50 if(!connection || !upgrade) {
51 return REQ_NOACTION;
52 }
53
54 if(cx_strcasecmp(cx_str(connection), (cxstring)
CX_STR(
"upgrade"))) {
55 return REQ_NOACTION;
56 }
57 if(cx_strcasecmp(cx_str(upgrade), (cxstring)
CX_STR(
"websocket"))) {
58 return REQ_NOACTION;
59 }
60
61 cxmutstr wsaccept = cx_strcat(
2, cx_str(wskey), (cxstring)
CX_STR(
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
62 unsigned char hash[
20];
63 SHA1((
const unsigned char*)wsaccept.ptr, wsaccept.length, hash);
64 char *websocket_accept = util_base64encode((
char*)hash,
20);
65
66 sbuf_t *response = sbuf_new(
512);
67 sbuf_append(response, (cxstring)
CX_STR(
"HTTP/1.1 101 Switching Protocols\r\n"));
68 sbuf_append(response, (cxstring)
CX_STR(
"Upgrade: websocket\r\n"));
69 sbuf_append(response, (cxstring)
CX_STR(
"Connection: Upgrade\r\n"));
70 sbuf_append(response, (cxstring)
CX_STR(
"Sec-WebSocket-Accept: "));
71 sbuf_puts(response, websocket_accept);
72 sbuf_append(response, (cxstring)
CX_STR(
"\r\n\r\n"));
73
74 net_write(sn->csd, response->ptr, response->length);
75 sbuf_free(response);
76 free(websocket_accept);
77 free(wsaccept.ptr);
78
79
80 WSParser *parser = websocket_parser(sn);
81
82 WSFrame frame;
83
84 int ret =
REQ_PROCEED;
85 char *inbuf = pool_malloc(sn->pool,
WS_BUFFER_LEN);
86 ssize_t r =
0;
87 while((r = net_read(sn->csd, inbuf,
WS_BUFFER_LEN)) >
0) {
88 websocket_input(parser, inbuf, r);
89 WSMessage *msg;
90 int error;
91 while((msg = websocket_get_message(parser, &error)) !=
NULL) {
92 websocket->on_message(websocket, msg);
93 }
94 if(error) {
95 log_ereport(
LOG_FAILURE,
"websocket protocol error");
96 break;
97 }
98 }
99
100 return ret;
101 }
102
103
104 WSParser* websocket_parser(Session *sn) {
105 WSParser *parser = pool_malloc(sn->pool,
sizeof(WSParser));
106 if(!parser) {
107 return NULL;
108 }
109 ZERO(parser,
sizeof(WSParser));
110 parser->pool = sn->pool;
111 return parser;
112 }
113
114 void websocket_input(WSParser *parser,
const char *data,
size_t length) {
115 parser->inbuf = data;
116 parser->length = length;
117 parser->pos =
0;
118 }
119
120 WSMessage* websocket_get_message(WSParser *parser,
int *error) {
121 WSFrame rframe;
122 WSMessage *retmsg =
NULL;
123
124 while(parser->pos < parser->length) {
125 const char *inbuf = parser->inbuf + parser->pos;
126 size_t length = parser->length - parser->pos;
127
128 if(parser->state ==
0) {
129 WSFrame frame;
130 ZERO(&frame,
sizeof(WSFrame));
131
132
133
134
135
136
137 char frame_data[
WS_FRAMEHEADER_BUFLEN];
138 size_t flen =
0;
139
140
141
142
143
144
145 if(parser->tmplen >
0) {
146 memcpy(parser->tmpbuf, frame_data, parser->tmplen);
147 flen = parser->tmplen;
148 }
149 size_t cp_remaining = length <
WS_FRAMEHEADER_BUFLEN-flen ?
150 length :
WS_FRAMEHEADER_BUFLEN-flen;
151 memcpy(&frame_data[flen], inbuf, cp_remaining);
152 flen += cp_remaining;
153
154
155 ssize_t frame_hlen = websocket_get_frameheader(
156 &frame,
157 frame_data,
158 flen);
159
160 if(frame_hlen == -
1) {
161
162 *error =
1;
163 return NULL;
164 }
165 if(frame_hlen ==
0) {
166 memcpy(parser->tmpbuf, frame_data, flen);
167 }
else {
168 inbuf += frame_hlen;
169 length -= frame_hlen;
170 parser->pos += frame_hlen;
171
172
173 if(frame.payload_length >
0) {
174 WSMessage *msg = pool_malloc(parser->pool,
sizeof(WSMessage));
175 msg->data = pool_malloc(parser->pool, frame.payload_length);
176 msg->length = frame.payload_length;
177 msg->next =
NULL;
178 msg->type = frame.opcode;
179
180 if(frame.payload_length >= length) {
181
182 memcpy(msg->data, inbuf, frame.payload_length);
183 parser->pos += frame.payload_length;
184
185 rframe = frame;
186 retmsg = msg;
187 break;
188 }
else {
189 memcpy(msg->data, inbuf, length);
190 parser->state =
1;
191 parser->current = msg;
192 parser->cur_plen = length;
193 parser->frame = frame;
194 return NULL;
195 }
196 }
197 }
198 }
else {
199 WSMessage *msg = parser->current;
200 if(msg->length >= parser->cur_plen + length) {
201
202 memcpy(msg->data + parser->cur_plen, inbuf, length);
203 parser->cur_plen += length;
204 return NULL;
205 }
else {
206 size_t cplen = msg->length - parser->cur_plen;
207 memcpy(msg->data + parser->cur_plen, inbuf, cplen);
208 parser->pos += cplen;
209 parser->state =
0;
210 parser->current =
NULL;
211
212 rframe = parser->frame;
213 retmsg = msg;
214 break;
215 }
216 }
217 }
218
219 if(retmsg && rframe.mask) {
220 websocket_mask_data(retmsg->data, retmsg->length, rframe.masking_key);
221 }
222 return retmsg;
223 }
224
225
226 ssize_t websocket_get_frameheader(WSFrame *frame,
const char *buf,
size_t len) {
227 if(len <
2) {
228 return 0;
229 }
230
231
232
233
234
235
236
237
238
239
240
241
242 size_t msglen =
2;
243
244 uint8_t fin = (buf[
0] & 0x80) !=
0;
245 uint8_t opcode = buf[
0] & 0xf;
246
247 uint8_t mask = (buf[
1] & 0x80) !=
0;
248 uint8_t payload_len = buf[
1] & 0x7f;
249
250 uint64_t payload_length = payload_len;
251 if(payload_len ==
126) {
252 msglen +=
2;
253 if(len < msglen) {
254 return 0;
255 }
256 payload_length = *((
uint16_t*)(buf+
2));
257 }
else if(payload_len ==
127) {
258 msglen +=
8;
259 if(len < msglen) {
260 return 0;
261 }
262 payload_length = *((
uint64_t*)(buf+
2));
263 }
else if(payload_len >
127) {
264 return -
1;
265 }
266
267 uint32_t masking_key =
0;
268 if(mask) {
269 msglen +=
4;
270 if(len < msglen) {
271 return 0;
272 }
273 masking_key = *((
uint32_t*)(buf+msglen-
4));
274 }
275
276 frame->header_complete =
TRUE;
277 frame->fin = fin;
278 frame->opcode = opcode;
279 frame->mask = mask;
280 frame->masking_key = masking_key;
281 frame->payload_length = payload_length;
282
283 return msglen;
284 }
285
286 void websocket_mask_data(
char *buf,
size_t len,
uint32_t mask) {
287 size_t m = len %
4;
288 size_t alen = (len - m) /
4;
289
290 uint32_t *data = (
uint32_t*)buf;
291 for(
int i=
0;i<alen;i++) {
292 data[i] = data[i] ^ mask;
293 }
294
295 int j =
0;
296 char *cmask = (
char*)&mask;
297 for(
int i=len-m;i<len;i++) {
298 buf[i] = buf[i] ^ cmask[j];
299 j++;
300 }
301 }
302
303
304
305 NSAPI_PUBLIC int websocket_send_text(
SYS_NETFD csd,
char *msg,
size_t len) {
306 char frame[
WS_FRAMEHEADER_BUFLEN];
307 frame[
0] = (
char)
129;
308 size_t hlen;
309 if(len <
126) {
310 frame[
1] = (
char)len;
311 hlen =
2;
312 }
else if(len <
65536) {
313 frame[
1] =
126;
314 uint16_t plen = htons(len);
315 memcpy(frame +
2, &plen,
2);
316 hlen =
4;
317 }
else {
318 frame[
1] =
127;
319
320 hlen =
10;
321 }
322
323 struct iovec iov[
2];
324 iov[
0].iov_base = frame;
325 iov[
0].iov_len = hlen;
326
327 iov[
1].iov_base = msg;
328 iov[
1].iov_len = len;
329
330 ssize_t w = net_writev(csd, iov,
2);
331 if(w >
0) {
332 return 0;
333 }
else {
334 return 1;
335 }
336 }
337