1 /*******************************************************************************
2 * Copyright (c) 2018, 2022 Wind River Systems, Inc., Ian Craggs and others
3 *
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v2.0
6 * and Eclipse Distribution License v1.0 which accompany this distribution.
7 *
8 * The Eclipse Public License is available at
9 * https://www.eclipse.org/legal/epl-2.0/
10 * and the Eclipse Distribution License is available at
11 * http://www.eclipse.org/org/documents/edl-v10.php.
12 *
13 * Contributors:
14 * Keith Holman - initial implementation and documentation
15 * Ian Craggs - use memory tracking
16 * Ian Craggs - fix for one MQTT packet spread over >1 ws frame
17 * Sven Gambel - move WebSocket proxy support to generic proxy support
18 *******************************************************************************/
19
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <string.h>
23
24 #include "WebSocket.h"
25
26 #include "Base64.h"
27 #include "Log.h"
28 #include "SHA1.h"
29 #include "LinkedList.h"
30 #include "MQTTProtocolOut.h"
31 #include "SocketBuffer.h"
32 #include "StackTrace.h"
33
34 #if defined(__linux__)
35 # include <endian.h>
36 #elif defined(__APPLE__)
37 # include <libkern/OSByteOrder.h>
38 # define htobe16(x) OSSwapHostToBigInt16(x)
39 # define htobe32(x) OSSwapHostToBigInt32(x)
40 # define htobe64(x) OSSwapHostToBigInt64(x)
41 # define be16toh(x) OSSwapBigToHostInt16(x)
42 # define be32toh(x) OSSwapBigToHostInt32(x)
43 # define be64toh(x) OSSwapBigToHostInt64(x)
44 #elif defined(__FreeBSD__) || defined(__NetBSD__)
45 # include <sys/endian.h>
46 #elif defined(_WIN32) || defined(_WIN64)
47 # pragma comment(lib, "rpcrt4.lib")
48 # include <rpc.h>
49 # if !(defined(__MINGW32__))
50 # define strncasecmp(s1,s2,c) _strnicmp(s1,s2,c)
51 # endif
52 # if defined(__MINGW32__)
53 # define htonll __builtin_bswap64
54 # define ntohll __builtin_bswap64
55 # else
56 # define htonll(x) _byteswap_uint64(x)
57 # define ntohll(x) _byteswap_uint64(x)
58 # endif
59
60 # if BYTE_ORDER == LITTLE_ENDIAN
61 # define htobe16(x) htons(x)
62 # define htobe32(x) htonl(x)
63 # define htobe64(x) htonll(x)
64 # define be16toh(x) ntohs(x)
65 # define be32toh(x) ntohl(x)
66 # define be64toh(x) ntohll(x)
67 # elif BYTE_ORDER == BIG_ENDIAN
68 # define htobe16(x) (x)
69 # define htobe32(x) (x)
70 # define htobe64(x) (x)
71 # define be16toh(x) (x)
72 # define be32toh(x) (x)
73 # define be64toh(x) (x)
74 # else
75 # error "unknown endian"
76 # endif
77 /* For Microsoft Visual Studio < 2015 */
78 # if defined(_MSC_VER) && _MSC_VER < 1900
79 # define snprintf _snprintf
80 # endif
81 #endif
82
83 #if defined(IOT_CONNECT)
84 # include <sys/endian.h>
85 #endif
86 #if defined(OPENSSL) || defined(MBEDTLS)
87 #include "SSLSocket.h"
88 #endif /* defined(OPENSSL) || defined(MBEDTLS) */
89 #if defined(OPENSSL)
90 #include <openssl/rand.h>
91 #endif /* defined(OPENSSL) */
92 #if defined(MBEDTLS)
93 #include <entropy_poll.h>
94 #endif /* defined(MBEDTLS) */
95 #include "Socket.h"
96
97 #define HTTP_PROTOCOL(x) x ? "https" : "http"
98
99 #if !(defined(_WIN32) || defined(_WIN64))
100 #if defined(LIBUUID)
101 #include <uuid/uuid.h>
102 #else /* if defined(USE_LIBUUID) */
103 #include <limits.h>
104 #include <stdlib.h>
105 #include <time.h>
106
107 /** @brief raw uuid type */
108 typedef unsigned char uuid_t[16];
109
110 /**
111 * @brief generates a uuid, compatible with RFC 4122, version 4 (random)
112 * @note Uses a very insecure algorithm but no external dependencies
113 */
uuid_generate(uuid_t out)114 void uuid_generate( uuid_t out )
115 {
116 #if defined(OPENSSL)
117 int rc = RAND_bytes( out, sizeof(uuid_t));
118 if ( !rc )
119 #elif defined(MBEDTLS) && defined (MBEDTLS_ENTROPY_HARDWARE_ALT)
120 size_t out_len;
121 int rc = mbedtls_hardware_poll( NULL, out, sizeof(uuid_t), &out_len);
122 if (rc != 0)
123 #endif /* defined (OPENSSL) */
124 {
125 /* very insecure, but generates a random uuid */
126 int i;
127 srand(time(NULL));
128 for ( i = 0; i < 16; ++i )
129 out[i] = (unsigned char)(rand() % UCHAR_MAX);
130 out[6] = (out[6] & 0x0f) | 0x40;
131 out[8] = (out[8] & 0x3F) | 0x80;
132 }
133 }
134
135 /** @brief converts a uuid to a string */
uuid_unparse(uuid_t uu,char * out)136 void uuid_unparse( uuid_t uu, char *out )
137 {
138 int i;
139 for ( i = 0; i < 16; ++i )
140 {
141 if ( i == 4 || i == 6 || i == 8 || i == 10 )
142 {
143 *out = '-';
144 ++out;
145 }
146 out += sprintf( out, "%02x", uu[i] );
147 }
148 *out = '\0';
149 }
150 #endif /* else if defined(LIBUUID) */
151 #endif /* if !(defined(_WIN32) || defined(_WIN64)) */
152
153 #include "Heap.h"
154
155 /** raw websocket frame data */
156 struct ws_frame
157 {
158 size_t len; /**< length of frame */
159 size_t pos; /**< current position within the buffer */
160 };
161
162 /** Current frame being processed */
163 struct ws_frame *last_frame = NULL;
164
165 /** Holds any received websocket frames, to be process */
166 static List* in_frames = NULL;
167
168 static char * frame_buffer = NULL;
169 static size_t frame_buffer_len = 0;
170 static size_t frame_buffer_index = 0;
171 static size_t frame_buffer_data_len = 0;
172
173 /* static function declarations */
174 static const char *WebSocket_strcasefind(
175 const char *buf, const char *str, size_t len);
176
177 static char *WebSocket_getRawSocketData(
178 networkHandles *net, size_t bytes, size_t* actual_len, int* rc);
179
180 static void WebSocket_rewindData( void );
181
182 static void WebSocket_pong(
183 networkHandles *net, char *app_data, size_t app_data_len);
184
185 static int WebSocket_receiveFrame(networkHandles *net, size_t *actual_len);
186
187
188 /**
189 * calculates the amount of data required for the websocket header
190 *
191 * this function is used to calculate how much offset is required before calling
192 * @p WebSocket_putdatas, as that function will write data before the passed in
193 * buffer
194 *
195 * @param[in,out] net network connection
196 * @param[in] mask_data whether to mask the data
197 * @param[in] data_len amount of data in the payload
198 *
199 * @return the size in bytes of the websocket header required
200 *
201 * @see WebSocket_putdatas
202 */
WebSocket_calculateFrameHeaderSize(networkHandles * net,int mask_data,size_t data_len)203 size_t WebSocket_calculateFrameHeaderSize(networkHandles *net, int mask_data, size_t data_len)
204 {
205 int ret = 0;
206 if ( net && net->websocket )
207 {
208 if ( data_len < 126u)
209 ret = 2; /* header 2 bytes */
210 else if ( data_len < 65536u )
211 ret = 4; /* for extra 2-bytes for payload length */
212 #if defined(IOT_CONNECT) || defined(IOT_LITEOS_ADAPT)
213 else if ( data_len < 0xFFFFFFFF )
214 #else
215 else if ( data_len < 0xFFFFFFFFFFFFFFFF )
216 #endif
217 ret = 10; /* for extra 8-bytes for payload length */
218 if ( mask_data & 0x1 )
219 ret += sizeof(uint32_t); /* for mask */
220 }
221 return ret;
222 }
223
224
225 /**
226 * @brief builds a websocket frame for data transmission
227 *
228 * write a websocket header and will mask the payload in all the passed in
229 * buffers
230 *
231 * @param[in,out] net network connection
232 * @param[in] opcode websocket opcode for the packet
233 * @param[in] mask_data whether to mask the data
234 * @param[in,out] buf0 first buffer, will write before this
235 * @param[in] buf0len size of first buffer
236 * @param[in] count number of payload buffers
237 * @param[in,out] buffers array of payload buffers
238 * @param[in] buflens array of payload buffer sizes
239 * @param[in] freeData array indicating to free payload buffers
240 *
241 * @return amount of data to write to socket
242 */
243 struct frameData {
244 char* wsbuf0;
245 size_t wsbuf0len;
246 };
247
WebSocket_buildFrame(networkHandles * net,int opcode,int mask_data,char ** pbuf0,size_t * pbuf0len,PacketBuffers * bufs)248 static struct frameData WebSocket_buildFrame(networkHandles* net, int opcode, int mask_data,
249 char** pbuf0, size_t* pbuf0len, PacketBuffers* bufs)
250 {
251 int buf_len = 0u;
252 struct frameData rc;
253 int new_mask = 0;
254
255 FUNC_ENTRY;
256 memset(&rc, '\0', sizeof(rc));
257 if ( net->websocket )
258 {
259 size_t ws_header_size = 0u;
260 size_t data_len = 0L;
261 int i;
262
263 /* Calculate total length of MQTT buffers */
264 data_len = *pbuf0len;
265 for (i = 0; i < bufs->count; ++i)
266 data_len += bufs->buflens[i];
267
268 /* add space for websocket frame header */
269 ws_header_size = WebSocket_calculateFrameHeaderSize(net, mask_data, data_len);
270 if (*pbuf0)
271 {
272 rc.wsbuf0len = *pbuf0len + ws_header_size;
273 rc.wsbuf0 = malloc(rc.wsbuf0len);
274 if (rc.wsbuf0 == NULL)
275 goto exit;
276 memcpy(&rc.wsbuf0[ws_header_size], *pbuf0, *pbuf0len);
277 }
278 else
279 {
280 rc.wsbuf0 = malloc(ws_header_size);
281 if (rc.wsbuf0 == NULL)
282 goto exit;
283 rc.wsbuf0len = ws_header_size;
284 }
285
286 if (mask_data && (bufs->mask[0] == 0))
287 {
288 /* generate mask, since we are a client */
289 #if defined(OPENSSL)
290 RAND_bytes(&bufs->mask[0], sizeof(bufs->mask));
291 #elif defined(MBEDTLS) && defined (MBEDTLS_ENTROPY_HARDWARE_ALT)
292 size_t out_len;
293 mbedtls_hardware_poll( NULL, &bufs->mask[0], sizeof(bufs->mask), &out_len );
294 #else /* if defined(OPENSSL) */
295 bufs->mask[0] = (rand() % UINT8_MAX);
296 bufs->mask[1] = (rand() % UINT8_MAX);
297 bufs->mask[2] = (rand() % UINT8_MAX);
298 bufs->mask[3] = (rand() % UINT8_MAX);
299 #endif /* else if defined(OPENSSL) */
300 new_mask = 1;
301 }
302
303 /* 1st byte */
304 rc.wsbuf0[buf_len] = (char)(1 << 7); /* final flag */
305 /* 3 bits reserved for negotiation of protocol */
306 rc.wsbuf0[buf_len] |= (char)(opcode & 0x0F); /* op code */
307 ++buf_len;
308
309 /* 2nd byte */
310 rc.wsbuf0[buf_len] = (char)((mask_data & 0x1) << 7); /* masking bit */
311
312 /* payload length */
313 if ( data_len < 126u )
314 rc.wsbuf0[buf_len++] |= data_len & 0x7F;
315
316 /* 3rd byte & 4th bytes - extended payload length */
317 else if ( data_len < 65536u )
318 {
319 uint16_t len = htobe16((uint16_t)data_len);
320 rc.wsbuf0[buf_len++] |= (126u & 0x7F);
321 memcpy( &rc.wsbuf0[buf_len], &len, 2u );
322 buf_len += 2;
323 }
324 #if defined(IOT_CONNECT) || defined(IOT_LITEOS_ADAPT)
325 else if ( data_len < 0xFFFFFFFF )
326 #else
327 else if ( data_len < 0xFFFFFFFFFFFFFFFF )
328 #endif
329 {
330 uint64_t len = htobe64((uint64_t)data_len);
331 rc.wsbuf0[buf_len++] |= (127u & 0x7F);
332 memcpy( &rc.wsbuf0[buf_len], &len, 8 );
333 buf_len += 8;
334 }
335 else
336 {
337 Log(TRACE_PROTOCOL, 1, "Data too large for websocket frame" );
338 buf_len = -1;
339 }
340
341 if (mask_data)
342 {
343 size_t idx = 0u;
344
345 /* copy masking key into ws header */
346 memcpy( &rc.wsbuf0[buf_len], &bufs->mask, sizeof(uint32_t));
347 buf_len += sizeof(uint32_t);
348
349 /* mask packet fixed header */
350 for (i = (int)ws_header_size; i < (int)rc.wsbuf0len; ++i, ++idx)
351 rc.wsbuf0[i] ^= bufs->mask[idx % 4];
352
353 /* variable data buffers */
354 for (i = 0; i < bufs->count; ++i)
355 {
356 size_t j;
357
358 if (new_mask == 0 && (i == 2 || i == bufs->count-1))
359 /* topic (2) and payload (last) buffers are already masked */
360 break;
361 for ( j = 0u; j < bufs->buflens[i]; ++j, ++idx )
362 {
363 bufs->buffers[i][j] ^= bufs->mask[idx % 4];
364 }
365 }
366 }
367 }
368 exit:
369 FUNC_EXIT_RC(buf_len);
370 return rc;
371 }
372
373
WebSocket_unmaskData(size_t idx,PacketBuffers * bufs)374 static void WebSocket_unmaskData(size_t idx, PacketBuffers* bufs)
375 {
376 int i;
377
378 FUNC_ENTRY;
379 for (i = 0; i < bufs->count; ++i)
380 {
381 size_t j;
382 for (j = 0u; j < bufs->buflens[i]; ++j, ++idx)
383 bufs->buffers[i][j] ^= bufs->mask[idx % 4];
384 }
385 /* show that the mask has been removed */
386 bufs->mask[0] = bufs->mask[1] = bufs->mask[2] = bufs->mask[3] = 0;
387 FUNC_EXIT;
388 }
389
390
391 /**
392 * sends out a websocket request on the given uri
393 *
394 * @param[in] net network connection
395 * @param[in] ssl ssl flag
396 * @param[in] uri uri to connect to
397 *
398 * @retval SOCKET_ERROR on failure
399 * @retval 1 on success
400 *
401 * @see WebSocket_upgrade
402 */
WebSocket_connect(networkHandles * net,int ssl,const char * uri)403 int WebSocket_connect( networkHandles *net, int ssl, const char *uri)
404 {
405 int rc;
406 char *buf = NULL;
407 char *headers_buf = NULL;
408 const MQTTClient_nameValue *headers = net->httpHeaders;
409 int i, buf_len = 0;
410 int headers_buf_len = 0;
411 size_t hostname_len;
412 int port = 80;
413 const char *topic = NULL;
414 #if defined(_WIN32) || defined(_WIN64)
415 UUID uuid;
416 #else /* if defined(_WIN32) || defined(_WIN64) */
417 uuid_t uuid;
418 #endif /* else if defined(_WIN32) || defined(_WIN64) */
419
420 FUNC_ENTRY;
421 /* Generate UUID */
422 if (net->websocket_key == NULL)
423 net->websocket_key = malloc(25u);
424 else
425 net->websocket_key = realloc(net->websocket_key, 25u);
426 if (net->websocket_key == NULL)
427 {
428 rc = PAHO_MEMORY_ERROR;
429 goto exit;
430 }
431 #if defined(_WIN32) || defined(_WIN64)
432 ZeroMemory( &uuid, sizeof(UUID) );
433 UuidCreate( &uuid );
434 Base64_encode( net->websocket_key, 25u, (const b64_data_t*)&uuid, sizeof(UUID) );
435 #else /* if defined(_WIN32) || defined(_WIN64) */
436 uuid_generate( uuid );
437 Base64_encode( net->websocket_key, 25u, uuid, sizeof(uuid_t) );
438 #endif /* else if defined(_WIN32) || defined(_WIN64) */
439
440 hostname_len = MQTTProtocol_addressPort(uri, &port, &topic, ssl ? WSS_DEFAULT_PORT : WS_DEFAULT_PORT);
441
442 /* if no topic, use default */
443 if ( !topic )
444 topic = "/mqtt";
445
446 if ( headers )
447 {
448 char *headers_buf_cur = NULL;
449 while ( headers->name != NULL && headers->value != NULL )
450 {
451 headers_buf_len += (int)(strlen(headers->name) + strlen(headers->value) + 4);
452 headers++;
453 }
454 headers_buf_len++;
455
456 if ((headers_buf = malloc(headers_buf_len)) == NULL)
457 {
458 rc = PAHO_MEMORY_ERROR;
459 goto exit;
460 }
461 headers = net->httpHeaders;
462 headers_buf_cur = headers_buf;
463
464 while ( headers->name != NULL && headers->value != NULL )
465 {
466 headers_buf_cur += snprintf(headers_buf_cur, headers_buf_len - (headers_buf_cur - headers_buf),
467 "%s: %s\r\n", headers->name, headers->value);
468 headers++;
469 }
470 *headers_buf_cur = '\0';
471 }
472
473 for ( i = 0; i < 2; ++i )
474 {
475 buf_len = snprintf( buf, (size_t)buf_len,
476 "GET %s HTTP/1.1\r\n"
477 "Host: %.*s:%d\r\n"
478 "Upgrade: websocket\r\n"
479 "Connection: Upgrade\r\n"
480 "Origin: %s://%.*s:%d\r\n"
481 "Sec-WebSocket-Key: %s\r\n"
482 "Sec-WebSocket-Version: 13\r\n"
483 "Sec-WebSocket-Protocol: mqtt\r\n"
484 "%s"
485 "\r\n", topic,
486 (int)hostname_len, uri, port,
487 #if defined(OPENSSL)
488 HTTP_PROTOCOL(net->ssl),
489 #else
490 HTTP_PROTOCOL(0),
491 #endif
492
493 (int)hostname_len, uri, port,
494 net->websocket_key,
495 headers_buf ? headers_buf : "");
496
497 if ( i == 0 && buf_len > 0 )
498 {
499 ++buf_len; /* need 1 extra byte for ending '\0' */
500 if ((buf = malloc( buf_len )) == NULL)
501 {
502 rc = PAHO_MEMORY_ERROR;
503 goto exit;
504 }
505 }
506 }
507
508 if (headers_buf)
509 free( headers_buf );
510
511 if ( buf )
512 {
513 PacketBuffers nulbufs = {0, NULL, NULL, NULL, {0, 0, 0, 0}};
514
515 #if defined(OPENSSL) || defined(MBEDTLS)
516 if (net->ssl)
517 #if defined(IOT_CONNECT) || defined(IOT_LITEOS_ADAPT)
518 rc = SSLSocket_putdatas(net->ssl, net->socket, buf, buf_len, nulbufs);
519 #else
520 SSLSocket_putdatas(net->ssl, net->socket, buf, buf_len, nulbufs);
521 #endif
522 else
523 #endif
524 #if defined(IOT_CONNECT) || defined(IOT_LITEOS_ADAPT)
525 rc = Socket_putdatas(net->socket, buf, buf_len, nulbufs);
526 if (rc != TCPSOCKET_INTERRUPTED)
527 free( buf );
528 #else
529 Socket_putdatas(net->socket, buf, buf_len, nulbufs);
530 free( buf );
531 #endif
532 rc = 1;
533 }
534 else
535 {
536 free(net->websocket_key);
537 net->websocket_key = NULL;
538 rc = SOCKET_ERROR;
539 }
540 exit:
541 FUNC_EXIT_RC(rc);
542 return rc;
543 }
544
545 /**
546 * closes a websocket connection
547 *
548 * @param[in,out] net structure containing network connection
549 * @param[in] status_code websocket close status code
550 * @param[in] reason reason for closing connection (optional)
551 */
WebSocket_close(networkHandles * net,int status_code,const char * reason)552 void WebSocket_close(networkHandles *net, int status_code, const char *reason)
553 {
554 struct frameData fd;
555 PacketBuffers nulbufs = {0, NULL, NULL, NULL, {0, 0, 0, 0}};
556
557 FUNC_ENTRY;
558 if ( net->websocket )
559 {
560 #if defined(IOT_CONNECT) || defined(IOT_LITEOS_ADAPT)
561 int rc;
562 #endif
563 char *buf0;
564 size_t buf0len = sizeof(uint16_t);
565 uint16_t status_code_be;
566 const int mask_data = 1; /* all frames from client must be masked */
567
568 if ( status_code < WebSocket_CLOSE_NORMAL ||
569 status_code > WebSocket_CLOSE_TLS_FAIL )
570 status_code = WebSocket_CLOSE_GOING_AWAY;
571
572 if ( reason )
573 buf0len += strlen(reason);
574
575 buf0 = malloc(buf0len);
576 if ( !buf0 )
577 goto exit;
578
579 /* encode status code */
580 status_code_be = htobe16((uint16_t)status_code);
581 memcpy(buf0, &status_code_be, sizeof(uint16_t));
582
583 /* encode reason, if provided */
584 if ( reason )
585 strcpy( &buf0[sizeof(uint16_t)], reason );
586
587 fd = WebSocket_buildFrame( net, WebSocket_OP_CLOSE, mask_data, &buf0, &buf0len, &nulbufs);
588
589 #if defined(OPENSSL) || defined(MBEDTLS)
590 if (net->ssl)
591 #if defined(IOT_CONNECT) || defined(IOT_LITEOS_ADAPT)
592 rc = SSLSocket_putdatas(net->ssl, net->socket, fd.wsbuf0, fd.wsbuf0len, nulbufs);
593 #else
594 SSLSocket_putdatas(net->ssl, net->socket, fd.wsbuf0, fd.wsbuf0len, nulbufs);
595 #endif
596 else
597 #endif
598 #if defined(IOT_CONNECT) || defined(IOT_LITEOS_ADAPT)
599 rc = Socket_putdatas(net->socket, fd.wsbuf0, fd.wsbuf0len, nulbufs);
600
601 if (rc != TCPSOCKET_INTERRUPTED)
602 free(fd.wsbuf0); /* free temporary ws header */
603 #else
604 Socket_putdatas(net->socket, fd.wsbuf0, fd.wsbuf0len, nulbufs);
605
606 free(fd.wsbuf0); /* free temporary ws header */
607 #endif
608
609 /* websocket connection is now closed */
610 net->websocket = 0;
611 free( buf0 );
612 }
613 if ( net->websocket_key )
614 {
615 free( net->websocket_key );
616 net->websocket_key = NULL;
617 }
618 exit:
619 FUNC_EXIT;
620 }
621
622 /**
623 * @brief receives 1 byte from a socket
624 *
625 * @param[in,out] net network connection
626 * @param[out] c byte that was read
627 *
628 * @retval SOCKET_ERROR on error
629 * @retval TCPSOCKET_INTERRUPTED no data available
630 * @retval TCPSOCKET_COMPLETE on success
631 *
632 * @see WebSocket_getdata
633 */
WebSocket_getch(networkHandles * net,char * c)634 int WebSocket_getch(networkHandles *net, char* c)
635 {
636 int rc = SOCKET_ERROR;
637
638 FUNC_ENTRY;
639 if ( net->websocket )
640 {
641 struct ws_frame *frame = NULL;
642
643 if ( in_frames && in_frames->first )
644 frame = in_frames->first->content;
645
646 if ( !frame || frame->len == frame->pos )
647 {
648 size_t actual_len = 0u;
649 rc = WebSocket_receiveFrame( net, &actual_len);
650 if ( rc != TCPSOCKET_COMPLETE )
651 goto exit;
652
653 /* we got a frame, let take off the top of queue */
654 if ( in_frames->first )
655 frame = in_frames->first->content;
656 }
657
658 /* set current working frame */
659 if (frame && frame->len > frame->pos)
660 {
661 unsigned char *buf =
662 (unsigned char *)frame + sizeof(struct ws_frame);
663 *c = buf[frame->pos++];
664 rc = TCPSOCKET_COMPLETE;
665 }
666 }
667 #if defined(OPENSSL) || defined(MBEDTLS)
668 else if ( net->ssl )
669 rc = SSLSocket_getch(net->ssl, net->socket, c);
670 #endif
671 else
672 rc = Socket_getch(net->socket, c);
673
674 exit:
675 FUNC_EXIT_RC(rc);
676 return rc;
677 }
678
WebSocket_framePos()679 size_t WebSocket_framePos()
680 {
681 if ( in_frames && in_frames->first )
682 {
683 struct ws_frame *frame = in_frames->first->content;
684 return frame->pos;
685 }
686 else
687 {
688 return 0;
689 }
690 }
691
WebSocket_framePosSeekTo(size_t pos)692 void WebSocket_framePosSeekTo(size_t pos)
693 {
694 if ( in_frames && in_frames->first )
695 {
696 struct ws_frame *frame = in_frames->first->content;
697 frame->pos = pos;
698 }
699 }
700
701 /**
702 * @brief receives data from a socket.
703 * It should receive all data from the socket that is immediately available.
704 * Because it is encapsulated in websocket frames which cannot be
705 *
706 * @param[in,out] net network connection
707 * @param[in] bytes amount of data to get (0 if last packet)
708 * @param[out] actual_len amount of data read
709 *
710 * @return a pointer to the read data
711 *
712 * @see WebSocket_getch
713 */
WebSocket_getdata(networkHandles * net,size_t bytes,size_t * actual_len)714 char *WebSocket_getdata(networkHandles *net, size_t bytes, size_t* actual_len)
715 {
716 char *rv = NULL;
717 int rc;
718
719 FUNC_ENTRY;
720 if ( net->websocket )
721 {
722 struct ws_frame *frame = NULL;
723
724 if ( bytes == 0u )
725 {
726 /* done with current frame, move it to last frame */
727 if ( in_frames && in_frames->first )
728 frame = in_frames->first->content;
729
730 /* return the data from the next frame, if we have one */
731 if ( frame && frame->pos == frame->len )
732 {
733 rv = (char *)frame +
734 sizeof(struct ws_frame) + frame->pos;
735 *actual_len = frame->len - frame->pos;
736
737 if ( last_frame )
738 free( last_frame );
739 last_frame = ListDetachHead(in_frames);
740 }
741 goto exit;
742 }
743
744 /* look at the first websocket frame */
745 if ( in_frames && in_frames->first )
746 frame = in_frames->first->content;
747
748 /* no current frame, so let's go receive one for the network */
749 if ( !frame )
750 {
751 const int rc =
752 WebSocket_receiveFrame( net, actual_len );
753
754 if ( rc == TCPSOCKET_COMPLETE && in_frames && in_frames->first)
755 frame = in_frames->first->content;
756 }
757
758 if ( frame )
759 {
760 rv = (char *)frame + sizeof(struct ws_frame) + frame->pos;
761 *actual_len = frame->len - frame->pos; /* use the rest of the frame */
762
763
764 while (*actual_len < bytes) {
765 const int rc = WebSocket_receiveFrame(net, actual_len);
766
767 if (rc != TCPSOCKET_COMPLETE) {
768 goto exit;
769 }
770
771 /* refresh pointers */
772 frame = in_frames->first->content;
773 rv = (char *)frame + sizeof(struct ws_frame) + frame->pos;
774 *actual_len = frame->len - frame->pos; /* use the rest of the frame */
775
776 } /* end while */
777
778 if (*actual_len > bytes)
779 {
780 frame->pos += bytes;
781 }
782 else if (*actual_len == bytes && in_frames)
783 {
784 if ( last_frame )
785 free( last_frame );
786 last_frame = ListDetachHead(in_frames);
787 }
788 }
789 }
790 #if defined(OPENSSL) || defined(MBEDTLS)
791 else if ( net->ssl )
792 rv = SSLSocket_getdata(net->ssl, net->socket, bytes, actual_len, &rc);
793 #endif
794 else
795 rv = Socket_getdata(net->socket, bytes, actual_len, &rc);
796
797 exit:
798 FUNC_EXIT_RC(rv);
799 return rv;
800 }
801
WebSocket_rewindData(void)802 void WebSocket_rewindData( void )
803 {
804 frame_buffer_index = 0;
805 }
806
807 /**
808 * reads raw socket data for underlying layers
809 *
810 * @param[in] net network connection
811 * @param[in] bytes number of bytes to read, 0 to complete packet
812 * @param[in] actual_len amount of data read
813 *
814 * @return a buffer containing raw data
815 */
WebSocket_getRawSocketData(networkHandles * net,size_t bytes,size_t * actual_len,int * rc)816 char *WebSocket_getRawSocketData(networkHandles *net, size_t bytes, size_t* actual_len, int* rc)
817 {
818 char *rv = NULL;
819
820 size_t bytes_requested = bytes;
821
822 FUNC_ENTRY;
823 if (bytes > 0)
824 {
825 if (frame_buffer_data_len - frame_buffer_index >= bytes)
826 {
827 *actual_len = bytes;
828 rv = frame_buffer + frame_buffer_index;
829 frame_buffer_index += bytes;
830 *rc = (int)bytes;
831 goto exit;
832 }
833 else
834 {
835 bytes = bytes - (frame_buffer_data_len - frame_buffer_index);
836 }
837 }
838
839 *actual_len = 0;
840
841 // not enough data in the buffer, get data from socket
842 #if defined(OPENSSL) || defined(MBEDTLS)
843 if ( net->ssl )
844 rv = SSLSocket_getdata(net->ssl, net->socket, bytes, actual_len, rc);
845 else
846 #endif
847 rv = Socket_getdata(net->socket, bytes, actual_len, rc);
848
849 if (*rc == 0)
850 {
851 *rc = SOCKET_ERROR;
852 goto exit;
853 }
854
855 // clear buffer
856 if (bytes == 0)
857 {
858 frame_buffer_index = 0;
859 frame_buffer_data_len = 0;
860 frame_buffer_len = 0;
861
862 if (frame_buffer)
863 {
864 free (frame_buffer);
865 frame_buffer = NULL;
866 }
867 }
868 // append data to the buffer
869 else if (rv != NULL && *actual_len != 0U)
870 {
871 // no buffer allocated
872 if (!frame_buffer)
873 {
874 if ((frame_buffer = (char *)malloc(*actual_len)) == NULL)
875 {
876 rv = NULL;
877 goto exit;
878 }
879 memcpy(frame_buffer, rv, *actual_len);
880
881 frame_buffer_index = 0;
882 frame_buffer_data_len = *actual_len;
883 frame_buffer_len = *actual_len;
884 }
885 // buffer size is big enough
886 else if (frame_buffer_data_len + *actual_len < frame_buffer_len)
887 {
888 memcpy(frame_buffer + frame_buffer_data_len, rv, *actual_len);
889 frame_buffer_data_len += *actual_len;
890 }
891 // resize buffer
892 else
893 {
894 frame_buffer = realloc(frame_buffer, frame_buffer_data_len + *actual_len);
895 frame_buffer_len = frame_buffer_data_len + *actual_len;
896
897 memcpy(frame_buffer + frame_buffer_data_len, rv, *actual_len);
898 frame_buffer_data_len += *actual_len;
899 }
900
901 SocketBuffer_complete(net->socket);
902 }
903 else
904 goto exit;
905
906 bytes = bytes_requested;
907
908 // if possible, return data from the buffer
909 if (bytes > 0)
910 {
911 if (frame_buffer_data_len - frame_buffer_index >= bytes)
912 {
913 *actual_len = bytes;
914 rv = frame_buffer + frame_buffer_index;
915 frame_buffer_index += bytes;
916 }
917 else
918 {
919 *actual_len = frame_buffer_data_len - frame_buffer_index;
920 rv = frame_buffer + frame_buffer_index;
921 frame_buffer_index += *actual_len;
922 }
923 }
924
925 exit:
926 FUNC_EXIT;
927 return rv;
928 }
929
930 /**
931 * sends a "websocket pong" message
932 *
933 * @param[in] net network connection
934 * @param[in] app_data application data to put in payload
935 * @param[in] app_data_len application data length
936 */
WebSocket_pong(networkHandles * net,char * app_data,size_t app_data_len)937 void WebSocket_pong(networkHandles *net, char *app_data, size_t app_data_len)
938 {
939 FUNC_ENTRY;
940 if ( net->websocket )
941 {
942 #if defined(IOT_CONNECT) || defined(IOT_LITEOS_ADAPT)
943 int rc;
944 #endif
945 char *buf0 = NULL;
946 size_t buf0len = 0;
947 int freeData = 0;
948 struct frameData fd;
949 const int mask_data = 1; /* all frames from client must be masked */
950 PacketBuffers appbuf = {1, &app_data, &app_data_len, &freeData, {0, 0, 0, 0}};
951
952 fd = WebSocket_buildFrame( net, WebSocket_OP_PONG, mask_data, &buf0, &buf0len, &appbuf);
953
954 Log(TRACE_PROTOCOL, 1, "Sending WebSocket PONG" );
955
956 #if defined(OPENSSL) || defined(MBEDTLS)
957 if (net->ssl)
958 #if defined(IOT_CONNECT) || defined(IOT_LITEOS_ADAPT)
959 rc = SSLSocket_putdatas(net->ssl, net->socket, fd.wsbuf0, fd.wsbuf0len /*header_len + app_data_len*/, appbuf);
960 #else
961 SSLSocket_putdatas(net->ssl, net->socket, fd.wsbuf0, fd.wsbuf0len /*header_len + app_data_len*/, appbuf);
962 #endif
963 else
964 #endif
965 #if defined(IOT_CONNECT) || defined(IOT_LITEOS_ADAPT)
966 rc = Socket_putdatas(net->socket, fd.wsbuf0, fd.wsbuf0len /*header_len + app_data_len*/, appbuf);
967
968 if (rc != TCPSOCKET_INTERRUPTED)
969 free(fd.wsbuf0);
970 #else
971 Socket_putdatas(net->socket, fd.wsbuf0, fd.wsbuf0len /*header_len + app_data_len*/, appbuf);
972 free(fd.wsbuf0);
973 #endif
974 free(buf0);
975 }
976 FUNC_EXIT;
977 }
978
979 /**
980 * writes data to a socket (websocket header will be prepended if required)
981 *
982 * @warning buf0 will be expanded (backwords before @p buf0 buffer, to add a
983 * websocket frame header to the data if required). So use
984 * @p WebSocket_calculateFrameHeader, to determine if extra space is needed
985 * before the @p buf0 pointer.
986 *
987 * @param[in,out] net network connection
988 * @param[in,out] buf0 first buffer
989 * @param[in] buf0len size of first buffer
990 * @param[in] count number of payload buffers
991 * @param[in,out] buffers array of paylaod buffers
992 * @param[in] buflens array of payload buffer sizes
993 * @param[in] freeData array indicating to free payload buffers
994 *
995 * @return amount of data wrote to socket
996 *
997 * @see WebSocket_calculateFrameHeaderSize
998 */
WebSocket_putdatas(networkHandles * net,char ** buf0,size_t * buf0len,PacketBuffers * bufs)999 int WebSocket_putdatas(networkHandles* net, char** buf0, size_t* buf0len, PacketBuffers* bufs)
1000 {
1001 const int mask_data = 1; /* must mask websocket data from client */
1002 int rc;
1003
1004 FUNC_ENTRY;
1005 if (net->websocket)
1006 {
1007 struct frameData wsdata;
1008
1009 wsdata = WebSocket_buildFrame(net, WebSocket_OP_BINARY, mask_data, buf0, buf0len, bufs);
1010
1011 #if defined(OPENSSL) || defined(MBEDTLS)
1012 if (net->ssl)
1013 rc = SSLSocket_putdatas(net->ssl, net->socket, wsdata.wsbuf0, wsdata.wsbuf0len, *bufs);
1014 else
1015 #endif
1016 rc = Socket_putdatas(net->socket, wsdata.wsbuf0, wsdata.wsbuf0len, *bufs);
1017
1018 if (rc != TCPSOCKET_INTERRUPTED)
1019 {
1020 if (mask_data)
1021 WebSocket_unmaskData(*buf0len, bufs);
1022 free(wsdata.wsbuf0); /* free temporary ws header */
1023 }
1024 }
1025 else
1026 {
1027 #if defined(OPENSSL) || defined(MBEDTLS)
1028 if (net->ssl)
1029 rc = SSLSocket_putdatas(net->ssl, net->socket, *buf0, *buf0len, *bufs);
1030 else
1031 #endif
1032 rc = Socket_putdatas(net->socket, *buf0, *buf0len, *bufs);
1033 }
1034
1035 FUNC_EXIT_RC(rc);
1036 return rc;
1037 }
1038
1039 /**
1040 * receives incoming socket data and parses websocket frames
1041 * Copes with socket reads returning partial websocket frames by using the
1042 * SocketBuffer mechanism.
1043 *
1044 * @param[in] net network connection
1045 * @param[out] actual_len amount of data actually read
1046 *
1047 * @retval TCPSOCKET_COMPLETE packet received
1048 * @retval TCPSOCKET_INTERRUPTED incomplete packet received
1049 * @retval SOCKET_ERROR an error was encountered
1050 */
WebSocket_receiveFrame(networkHandles * net,size_t * actual_len)1051 int WebSocket_receiveFrame(networkHandles *net, size_t *actual_len)
1052 {
1053 struct ws_frame *res = NULL;
1054 int rc = TCPSOCKET_COMPLETE;
1055 int opcode = 0;
1056
1057 FUNC_ENTRY;
1058 if ( !in_frames )
1059 #if defined(IOT_CONNECT) || defined(IOT_LITEOS_ADAPT)
1060 {
1061 #endif
1062 in_frames = ListInitialize();
1063 #if defined(IOT_CONNECT) || defined(IOT_LITEOS_ADAPT)
1064 if (in_frames == NULL)
1065 {
1066 rc = SOCKET_ERROR;
1067 goto exit;
1068 }
1069 }
1070 #endif
1071 /* see if there is frame currently on queue */
1072 if ( in_frames->first )
1073 {res = in_frames->first->content;}
1074
1075 //while( !res )
1076 //{
1077 opcode = WebSocket_OP_BINARY;
1078 do
1079 {
1080 /* obtain all frames in the sequence */
1081 int is_final = 0;
1082 while ( is_final == 0 )
1083 {
1084 char *b;
1085 size_t len = 0u;
1086 int tmp_opcode;
1087 int has_mask;
1088 size_t cur_len = 0u;
1089 uint8_t mask[4] = { 0u, 0u, 0u, 0u };
1090 size_t payload_len;
1091 int rcs; /* socket return code */
1092
1093 b = WebSocket_getRawSocketData(net, 2u, &len, &rcs);
1094 if (rcs == SOCKET_ERROR)
1095 {
1096 rc = rcs;
1097 goto exit;
1098 }
1099 if ( !b )
1100 {
1101 rc = TCPSOCKET_INTERRUPTED;
1102 goto exit;
1103 }
1104 else if (len < 2u )
1105 {
1106 rc = TCPSOCKET_INTERRUPTED;
1107 goto exit;
1108 }
1109
1110 /* 1st byte */
1111 is_final = (b[0] & 0xFF) >> 7;
1112 tmp_opcode = (b[0] & 0x0F);
1113
1114 if ( tmp_opcode ) /* not a continuation frame */
1115 opcode = tmp_opcode;
1116
1117 /* invalid websocket packet must return error */
1118 if ( opcode < WebSocket_OP_CONTINUE ||
1119 opcode > WebSocket_OP_PONG ||
1120 ( opcode > WebSocket_OP_BINARY &&
1121 opcode < WebSocket_OP_CLOSE ) )
1122 {
1123 rc = SOCKET_ERROR;
1124 goto exit;
1125 }
1126
1127 /* 2nd byte */
1128 has_mask = (b[1] & 0xFF) >> 7;
1129 payload_len = (b[1] & 0x7F);
1130
1131 /* determine payload length */
1132 if ( payload_len == 126 )
1133 {
1134 /* If 126, the following 2 bytes interpreted as a
1135 16-bit unsigned integer are the payload length. */
1136 b = WebSocket_getRawSocketData(net, 2u, &len, &rcs);
1137 if (rcs == SOCKET_ERROR)
1138 {
1139 rc = rcs;
1140 goto exit;
1141 }
1142 if ( !b )
1143 {
1144 rc = SOCKET_ERROR;
1145 goto exit;
1146 }
1147 else if (len < 2u )
1148 {
1149 rc = TCPSOCKET_INTERRUPTED;
1150 goto exit;
1151 }
1152 /* convert from big endian 16 to host */
1153 payload_len = be16toh(*(uint16_t*)b);
1154 }
1155 else if ( payload_len == 127 )
1156 {
1157 /* If 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the
1158 most significant bit MUST be 0) are the payload length */
1159 b = WebSocket_getRawSocketData(net, 8u, &len, &rcs);
1160 if (rcs == SOCKET_ERROR)
1161 {
1162 rc = rcs;
1163 goto exit;
1164 }
1165 if ( !b )
1166 {
1167 rc = SOCKET_ERROR;
1168 goto exit;
1169 }
1170 else if (len < 8u )
1171 {
1172 rc = TCPSOCKET_INTERRUPTED;
1173 goto exit;
1174 }
1175 /* convert from big-endian 64 to host */
1176 payload_len = (size_t)be64toh(*(uint64_t*)b);
1177 }
1178
1179 if ( has_mask )
1180 {
1181 uint8_t mask[4];
1182 b = WebSocket_getRawSocketData(net, 4u, &len, &rcs);
1183 if (rcs == SOCKET_ERROR)
1184 {
1185 rc = rcs;
1186 goto exit;
1187 }
1188 if ( !b )
1189 {
1190 rc = SOCKET_ERROR;
1191 goto exit;
1192 }
1193 if (len < 4u )
1194 {
1195 rc = TCPSOCKET_INTERRUPTED;
1196 goto exit;
1197 }
1198 memcpy( &mask[0], b, sizeof(uint32_t));
1199 }
1200
1201 /* use the socket buffer to read in the whole websocket frame */
1202 b = WebSocket_getRawSocketData(net, payload_len, &len, &rcs);
1203 if (rcs == SOCKET_ERROR)
1204 {
1205 rc = rcs;
1206 goto exit;
1207 }
1208 if (!b)
1209 {
1210 rc = SOCKET_ERROR;
1211 goto exit;
1212 }
1213 if (len < payload_len )
1214 {
1215 rc = TCPSOCKET_INTERRUPTED;
1216 goto exit;
1217 }
1218
1219 /* unmask data */
1220 if ( has_mask )
1221 {
1222 size_t i;
1223 for ( i = 0u; i < payload_len; ++i )
1224 b[i] ^= mask[i % 4];
1225 }
1226
1227 if ( res )
1228 cur_len = res->len;
1229
1230 if (res == NULL)
1231 {
1232 if ((res = malloc( sizeof(struct ws_frame) + cur_len + len)) == NULL)
1233 {
1234 rc = PAHO_MEMORY_ERROR;
1235 goto exit;
1236 }
1237 res->pos = 0u;
1238 } else
1239 {
1240 if ((res = realloc( res, sizeof(struct ws_frame) + cur_len + len )) == NULL)
1241 {
1242 rc = PAHO_MEMORY_ERROR;
1243 goto exit;
1244 }
1245 }
1246 if (in_frames && in_frames->first)
1247 in_frames->first->content = res; /* realloc moves the data */
1248 memcpy( (unsigned char *)res + sizeof(struct ws_frame) + cur_len, b, len );
1249 res->len = cur_len + len;
1250
1251 WebSocket_getRawSocketData(net, 0u, &len, &rcs);
1252 if (rcs == SOCKET_ERROR)
1253 {
1254 rc = rcs;
1255 goto exit;
1256 }
1257 }
1258
1259 if ( opcode == WebSocket_OP_PING || opcode == WebSocket_OP_PONG )
1260 {
1261 /* respond to a "ping" with a "pong" */
1262 if ( opcode == WebSocket_OP_PING )
1263 WebSocket_pong( net,
1264 (char *)res + sizeof(struct ws_frame),
1265 res->len );
1266
1267 /* discard message */
1268 free( res );
1269 res = NULL;
1270 }
1271 else if ( opcode == WebSocket_OP_CLOSE )
1272 {
1273 /* server end closed websocket connection */
1274 free( res );
1275 WebSocket_close( net, WebSocket_CLOSE_GOING_AWAY, NULL );
1276 rc = SOCKET_ERROR; /* closes socket */
1277 goto exit;
1278 }
1279 } while ( opcode == WebSocket_OP_PING || opcode == WebSocket_OP_PONG );
1280 //}
1281
1282 if (in_frames->count == 0)
1283 ListAppend( in_frames, res, sizeof(struct ws_frame) + res->len);
1284 *actual_len = res->len - res->pos;
1285
1286 exit:
1287 if (rc == TCPSOCKET_INTERRUPTED)
1288 {
1289 WebSocket_rewindData();
1290 }
1291
1292 FUNC_EXIT_RC(rc);
1293 return rc;
1294 }
1295
1296 /**
1297 * case-insensitive string search
1298 *
1299 * similar to @p strcase, but takes a maximum length
1300 *
1301 * @param[in] buf buffer to search
1302 * @param[in] str string to find
1303 * @param[in] len length of the buffer
1304 *
1305 * @retval !NULL location of string found
1306 * @retval NULL string not found
1307 */
WebSocket_strcasefind(const char * buf,const char * str,size_t len)1308 const char *WebSocket_strcasefind(const char *buf, const char *str, size_t len)
1309 {
1310 const char *res = NULL;
1311 if ( buf && len > 0u && str )
1312 {
1313 const size_t str_len = strlen( str );
1314 while ( len >= str_len && !res )
1315 {
1316 if ( strncasecmp( buf, str, str_len ) == 0 )
1317 res = buf;
1318 ++buf;
1319 --len;
1320 }
1321 }
1322 return res;
1323 }
1324
1325 /**
1326 * releases resources used by the websocket sub-system
1327 */
WebSocket_terminate(void)1328 void WebSocket_terminate( void )
1329 {
1330 FUNC_ENTRY;
1331 /* clean up and un-processed websocket frames */
1332 if ( in_frames )
1333 {
1334 struct ws_frame *f = ListDetachHead( in_frames );
1335 while ( f )
1336 {
1337 free( f );
1338 f = ListDetachHead( in_frames );
1339 }
1340 ListFree( in_frames );
1341 in_frames = NULL;
1342 }
1343 if ( last_frame )
1344 {
1345 free( last_frame );
1346 last_frame = NULL;
1347 }
1348
1349 if ( frame_buffer )
1350 {
1351 free( frame_buffer );
1352 frame_buffer = NULL;
1353 }
1354
1355 frame_buffer_len = 0;
1356 frame_buffer_index = 0;
1357 frame_buffer_data_len = 0;
1358
1359 Socket_outTerminate();
1360 #if defined(OPENSSL) || defined(MBEDTLS)
1361 SSLSocket_terminate();
1362 #endif
1363 FUNC_EXIT;
1364 }
1365
1366 /**
1367 * handles the websocket upgrade response
1368 *
1369 * @param[in,out] net network connection to upgrade
1370 *
1371 * @retval SOCKET_ERROR failed to upgrade network connection
1372 * @retval TCPSOCKET_INTERRUPTED upgrade not complete, but not failed. Try again
1373 * @retval 1 socket upgraded to use websockets
1374 *
1375 * @see WebSocket_connect
1376 */
WebSocket_upgrade(networkHandles * net)1377 int WebSocket_upgrade( networkHandles *net )
1378 {
1379 static const char *const ws_guid =
1380 "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
1381 int rc = SOCKET_ERROR;
1382
1383 FUNC_ENTRY;
1384 if ( net->websocket_key )
1385 {
1386 SHA_CTX ctx;
1387 char ws_key[62u] = { 0 };
1388 unsigned char sha_hash[SHA1_DIGEST_LENGTH];
1389 size_t rcv = 0u;
1390 char *read_buf;
1391
1392 /* calculate the expected websocket key, expected from server */
1393 snprintf( ws_key, sizeof(ws_key), "%s%s", net->websocket_key, ws_guid );
1394 SHA1_Init( &ctx );
1395 SHA1_Update( &ctx, ws_key, strlen(ws_key));
1396 SHA1_Final( sha_hash, &ctx );
1397 Base64_encode( ws_key, sizeof(ws_key), sha_hash, SHA1_DIGEST_LENGTH );
1398
1399 read_buf = WebSocket_getRawSocketData( net, 12u, &rcv, &rc);
1400 if (rc == SOCKET_ERROR)
1401 goto exit;
1402
1403 if ((read_buf == NULL) || rcv < 12u) {
1404 Log(TRACE_PROTOCOL, 1, "WebSocket upgrade read not complete %lu", (unsigned long)rcv );
1405 rc = TCPSOCKET_INTERRUPTED;
1406 goto exit;
1407 }
1408
1409 if (strncmp( read_buf, "HTTP/1.1", 8u ) == 0)
1410 {
1411 if (strncmp( &read_buf[9], "101", 3u ) != 0)
1412 {
1413 Log(TRACE_PROTOCOL, 1, "WebSocket HTTP rc %.3s", &read_buf[9]);
1414 rc = SOCKET_ERROR;
1415 goto exit;
1416 }
1417 }
1418
1419 if (strncmp( read_buf, "HTTP/1.1 101", 12u ) == 0)
1420 {
1421 const char *p;
1422
1423 read_buf = WebSocket_getRawSocketData(net, 1024u, &rcv, &rc);
1424 if (rc == SOCKET_ERROR)
1425 goto exit;
1426
1427 /* Did we read the whole response? */
1428 if (read_buf && rcv > 4 && memcmp(&read_buf[rcv-4], "\r\n\r\n", 4) != 0)
1429 {
1430 Log(TRACE_PROTOCOL, -1, "WebSocket HTTP upgrade response read not complete %lu", (unsigned long)rcv);
1431 rc = SOCKET_ERROR;
1432 goto exit;
1433 }
1434
1435 /* check for upgrade */
1436 p = WebSocket_strcasefind(
1437 read_buf, "Connection", rcv );
1438 if ( p )
1439 {
1440 const char *eol;
1441 eol = memchr( p, '\n', rcv-(read_buf-p) );
1442 if ( eol )
1443 p = WebSocket_strcasefind(
1444 p, "Upgrade", eol - p);
1445 else
1446 p = NULL;
1447 }
1448
1449 /* check key hash */
1450 if ( p )
1451 p = WebSocket_strcasefind( read_buf,
1452 "sec-websocket-accept", rcv );
1453 if ( p )
1454 {
1455 const char *eol;
1456 eol = memchr( p, '\n', rcv-(read_buf-p) );
1457 if ( eol )
1458 {
1459 p = memchr( p, ':', eol-p );
1460 if ( p )
1461 {
1462 size_t hash_len = eol-p-1;
1463 while ( *p == ':' || *p == ' ' )
1464 {
1465 ++p;
1466 --hash_len;
1467 }
1468
1469 if ( strncmp( p, ws_key, hash_len ) != 0 )
1470 p = NULL;
1471 }
1472 }
1473 else
1474 p = NULL;
1475 }
1476
1477 if ( p )
1478 {
1479 net->websocket = 1;
1480 Log(TRACE_PROTOCOL, 1, "WebSocket connection upgraded" );
1481 rc = 1;
1482 }
1483 else
1484 {
1485 Log(TRACE_PROTOCOL, 1, "WebSocket failed to upgrade connection" );
1486 rc = SOCKET_ERROR;
1487 }
1488
1489 if ( net->websocket_key )
1490 {
1491 free(net->websocket_key);
1492 net->websocket_key = NULL;
1493 }
1494
1495 /* indicate that we done with the packet */
1496 WebSocket_getRawSocketData( net, 0u, &rcv, &rc);
1497 }
1498 }
1499
1500 exit:
1501 FUNC_EXIT_RC(rc);
1502 return rc;
1503 }
1504