• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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