websocket: Tune maximum received length
[src/app-framework-binder.git] / src / websock.c
1 /*
2  * Copyright (C) 2016, 2017 "IoT.bzh"
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * This work is a far adaptation of apache-websocket:
19  *   origin:  https://github.com/disconnect/apache-websocket
20  *   commit:  cfaef071223f11ba016bff7e1e4b7c9e5df45b50
21  *   Copyright 2010-2012 self.disconnect (APACHE-2)
22  */
23
24 #include <stdlib.h>
25 #include <stdint.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <sys/uio.h>
29
30 #include "websock.h"
31
32 #define BLOCK_DATA_SIZE              4096
33 #if !defined(WEBSOCKET_DEFAULT_MAXLENGTH)
34 #  define WEBSOCKET_DEFAULT_MAXLENGTH 1048500  /* 76 less than 1M, probably enougth for headers */
35 #endif
36
37 #define FRAME_GET_FIN(BYTE)         (((BYTE) >> 7) & 0x01)
38 #define FRAME_GET_RSV1(BYTE)        (((BYTE) >> 6) & 0x01)
39 #define FRAME_GET_RSV2(BYTE)        (((BYTE) >> 5) & 0x01)
40 #define FRAME_GET_RSV3(BYTE)        (((BYTE) >> 4) & 0x01)
41 #define FRAME_GET_OPCODE(BYTE)      ( (BYTE)       & 0x0F)
42 #define FRAME_GET_MASK(BYTE)        (((BYTE) >> 7) & 0x01)
43 #define FRAME_GET_PAYLOAD_LEN(BYTE) ( (BYTE)       & 0x7F)
44
45 #define FRAME_SET_FIN(BYTE)         (((BYTE) & 0x01) << 7)
46 #define FRAME_SET_RSV1(BYTE)        (((BYTE) & 0x01) << 6)
47 #define FRAME_SET_RSV2(BYTE)        (((BYTE) & 0x01) << 5)
48 #define FRAME_SET_RSV3(BYTE)        (((BYTE) & 0x01) << 4)
49 #define FRAME_SET_OPCODE(BYTE)      ((BYTE) & 0x0F)
50 #define FRAME_SET_MASK(BYTE)        (((BYTE) & 0x01) << 7)
51 #define FRAME_SET_LENGTH(X64, IDX)  (unsigned char)((sizeof(X64)) <= (IDX) ? 0 : (((X64) >> ((IDX)*8)) & 0xFF))
52
53 #define OPCODE_CONTINUATION 0x0
54 #define OPCODE_TEXT         0x1
55 #define OPCODE_BINARY       0x2
56 #define OPCODE_CLOSE        0x8
57 #define OPCODE_PING         0x9
58 #define OPCODE_PONG         0xA
59
60 #define STATE_INIT    0
61 #define STATE_START   1
62 #define STATE_LENGTH  2
63 #define STATE_DATA    3
64
65 static size_t default_maxlength = WEBSOCKET_DEFAULT_MAXLENGTH;
66
67 struct websock {
68         int state;
69         uint64_t maxlength;
70         int lenhead, szhead;
71         uint64_t length;
72         uint32_t mask;
73         unsigned char header[14];       /* 2 + 8 + 4 */
74         const struct websock_itf *itf;
75         void *closure;
76 };
77
78 static ssize_t ws_writev(struct websock *ws, const struct iovec *iov, int iovcnt)
79 {
80         return ws->itf->writev(ws->closure, iov, iovcnt);
81 }
82
83 static ssize_t ws_readv(struct websock *ws, const struct iovec *iov, int iovcnt)
84 {
85         return ws->itf->readv(ws->closure, iov, iovcnt);
86 }
87
88 #if 0
89 static ssize_t ws_write(struct websock *ws, const void *buffer, size_t buffer_size)
90 {
91         struct iovec iov;
92         iov.iov_base = (void *)buffer;  /* const cast */
93         iov.iov_len = buffer_size;
94         return ws_writev(ws, &iov, 1);
95 }
96 #endif
97
98 static ssize_t ws_read(struct websock *ws, void *buffer, size_t buffer_size)
99 {
100         struct iovec iov;
101         iov.iov_base = buffer;
102         iov.iov_len = buffer_size;
103         return ws_readv(ws, &iov, 1);
104 }
105
106 static int websock_send_internal_v(struct websock *ws, unsigned char first, const struct iovec *iovec, int count)
107 {
108         struct iovec iov[32];
109         int i, j;
110         size_t pos, size, len;
111         ssize_t rc;
112         unsigned char header[32];
113
114         /* checks count */
115         if (count < 0 || (count + 1) > (int)(sizeof iov / sizeof * iov)) {
116                 errno = EINVAL;
117                 return -1;
118         }
119
120         /* computes the size */
121         size = 0;
122         i = 1;
123         for (j = 0 ; j < count ; j++) {
124                 iov[i].iov_base = iovec[j].iov_base;
125                 len = iovec[j].iov_len;
126                 if (len != 0) {
127                         iov[i].iov_len = len;
128                         size += len;
129                         i++;
130                 }
131         }
132
133         /* makes the header */
134         pos = 0;
135         header[pos++] = first;
136         size = (uint64_t) size;
137         if (size < 126) {
138                 header[pos++] = FRAME_SET_MASK(0) | FRAME_SET_LENGTH(size, 0);
139         } else {
140                 if (size < 65536) {
141                         header[pos++] = FRAME_SET_MASK(0) | 126;
142                 } else {
143                         header[pos++] = FRAME_SET_MASK(0) | 127;
144                         header[pos++] = FRAME_SET_LENGTH(size, 7);
145                         header[pos++] = FRAME_SET_LENGTH(size, 6);
146                         header[pos++] = FRAME_SET_LENGTH(size, 5);
147                         header[pos++] = FRAME_SET_LENGTH(size, 4);
148                         header[pos++] = FRAME_SET_LENGTH(size, 3);
149                         header[pos++] = FRAME_SET_LENGTH(size, 2);
150                 }
151                 header[pos++] = FRAME_SET_LENGTH(size, 1);
152                 header[pos++] = FRAME_SET_LENGTH(size, 0);
153         }
154
155         /* allocates the vec */
156         iov[0].iov_base = header;
157         iov[0].iov_len = pos;
158         rc = ws_writev(ws, iov, i);
159
160         return rc < 0 ? -1 : 0;
161 }
162
163 static int websock_send_internal(struct websock *ws, unsigned char first, const void *buffer, size_t size)
164 {
165         struct iovec iov;
166
167         iov.iov_base = (void *)buffer;
168         iov.iov_len = size;
169         return websock_send_internal_v(ws, first, &iov, 1);
170 }
171
172 static inline int websock_send_v(struct websock *ws, int last, int rsv1, int rsv2, int rsv3, int opcode, const struct iovec *iovec, int count)
173 {
174         unsigned char first = (unsigned char)(FRAME_SET_FIN(last)
175                                 | FRAME_SET_RSV1(rsv1)
176                                 | FRAME_SET_RSV1(rsv2)
177                                 | FRAME_SET_RSV1(rsv3)
178                                 | FRAME_SET_OPCODE(opcode));
179         return websock_send_internal_v(ws, first, iovec, count);
180 }
181
182 static inline int websock_send(struct websock *ws, int last, int rsv1, int rsv2, int rsv3, int opcode, const void *buffer, size_t size)
183 {
184         unsigned char first = (unsigned char)(FRAME_SET_FIN(last)
185                                 | FRAME_SET_RSV1(rsv1)
186                                 | FRAME_SET_RSV1(rsv2)
187                                 | FRAME_SET_RSV1(rsv3)
188                                 | FRAME_SET_OPCODE(opcode));
189         return websock_send_internal(ws, first, buffer, size);
190 }
191
192 int websock_close_empty(struct websock *ws)
193 {
194         return websock_close(ws, WEBSOCKET_CODE_NOT_SET, NULL, 0);
195 }
196
197 int websock_close(struct websock *ws, uint16_t code, const void *data, size_t length)
198 {
199         unsigned char buffer[2];
200         struct iovec iov[2];
201
202         if (code == WEBSOCKET_CODE_NOT_SET && length == 0)
203                 return websock_send(ws, 1, 0, 0, 0, OPCODE_CLOSE, NULL, 0);
204
205         /* checks the length */
206         if (length > 123) {
207                 errno = EINVAL;
208                 return -1;
209         }
210
211         /* prepare the buffer */
212         buffer[0] = (unsigned char)((code >> 8) & 0xFF);
213         buffer[1] = (unsigned char)(code & 0xFF);
214
215         /* Send server-side closing handshake */
216         iov[0].iov_base = (void *)buffer;
217         iov[0].iov_len = 2;
218         iov[1].iov_base = (void *)data;
219         iov[1].iov_len = length;
220         return websock_send_v(ws, 1, 0, 0, 0, OPCODE_CLOSE, iov, 2);
221 }
222
223 int websock_ping(struct websock *ws, const void *data, size_t length)
224 {
225         /* checks the length */
226         if (length > 125) {
227                 errno = EINVAL;
228                 return -1;
229         }
230
231         return websock_send(ws, 1, 0, 0, 0, OPCODE_PING, data, length);
232 }
233
234 int websock_pong(struct websock *ws, const void *data, size_t length)
235 {
236         /* checks the length */
237         if (length > 125) {
238                 errno = EINVAL;
239                 return -1;
240         }
241
242         return websock_send(ws, 1, 0, 0, 0, OPCODE_PONG, data, length);
243 }
244
245 int websock_text(struct websock *ws, int last, const void *text, size_t length)
246 {
247         return websock_send(ws, last, 0, 0, 0, OPCODE_TEXT, text, length);
248 }
249
250 int websock_text_v(struct websock *ws, int last, const struct iovec *iovec, int count)
251 {
252         return websock_send_v(ws, last, 0, 0, 0, OPCODE_TEXT, iovec, count);
253 }
254
255 int websock_binary(struct websock *ws, int last, const void *data, size_t length)
256 {
257         return websock_send(ws, last, 0, 0, 0, OPCODE_BINARY, data, length);
258 }
259
260 int websock_binary_v(struct websock *ws, int last, const struct iovec *iovec, int count)
261 {
262         return websock_send_v(ws, last, 0, 0, 0, OPCODE_BINARY, iovec, count);
263 }
264
265 int websock_continue(struct websock *ws, int last, const void *data, size_t length)
266 {
267         return websock_send(ws, last, 0, 0, 0, OPCODE_CONTINUATION, data, length);
268 }
269
270 int websock_continue_v(struct websock *ws, int last, const struct iovec *iovec, int count)
271 {
272         return websock_send_v(ws, last, 0, 0, 0, OPCODE_CONTINUATION, iovec, count);
273 }
274
275 int websock_error(struct websock *ws, uint16_t code, const void *data, size_t size)
276 {
277         int rc = websock_close(ws, code, data, size);
278         if (ws->itf->on_error != NULL)
279                 ws->itf->on_error(ws->closure, code, data, size);
280         return rc;
281 }
282
283 static int read_header(struct websock *ws)
284 {
285         if (ws->lenhead < ws->szhead) {
286                 ssize_t rbc =
287                     ws_read(ws, &ws->header[ws->lenhead], (size_t)(ws->szhead - ws->lenhead));
288                 if (rbc < 0)
289                         return -1;
290                 ws->lenhead += (int)rbc;
291         }
292         return 0;
293 }
294
295 static int check_control_header(struct websock *ws)
296 {
297         /* sanity checks */
298         if (FRAME_GET_RSV1(ws->header[0]) != 0)
299                 return 0;
300         if (FRAME_GET_RSV2(ws->header[0]) != 0)
301                 return 0;
302         if (FRAME_GET_RSV3(ws->header[0]) != 0)
303                 return 0;
304         if (FRAME_GET_PAYLOAD_LEN(ws->header[1]) > 125)
305                 return 0;
306         if (FRAME_GET_OPCODE(ws->header[0]) == OPCODE_CLOSE)
307                 return FRAME_GET_PAYLOAD_LEN(ws->header[1]) != 1;
308         return 1;
309 }
310
311 int websock_dispatch(struct websock *ws, int loop)
312 {
313         uint16_t code;
314 loop:
315         switch (ws->state) {
316         case STATE_INIT:
317                 ws->lenhead = 0;
318                 ws->szhead = 2;
319                 ws->state = STATE_START;
320
321         case STATE_START:
322                 /* read the header */
323                 if (read_header(ws))
324                         return -1;
325                 else if (ws->lenhead < ws->szhead)
326                         return 0;
327                 /* fast track */
328                 switch (FRAME_GET_OPCODE(ws->header[0])) {
329                 case OPCODE_CONTINUATION:
330                 case OPCODE_TEXT:
331                 case OPCODE_BINARY:
332                         break;
333                 case OPCODE_CLOSE:
334                         if (!check_control_header(ws))
335                                 goto protocol_error;
336                         if (FRAME_GET_PAYLOAD_LEN(ws->header[1]))
337                                 ws->szhead += 2;
338                         break;
339                 case OPCODE_PING:
340                 case OPCODE_PONG:
341                         if (!check_control_header(ws))
342                                 goto protocol_error;
343                 default:
344                         break;
345                 }
346                 /* update heading size */
347                 switch (FRAME_GET_PAYLOAD_LEN(ws->header[1])) {
348                 case 127:
349                         ws->szhead += 6;
350                 case 126:
351                         ws->szhead += 2;
352                 default:
353                         ws->szhead += 4 * FRAME_GET_MASK(ws->header[1]);
354                 }
355                 ws->state = STATE_LENGTH;
356
357         case STATE_LENGTH:
358                 /* continue to read the header */
359                 if (read_header(ws))
360                         return -1;
361                 else if (ws->lenhead < ws->szhead)
362                         return 0;
363
364                 /* compute length */
365                 switch (FRAME_GET_PAYLOAD_LEN(ws->header[1])) {
366                 case 127:
367                         ws->length = (((uint64_t) ws->header[2]) << 56)
368                             | (((uint64_t) ws->header[3]) << 48)
369                             | (((uint64_t) ws->header[4]) << 40)
370                             | (((uint64_t) ws->header[5]) << 32)
371                             | (((uint64_t) ws->header[6]) << 24)
372                             | (((uint64_t) ws->header[7]) << 16)
373                             | (((uint64_t) ws->header[8]) << 8)
374                             | (uint64_t) ws->header[9];
375                         break;
376                 case 126:
377                         ws->length = (((uint64_t) ws->header[2]) << 8)
378                             | (uint64_t) ws->header[3];
379                         break;
380                 default:
381                         ws->length = FRAME_GET_PAYLOAD_LEN(ws->header[1]);
382                         break;
383                 }
384                 if (FRAME_GET_OPCODE(ws->header[0]) == OPCODE_CLOSE && ws->length != 0)
385                         ws->length -= 2;
386                 if (ws->length > ws->maxlength)
387                         goto too_long_error;
388
389                 /* compute mask */
390                 if (FRAME_GET_MASK(ws->header[1])) {
391                         ((unsigned char *)&ws->mask)[0] = ws->header[ws->szhead - 4];
392                         ((unsigned char *)&ws->mask)[1] = ws->header[ws->szhead - 3];
393                         ((unsigned char *)&ws->mask)[2] = ws->header[ws->szhead - 2];
394                         ((unsigned char *)&ws->mask)[3] = ws->header[ws->szhead - 1];
395                 } else
396                         ws->mask = 0;
397
398                 /* all heading fields are known, process */
399                 ws->state = STATE_DATA;
400                 if (ws->itf->on_extension != NULL) {
401                         if (ws->itf->on_extension(ws->closure,
402                                         FRAME_GET_FIN(ws->header[0]),
403                                         FRAME_GET_RSV1(ws->header[0]),
404                                         FRAME_GET_RSV2(ws->header[0]),
405                                         FRAME_GET_RSV3(ws->header[0]),
406                                         FRAME_GET_OPCODE(ws->header[0]),
407                                         (size_t) ws->length)) {
408                                 return 0;
409                         }
410                 }
411
412                 /* not an extension case */
413                 if (FRAME_GET_RSV1(ws->header[0]) != 0)
414                         goto protocol_error;
415                 if (FRAME_GET_RSV2(ws->header[0]) != 0)
416                         goto protocol_error;
417                 if (FRAME_GET_RSV3(ws->header[0]) != 0)
418                         goto protocol_error;
419
420                 /* handle */
421                 switch (FRAME_GET_OPCODE(ws->header[0])) {
422                 case OPCODE_CONTINUATION:
423                         ws->itf->on_continue(ws->closure,
424                                              FRAME_GET_FIN(ws->header[0]),
425                                              (size_t) ws->length);
426                         if (!loop)
427                                 return 0;
428                         break;
429                 case OPCODE_TEXT:
430                         ws->itf->on_text(ws->closure,
431                                          FRAME_GET_FIN(ws->header[0]),
432                                          (size_t) ws->length);
433                         if (!loop)
434                                 return 0;
435                         break;
436                 case OPCODE_BINARY:
437                         ws->itf->on_binary(ws->closure,
438                                            FRAME_GET_FIN(ws->header[0]),
439                                            (size_t) ws->length);
440                         if (!loop)
441                                 return 0;
442                         break;
443                 case OPCODE_CLOSE:
444                         if (ws->length == 0)
445                                 code = WEBSOCKET_CODE_NOT_SET;
446                         else {
447                                 code = (uint16_t)(ws->header[ws->szhead - 2] & 0xff);
448                                 code = (uint16_t)(code << 8);
449                                 code = (uint16_t)(code | (uint16_t)(ws->header[ws->szhead - 1] & 0xff));
450                         }
451                         ws->itf->on_close(ws->closure, code, (size_t) ws->length);
452                         return 0;
453                 case OPCODE_PING:
454                         if (ws->itf->on_ping)
455                                 ws->itf->on_ping(ws->closure, ws->length);
456                         else {
457                                 websock_drop(ws);
458                                 websock_pong(ws, NULL, 0);
459                         }
460                         ws->state = STATE_INIT;
461                         if (!loop)
462                                 return 0;
463                         break;
464                 case OPCODE_PONG:
465                         if (ws->itf->on_pong)
466                                 ws->itf->on_pong(ws->closure, ws->length);
467                         else
468                                 websock_drop(ws);
469                         ws->state = STATE_INIT;
470                         if (!loop)
471                                 return 0;
472                         break;
473                 default:
474                         goto protocol_error;
475                 }
476                 break;
477
478         case STATE_DATA:
479                 if (ws->length)
480                         return 0;
481                 ws->state = STATE_INIT;
482                 break;
483         }
484         goto loop;
485
486  too_long_error:
487         websock_error(ws, WEBSOCKET_CODE_MESSAGE_TOO_LARGE, NULL, 0);
488         return 0;
489
490  protocol_error:
491         websock_error(ws, WEBSOCKET_CODE_PROTOCOL_ERROR, NULL, 0);
492         return 0;
493 }
494
495 static void unmask(struct websock * ws, void *buffer, size_t size)
496 {
497         uint32_t mask, *b32;
498         uint8_t m, *b8;
499
500         mask = ws->mask;
501         b8 = buffer;
502         while (size && ((sizeof(uint32_t) - 1) & (uintptr_t) b8)) {
503                 m = ((uint8_t *) & mask)[0];
504                 ((uint8_t *) & mask)[0] = ((uint8_t *) & mask)[1];
505                 ((uint8_t *) & mask)[1] = ((uint8_t *) & mask)[2];
506                 ((uint8_t *) & mask)[2] = ((uint8_t *) & mask)[3];
507                 ((uint8_t *) & mask)[3] = m;
508                 *b8++ ^= m;
509                 size--;
510         }
511         b32 = (uint32_t *) b8;
512         while (size >= sizeof(uint32_t)) {
513                 *b32++ ^= mask;
514                 size -= sizeof(uint32_t);
515         }
516         b8 = (uint8_t *) b32;
517         while (size) {
518                 m = ((uint8_t *) & mask)[0];
519                 ((uint8_t *) & mask)[0] = ((uint8_t *) & mask)[1];
520                 ((uint8_t *) & mask)[1] = ((uint8_t *) & mask)[2];
521                 ((uint8_t *) & mask)[2] = ((uint8_t *) & mask)[3];
522                 ((uint8_t *) & mask)[3] = m;
523                 *b8++ ^= m;
524                 size--;
525         }
526         ws->mask = mask;
527 }
528
529 ssize_t websock_read(struct websock * ws, void *buffer, size_t size)
530 {
531         ssize_t rc;
532
533         if (ws->state != STATE_DATA)
534                 return 0;
535
536         if (size > ws->length)
537                 size = (size_t) ws->length;
538
539         rc = ws_read(ws, buffer, size);
540         if (rc > 0) {
541                 size = (size_t) rc;
542                 ws->length -= size;
543
544                 if (ws->mask != 0)
545                         unmask(ws, buffer, size);
546         }
547         return rc;
548 }
549
550 int websock_drop(struct websock *ws)
551 {
552         char buffer[8000];
553
554         while (ws->length)
555                 if (websock_read(ws, buffer, sizeof buffer) < 0)
556                         return -1;
557         return 0;
558 }
559
560 struct websock *websock_create_v13(const struct websock_itf *itf, void *closure)
561 {
562         struct websock *result = calloc(1, sizeof *result);
563         if (result) {
564                 result->itf = itf;
565                 result->closure = closure;
566                 result->maxlength = default_maxlength;
567         }
568         return result;
569 }
570
571 void websock_destroy(struct websock *ws)
572 {
573         free(ws);
574 }
575
576 void websock_set_default_max_length(size_t maxlen)
577 {
578         default_maxlength = maxlen;
579 }
580
581 void websock_set_max_length(struct websock *ws, size_t maxlen)
582 {
583         ws->maxlength = (uint64_t)maxlen;
584 }