1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** NetX WebSocket Component */
17 /** */
18 /** WebSocket Protocol */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define NX_WEBSOCKET_CLIENT_SOURCE_CODE
24
25 /* Force error checking to be disabled in this module */
26
27 #ifndef NX_DISABLE_ERROR_CHECKING
28 #define NX_DISABLE_ERROR_CHECKING
29 #endif
30
31 /* Include necessary system files. */
32
33 #include "tx_api.h"
34 #include "nx_ip.h"
35 #include "nx_packet.h"
36 #include "nx_tcp.h"
37 #include "nx_websocket_client.h"
38
39
40 /* Bring in externs for caller checking code. */
41
42 NX_CALLER_CHECKING_EXTERNS
43
44 #define NX_WEBSOCKET_CRLF "\r\n"
45 #define NX_WEBSOCKET_CRLF_SIZE 2
46
47 #define NX_WEBSOCKET_HEADER_MINIMUM_LENGTH 2
48
49 #define NX_WEBSOCKET_ACCEPT_PREDEFINED_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
50 #define NX_WEBSOCKET_ACCEPT_PREDEFINED_GUID_SIZE (sizeof(NX_WEBSOCKET_ACCEPT_PREDEFINED_GUID) - 1)
51 #define NX_WEBSOCKET_ACCEPT_DIGEST_SIZE 20 /* The length of SHA-1 hash is 20 bytes */
52 #define NX_WEBSOCKET_ACCEPT_KEY_SIZE 28 /* The base64 encode key for 20 bytes digest requires (27 bytes name size + 1 byte pad) = 28 bytes */
53
54 /**************************************************************************/
55 /* */
56 /* FUNCTION RELEASE */
57 /* */
58 /* _nxe_websocket_client_create PORTABLE C */
59 /* 6.2.0 */
60 /* AUTHOR */
61 /* */
62 /* Bo Chen, Microsoft Corporation */
63 /* */
64 /* DESCRIPTION */
65 /* */
66 /* This function checks for errors in the WebSocket instance create */
67 /* function call. */
68 /* */
69 /* INPUT */
70 /* */
71 /* client_ptr Pointer to WebSocket Client */
72 /* client_name Name of this WebSocket */
73 /* ip_ptr Pointer to IP instance */
74 /* pool_ptr Pointer to packet pool */
75 /* */
76 /* OUTPUT */
77 /* */
78 /* status Completion status */
79 /* */
80 /* CALLS */
81 /* */
82 /* _nx_websocket_client_create Actual websocket create call */
83 /* */
84 /* CALLED BY */
85 /* */
86 /* Application Code */
87 /* */
88 /* RELEASE HISTORY */
89 /* */
90 /* DATE NAME DESCRIPTION */
91 /* */
92 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
93 /* */
94 /**************************************************************************/
_nxe_websocket_client_create(NX_WEBSOCKET_CLIENT * client_ptr,UCHAR * client_name,NX_IP * ip_ptr,NX_PACKET_POOL * pool_ptr)95 UINT _nxe_websocket_client_create(NX_WEBSOCKET_CLIENT *client_ptr, UCHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr)
96 {
97
98 UINT status;
99
100 /* Check for invalid input pointers. */
101 if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) ||
102 (client_ptr == NX_NULL) || (client_ptr -> nx_websocket_client_id == NX_WEBSOCKET_CLIENT_ID) ||
103 (pool_ptr == NX_NULL) || (pool_ptr -> nx_packet_pool_id != NX_PACKET_POOL_ID))
104 {
105 return(NX_PTR_ERROR);
106 }
107
108 /* Call actual client create function. */
109 status = _nx_websocket_client_create(client_ptr, client_name, ip_ptr, pool_ptr);
110
111 /* Return completion status. */
112 return(status);
113 }
114
115 /**************************************************************************/
116 /* */
117 /* FUNCTION RELEASE */
118 /* */
119 /* _nx_websocket_client_create PORTABLE C */
120 /* 6.2.0 */
121 /* AUTHOR */
122 /* */
123 /* Bo Chen, Microsoft Corporation */
124 /* */
125 /* DESCRIPTION */
126 /* */
127 /* This function creates an instance for WebSocket Client. */
128 /* */
129 /* INPUT */
130 /* */
131 /* client_ptr Pointer to WebSocket Client */
132 /* client_name Name of this WebSocket */
133 /* ip_ptr Pointer to IP instance */
134 /* pool_ptr Pointer to packet pool */
135 /* */
136 /* OUTPUT */
137 /* */
138 /* status Completion status */
139 /* */
140 /* CALLS */
141 /* */
142 /* None */
143 /* */
144 /* CALLED BY */
145 /* */
146 /* Application Code */
147 /* */
148 /* RELEASE HISTORY */
149 /* */
150 /* DATE NAME DESCRIPTION */
151 /* */
152 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
153 /* */
154 /**************************************************************************/
_nx_websocket_client_create(NX_WEBSOCKET_CLIENT * client_ptr,UCHAR * client_name,NX_IP * ip_ptr,NX_PACKET_POOL * pool_ptr)155 UINT _nx_websocket_client_create(NX_WEBSOCKET_CLIENT *client_ptr, UCHAR *client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr)
156 {
157
158 UINT status;
159
160 /* Clear the WebSocket structure. */
161 memset((void *)client_ptr, 0, sizeof(NX_WEBSOCKET_CLIENT));
162
163 /* Create WebSocket mutex. */
164 status = tx_mutex_create(&client_ptr -> nx_websocket_client_mutex, (CHAR *)client_name, TX_NO_INHERIT);
165 if (status)
166 {
167 return(status);
168 }
169
170 /* Save the Client name. */
171 client_ptr -> nx_websocket_client_name = client_name;
172
173 /* Save the IP pointer address. */
174 client_ptr -> nx_websocket_client_ip_ptr = ip_ptr;
175
176 /* Save the packet pool pointer. */
177 client_ptr -> nx_websocket_client_packet_pool_ptr = pool_ptr;
178
179 /* Set the Client ID to indicate the WebSocket client thread is ready. */
180 client_ptr -> nx_websocket_client_id = NX_WEBSOCKET_CLIENT_ID;
181
182 /* Update the state. */
183 client_ptr -> nx_websocket_client_state = NX_WEBSOCKET_CLIENT_STATE_IDLE;
184
185 /* Return successful completion. */
186 return(NX_SUCCESS);
187 }
188
189 /**************************************************************************/
190 /* */
191 /* FUNCTION RELEASE */
192 /* */
193 /* _nxe_websocket_client_delete PORTABLE C */
194 /* 6.2.0 */
195 /* AUTHOR */
196 /* */
197 /* Bo Chen, Microsoft Corporation */
198 /* */
199 /* DESCRIPTION */
200 /* */
201 /* This function checks for errors in the WebSocket instance delete */
202 /* function call. */
203 /* */
204 /* */
205 /* INPUT */
206 /* */
207 /* client_ptr Pointer to WebSocket Client */
208 /* */
209 /* OUTPUT */
210 /* */
211 /* status Completion status */
212 /* */
213 /* CALLS */
214 /* */
215 /* _nx_websocket_client_delete Actual websocket delete call */
216 /* */
217 /* CALLED BY */
218 /* */
219 /* Application Code */
220 /* */
221 /* RELEASE HISTORY */
222 /* */
223 /* DATE NAME DESCRIPTION */
224 /* */
225 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
226 /* */
227 /**************************************************************************/
_nxe_websocket_client_delete(NX_WEBSOCKET_CLIENT * client_ptr)228 UINT _nxe_websocket_client_delete(NX_WEBSOCKET_CLIENT *client_ptr)
229 {
230
231 UINT status;
232
233 /* Check for invalid input pointers. */
234 if ((client_ptr == NX_NULL) || (client_ptr -> nx_websocket_client_id != NX_WEBSOCKET_CLIENT_ID))
235 {
236 return(NX_PTR_ERROR);
237 }
238
239 /* Call actual client delete function. */
240 status = _nx_websocket_client_delete(client_ptr);
241
242 /* Return completion status. */
243 return(status);
244 }
245
246 /**************************************************************************/
247 /* */
248 /* FUNCTION RELEASE */
249 /* */
250 /* _nx_websocket_client_delete PORTABLE C */
251 /* 6.2.0 */
252 /* AUTHOR */
253 /* */
254 /* Bo Chen, Microsoft Corporation */
255 /* */
256 /* DESCRIPTION */
257 /* */
258 /* This function deletes an instance for WebSocket Client. */
259 /* */
260 /* INPUT */
261 /* */
262 /* client_ptr Pointer to WebSocket Client */
263 /* */
264 /* OUTPUT */
265 /* */
266 /* _nx_websocket_client_cleanup Cleanup unused resources */
267 /* */
268 /* CALLS */
269 /* */
270 /* None */
271 /* */
272 /* CALLED BY */
273 /* */
274 /* Application Code */
275 /* */
276 /* RELEASE HISTORY */
277 /* */
278 /* DATE NAME DESCRIPTION */
279 /* */
280 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
281 /* */
282 /**************************************************************************/
_nx_websocket_client_delete(NX_WEBSOCKET_CLIENT * client_ptr)283 UINT _nx_websocket_client_delete(NX_WEBSOCKET_CLIENT *client_ptr)
284 {
285
286 /* Obtain the mutex. */
287 tx_mutex_get(&(client_ptr -> nx_websocket_client_mutex), NX_WAIT_FOREVER);
288
289 /* Clean up unused resources. */
290 _nx_websocket_client_cleanup(client_ptr);
291
292 /* Set the Client ID to a default value. */
293 client_ptr -> nx_websocket_client_id = 0;
294
295 /* Update the state. */
296 client_ptr -> nx_websocket_client_state = NX_WEBSOCKET_CLIENT_STATE_INITIALIZE;
297
298 /* Release the mutex, delete the mutex and assign the pointer to NULL. */
299 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
300 tx_mutex_delete(&(client_ptr -> nx_websocket_client_mutex));
301
302 /* Return successful completion. */
303 return(NX_SUCCESS);
304 }
305
306 /**************************************************************************/
307 /* */
308 /* FUNCTION RELEASE */
309 /* */
310 /* _nxe_websocket_client_connect PORTABLE C */
311 /* 6.2.0 */
312 /* AUTHOR */
313 /* */
314 /* Bo Chen, Microsoft Corporation */
315 /* */
316 /* DESCRIPTION */
317 /* */
318 /* This function checks for errors in the WebSocket connect. */
319 /* */
320 /* INPUT */
321 /* */
322 /* client_ptr Pointer to WebSocket Client */
323 /* socket_ptr Pointer to TCP socket */
324 /* host Pointer to host */
325 /* host_length Length of host */
326 /* uri_path Pointer to uri path */
327 /* uri_path_length Length of uri path */
328 /* protocol Pointer to protocol */
329 /* protocol_length Length of protocol */
330 /* wait_option Wait option */
331 /* */
332 /* OUTPUT */
333 /* */
334 /* status Completion status */
335 /* */
336 /* CALLS */
337 /* */
338 /* _nx_websocket_client_connect Actual websocket connect call */
339 /* */
340 /* CALLED BY */
341 /* */
342 /* Application Code */
343 /* */
344 /* RELEASE HISTORY */
345 /* */
346 /* DATE NAME DESCRIPTION */
347 /* */
348 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
349 /* */
350 /**************************************************************************/
_nxe_websocket_client_connect(NX_WEBSOCKET_CLIENT * client_ptr,NX_TCP_SOCKET * socket_ptr,UCHAR * host,UINT host_length,UCHAR * uri_path,UINT uri_path_length,UCHAR * protocol,UINT protocol_length,UINT wait_option)351 UINT _nxe_websocket_client_connect(NX_WEBSOCKET_CLIENT *client_ptr, NX_TCP_SOCKET *socket_ptr,
352 UCHAR *host, UINT host_length,
353 UCHAR *uri_path, UINT uri_path_length,
354 UCHAR *protocol, UINT protocol_length,UINT wait_option)
355 {
356
357 UINT status;
358
359
360 /* Check for invalid input pointers. */
361 if ((client_ptr == NX_NULL) || (client_ptr -> nx_websocket_client_id != NX_WEBSOCKET_CLIENT_ID) ||
362 (socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID) ||
363 (host == NX_NULL) || (host_length == 0) ||
364 (uri_path == NX_NULL) || (uri_path_length == 0) ||
365 (protocol == NX_NULL) || (protocol_length == 0))
366 {
367 return(NX_PTR_ERROR);
368 }
369
370 /* Call actual connect function. */
371 status = _nx_websocket_client_connect(client_ptr, socket_ptr, host, host_length, uri_path, uri_path_length, protocol, protocol_length, wait_option);
372
373 /* Return completion status. */
374 return(status);
375 }
376
377 /**************************************************************************/
378 /* */
379 /* FUNCTION RELEASE */
380 /* */
381 /* _nx_websocket_client_connect PORTABLE C */
382 /* 6.2.0 */
383 /* AUTHOR */
384 /* */
385 /* Bo Chen, Microsoft Corporation */
386 /* */
387 /* DESCRIPTION */
388 /* */
389 /* This function makes a WebSocket connection over TCP socket to the */
390 /* server. */
391 /* Note: Application must establish a TCP connection before. */
392 /* */
393 /* INPUT */
394 /* */
395 /* client_ptr Pointer to WebSocket Client */
396 /* socket_ptr Pointer to TCP socket */
397 /* host Pointer to host */
398 /* host_length Length of host */
399 /* uri_path Pointer to uri path */
400 /* uri_path_length Length of uri path */
401 /* protocol Pointer to protocol */
402 /* protocol_length Length of protocol */
403 /* wait_option Wait option */
404 /* */
405 /* OUTPUT */
406 /* */
407 /* status Completion status */
408 /* */
409 /* CALLS */
410 /* */
411 /* _nx_websocket_client_connect_internal Make websocket connection */
412 /* */
413 /* CALLED BY */
414 /* */
415 /* Application Code */
416 /* */
417 /* RELEASE HISTORY */
418 /* */
419 /* DATE NAME DESCRIPTION */
420 /* */
421 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
422 /* */
423 /**************************************************************************/
_nx_websocket_client_connect(NX_WEBSOCKET_CLIENT * client_ptr,NX_TCP_SOCKET * socket_ptr,UCHAR * host,UINT host_length,UCHAR * resource,UINT resource_length,UCHAR * protocol,UINT protocol_length,UINT wait_option)424 UINT _nx_websocket_client_connect(NX_WEBSOCKET_CLIENT *client_ptr, NX_TCP_SOCKET *socket_ptr,
425 UCHAR *host, UINT host_length,
426 UCHAR *resource, UINT resource_length,
427 UCHAR *protocol, UINT protocol_length,UINT wait_option)
428 {
429
430 UINT status;
431
432
433 /* Obtain the mutex. */
434 tx_mutex_get(&(client_ptr -> nx_websocket_client_mutex), NX_WAIT_FOREVER);
435
436 /* Check the state. */
437 if (client_ptr -> nx_websocket_client_state == NX_WEBSOCKET_CLIENT_STATE_CONNECTED)
438 {
439
440 /* Release the mutex and return */
441 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
442 return(NX_WEBSOCKET_ALREADY_CONNECTED);
443 }
444 else if (client_ptr -> nx_websocket_client_state == NX_WEBSOCKET_CLIENT_STATE_CONNECTING)
445 {
446
447 /* Release the mutex and return */
448 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
449 return(NX_WEBSOCKET_CONNECTING);
450 }
451 else if (client_ptr -> nx_websocket_client_state == NX_WEBSOCKET_CLIENT_STATE_INITIALIZE)
452 {
453
454 /* Release the mutex and return */
455 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
456 return(NX_WEBSOCKET_INVALID_STATE);
457 }
458
459 /* Save the socket pointer. */
460 client_ptr -> nx_websocket_client_socket_ptr = socket_ptr;
461
462 #ifdef NX_SECURE_ENABLE
463 client_ptr -> nx_websocket_client_use_tls = NX_FALSE;
464 #endif /* NX_SECURE_ENABLE */
465
466 status = _nx_websocket_client_connect_internal(client_ptr, host, host_length, resource, resource_length, protocol, protocol_length, wait_option);
467
468 /* Release the mutex and return */
469 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
470 return(status);
471 }
472
473 /**************************************************************************/
474 /* */
475 /* FUNCTION RELEASE */
476 /* */
477 /* _nx_websocket_client_connect_internal PORTABLE C */
478 /* 6.2.0 */
479 /* AUTHOR */
480 /* */
481 /* Bo Chen, Microsoft Corporation */
482 /* */
483 /* DESCRIPTION */
484 /* */
485 /* This function makes a WebSocket connection over TCP socket or TLS */
486 /* session to the server. */
487 /* */
488 /* INPUT */
489 /* */
490 /* client_ptr Pointer to WebSocket Client */
491 /* host Pointer to host */
492 /* host_length Length of host */
493 /* uri_path Pointer to uri path */
494 /* uri_path_length Length of uri path */
495 /* protocol Pointer to protocol */
496 /* protocol_length Length of protocol */
497 /* wait_option Wait option */
498 /* */
499 /* OUTPUT */
500 /* */
501 /* status Completion status */
502 /* */
503 /* CALLS */
504 /* */
505 /* nx_packet_allocate Allocate a packet */
506 /* nx_packet_release Release the packet */
507 /* nx_secure_tls_packet_allocate Allocate a TLS packet */
508 /* nx_packet_data_append Append data */
509 /* _nx_utility_base64_encode Base64 encode */
510 /* _nx_websocket_client_packet_send Send out websocket packet */
511 /* _nx_websocket_client_packet_receive Receive a websocket packet */
512 /* _nx_websocket_client_connect_response_check */
513 /* Process connect response */
514 /* _nx_websocket_client_cleanup Cleanup resources */
515 /* */
516 /* CALLED BY */
517 /* */
518 /* _nx_websocket_client_connect Make websocket connection */
519 /* _nx_websocket_client_secure_connect Make secure websocket */
520 /* connection */
521 /* */
522 /* RELEASE HISTORY */
523 /* */
524 /* DATE NAME DESCRIPTION */
525 /* */
526 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
527 /* */
528 /**************************************************************************/
_nx_websocket_client_connect_internal(NX_WEBSOCKET_CLIENT * client_ptr,UCHAR * host,UINT host_length,UCHAR * uri_path,UINT uri_path_length,UCHAR * protocol,UINT protocol_length,UINT wait_option)529 UINT _nx_websocket_client_connect_internal(NX_WEBSOCKET_CLIENT *client_ptr,
530 UCHAR *host, UINT host_length,
531 UCHAR *uri_path, UINT uri_path_length,
532 UCHAR *protocol, UINT protocol_length,UINT wait_option)
533 {
534
535 UINT i;
536 UINT status;
537 NX_PACKET *packet_ptr;
538
539
540 /* To guarantee resources are cleaned-up if a re-connect happens. */
541 _nx_websocket_client_cleanup(client_ptr);
542
543 /* Generate GUID for WebSocket Key. */
544 for (i = 0; i < NX_WEBSOCKET_CLIENT_GUID_SIZE; i ++)
545 {
546 client_ptr -> nx_websocket_client_guid[i] = (UCHAR)(NX_RAND());
547 }
548
549 /* Encode the GUID as key. */
550 _nx_utility_base64_encode(client_ptr -> nx_websocket_client_guid, NX_WEBSOCKET_CLIENT_GUID_SIZE,
551 client_ptr -> nx_websocket_client_key, NX_WEBSOCKET_CLIENT_KEY_SIZE,
552 &client_ptr -> nx_websocket_client_key_size);
553
554 /* Release the mutex */
555 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
556
557 /* Allocate a packet. */
558 #ifdef NX_SECURE_ENABLE
559 if (client_ptr -> nx_websocket_client_use_tls)
560 {
561
562 /* Use TLS packet allocate. The TLS packet allocate is able to count for
563 TLS-related header space including crypto initial vector area. */
564 status = nx_secure_tls_packet_allocate(client_ptr -> nx_websocket_client_tls_session_ptr,
565 client_ptr -> nx_websocket_client_packet_pool_ptr,
566 &packet_ptr, TX_WAIT_FOREVER);
567 }
568 else
569 {
570 #endif /* NX_SECURE_ENABLE */
571
572 /* Allocate packet. */
573 if (client_ptr -> nx_websocket_client_socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V4)
574 {
575 status = nx_packet_allocate(client_ptr -> nx_websocket_client_packet_pool_ptr,
576 &packet_ptr,
577 NX_IPv4_TCP_PACKET, wait_option);
578 }
579 else
580 {
581 status = nx_packet_allocate(client_ptr -> nx_websocket_client_packet_pool_ptr,
582 &packet_ptr,
583 NX_IPv6_TCP_PACKET, wait_option);
584 }
585 #ifdef NX_SECURE_ENABLE
586 }
587 #endif /* NX_SECURE_ENABLE */
588
589 /* Check status. */
590 if (status)
591 {
592
593 /* Obtain the mutex again and return error status. */
594 tx_mutex_get(&(client_ptr -> nx_websocket_client_mutex), NX_WAIT_FOREVER);
595 return(status);
596 }
597
598 /* WebSocket opening handshake message format:
599 GET /mqtt HTTP/1.1\r\n
600 Host: example.com\r\n
601 Upgrade: websocket\r\n
602 connection: Upgrade\r\n
603 Sec-WebSocket-Key: xxxxxxx=\r\n
604 Sec-WebSocket-Protocol: mqtt\r\n
605 Sec-WebSocket-Version: 13\r\n
606 \r\n
607 */
608
609 /* Build the GET request: Get + Request URI + HTTP version. */
610 status = nx_packet_data_append(packet_ptr, "GET ", sizeof("GET ") - 1, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
611 status += nx_packet_data_append(packet_ptr, uri_path, uri_path_length, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
612 status += nx_packet_data_append(packet_ptr, " HTTP/1.1", sizeof(" HTTP/1.1") - 1, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
613 status += nx_packet_data_append(packet_ptr, NX_WEBSOCKET_CRLF, NX_WEBSOCKET_CRLF_SIZE, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
614
615 /* Place the Host in the header. */
616 status += nx_packet_data_append(packet_ptr, "Host: ", sizeof("Host: ") - 1, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
617 status += nx_packet_data_append(packet_ptr, host, host_length, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
618 status += nx_packet_data_append(packet_ptr, NX_WEBSOCKET_CRLF, NX_WEBSOCKET_CRLF_SIZE, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
619
620 /* Place the Upgrade in the header. */
621 status += nx_packet_data_append(packet_ptr, "Upgrade: websocket", sizeof("Upgrade: websocket") - 1, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
622 status += nx_packet_data_append(packet_ptr, NX_WEBSOCKET_CRLF, NX_WEBSOCKET_CRLF_SIZE, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
623
624 /* Place the Connection in the header. */
625 status += nx_packet_data_append(packet_ptr, "Connection: Upgrade", sizeof("Connection: Upgrade") - 1, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
626 status += nx_packet_data_append(packet_ptr, NX_WEBSOCKET_CRLF, NX_WEBSOCKET_CRLF_SIZE, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
627
628 /* Place the Sec-WebSocket-Key in the header. */
629 status += nx_packet_data_append(packet_ptr, "Sec-WebSocket-Key: ", sizeof("Sec-WebSocket-Key: ") - 1, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
630 status += nx_packet_data_append(packet_ptr, client_ptr -> nx_websocket_client_key, client_ptr -> nx_websocket_client_key_size, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
631 status += nx_packet_data_append(packet_ptr, NX_WEBSOCKET_CRLF, NX_WEBSOCKET_CRLF_SIZE, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
632
633 /* Place the connection in the header. */
634 status += nx_packet_data_append(packet_ptr, "Sec-WebSocket-Protocol: ", sizeof("Sec-WebSocket-Protocol: ") - 1, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
635 status += nx_packet_data_append(packet_ptr, protocol, protocol_length, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
636 status += nx_packet_data_append(packet_ptr, NX_WEBSOCKET_CRLF, NX_WEBSOCKET_CRLF_SIZE, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
637
638 /* Place the connection in the header. */
639 status += nx_packet_data_append(packet_ptr, "Sec-WebSocket-Version: 13", sizeof("Sec-WebSocket-Version: 13") - 1, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
640 status += nx_packet_data_append(packet_ptr, NX_WEBSOCKET_CRLF, NX_WEBSOCKET_CRLF_SIZE, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
641
642 /* Fill the last \r\n. */
643 status += nx_packet_data_append(packet_ptr, NX_WEBSOCKET_CRLF, NX_WEBSOCKET_CRLF_SIZE, client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
644
645 /* Check status. */
646 if (status)
647 {
648
649 /* Obtain the mutex, release the packet and return error status. */
650 tx_mutex_get(&(client_ptr -> nx_websocket_client_mutex), NX_WAIT_FOREVER);
651 nx_packet_release(packet_ptr);
652 return(NX_WEBSOCKET_DATA_APPEND_FAILURE);
653 }
654
655 /* Send out the packet. */
656 status = _nx_websocket_client_packet_send(client_ptr, packet_ptr, wait_option);
657 if (status)
658 {
659
660 /* Release the packet and return error status. */
661 nx_packet_release(packet_ptr);
662 return(status);
663 }
664
665 /* Obtain the mutex again. */
666 tx_mutex_get(&(client_ptr -> nx_websocket_client_mutex), NX_WAIT_FOREVER);
667
668 /* Update the subprotocol name and length */
669 client_ptr -> nx_websocket_client_subprotocol = protocol;
670 client_ptr -> nx_websocket_client_subprotocol_length = protocol_length;
671
672 /* Update the state. */
673 client_ptr -> nx_websocket_client_state = NX_WEBSOCKET_CLIENT_STATE_CONNECTING;
674
675 /* Set the frame flag to be unfragmented and corresponding opcode to be zero */
676 client_ptr -> nx_websocket_client_frame_fragmented = NX_FALSE;
677 client_ptr -> nx_websocket_client_frame_opcode = 0;
678
679 /* Check if using non-blocking mode. */
680 if (wait_option == 0)
681 {
682 return(NX_IN_PROGRESS);
683 }
684
685 while (1)
686 {
687
688 /* Receive response. */
689 status = _nx_websocket_client_packet_receive(client_ptr, &packet_ptr, wait_option);
690 if (status)
691 {
692 return(status);
693 }
694
695 /* Process the response. */
696 status = _nx_websocket_client_connect_response_check(client_ptr, packet_ptr, wait_option);
697
698 /* If status is NX_IN_PROGRESS, continue to receive connect response.
699 Otherwise, break the while loop. */
700 if (status != NX_IN_PROGRESS)
701 {
702 break;
703 }
704 }
705
706 /* Return status. */
707 return(status);
708 }
709
710 #ifdef NX_SECURE_ENABLE
711 /**************************************************************************/
712 /* */
713 /* FUNCTION RELEASE */
714 /* */
715 /* _nxe_websocket_client_secure_connect PORTABLE C */
716 /* 6.2.0 */
717 /* AUTHOR */
718 /* */
719 /* Bo Chen, Microsoft Corporation */
720 /* */
721 /* DESCRIPTION */
722 /* */
723 /* This function checks for errors in the WebSocket secure connect. */
724 /* */
725 /* INPUT */
726 /* */
727 /* client_ptr Pointer to WebSocket Client */
728 /* tls_session Pointer to TLS session */
729 /* host Pointer to host */
730 /* host_length Length of host */
731 /* uri_path Pointer to uri path */
732 /* uri_path_length Length of uri path */
733 /* protocol Pointer to protocol */
734 /* protocol_length Length of protocol */
735 /* wait_option Wait option */
736 /* */
737 /* OUTPUT */
738 /* */
739 /* status Completion status */
740 /* */
741 /* CALLS */
742 /* */
743 /* _nx_websocket_client_secure_connect Actual websocket connect call */
744 /* */
745 /* CALLED BY */
746 /* */
747 /* Application Code */
748 /* */
749 /* RELEASE HISTORY */
750 /* */
751 /* DATE NAME DESCRIPTION */
752 /* */
753 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
754 /* */
755 /**************************************************************************/
_nxe_websocket_client_secure_connect(NX_WEBSOCKET_CLIENT * client_ptr,NX_SECURE_TLS_SESSION * tls_session,UCHAR * host,UINT host_length,UCHAR * uri_path,UINT uri_path_length,UCHAR * protocol,UINT protocol_length,UINT wait_option)756 UINT _nxe_websocket_client_secure_connect(NX_WEBSOCKET_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *tls_session,
757 UCHAR *host, UINT host_length,
758 UCHAR *uri_path, UINT uri_path_length,
759 UCHAR *protocol, UINT protocol_length,UINT wait_option)
760 {
761
762 UINT status;
763
764
765 /* Check for invalid input pointers. */
766 if ((client_ptr == NX_NULL) || (client_ptr -> nx_websocket_client_id != NX_WEBSOCKET_CLIENT_ID) ||
767 (tls_session == NX_NULL) ||
768 (host == NX_NULL) || (host_length == 0) ||
769 (uri_path == NX_NULL) || (uri_path_length == 0) ||
770 (protocol == NX_NULL) || (protocol_length == 0))
771 {
772 return(NX_PTR_ERROR);
773 }
774
775 /* Call actual secure connect function. */
776 status = _nx_websocket_client_secure_connect(client_ptr, tls_session, host, host_length, uri_path, uri_path_length, protocol, protocol_length, wait_option);
777
778 /* Return completion status. */
779 return(status);
780 }
781
782 /**************************************************************************/
783 /* */
784 /* FUNCTION RELEASE */
785 /* */
786 /* _nx_websocket_client_secure_connect PORTABLE C */
787 /* 6.2.0 */
788 /* AUTHOR */
789 /* */
790 /* Bo Chen, Microsoft Corporation */
791 /* */
792 /* DESCRIPTION */
793 /* */
794 /* This function makes a WebSocket connection over TLS session to the */
795 /* server. */
796 /* Note: Application must establish a TLS connection before. */
797 /* */
798 /* INPUT */
799 /* */
800 /* client_ptr Pointer to WebSocket Client */
801 /* tls_session Pointer to TLS session */
802 /* host Pointer to host */
803 /* host_length Length of host */
804 /* uri_path Pointer to uri path */
805 /* uri_path_length Length of uri path */
806 /* protocol Pointer to protocol */
807 /* protocol_length Length of protocol */
808 /* wait_option Wait option */
809 /* */
810 /* OUTPUT */
811 /* */
812 /* status Completion status */
813 /* */
814 /* CALLS */
815 /* */
816 /* _nx_websocket_client_connect_internal Make websocket connection */
817 /* */
818 /* CALLED BY */
819 /* */
820 /* Application Code */
821 /* */
822 /* RELEASE HISTORY */
823 /* */
824 /* DATE NAME DESCRIPTION */
825 /* */
826 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
827 /* */
828 /**************************************************************************/
_nx_websocket_client_secure_connect(NX_WEBSOCKET_CLIENT * client_ptr,NX_SECURE_TLS_SESSION * tls_session,UCHAR * host,UINT host_length,UCHAR * uri_path,UINT uri_path_length,UCHAR * protocol,UINT protocol_length,UINT wait_option)829 UINT _nx_websocket_client_secure_connect(NX_WEBSOCKET_CLIENT *client_ptr, NX_SECURE_TLS_SESSION *tls_session,
830 UCHAR *host, UINT host_length,
831 UCHAR *uri_path, UINT uri_path_length,
832 UCHAR *protocol, UINT protocol_length,UINT wait_option)
833 {
834
835 UINT status;
836
837
838 /* Obtain the mutex. */
839 tx_mutex_get(&(client_ptr -> nx_websocket_client_mutex), NX_WAIT_FOREVER);
840
841 /* Check the state. */
842 if (client_ptr -> nx_websocket_client_state == NX_WEBSOCKET_CLIENT_STATE_CONNECTED)
843 {
844
845 /* Release the mutex and return */
846 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
847 return(NX_WEBSOCKET_ALREADY_CONNECTED);
848 }
849 else if (client_ptr -> nx_websocket_client_state == NX_WEBSOCKET_CLIENT_STATE_CONNECTING)
850 {
851
852 /* Release the mutex and return */
853 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
854 return(NX_WEBSOCKET_CONNECTING);
855 }
856 else if (client_ptr -> nx_websocket_client_state == NX_WEBSOCKET_CLIENT_STATE_INITIALIZE)
857 {
858
859 /* Release the mutex and return */
860 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
861 return(NX_WEBSOCKET_INVALID_STATE);
862 }
863
864 /* Save the tls session pointer. */
865 client_ptr -> nx_websocket_client_tls_session_ptr = tls_session;
866 client_ptr -> nx_websocket_client_use_tls = NX_TRUE;
867
868 status = _nx_websocket_client_connect_internal(client_ptr, host, host_length, uri_path, uri_path_length, protocol, protocol_length, wait_option);
869
870 /* Release the mutex and return */
871 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
872 return(status);
873 }
874 #endif /* NX_SECURE_ENABLE */
875
876 /**************************************************************************/
877 /* */
878 /* FUNCTION RELEASE */
879 /* */
880 /* _nx_websocket_client_name_compare PORTABLE C */
881 /* 6.2.0 */
882 /* AUTHOR */
883 /* */
884 /* Bo Chen, Microsoft Corporation */
885 /* */
886 /* DESCRIPTION */
887 /* */
888 /* This function compares two pieces of memory case insensitive. */
889 /* */
890 /* INPUT */
891 /* */
892 /* src Pointer to source */
893 /* src_length Length of source */
894 /* dest Pointer to destination */
895 /* dest_length Length of destination */
896 /* */
897 /* OUTPUT */
898 /* */
899 /* status Completion status */
900 /* */
901 /* CALLS */
902 /* */
903 /* None */
904 /* */
905 /* CALLED BY */
906 /* */
907 /* _nx_websocket_client_connect_response_process */
908 /* Process connect response */
909 /* */
910 /* RELEASE HISTORY */
911 /* */
912 /* DATE NAME DESCRIPTION */
913 /* */
914 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
915 /* */
916 /**************************************************************************/
_nx_websocket_client_name_compare(UCHAR * src,ULONG src_length,UCHAR * dest,ULONG dest_length)917 UINT _nx_websocket_client_name_compare(UCHAR *src, ULONG src_length, UCHAR *dest, ULONG dest_length)
918 {
919 UCHAR ch;
920
921 /* Compare the length. */
922 if(src_length != dest_length)
923 {
924 return(NX_WEBSOCKET_ERROR);
925 }
926
927 while(src_length)
928 {
929
930 /* Is src lowercase? */
931 if((*src >= 'a') && (*src <= 'z'))
932 ch = (UCHAR)(*src - 'a' + 'A');
933
934 /* Is src uppercase? */
935 else if((*src >= 'A') && (*src <= 'Z'))
936 ch = (UCHAR)(*src - 'A' + 'a');
937 else
938 ch = *src;
939
940 /* Compare case insensitive. */
941 if((*src != *dest) && (ch != *dest))
942 {
943 return(NX_WEBSOCKET_ERROR);
944 }
945
946 /* Pickup next character. */
947 src_length--;
948 src++;
949 dest++;
950 }
951
952 return(NX_WEBSOCKET_SUCCESS);
953 }
954
955 /**************************************************************************/
956 /* */
957 /* FUNCTION RELEASE */
958 /* */
959 /* _nx_websocket_client_connect_response_process PORTABLE C */
960 /* 6.2.0 */
961 /* AUTHOR */
962 /* */
963 /* Bo Chen, Microsoft Corporation */
964 /* */
965 /* DESCRIPTION */
966 /* */
967 /* This function processes connect response. */
968 /* */
969 /* */
970 /* INPUT */
971 /* */
972 /* client_ptr Pointer to WebSocket Client */
973 /* packet_ptr Pointer to packet */
974 /* */
975 /* OUTPUT */
976 /* */
977 /* status Completion status */
978 /* */
979 /* CALLS */
980 /* */
981 /* _nx_websocket_client_name_compare Compare memory data */
982 /* _nx_sha1_initialize Initialize sha1 */
983 /* _nx_sha1_update Update sha1 */
984 /* _nx_sha1_digest_calculate Calculate sha1 digest */
985 /* _nx_utility_base64_encode Base64 encode */
986 /* */
987 /* CALLED BY */
988 /* */
989 /* _nx_websocket_client_connect_response_check */
990 /* Check connect response */
991 /* */
992 /* RELEASE HISTORY */
993 /* */
994 /* DATE NAME DESCRIPTION */
995 /* */
996 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
997 /* */
998 /**************************************************************************/
_nx_websocket_client_connect_response_process(NX_WEBSOCKET_CLIENT * client_ptr,NX_PACKET * packet_ptr)999 UINT _nx_websocket_client_connect_response_process(NX_WEBSOCKET_CLIENT *client_ptr, NX_PACKET *packet_ptr)
1000 {
1001 UCHAR *buffer_ptr;
1002 UINT offset;
1003 UCHAR *field_name;
1004 UINT field_name_length;
1005 UCHAR *field_value;
1006 UINT field_value_length;
1007 UCHAR digest[NX_WEBSOCKET_ACCEPT_DIGEST_SIZE];
1008 UCHAR key[NX_WEBSOCKET_ACCEPT_KEY_SIZE + 1];
1009 UINT key_size = 0;
1010 UCHAR upgrade_flag = NX_FALSE;
1011 UCHAR connection_flag = NX_FALSE;
1012 UCHAR protocol_cnt = 0;
1013 UCHAR accept_cnt = 0;
1014
1015 NX_PARAMETER_NOT_USED(client_ptr);
1016
1017 /* WebSocket opening handshake message format:
1018 HTTP/1.1 101 Switching Protocols
1019 Upgrade: websocket\r\n
1020 Server: Microsoft-HTTPAPI/2.0\r\n
1021 Sec-WebSocket-Protocol: mqtt\r\n
1022 Connection: Upgrade\r\n
1023 Sec-WebSocket-Accept: xxxxxxxxxx=\r\n
1024 Date: Mon, 06 Jun 2022 07:46:53 GMT\r\n
1025 \r\n
1026 */
1027
1028 /* Setup pointer and offset. */
1029 buffer_ptr = packet_ptr -> nx_packet_prepend_ptr;
1030 offset = 0;
1031
1032 /* Check the length. */
1033 if ((packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr) < 12)
1034 {
1035 return(NX_WEBSOCKET_INVALID_PACKET);
1036 }
1037
1038 /* Check the status code. Must be "101" Switching Protocols. */
1039 if ((buffer_ptr[9] != '1') || (buffer_ptr[10] != '0') || (buffer_ptr[11] != '1'))
1040 {
1041 return(NX_WEBSOCKET_INVALID_STATUS_CODE);
1042 }
1043
1044 /* Skip over the first HTTP line (HTTP/1.1 101 Switching Protocols\r\n). */
1045 offset = 12;
1046 buffer_ptr += 12;
1047 while(((buffer_ptr + 1) < packet_ptr -> nx_packet_append_ptr) &&
1048 (*buffer_ptr != '\r') && (*(buffer_ptr + 1) != '\n'))
1049 {
1050 buffer_ptr++;
1051 offset++;
1052 }
1053
1054 /* Skip over the CR,LF. */
1055 buffer_ptr += 2;
1056 offset += 2;
1057
1058 /* Loop until we find the "cr,lf,cr,lf" token. */
1059 while (((buffer_ptr + 1) < packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != 0))
1060 {
1061
1062 /* Check for the <cr,lf,cr,lf> token. This signals a blank line, which also
1063 specifies the start of the content. */
1064 if ((*buffer_ptr == '\r') &&
1065 (*(buffer_ptr + 1) == '\n'))
1066 {
1067
1068 /* Adjust the offset. */
1069 offset = offset + 2;
1070 break;
1071 }
1072
1073 /* We haven't seen the <cr,lf,cr,lf> so we are still processing header data.
1074 Extract the field name and it's value. */
1075 field_name = buffer_ptr;
1076 field_name_length = 0;
1077
1078 /* Look for the ':' that separates the field name from its value. */
1079 while ((buffer_ptr < packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != ':'))
1080 {
1081 buffer_ptr++;
1082 field_name_length++;
1083 }
1084 offset += field_name_length;
1085
1086 /* Skip ':'. */
1087 buffer_ptr++;
1088 offset++;
1089
1090 /* Now skip over white space. */
1091 while ((buffer_ptr < packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr == ' '))
1092 {
1093 buffer_ptr++;
1094 offset++;
1095 }
1096
1097 /* Now get the field value. */
1098 field_value = buffer_ptr;
1099 field_value_length = 0;
1100
1101 /* Loop until we see a <CR, LF>. */
1102 while (((buffer_ptr + 1) < packet_ptr -> nx_packet_append_ptr) && (*buffer_ptr != '\r') && (*(buffer_ptr+1) != '\n'))
1103 {
1104 buffer_ptr++;
1105 field_value_length++;
1106 }
1107 offset += field_value_length;
1108
1109 /* Skip over the CR,LF. */
1110 buffer_ptr += 2;
1111 offset += 2;
1112
1113 /* Check the upgrade. */
1114 if (_nx_websocket_client_name_compare((UCHAR *)field_name, field_name_length, (UCHAR *)"Upgrade", sizeof("Upgrade") - 1) == NX_SUCCESS)
1115 {
1116 if (_nx_websocket_client_name_compare((UCHAR *)field_value, field_value_length, (UCHAR *)"websocket", sizeof("websocket") - 1))
1117 {
1118 return(NX_WEBSOCKET_INVALID_PACKET);
1119 }
1120
1121 upgrade_flag = NX_TRUE;
1122 }
1123 else if (_nx_websocket_client_name_compare((UCHAR *)field_name, field_name_length, (UCHAR *)"Connection", sizeof("Connection") - 1) == NX_SUCCESS)
1124 {
1125 if (_nx_websocket_client_name_compare((UCHAR *)field_value, field_value_length, (UCHAR *)"Upgrade", sizeof("Upgrade") - 1))
1126 {
1127 return(NX_WEBSOCKET_INVALID_PACKET);
1128 }
1129
1130 connection_flag = NX_TRUE;
1131 }
1132 else if (_nx_websocket_client_name_compare((UCHAR *)field_name, field_name_length, (UCHAR *)"Sec-WebSocket-Protocol", sizeof("Sec-WebSocket-Protocol") - 1) == NX_SUCCESS)
1133 {
1134 if (_nx_websocket_client_name_compare((UCHAR *)field_value, field_value_length, client_ptr -> nx_websocket_client_subprotocol, client_ptr -> nx_websocket_client_subprotocol_length))
1135 {
1136 return(NX_WEBSOCKET_INVALID_PACKET);
1137 }
1138
1139 protocol_cnt++;
1140 }
1141 else if (_nx_websocket_client_name_compare((UCHAR *)field_name, field_name_length, (UCHAR *)"Sec-WebSocket-Accept", sizeof("Sec-WebSocket-Accept") - 1) == NX_SUCCESS)
1142 {
1143
1144 /* Calculate the SHA-1 hash of the concatenation of the client key and the Globally Unique Identifier (GUID)
1145 Referenced in RFC 6455, Section 1.3, Page 6 */
1146 _nx_sha1_initialize(&(client_ptr -> nx_websocket_client_sha1));
1147 _nx_sha1_update(&(client_ptr -> nx_websocket_client_sha1), client_ptr->nx_websocket_client_key, client_ptr->nx_websocket_client_key_size);
1148 _nx_sha1_update(&(client_ptr -> nx_websocket_client_sha1), (UCHAR*)NX_WEBSOCKET_ACCEPT_PREDEFINED_GUID, NX_WEBSOCKET_ACCEPT_PREDEFINED_GUID_SIZE);
1149 _nx_sha1_digest_calculate(&(client_ptr -> nx_websocket_client_sha1), digest);
1150
1151 /* Encode the hash and compare it with the field value from the server. */
1152 _nx_utility_base64_encode(digest, NX_WEBSOCKET_ACCEPT_DIGEST_SIZE, key, (NX_WEBSOCKET_ACCEPT_KEY_SIZE + 1), &key_size);
1153 if ((field_value_length != NX_WEBSOCKET_ACCEPT_KEY_SIZE) || (memcmp((void *)field_value, (void *)key, NX_WEBSOCKET_ACCEPT_KEY_SIZE))) /* Use case of memcpy is verified. */
1154 {
1155 return(NX_WEBSOCKET_INVALID_PACKET);
1156 }
1157
1158 accept_cnt++;
1159 }
1160 }
1161
1162 /* Check if the all fields are processed and found as required. */
1163 if ((offset != packet_ptr -> nx_packet_length) ||
1164 (upgrade_flag != NX_TRUE) || (connection_flag != NX_TRUE) ||
1165 (protocol_cnt != 1) || (accept_cnt != 1)) /* Both sec-websocket-protocol field and sec-websocket-accept field are allowed occur once only.
1166 Reference in RFC 6455, Section 11.3.3 and 11.3.4, Page 59-60 */
1167 {
1168 return(NX_WEBSOCKET_INVALID_PACKET);
1169 }
1170
1171 return(NX_SUCCESS);
1172 }
1173
1174 /**************************************************************************/
1175 /* */
1176 /* FUNCTION RELEASE */
1177 /* */
1178 /* _nxe_websocket_client_disconnect PORTABLE C */
1179 /* 6.2.0 */
1180 /* AUTHOR */
1181 /* */
1182 /* Bo Chen, Microsoft Corporation */
1183 /* */
1184 /* DESCRIPTION */
1185 /* */
1186 /* This function checks for errors in the WebSocket disconnect. */
1187 /* */
1188 /* INPUT */
1189 /* */
1190 /* client_ptr Pointer to WebSocket Client */
1191 /* wait_option Wait option */
1192 /* */
1193 /* OUTPUT */
1194 /* */
1195 /* status Completion status */
1196 /* */
1197 /* CALLS */
1198 /* */
1199 /* _nx_websocket_client_disconnect Actual disconnect call */
1200 /* */
1201 /* CALLED BY */
1202 /* */
1203 /* Application Code */
1204 /* */
1205 /* RELEASE HISTORY */
1206 /* */
1207 /* DATE NAME DESCRIPTION */
1208 /* */
1209 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
1210 /* */
1211 /**************************************************************************/
_nxe_websocket_client_disconnect(NX_WEBSOCKET_CLIENT * client_ptr,UINT wait_option)1212 UINT _nxe_websocket_client_disconnect(NX_WEBSOCKET_CLIENT *client_ptr, UINT wait_option)
1213 {
1214
1215 UINT status;
1216
1217
1218 /* Check for invalid input pointers. */
1219 if ((client_ptr == NX_NULL) || (client_ptr -> nx_websocket_client_id != NX_WEBSOCKET_CLIENT_ID))
1220 {
1221 return(NX_PTR_ERROR);
1222 }
1223
1224 /* Call actual disconnect function. */
1225 status = _nx_websocket_client_disconnect(client_ptr, wait_option);
1226
1227 /* Return completion status. */
1228 return(status);
1229 }
1230
1231 /**************************************************************************/
1232 /* */
1233 /* FUNCTION RELEASE */
1234 /* */
1235 /* _nx_websocket_client_disconnect PORTABLE C */
1236 /* 6.2.0 */
1237 /* AUTHOR */
1238 /* */
1239 /* Bo Chen, Microsoft Corporation */
1240 /* */
1241 /* DESCRIPTION */
1242 /* */
1243 /* This function disconnects the WebSocket connection created */
1244 /* previously. */
1245 /* */
1246 /* INPUT */
1247 /* */
1248 /* client_ptr Pointer to WebSocket Client */
1249 /* wait_option Wait option */
1250 /* */
1251 /* OUTPUT */
1252 /* */
1253 /* status Completion status */
1254 /* */
1255 /* CALLS */
1256 /* */
1257 /* _nx_websocket_client_packet_allocate Allocate websocket packet */
1258 /* _nx_websocket_client_send Send websocket packet */
1259 /* nx_packet_release Release websocket packet */
1260 /* */
1261 /* CALLED BY */
1262 /* */
1263 /* Application Code */
1264 /* */
1265 /* RELEASE HISTORY */
1266 /* */
1267 /* DATE NAME DESCRIPTION */
1268 /* */
1269 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
1270 /* */
1271 /**************************************************************************/
_nx_websocket_client_disconnect(NX_WEBSOCKET_CLIENT * client_ptr,UINT wait_option)1272 UINT _nx_websocket_client_disconnect(NX_WEBSOCKET_CLIENT *client_ptr, UINT wait_option)
1273 {
1274
1275 UINT status;
1276 NX_PACKET *packet_ptr;
1277
1278
1279 /* Check the state. */
1280 if ((client_ptr -> nx_websocket_client_state <= NX_WEBSOCKET_CLIENT_STATE_IDLE) || (client_ptr -> nx_websocket_client_state == NX_WEBSOCKET_CLIENT_STATE_DISCONNECT_SENT))
1281 {
1282
1283 /* Return error status */
1284 return(NX_WEBSOCKET_INVALID_STATE);
1285 }
1286 else if (client_ptr -> nx_websocket_client_state == NX_WEBSOCKET_CLIENT_STATE_CONNECTING)
1287 {
1288
1289 /* Update the state and return */
1290 client_ptr -> nx_websocket_client_state = NX_WEBSOCKET_CLIENT_STATE_IDLE;
1291 return(NX_WEBSOCKET_NOT_CONNECTED);
1292 }
1293
1294 /* Allocate a packet. */
1295 status = _nx_websocket_client_packet_allocate(client_ptr, &packet_ptr, wait_option);
1296
1297 /* Check the status. */
1298 if (status == NX_SUCCESS)
1299 {
1300
1301 /* Send out the packet. */
1302 status = _nx_websocket_client_send(client_ptr, packet_ptr, NX_WEBSOCKET_OPCODE_CONNECTION_CLOSE, NX_TRUE, wait_option);
1303
1304 /* Check the status. */
1305 if (status)
1306 {
1307 nx_packet_release(packet_ptr);
1308 }
1309 }
1310
1311 /* Obtain the mutex. */
1312 tx_mutex_get(&(client_ptr -> nx_websocket_client_mutex), NX_WAIT_FOREVER);
1313
1314 /* Check if the CLOSE frame has already been received before */
1315 if (client_ptr -> nx_websocket_client_state == NX_WEBSOCKET_CLIENT_STATE_DISCONNECT_RECEIVED)
1316 {
1317 client_ptr -> nx_websocket_client_state = NX_WEBSOCKET_CLIENT_STATE_IDLE;
1318 }
1319 else /* i.e. The state is CONNECTED */
1320 {
1321 client_ptr -> nx_websocket_client_state = NX_WEBSOCKET_CLIENT_STATE_DISCONNECT_SENT;
1322 }
1323
1324 /* Release the mutex and return completion status */
1325 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
1326 return(status);
1327 }
1328
1329 /**************************************************************************/
1330 /* */
1331 /* FUNCTION RELEASE */
1332 /* */
1333 /* _nxe_websocket_client_send PORTABLE C */
1334 /* 6.2.0 */
1335 /* AUTHOR */
1336 /* */
1337 /* Bo Chen, Microsoft Corporation */
1338 /* */
1339 /* DESCRIPTION */
1340 /* */
1341 /* This function checks for errors in the WebSocket send. */
1342 /* */
1343 /* INPUT */
1344 /* */
1345 /* client_ptr Pointer to WebSocket Client */
1346 /* packet_ptr Pointer to packet */
1347 /* code Opcode: text or binary frame */
1348 /* is_final Flag: final fragment or not */
1349 /* wait_option Wait option */
1350 /* */
1351 /* OUTPUT */
1352 /* */
1353 /* status Completion status */
1354 /* */
1355 /* CALLS */
1356 /* */
1357 /* _nx_websocket_client_send Actual websocket send call */
1358 /* */
1359 /* CALLED BY */
1360 /* */
1361 /* Application Code */
1362 /* */
1363 /* RELEASE HISTORY */
1364 /* */
1365 /* DATE NAME DESCRIPTION */
1366 /* */
1367 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
1368 /* */
1369 /**************************************************************************/
_nxe_websocket_client_send(NX_WEBSOCKET_CLIENT * client_ptr,NX_PACKET * packet_ptr,UINT code,UINT is_final,UINT wait_option)1370 UINT _nxe_websocket_client_send(NX_WEBSOCKET_CLIENT *client_ptr, NX_PACKET *packet_ptr, UINT code, UINT is_final, UINT wait_option)
1371 {
1372
1373 UINT status;
1374
1375
1376 /* Check for invalid input pointers. */
1377 if ((client_ptr == NX_NULL) || (client_ptr -> nx_websocket_client_id != NX_WEBSOCKET_CLIENT_ID) ||
1378 (packet_ptr == NX_NULL))
1379 {
1380 return(NX_PTR_ERROR);
1381 }
1382
1383 /* Call actual send function. */
1384 status = _nx_websocket_client_send(client_ptr, packet_ptr, code, is_final, wait_option);
1385
1386 /* Return completion status. */
1387 return(status);
1388 }
1389
1390 /**************************************************************************/
1391 /* */
1392 /* FUNCTION RELEASE */
1393 /* */
1394 /* _nx_websocket_client_send PORTABLE C */
1395 /* 6.2.0 */
1396 /* AUTHOR */
1397 /* */
1398 /* Bo Chen, Microsoft Corporation */
1399 /* */
1400 /* DESCRIPTION */
1401 /* */
1402 /* This function sends Websocket data frame to server. */
1403 /* */
1404 /* INPUT */
1405 /* */
1406 /* client_ptr Pointer to WebSocket Client */
1407 /* packet_ptr Pointer to packet */
1408 /* code Opcode: text or binary frame */
1409 /* is_final Flag: final fragment or not */
1410 /* wait_option Wait option */
1411 /* */
1412 /* OUTPUT */
1413 /* */
1414 /* status Completion status */
1415 /* */
1416 /* CALLS */
1417 /* */
1418 /* _nx_websocket_client_packet_send Send websocket packet */
1419 /* */
1420 /* CALLED BY */
1421 /* */
1422 /* Application Code */
1423 /* */
1424 /* RELEASE HISTORY */
1425 /* */
1426 /* DATE NAME DESCRIPTION */
1427 /* */
1428 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
1429 /* */
1430 /**************************************************************************/
_nx_websocket_client_send(NX_WEBSOCKET_CLIENT * client_ptr,NX_PACKET * packet_ptr,UINT code,UINT is_final,UINT wait_option)1431 UINT _nx_websocket_client_send(NX_WEBSOCKET_CLIENT *client_ptr, NX_PACKET *packet_ptr, UINT code, UINT is_final, UINT wait_option)
1432 {
1433
1434 UINT status;
1435 UCHAR *data_ptr;
1436 NX_PACKET *data_packet;
1437 USHORT message;
1438 ULONG tmp;
1439 UCHAR masking_key[4];
1440 UINT mask_id = 0;
1441 UINT header_size = NX_WEBSOCKET_HEADER_NORMAL_SIZE;
1442
1443
1444 /* Obtain the mutex. */
1445 tx_mutex_get(&(client_ptr -> nx_websocket_client_mutex), NX_WAIT_FOREVER);
1446
1447 /* Check the state */
1448 if (client_ptr -> nx_websocket_client_state < NX_WEBSOCKET_CLIENT_STATE_CONNECTED)
1449 {
1450
1451 /* Release the mutex and return error status */
1452 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
1453 return(NX_WEBSOCKET_NOT_CONNECTED);
1454 }
1455 else if (client_ptr -> nx_websocket_client_state == NX_WEBSOCKET_CLIENT_STATE_DISCONNECT_SENT)
1456 {
1457
1458 /* Release the mutex and return error status */
1459 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
1460 return(NX_WEBSOCKET_INVALID_STATE);
1461 }
1462
1463 /* Check the payload length. */
1464 if (packet_ptr -> nx_packet_length > 65535)
1465 {
1466
1467 /* Release the mutex and return error status */
1468 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
1469 return(NX_NOT_SUPPORTED);
1470 }
1471 else if (packet_ptr -> nx_packet_length > 125)
1472 {
1473 header_size += 2;
1474 }
1475
1476 /* Check the packet. */
1477 if ((UINT)(packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < header_size)
1478 {
1479
1480 /* Release the mutex and return error status */
1481 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
1482 return(NX_WEBSOCKET_INVALID_PACKET);
1483 }
1484
1485 /* Adjust the pointer for filling the WebSocket header. */
1486 data_ptr = packet_ptr -> nx_packet_prepend_ptr - header_size;
1487
1488 /* Fill the first byte (FIN + OPCODE) in header. */
1489 if (is_final == NX_TRUE)
1490 {
1491 *data_ptr = (UCHAR)(NX_WEBSOCKET_FIN | code);
1492 }
1493 else
1494 {
1495 *data_ptr = (UCHAR)code;
1496 }
1497 data_ptr++;
1498
1499 /* Fill the next byte for MASK and Payload length. */
1500 *data_ptr = NX_WEBSOCKET_MASK;
1501 if (packet_ptr -> nx_packet_length < 125)
1502 {
1503 *data_ptr |= (UCHAR)packet_ptr -> nx_packet_length;
1504 data_ptr++;
1505 }
1506 else
1507 {
1508 *data_ptr |= NX_WEBSOCKET_PAYLOAD_LEN_16BITS;
1509 data_ptr++;
1510
1511 /* Fill the next two bytes for extended payload length. */
1512 message = (USHORT)packet_ptr -> nx_packet_length;
1513 NX_CHANGE_USHORT_ENDIAN(message);
1514 memcpy(data_ptr, &message, NX_WEBSOCKET_EXTENDED_PAYLOAD_16BITS_SIZE); /* Use case of memcpy is verified. */
1515 data_ptr += NX_WEBSOCKET_EXTENDED_PAYLOAD_16BITS_SIZE;
1516 }
1517
1518 /* Fill the masking key, the masking key is a 32-bit value chosen at random, must mask websocket data from client*/
1519 tmp = (ULONG)NX_RAND();
1520 masking_key[0] = (UCHAR)(tmp >> 24);
1521 masking_key[1] = (UCHAR)(tmp >> 16);
1522 masking_key[2] = (UCHAR)(tmp >> 8);
1523 masking_key[3] = (UCHAR)(tmp);
1524 memcpy(data_ptr, &masking_key, NX_WEBSOCKET_MASKING_KEY_SIZE); /* Use case of memcpy is verified. */
1525 data_ptr += NX_WEBSOCKET_MASKING_KEY_SIZE;
1526
1527 /* Mask all payload data. */
1528 data_packet = packet_ptr;
1529 #ifndef NX_DISABLE_PACKET_CHAIN
1530 while(data_packet)
1531 {
1532 #endif /* NX_DISABLE_PACKET_CHAIN */
1533
1534 data_ptr = data_packet -> nx_packet_prepend_ptr;
1535 while(data_ptr < data_packet -> nx_packet_append_ptr)
1536 {
1537 *data_ptr ^= masking_key[mask_id % 4];
1538 mask_id++;
1539 data_ptr++;
1540 }
1541
1542 #ifndef NX_DISABLE_PACKET_CHAIN
1543 data_packet = data_packet -> nx_packet_next;
1544 }
1545 #endif /* NX_DISABLE_PACKET_CHAIN */
1546
1547 /* Update prepend pointer and packet length to include WebSocket header. */
1548 packet_ptr -> nx_packet_prepend_ptr -= header_size;
1549 packet_ptr -> nx_packet_length += header_size;
1550
1551 /* Release the mutex */
1552 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
1553
1554 /* Send out the packet. */
1555 status = _nx_websocket_client_packet_send(client_ptr, packet_ptr, wait_option);
1556
1557 return(status);
1558 }
1559
1560 /**************************************************************************/
1561 /* */
1562 /* FUNCTION RELEASE */
1563 /* */
1564 /* _nxe_websocket_client_receive PORTABLE C */
1565 /* 6.2.0 */
1566 /* AUTHOR */
1567 /* */
1568 /* Bo Chen, Microsoft Corporation */
1569 /* */
1570 /* DESCRIPTION */
1571 /* */
1572 /* This function checks for errors in the WebSocket receive. */
1573 /* */
1574 /* INPUT */
1575 /* */
1576 /* client_ptr Pointer to WebSocket Client */
1577 /* packet_ptr Pointer to packet pointer */
1578 /* code Opcode: text or binary frame */
1579 /* wait_option Wait option */
1580 /* */
1581 /* OUTPUT */
1582 /* */
1583 /* status Completion status */
1584 /* */
1585 /* CALLS */
1586 /* */
1587 /* _nx_websocket_client_receive Actual websocket receive call */
1588 /* */
1589 /* CALLED BY */
1590 /* */
1591 /* Application Code */
1592 /* */
1593 /* RELEASE HISTORY */
1594 /* */
1595 /* DATE NAME DESCRIPTION */
1596 /* */
1597 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
1598 /* */
1599 /**************************************************************************/
_nxe_websocket_client_receive(NX_WEBSOCKET_CLIENT * client_ptr,NX_PACKET ** packet_ptr,UINT * code,UINT wait_option)1600 UINT _nxe_websocket_client_receive(NX_WEBSOCKET_CLIENT *client_ptr, NX_PACKET **packet_ptr, UINT *code, UINT wait_option)
1601 {
1602
1603 UINT status;
1604
1605
1606 /* Check for invalid input pointers. */
1607 if ((client_ptr == NX_NULL) || (client_ptr -> nx_websocket_client_id != NX_WEBSOCKET_CLIENT_ID) ||
1608 (packet_ptr == NX_NULL) || (code == NX_NULL))
1609 {
1610 return(NX_PTR_ERROR);
1611 }
1612
1613 /* Call actual process function. */
1614 status = _nx_websocket_client_receive(client_ptr, packet_ptr, code, wait_option);
1615
1616 /* Return completion status. */
1617 return(status);
1618 }
1619
1620 /**************************************************************************/
1621 /* */
1622 /* FUNCTION RELEASE */
1623 /* */
1624 /* _nx_websocket_client_receive PORTABLE C */
1625 /* 6.2.0 */
1626 /* AUTHOR */
1627 /* */
1628 /* Bo Chen, Microsoft Corporation */
1629 /* */
1630 /* DESCRIPTION */
1631 /* */
1632 /* This function receives Websocket data frame from server. */
1633 /* */
1634 /* INPUT */
1635 /* */
1636 /* client_ptr Pointer to WebSocket Client */
1637 /* packet_ptr Pointer to packet pointer */
1638 /* code Opcode: text or binary frame */
1639 /* wait_option Wait option */
1640 /* */
1641 /* OUTPUT */
1642 /* */
1643 /* status Completion status */
1644 /* */
1645 /* CALLS */
1646 /* */
1647 /* _nx_websocket_client_packet_receive Receive websocket packet */
1648 /* _nx_websocket_client_data_process Process data frame */
1649 /* _nx_websocket_client_connect_response_check */
1650 /* Check connect response */
1651 /* */
1652 /* CALLED BY */
1653 /* */
1654 /* Application Code */
1655 /* */
1656 /* RELEASE HISTORY */
1657 /* */
1658 /* DATE NAME DESCRIPTION */
1659 /* */
1660 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
1661 /* */
1662 /**************************************************************************/
_nx_websocket_client_receive(NX_WEBSOCKET_CLIENT * client_ptr,NX_PACKET ** packet_ptr,UINT * code,UINT wait_option)1663 UINT _nx_websocket_client_receive(NX_WEBSOCKET_CLIENT *client_ptr, NX_PACKET **packet_ptr, UINT *code, UINT wait_option)
1664 {
1665
1666 UINT status = NX_SUCCESS;
1667
1668
1669 /* Initialize here since packet_ptr will be compared with NX_NULL in following function */
1670 *packet_ptr = NX_NULL;
1671
1672 /* Obtain the mutex. */
1673 tx_mutex_get(&(client_ptr -> nx_websocket_client_mutex), NX_WAIT_FOREVER);
1674
1675 while (1) /* The while loop ensures parsing all received packets. */
1676 {
1677
1678 /* Check the state */
1679 if ((client_ptr -> nx_websocket_client_state < NX_WEBSOCKET_CLIENT_STATE_CONNECTING) ||
1680 (client_ptr -> nx_websocket_client_state == NX_WEBSOCKET_CLIENT_STATE_DISCONNECT_RECEIVED))
1681 {
1682
1683 /* Release the mutex and return error status */
1684 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
1685 return(NX_WEBSOCKET_INVALID_STATE);
1686 }
1687
1688 /* If the state is NX_WEBSOCKET_CLIENT_STATE_CONNECTING, the received packet should be connect response. */
1689 if (client_ptr -> nx_websocket_client_state == NX_WEBSOCKET_CLIENT_STATE_CONNECTING)
1690 {
1691
1692 /* Receive the data packet */
1693 status = _nx_websocket_client_packet_receive(client_ptr, packet_ptr, wait_option);
1694 if (status != NX_SUCCESS)
1695 {
1696
1697 /* Release the mutex and return status */
1698 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
1699 return(status);
1700 }
1701
1702 /* Process the connect response. */
1703 status = _nx_websocket_client_connect_response_check(client_ptr, *packet_ptr, wait_option);
1704
1705 if ((status == NX_SUCCESS) || (status == NX_IN_PROGRESS))
1706 {
1707
1708 /* Continue to receive remaining connect response or application data. */
1709 continue;
1710 }
1711 else
1712 {
1713
1714 /* Release the mutex and return status */
1715 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
1716 return(status);
1717 }
1718 }
1719 else
1720 {
1721
1722 /* Check if there is an existing complete frame in the waiting list */
1723 if ((status == NX_SUCCESS) && (client_ptr -> nx_websocket_client_processing_packet != NX_NULL))
1724 {
1725
1726 /* Parse the data packet. */
1727 status = _nx_websocket_client_data_process(client_ptr, packet_ptr, code);
1728 if (status != NX_CONTINUE)
1729 {
1730
1731 /* Release the mutex and return directly if a complete frame is parsed or any error status is found. */
1732 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
1733 return(status);
1734 }
1735 }
1736
1737 /* No existing frame, go to receive the data packet */
1738 status = _nx_websocket_client_packet_receive(client_ptr, packet_ptr, wait_option);
1739 if (status != NX_SUCCESS)
1740 {
1741
1742 /* Release the mutex and return status */
1743 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
1744 return(status);
1745 }
1746
1747 /* Parse with the new data packet. */
1748 status = _nx_websocket_client_data_process(client_ptr, packet_ptr, code);
1749 if (status != NX_CONTINUE)
1750 {
1751
1752 /* Release the mutex and return directly if a complete frame is parsed or any error status is found. */
1753 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
1754 return(status);
1755 }
1756
1757 /* Due to no application data found, continue to check if there is any pending data packet. */
1758 }
1759 }
1760 }
1761
1762 /**************************************************************************/
1763 /* */
1764 /* FUNCTION RELEASE */
1765 /* */
1766 /* _nx_websocket_client_data_process PORTABLE C */
1767 /* 6.2.0 */
1768 /* AUTHOR */
1769 /* */
1770 /* Bo Chen, Microsoft Corporation */
1771 /* */
1772 /* DESCRIPTION */
1773 /* */
1774 /* This function processes Websocket data frame from server. */
1775 /* */
1776 /* INPUT */
1777 /* */
1778 /* client_ptr Pointer to WebSocket Client */
1779 /* packet_ptr Pointer to packet pointer */
1780 /* code Opcode: text or binary frame */
1781 /* */
1782 /* OUTPUT */
1783 /* */
1784 /* status Completion status */
1785 /* */
1786 /* CALLS */
1787 /* */
1788 /* nx_packet_data_extract_offset Extract data from packet */
1789 /* nx_packet_allocate Allocate a packet */
1790 /* _nx_websocket_client_packet_trim Trim data from packet */
1791 /* _nx_websocket_client_cleanup Cleanup resource */
1792 /* */
1793 /* CALLED BY */
1794 /* */
1795 /* _nx_websocket_client_receive Receive websocket data */
1796 /* */
1797 /* RELEASE HISTORY */
1798 /* */
1799 /* DATE NAME DESCRIPTION */
1800 /* */
1801 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
1802 /* */
1803 /**************************************************************************/
_nx_websocket_client_data_process(NX_WEBSOCKET_CLIENT * client_ptr,NX_PACKET ** packet_ptr,UINT * code)1804 UINT _nx_websocket_client_data_process(NX_WEBSOCKET_CLIENT *client_ptr, NX_PACKET **packet_ptr, UINT *code)
1805 {
1806 UINT status;
1807 UCHAR fin_bit = NX_FALSE;
1808 UCHAR opcode = 0;
1809 UCHAR bytes[4];
1810 ULONG payload_length;
1811 ULONG offset = 0;
1812 ULONG bytes_copied;
1813 ULONG packet_length;
1814 NX_PACKET *data_packet;
1815 UCHAR *data_ptr;
1816
1817
1818 /* Is there a packet waiting for processing? */
1819 if (client_ptr -> nx_websocket_client_processing_packet)
1820 {
1821 if (*packet_ptr != NX_NULL)
1822 {
1823
1824 /* Yes. Link received packet to existing one. */
1825 if (client_ptr -> nx_websocket_client_processing_packet -> nx_packet_last)
1826 {
1827 client_ptr -> nx_websocket_client_processing_packet -> nx_packet_last -> nx_packet_next = *packet_ptr;
1828 }
1829 else
1830 {
1831 client_ptr -> nx_websocket_client_processing_packet -> nx_packet_next = *packet_ptr;
1832 }
1833 if ((*packet_ptr) -> nx_packet_last)
1834 {
1835 client_ptr -> nx_websocket_client_processing_packet -> nx_packet_last = (*packet_ptr) -> nx_packet_last;
1836 }
1837 else
1838 {
1839 client_ptr -> nx_websocket_client_processing_packet -> nx_packet_last = *packet_ptr;
1840 }
1841 client_ptr -> nx_websocket_client_processing_packet -> nx_packet_length += (*packet_ptr) -> nx_packet_length;
1842 }
1843
1844 /* Make packet_ptr point to the waiting list */
1845 *packet_ptr = client_ptr -> nx_websocket_client_processing_packet;
1846 }
1847 else
1848 {
1849 if (*packet_ptr == NX_NULL)
1850 {
1851 return(NX_WEBSOCKET_INVALID_PACKET);
1852 }
1853
1854 client_ptr -> nx_websocket_client_processing_packet = *packet_ptr;
1855 }
1856
1857 /* Check if the websocket frame header shall be parsed and found first */
1858 if (client_ptr -> nx_websocket_client_frame_header_found == NX_FALSE)
1859 {
1860
1861 /* Parse the first 2 bytes. */
1862 if (nx_packet_data_extract_offset(*packet_ptr, offset, bytes, NX_WEBSOCKET_HEADER_MINIMUM_LENGTH, &bytes_copied)
1863 || (bytes_copied < NX_WEBSOCKET_HEADER_MINIMUM_LENGTH))
1864 {
1865 return(NX_CONTINUE);
1866 }
1867
1868 /* Update the offset */
1869 offset += NX_WEBSOCKET_HEADER_MINIMUM_LENGTH;
1870
1871 /* Obtain the fin bit and opcode */
1872 fin_bit = bytes[0] & NX_WEBSOCKET_FIN_MASK;
1873 opcode = bytes[0] & NX_WEBSOCKET_OPCODE_MASK;
1874
1875 /* Parse the mask bit and payload length */
1876 if (bytes[1] & NX_WEBSOCKET_MASK)
1877 {
1878 client_ptr -> nx_websocket_client_frame_masked = NX_TRUE;
1879 }
1880 else
1881 {
1882 client_ptr -> nx_websocket_client_frame_masked = NX_FALSE;
1883 }
1884
1885 payload_length = (UCHAR)(bytes[1] & NX_WEBSOCKET_PAYLOAD_LEN_MASK);
1886 if (payload_length < 126)
1887 {
1888
1889 /* No extend payload length; record data payload length directly. */
1890 }
1891 else if (payload_length == 126)
1892 {
1893
1894 /* Extract the 16-bit extended data payload length */
1895 if (nx_packet_data_extract_offset(*packet_ptr, offset, bytes, NX_WEBSOCKET_EXTENDED_PAYLOAD_16BITS_SIZE, &bytes_copied)
1896 || (bytes_copied < NX_WEBSOCKET_EXTENDED_PAYLOAD_16BITS_SIZE))
1897 {
1898 return(NX_CONTINUE);
1899 }
1900
1901 /* Record 16-bit data payload length. */
1902 payload_length = ((((ULONG)bytes[0]) << 8) + (ULONG)bytes[1]);
1903
1904 /* Add the byte count by the payload size */
1905 offset += NX_WEBSOCKET_EXTENDED_PAYLOAD_16BITS_SIZE;
1906 }
1907 else
1908 {
1909
1910 /* Since 64 bits extend payload length is not supported, clean up and return directly. */
1911 _nx_websocket_client_cleanup(client_ptr);
1912 return(NX_NOT_SUPPORTED);
1913 }
1914
1915 /* Parse the masking key */
1916 if (client_ptr -> nx_websocket_client_frame_masked == NX_TRUE)
1917 {
1918 if (nx_packet_data_extract_offset(*packet_ptr, offset, bytes, NX_WEBSOCKET_MASKING_KEY_SIZE, &bytes_copied)
1919 || (bytes_copied < NX_WEBSOCKET_MASKING_KEY_SIZE))
1920 {
1921 return(NX_CONTINUE);
1922 }
1923
1924 /* Get the masking key. */
1925 memcpy(client_ptr -> nx_websocket_client_frame_masking_key, bytes, NX_WEBSOCKET_MASKING_KEY_SIZE); /* Use case of memcpy is verified. */
1926
1927 /* Add the byte count by the masking key size */
1928 offset += NX_WEBSOCKET_MASKING_KEY_SIZE;
1929 }
1930
1931 /* Set the flag to indicate the frame header found, and re-initialize corresponding variables */
1932 client_ptr -> nx_websocket_client_frame_header_found = NX_TRUE;
1933 client_ptr -> nx_websocket_client_frame_data_received = 0;
1934
1935 /* Record the payload length for judging if all payload data received */
1936 client_ptr -> nx_websocket_client_frame_data_length = payload_length;
1937
1938 /* Check the rules apply to fragmentation corresponding to the FIN bit and opcode
1939 RFC 6455, Section 5.4, Page 33-35 */
1940 if (fin_bit == NX_WEBSOCKET_FIN) /* This is the final frame (tip: the first frame may also be the final frame) */
1941 {
1942 if (client_ptr -> nx_websocket_client_frame_fragmented == NX_FALSE) /* A single unfragmented frame shall be received */
1943 {
1944 if (opcode == 0) /* The opcode should not denotes a continuation frame for a single unfragmented frame */
1945 {
1946 _nx_websocket_client_cleanup(client_ptr);
1947 return(NX_INVALID_PACKET);
1948 }
1949
1950 /* Update the header opcode */
1951 client_ptr -> nx_websocket_client_frame_opcode = opcode;
1952 }
1953 else /* This is the termination frame in overall fragmented frames */
1954 {
1955 if (opcode != 0) /* The opcode of the termination frame shall be zero */
1956 {
1957 _nx_websocket_client_cleanup(client_ptr);
1958 return(NX_INVALID_PACKET);
1959 }
1960
1961 /* Set the header flag to be unfragmented for next time to use */
1962 client_ptr -> nx_websocket_client_frame_fragmented = NX_FALSE;
1963 }
1964 }
1965 else /* This is not the final header */
1966 {
1967 if (client_ptr -> nx_websocket_client_frame_fragmented == NX_FALSE) /* This is the beginning frame in fragmented frames */
1968 {
1969
1970 /* The opcode of the beginning frame shall indicate the opcode of overall fragmented frames. Besides,
1971 since control frames cannot be fragmented, the supported frame type shall be text or binary */
1972 if ((opcode != NX_WEBSOCKET_OPCODE_BINARY_FRAME) && (opcode != NX_WEBSOCKET_OPCODE_TEXT_FRAME))
1973 {
1974 _nx_websocket_client_cleanup(client_ptr);
1975 return(NX_INVALID_PACKET);
1976 }
1977
1978 /* Update the frame fragmented flag and the opcode since a beginning frame is received */
1979 client_ptr -> nx_websocket_client_frame_fragmented = NX_TRUE;
1980 client_ptr -> nx_websocket_client_frame_opcode = opcode;
1981 }
1982 else /* This is a continuation frame in overall fragmented frames */
1983 {
1984 if (opcode != 0) /* The opcode of a continuation frame shall be zero */
1985 {
1986 _nx_websocket_client_cleanup(client_ptr);
1987 return(NX_INVALID_PACKET);
1988 }
1989 }
1990 }
1991
1992 /* Trim the WebSocket header */
1993 status = _nx_websocket_client_packet_trim(client_ptr, packet_ptr, offset);
1994 client_ptr -> nx_websocket_client_processing_packet = *packet_ptr;
1995 if (status)
1996 {
1997 if (status == NX_NO_PACKET)
1998 {
1999
2000 /* Try to receive more payload data from TCP/TLS if the packet holds the WebSocket header only */
2001 return(NX_CONTINUE);
2002 }
2003
2004 /* Return error status */
2005 return(status);
2006 }
2007 }
2008
2009 /* Reset payload length and use the variable to count the data length processed by the function call this time */
2010 payload_length = 0;
2011
2012 /* Unmask payload data if there is masking key. */
2013 if (client_ptr -> nx_websocket_client_frame_masked == NX_TRUE)
2014 {
2015 data_packet = (*packet_ptr);
2016 #ifndef NX_DISABLE_PACKET_CHAIN
2017 while (data_packet && client_ptr -> nx_websocket_client_frame_header_found)
2018 {
2019 #endif /* NX_DISABLE_PACKET_CHAIN */
2020
2021 data_ptr = (*packet_ptr) -> nx_packet_prepend_ptr;
2022 while (data_ptr < data_packet -> nx_packet_append_ptr)
2023 {
2024
2025 /* Unmask payload data byte by byte */
2026 *data_ptr ^= client_ptr -> nx_websocket_client_frame_masking_key[client_ptr -> nx_websocket_client_frame_data_received % 4];
2027 data_ptr++;
2028
2029 /* Increase the payload length for the usage in frame process */
2030 payload_length++;
2031
2032 /* Check and jump out if all data payload in the frame have been processed. */
2033 client_ptr -> nx_websocket_client_frame_data_received++;
2034 if (client_ptr -> nx_websocket_client_frame_data_received >= client_ptr -> nx_websocket_client_frame_data_length)
2035 {
2036
2037 /* Reset the frame header flag as not found and break. */
2038 client_ptr -> nx_websocket_client_frame_header_found = NX_FALSE;
2039 break;
2040 }
2041 }
2042
2043 #ifndef NX_DISABLE_PACKET_CHAIN
2044 data_packet = data_packet -> nx_packet_next;
2045 }
2046 #endif /* NX_DISABLE_PACKET_CHAIN */
2047 }
2048
2049 /* Add the payload length if no masking key */
2050 else
2051 {
2052
2053 /* Check and adjust received data length for processing */
2054 payload_length = (*packet_ptr) -> nx_packet_length;
2055 if (payload_length >= (client_ptr -> nx_websocket_client_frame_data_length - client_ptr -> nx_websocket_client_frame_data_received))
2056 {
2057
2058 /* The maximum the payload length for each frame process shall not exceed the remaining frame data to be received */
2059 payload_length = (client_ptr -> nx_websocket_client_frame_data_length - client_ptr -> nx_websocket_client_frame_data_received);
2060
2061 /* Reset the frame header flag as not found. */
2062 client_ptr -> nx_websocket_client_frame_header_found = NX_FALSE;
2063 }
2064
2065 /* Add the length to the total count */
2066 client_ptr -> nx_websocket_client_frame_data_received += payload_length;
2067 }
2068
2069 /* Check the opcode for the received frame, and return corresponding status. */
2070 switch (opcode)
2071 {
2072 case NX_WEBSOCKET_OPCODE_CONTINUATION_FRAME:
2073 case NX_WEBSOCKET_OPCODE_TEXT_FRAME:
2074 case NX_WEBSOCKET_OPCODE_BINARY_FRAME:
2075 {
2076
2077 /* Assign the return opcode by the pre-stored opcode */
2078 *code = client_ptr -> nx_websocket_client_frame_opcode;
2079
2080 /* Update the offset by payload length */
2081 offset = payload_length;
2082
2083 /* For a data frame (i.e. text/binary frame), search and find the end of the complete frame */
2084 data_packet = *packet_ptr;
2085 packet_length = (ULONG)(data_packet -> nx_packet_append_ptr - data_packet -> nx_packet_prepend_ptr);
2086 while (packet_length < offset)
2087 {
2088 offset -= packet_length;
2089
2090 /* Move the current data packet pointer to next and compute the length of next packet */
2091 data_packet = data_packet -> nx_packet_next;
2092 packet_length = (ULONG)(data_packet -> nx_packet_append_ptr - data_packet -> nx_packet_prepend_ptr);
2093 }
2094
2095 /* After subtracting by the offset, packet_length represents the size of remaining data in the single packet to be linked into the waiting list */
2096 packet_length -= offset;
2097
2098 /* Check if the frame end is just in the end of one of the packet(s) */
2099 if (packet_length == 0)
2100 {
2101
2102 /* Put remaining packet(s) into the waiting list */
2103 client_ptr -> nx_websocket_client_processing_packet = data_packet -> nx_packet_next;
2104
2105 /* Check if there is data remaining and determine whether to go on to following logic. */
2106 if (data_packet -> nx_packet_next == NX_NULL)
2107 {
2108
2109 /* The packet is fully parsed, return success directly. */
2110 return(NX_WEBSOCKET_SUCCESS);
2111 }
2112 }
2113 else /* One more frame in the packet */
2114 {
2115
2116 /* Release the mutex. */
2117 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
2118
2119 /* Allocate a packet for the remaining data in the packet. */
2120 status = nx_packet_allocate((*packet_ptr) -> nx_packet_pool_owner, &client_ptr -> nx_websocket_client_processing_packet, NX_RECEIVE_PACKET, NX_WAIT_FOREVER);
2121
2122 /* The return status may be not NX_SUCCESS only there is an unexpected issue from the packet pool (e.g. a delete operation ).
2123 Assert here for the unexpected issue shall not happen in normal status */
2124 NX_ASSERT(status == NX_SUCCESS);
2125
2126 /* Obtain the mutex again. */
2127 tx_mutex_get(&(client_ptr -> nx_websocket_client_mutex), NX_WAIT_FOREVER);
2128
2129 /* Copy the contents of the remaining part of current packet into the new allocated packet */
2130 memcpy((void *)client_ptr -> nx_websocket_client_processing_packet -> nx_packet_prepend_ptr,
2131 (void *)(data_packet -> nx_packet_prepend_ptr + offset), packet_length); /* Use case of memcpy is verified. */
2132
2133 /* Move the append pointer with by the extended length */
2134 client_ptr -> nx_websocket_client_processing_packet -> nx_packet_append_ptr += packet_length;
2135
2136 /* Link the possibly had remaining packet(s) to the waiting list. The overall packet length will be updated outside this else branch */
2137 client_ptr -> nx_websocket_client_processing_packet -> nx_packet_next = data_packet -> nx_packet_next;
2138 }
2139
2140 /* Update the last packet pointer in the waiting liast */
2141 if (client_ptr -> nx_websocket_client_processing_packet -> nx_packet_next)
2142 {
2143 client_ptr -> nx_websocket_client_processing_packet -> nx_packet_last = (*packet_ptr) -> nx_packet_last;
2144 }
2145 else
2146 {
2147 client_ptr -> nx_websocket_client_processing_packet -> nx_packet_last = NX_NULL;
2148 }
2149
2150 /* Update the overall packet length for the waiting list */
2151 client_ptr -> nx_websocket_client_processing_packet -> nx_packet_length = (*packet_ptr) -> nx_packet_length - payload_length;
2152
2153 /* Disconnect the link between the return packet and the waiting list */
2154 data_packet -> nx_packet_next = NX_NULL;
2155 data_packet -> nx_packet_append_ptr -= packet_length;
2156 (*packet_ptr) -> nx_packet_length = payload_length;
2157
2158 /* Update the last packet pointer of the returned packet */
2159 if ((*packet_ptr) -> nx_packet_next)
2160 {
2161 (*packet_ptr) -> nx_packet_last = data_packet;
2162 }
2163 else
2164 {
2165 (*packet_ptr) -> nx_packet_last = NX_NULL;
2166 }
2167
2168 /* Return success status */
2169 return(NX_WEBSOCKET_SUCCESS);
2170 }
2171
2172 case NX_WEBSOCKET_OPCODE_CONNECTION_CLOSE:
2173 {
2174 /* Make sure the complete control frame is received */
2175 if (client_ptr -> nx_websocket_client_frame_data_received < client_ptr -> nx_websocket_client_frame_data_length)
2176 {
2177 return(NX_CONTINUE);
2178 }
2179
2180 /* A disconnection is informed, notify the application. */
2181 if (client_ptr -> nx_websocket_client_connection_status_callback)
2182 {
2183 client_ptr -> nx_websocket_client_connection_status_callback(client_ptr, client_ptr -> nx_websocket_client_connection_context, NX_WEBSOCKET_DISCONNECTED);
2184 }
2185
2186 /* Check the current state and update the state when the CLOSE frame is found */
2187 if (client_ptr -> nx_websocket_client_state == NX_WEBSOCKET_CLIENT_STATE_DISCONNECT_SENT)
2188 {
2189 client_ptr -> nx_websocket_client_state = NX_WEBSOCKET_CLIENT_STATE_IDLE;
2190 }
2191 else
2192 {
2193 client_ptr -> nx_websocket_client_state = NX_WEBSOCKET_CLIENT_STATE_DISCONNECT_RECEIVED;
2194 }
2195
2196 /* Return disconnect received status only, without returning any packet data, since it is required no more data after the Close frame.
2197 There is no need to release the packet_ptr since it points to the same memory region as the waiting list
2198 Referenced in RFC 6455, Section 5.5.1, Page 36 */
2199 _nx_websocket_client_cleanup(client_ptr);
2200 return(NX_WEBSOCKET_DISCONNECTED);
2201 }
2202
2203 case NX_WEBSOCKET_OPCODE_PING:
2204 case NX_WEBSOCKET_OPCODE_PONG:
2205 {
2206
2207 /* Make sure the complete control frame is received */
2208 if (client_ptr -> nx_websocket_client_frame_data_received < client_ptr -> nx_websocket_client_frame_data_length)
2209 {
2210 return(NX_CONTINUE);
2211 }
2212
2213 /* Trim payload data in the frame. */
2214 status = _nx_websocket_client_packet_trim(client_ptr, packet_ptr, client_ptr -> nx_websocket_client_frame_data_received);
2215
2216 /* Update the waiting list */
2217 client_ptr -> nx_websocket_client_processing_packet = *packet_ptr;
2218
2219 /* Check if error status happens */
2220 if ((status != NX_WEBSOCKET_SUCCESS) && (status != NX_NO_PACKET))
2221 {
2222 return(status);
2223 }
2224
2225 /* A PING/PONG frame is parsed and found, continue to check any more data or frame received */
2226 return(NX_CONTINUE);
2227 }
2228
2229 default:
2230 {
2231
2232 /* Clean up and return invalid status */
2233 _nx_websocket_client_cleanup(client_ptr);
2234 return(NX_INVALID_PACKET);
2235 }
2236 }
2237 }
2238
2239 /**************************************************************************/
2240 /* */
2241 /* FUNCTION RELEASE */
2242 /* */
2243 /* _nx_websocket_client_packet_trim PORTABLE C */
2244 /* 6.2.0 */
2245 /* AUTHOR */
2246 /* */
2247 /* Bo Chen, Microsoft Corporation */
2248 /* */
2249 /* DESCRIPTION */
2250 /* */
2251 /* This function trims extra bytes from the data packet. */
2252 /* */
2253 /* INPUT */
2254 /* */
2255 /* client_ptr Pointer to WebSocket Client */
2256 /* packet_ptr Pointer to packet pointer */
2257 /* trim_size Number of bytes to remove */
2258 /* */
2259 /* OUTPUT */
2260 /* */
2261 /* status Completion status */
2262 /* */
2263 /* CALLS */
2264 /* */
2265 /* nx_packet_release Release the packet */
2266 /* */
2267 /* CALLED BY */
2268 /* */
2269 /* _nx_websocket_client_data_process Process data frame */
2270 /* */
2271 /* RELEASE HISTORY */
2272 /* */
2273 /* DATE NAME DESCRIPTION */
2274 /* */
2275 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
2276 /* */
2277 /**************************************************************************/
_nx_websocket_client_packet_trim(NX_WEBSOCKET_CLIENT * client_ptr,NX_PACKET ** packet_ptr,ULONG trim_size)2278 UINT _nx_websocket_client_packet_trim(NX_WEBSOCKET_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG trim_size)
2279 {
2280
2281 ULONG packet_length;
2282 NX_PACKET *head_packet_ptr = *packet_ptr;
2283 NX_PACKET *previous_packet_ptr = NX_NULL;
2284
2285 NX_PARAMETER_NOT_USED(client_ptr);
2286
2287 /* The trim size shall be less than or equal to the packet length */
2288 if ((*packet_ptr) -> nx_packet_length < trim_size)
2289 {
2290 return(NX_PACKET_OFFSET_ERROR);
2291 }
2292 packet_length = (*packet_ptr) -> nx_packet_length - trim_size;
2293
2294 /* Search and find the trim point */
2295 while ((ULONG)((*packet_ptr) -> nx_packet_append_ptr - (*packet_ptr) -> nx_packet_prepend_ptr) <= trim_size)
2296 {
2297 trim_size -= (ULONG)((*packet_ptr) -> nx_packet_append_ptr - (*packet_ptr) -> nx_packet_prepend_ptr);
2298
2299 previous_packet_ptr = *packet_ptr;
2300 *packet_ptr = (*packet_ptr) -> nx_packet_next;
2301
2302 if (*packet_ptr == NX_NULL)
2303 {
2304 break;
2305 }
2306 }
2307
2308 /* Disconnect the link if the trim point is not in the head packet */
2309 if (previous_packet_ptr != NX_NULL)
2310 {
2311 previous_packet_ptr -> nx_packet_next = NX_NULL;
2312
2313 /* Set the nx_packet_last pointer due to the packet header changed */
2314 if (*packet_ptr)
2315 {
2316 (*packet_ptr) -> nx_packet_last = head_packet_ptr -> nx_packet_last;
2317 }
2318
2319 nx_packet_release(head_packet_ptr);
2320 }
2321
2322 if (*packet_ptr)
2323 {
2324
2325 /* Adjust current packet */
2326 (*packet_ptr) -> nx_packet_prepend_ptr += trim_size;
2327 (*packet_ptr) -> nx_packet_length = packet_length;
2328
2329 return(NX_WEBSOCKET_SUCCESS);
2330 }
2331
2332 /* Return this value to tell the caller that the whole packet is trimmed */
2333 return(NX_NO_PACKET);
2334 }
2335
2336 /**************************************************************************/
2337 /* */
2338 /* FUNCTION RELEASE */
2339 /* */
2340 /* _nxe_websocket_client_packet_allocate PORTABLE C */
2341 /* 6.2.0 */
2342 /* AUTHOR */
2343 /* */
2344 /* Bo Chen, Microsoft Corporation */
2345 /* */
2346 /* DESCRIPTION */
2347 /* */
2348 /* This function checks for errors in the WebSocket packet allocate. */
2349 /* */
2350 /* INPUT */
2351 /* */
2352 /* client_ptr Pointer to WebSocket Client */
2353 /* packet_ptr Pointer to packet pointer */
2354 /* wait_option Wait option */
2355 /* */
2356 /* OUTPUT */
2357 /* */
2358 /* status Completion status */
2359 /* */
2360 /* CALLS */
2361 /* */
2362 /* _nx_websocket_client_packet_allocate Actual websocket allocate call*/
2363 /* */
2364 /* CALLED BY */
2365 /* */
2366 /* Application Code */
2367 /* */
2368 /* RELEASE HISTORY */
2369 /* */
2370 /* DATE NAME DESCRIPTION */
2371 /* */
2372 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
2373 /* */
2374 /**************************************************************************/
_nxe_websocket_client_packet_allocate(NX_WEBSOCKET_CLIENT * client_ptr,NX_PACKET ** packet_ptr,ULONG wait_option)2375 UINT _nxe_websocket_client_packet_allocate(NX_WEBSOCKET_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option)
2376 {
2377
2378 UINT status;
2379
2380
2381 /* Check for invalid input pointers */
2382 if ((client_ptr == NX_NULL) || (client_ptr -> nx_websocket_client_id != NX_WEBSOCKET_CLIENT_ID) || (packet_ptr == NX_NULL))
2383 {
2384 return(NX_PTR_ERROR);
2385 }
2386
2387 /* Call actual process function. */
2388 status = _nx_websocket_client_packet_allocate(client_ptr, packet_ptr, wait_option);
2389
2390 /* Return completion status. */
2391 return(status);
2392 }
2393
2394 /**************************************************************************/
2395 /* */
2396 /* FUNCTION RELEASE */
2397 /* */
2398 /* _nx_websocket_client_packet_allocate PORTABLE C */
2399 /* 6.2.0 */
2400 /* AUTHOR */
2401 /* */
2402 /* Bo Chen, Microsoft Corporation */
2403 /* */
2404 /* DESCRIPTION */
2405 /* */
2406 /* This function allocates a Websocket packet. */
2407 /* */
2408 /* INPUT */
2409 /* */
2410 /* client_ptr Pointer to WebSocket Client */
2411 /* packet_ptr Pointer to packet pointer */
2412 /* wait_option Wait option */
2413 /* */
2414 /* OUTPUT */
2415 /* */
2416 /* status Completion status */
2417 /* */
2418 /* CALLS */
2419 /* */
2420 /* nx_packet_allocate Allocate a packet */
2421 /* nx_packet_release Release packet */
2422 /* nx_secure_tls_packet_allocate Allocate a TLS packet */
2423 /* */
2424 /* CALLED BY */
2425 /* */
2426 /* Application Code */
2427 /* */
2428 /* RELEASE HISTORY */
2429 /* */
2430 /* DATE NAME DESCRIPTION */
2431 /* */
2432 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
2433 /* */
2434 /**************************************************************************/
_nx_websocket_client_packet_allocate(NX_WEBSOCKET_CLIENT * client_ptr,NX_PACKET ** packet_ptr,ULONG wait_option)2435 UINT _nx_websocket_client_packet_allocate(NX_WEBSOCKET_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option)
2436 {
2437
2438 UINT status;
2439
2440
2441 #ifdef NX_SECURE_ENABLE
2442 if (client_ptr -> nx_websocket_client_use_tls)
2443 {
2444
2445 /* Use TLS packet allocate. The TLS packet allocate is able to count for
2446 TLS-related header space including crypto initial vector area. */
2447 status = nx_secure_tls_packet_allocate(client_ptr -> nx_websocket_client_tls_session_ptr,
2448 client_ptr -> nx_websocket_client_packet_pool_ptr,
2449 packet_ptr, TX_WAIT_FOREVER);
2450 }
2451 else
2452 {
2453 #endif /* NX_SECURE_ENABLE */
2454
2455 /* Allocate packet. */
2456 if (client_ptr -> nx_websocket_client_socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V4)
2457 {
2458 status = nx_packet_allocate(client_ptr -> nx_websocket_client_packet_pool_ptr,
2459 packet_ptr,
2460 NX_IPv4_TCP_PACKET, wait_option);
2461 }
2462 else
2463 {
2464 status = nx_packet_allocate(client_ptr -> nx_websocket_client_packet_pool_ptr,
2465 packet_ptr,
2466 NX_IPv6_TCP_PACKET, wait_option);
2467 }
2468 #ifdef NX_SECURE_ENABLE
2469 }
2470 #endif /* NX_SECURE_ENABLE */
2471
2472 if (status == NX_SUCCESS)
2473 {
2474
2475 /* Check the buffer size for the basic data header of websocket. */
2476 if (((ULONG)(((*packet_ptr) -> nx_packet_data_end) - ((*packet_ptr) -> nx_packet_prepend_ptr))) < NX_WEBSOCKET_HEADER_SIZE)
2477 {
2478
2479 /* Packet buffer is too small. */
2480 nx_packet_release(*packet_ptr);
2481 return(NX_WEBSOCKET_INVALID_PACKET);
2482 }
2483
2484 /* Adjust the pointers. */
2485 ((*packet_ptr) -> nx_packet_prepend_ptr) += NX_WEBSOCKET_HEADER_SIZE;
2486 ((*packet_ptr) -> nx_packet_append_ptr) += NX_WEBSOCKET_HEADER_SIZE;
2487 }
2488
2489 /* Return completion status. */
2490 return(status);
2491 }
2492
2493 /**************************************************************************/
2494 /* */
2495 /* FUNCTION RELEASE */
2496 /* */
2497 /* _nx_websocket_client_packet_send PORTABLE C */
2498 /* 6.2.0 */
2499 /* AUTHOR */
2500 /* */
2501 /* Bo Chen, Microsoft Corporation */
2502 /* */
2503 /* DESCRIPTION */
2504 /* */
2505 /* This function sends Websocket packet. */
2506 /* */
2507 /* INPUT */
2508 /* */
2509 /* client_ptr Pointer to WebSocket Client */
2510 /* packet_ptr Pointer to packet */
2511 /* wait_option Wait option */
2512 /* */
2513 /* OUTPUT */
2514 /* */
2515 /* status Completion status */
2516 /* */
2517 /* CALLS */
2518 /* */
2519 /* nx_tcp_socket_send Send tcp packet */
2520 /* nx_secure_tls_session_send Send tls packet */
2521 /* */
2522 /* CALLED BY */
2523 /* */
2524 /* _nx_websocket_client_connect_internal Make websocket connection */
2525 /* _nx_websocket_client_send Send websocket data frame */
2526 /* */
2527 /* RELEASE HISTORY */
2528 /* */
2529 /* DATE NAME DESCRIPTION */
2530 /* */
2531 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
2532 /* */
2533 /**************************************************************************/
_nx_websocket_client_packet_send(NX_WEBSOCKET_CLIENT * client_ptr,NX_PACKET * packet_ptr,ULONG wait_option)2534 UINT _nx_websocket_client_packet_send(NX_WEBSOCKET_CLIENT *client_ptr, NX_PACKET *packet_ptr, ULONG wait_option)
2535 {
2536
2537 UINT status;
2538
2539 #ifdef NX_SECURE_ENABLE
2540 if (client_ptr -> nx_websocket_client_use_tls)
2541 {
2542 status = nx_secure_tls_session_send(client_ptr -> nx_websocket_client_tls_session_ptr, packet_ptr, wait_option);
2543 }
2544 else
2545 {
2546 status = nx_tcp_socket_send(client_ptr -> nx_websocket_client_socket_ptr, packet_ptr, wait_option);
2547 }
2548 #else
2549 status = nx_tcp_socket_send(client_ptr -> nx_websocket_client_socket_ptr, packet_ptr, wait_option);
2550 #endif /* NX_SECURE_ENABLE */
2551
2552 return(status);
2553 }
2554
2555 /**************************************************************************/
2556 /* */
2557 /* FUNCTION RELEASE */
2558 /* */
2559 /* _nx_websocket_client_packet_receive PORTABLE C */
2560 /* 6.2.0 */
2561 /* AUTHOR */
2562 /* */
2563 /* Bo Chen, Microsoft Corporation */
2564 /* */
2565 /* DESCRIPTION */
2566 /* */
2567 /* This function receives Websocket packet. */
2568 /* */
2569 /* INPUT */
2570 /* */
2571 /* client_ptr Pointer to WebSocket Client */
2572 /* packet_ptr Pointer to packet pointer */
2573 /* wait_option Wait option */
2574 /* */
2575 /* OUTPUT */
2576 /* */
2577 /* status Completion status */
2578 /* */
2579 /* CALLS */
2580 /* */
2581 /* nx_tcp_socket_receive Receive tcp packet */
2582 /* nx_secure_tls_session_receive Receive tls packet */
2583 /* */
2584 /* CALLED BY */
2585 /* */
2586 /* _nx_websocket_client_connect_internal Make websocket connection */
2587 /* _nx_websocket_client_receive Receive websocket data frame */
2588 /* */
2589 /* RELEASE HISTORY */
2590 /* */
2591 /* DATE NAME DESCRIPTION */
2592 /* */
2593 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
2594 /* */
2595 /**************************************************************************/
_nx_websocket_client_packet_receive(NX_WEBSOCKET_CLIENT * client_ptr,NX_PACKET ** packet_ptr,ULONG wait_option)2596 UINT _nx_websocket_client_packet_receive(NX_WEBSOCKET_CLIENT *client_ptr, NX_PACKET **packet_ptr, ULONG wait_option)
2597 {
2598
2599 UINT status;
2600
2601
2602 /* Release the mutex first */
2603 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
2604
2605 #ifdef NX_SECURE_ENABLE
2606 if (client_ptr -> nx_websocket_client_use_tls)
2607 {
2608 status = nx_secure_tls_session_receive(client_ptr -> nx_websocket_client_tls_session_ptr, packet_ptr, wait_option);
2609 }
2610 else
2611 {
2612 status = nx_tcp_socket_receive(client_ptr -> nx_websocket_client_socket_ptr, packet_ptr, wait_option);
2613 }
2614 #else
2615 status = nx_tcp_socket_receive(client_ptr -> nx_websocket_client_socket_ptr, packet_ptr, wait_option);
2616 #endif /* NX_SECURE_ENABLE */
2617
2618 /* Obtain the mutex again. */
2619 tx_mutex_get(&(client_ptr -> nx_websocket_client_mutex), NX_WAIT_FOREVER);
2620
2621 return(status);
2622 }
2623
2624 /**************************************************************************/
2625 /* */
2626 /* FUNCTION RELEASE */
2627 /* */
2628 /* _nx_websocket_client_connect_response_check PORTABLE C */
2629 /* 6.2.0 */
2630 /* AUTHOR */
2631 /* */
2632 /* Bo Chen, Microsoft Corporation */
2633 /* */
2634 /* DESCRIPTION */
2635 /* */
2636 /* This function checks if a whole connect response is received, then */
2637 /* process the response. */
2638 /* */
2639 /* INPUT */
2640 /* */
2641 /* client_ptr Pointer to WebSocket Client */
2642 /* packet_ptr Pointer to packet */
2643 /* wait_option Wait option */
2644 /* */
2645 /* OUTPUT */
2646 /* */
2647 /* status Completion status */
2648 /* */
2649 /* CALLS */
2650 /* */
2651 /* nx_packet_data_append Append data into packet */
2652 /* nx_packet_release Release packet */
2653 /* _nx_websocket_client_connect_response_process */
2654 /* Process connect response */
2655 /* _nx_websocket_client_cleanup Cleanup resource */
2656 /* */
2657 /* CALLED BY */
2658 /* */
2659 /* _nx_websocket_client_connect_internal Make websocket connection */
2660 /* _nx_websocket_client_receive Receive websocket data frame */
2661 /* */
2662 /* RELEASE HISTORY */
2663 /* */
2664 /* DATE NAME DESCRIPTION */
2665 /* */
2666 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
2667 /* */
2668 /**************************************************************************/
_nx_websocket_client_connect_response_check(NX_WEBSOCKET_CLIENT * client_ptr,NX_PACKET * packet_ptr,UINT wait_option)2669 UINT _nx_websocket_client_connect_response_check(NX_WEBSOCKET_CLIENT *client_ptr, NX_PACKET *packet_ptr, UINT wait_option)
2670 {
2671 CHAR *buffer_ptr;
2672 UINT status = NX_SUCCESS;
2673 UINT crlf_found = 0;
2674 NX_PACKET *tmp_ptr;
2675
2676
2677 if (client_ptr -> nx_websocket_client_processing_packet == NX_NULL)
2678 {
2679 client_ptr -> nx_websocket_client_processing_packet = packet_ptr;
2680 }
2681 else
2682 {
2683
2684 /* Its contents now need to be placed in the head packet. */
2685 tmp_ptr = packet_ptr;
2686
2687 #ifndef NX_DISABLE_PACKET_CHAIN
2688 while (tmp_ptr)
2689 #endif /* NX_DISABLE_PACKET_CHAIN */
2690 {
2691
2692 /* Release the mutex */
2693 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
2694
2695 /* Copy the contents of the current packet into the head packet. */
2696 status = nx_packet_data_append(client_ptr -> nx_websocket_client_processing_packet,
2697 (VOID *) tmp_ptr -> nx_packet_prepend_ptr,
2698 (ULONG)(tmp_ptr -> nx_packet_append_ptr - tmp_ptr -> nx_packet_prepend_ptr),
2699 client_ptr -> nx_websocket_client_packet_pool_ptr, wait_option);
2700
2701 /* Obtain the mutex. */
2702 tx_mutex_get(&(client_ptr -> nx_websocket_client_mutex), NX_WAIT_FOREVER);
2703
2704 /* Determine if an error occurred or an unexpected packet chain happens since the connect response shall not exceed the maximum length of one packet */
2705 if ((status != NX_SUCCESS) || (client_ptr -> nx_websocket_client_processing_packet -> nx_packet_next))
2706 {
2707
2708 /* Reset the state to idle */
2709 client_ptr -> nx_websocket_client_state = NX_WEBSOCKET_CLIENT_STATE_IDLE;
2710
2711 /* Clean up unused resources. */
2712 _nx_websocket_client_cleanup(client_ptr);
2713
2714 /* Release the new packet and return. */
2715 nx_packet_release(packet_ptr);
2716 return(status);
2717 }
2718 #ifndef NX_DISABLE_PACKET_CHAIN
2719 else
2720 {
2721 tmp_ptr = tmp_ptr -> nx_packet_next;
2722 }
2723 #endif /* NX_DISABLE_PACKET_CHAIN */
2724 }
2725
2726 /* Release the new packet. */
2727 nx_packet_release(packet_ptr);
2728 }
2729
2730 crlf_found = 0;
2731 tmp_ptr = client_ptr -> nx_websocket_client_processing_packet;
2732
2733 while (1)
2734 {
2735
2736 /* Build a pointer to the buffer area. */
2737 buffer_ptr = (CHAR *) tmp_ptr -> nx_packet_prepend_ptr;
2738
2739 /* See if there is a blank line present in the buffer. */
2740 /* Search the buffer for a cr/lf pair. */
2741 while ((buffer_ptr < (CHAR *) tmp_ptr -> nx_packet_append_ptr) &&
2742 (crlf_found < 4))
2743 {
2744 if (!(crlf_found & 1) && (*buffer_ptr == (CHAR)13))
2745 {
2746
2747 /* Found CR. */
2748 crlf_found++;
2749 }
2750 else if((crlf_found & 1) && (*buffer_ptr == (CHAR)10))
2751 {
2752
2753 /* Found LF. */
2754 crlf_found++;
2755 }
2756 else
2757 {
2758
2759 /* Reset the CRLF marker. */
2760 crlf_found = 0;
2761 }
2762
2763 /* Move the buffer pointer up. */
2764 buffer_ptr++;
2765 }
2766
2767 if (crlf_found == 4)
2768 {
2769
2770 /* Yes, we have found the end of the HTTP response header. */
2771 break;
2772 }
2773
2774 #ifndef NX_DISABLE_PACKET_CHAIN
2775
2776 if (tmp_ptr -> nx_packet_next != NX_NULL)
2777 {
2778
2779 /* Get the next packet in the chain. */
2780 tmp_ptr = tmp_ptr -> nx_packet_next;
2781 }
2782 else
2783 #endif
2784 {
2785 return(NX_IN_PROGRESS);
2786 }
2787 }
2788
2789 /* Process the response. */
2790 status = _nx_websocket_client_connect_response_process(client_ptr, client_ptr -> nx_websocket_client_processing_packet);
2791 if (status == NX_SUCCESS)
2792 {
2793
2794 /* Update the state. */
2795 client_ptr -> nx_websocket_client_state = NX_WEBSOCKET_CLIENT_STATE_CONNECTED;
2796
2797 /* If connection is established, notify application. */
2798 if (client_ptr -> nx_websocket_client_connection_status_callback)
2799 {
2800 client_ptr -> nx_websocket_client_connection_status_callback(client_ptr, client_ptr -> nx_websocket_client_connection_context, NX_SUCCESS);
2801 }
2802 }
2803 else
2804 {
2805 client_ptr -> nx_websocket_client_state = NX_WEBSOCKET_CLIENT_STATE_IDLE;
2806 }
2807
2808 /* Clean up unused resources. */
2809 _nx_websocket_client_cleanup(client_ptr);
2810
2811 return (status);
2812 }
2813
2814 /**************************************************************************/
2815 /* */
2816 /* FUNCTION RELEASE */
2817 /* */
2818 /* _nxe_websocket_client_connection_status_callback_set */
2819 /* PORTABLE C */
2820 /* 6.2.0 */
2821 /* AUTHOR */
2822 /* */
2823 /* Bo Chen, Microsoft Corporation */
2824 /* */
2825 /* DESCRIPTION */
2826 /* */
2827 /* This function checks for errors in the WebSocket callback set. */
2828 /* */
2829 /* INPUT */
2830 /* */
2831 /* client_ptr Pointer to WebSocket Client */
2832 /* context Context for callback */
2833 /* connection_status_callback Routine to call when connect */
2834 /* or disconnect occurs */
2835 /* */
2836 /* OUTPUT */
2837 /* */
2838 /* status Completion status */
2839 /* */
2840 /* CALLS */
2841 /* */
2842 /* _nx_websocket_client_connection_status_callback_set */
2843 /* Actual websocket callback set */
2844 /* */
2845 /* CALLED BY */
2846 /* */
2847 /* Application Code */
2848 /* */
2849 /* RELEASE HISTORY */
2850 /* */
2851 /* DATE NAME DESCRIPTION */
2852 /* */
2853 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
2854 /* */
2855 /**************************************************************************/
_nxe_websocket_client_connection_status_callback_set(NX_WEBSOCKET_CLIENT * client_ptr,VOID * context,VOID (* connection_status_callback)(NX_WEBSOCKET_CLIENT *,VOID *,UINT))2856 UINT _nxe_websocket_client_connection_status_callback_set(NX_WEBSOCKET_CLIENT *client_ptr, VOID *context,
2857 VOID (*connection_status_callback)(NX_WEBSOCKET_CLIENT *, VOID *, UINT))
2858 {
2859 UINT status;
2860
2861
2862 /* Check for invalid input pointers. */
2863 if ((client_ptr == NX_NULL) || (client_ptr -> nx_websocket_client_id != NX_WEBSOCKET_CLIENT_ID))
2864 {
2865 return(NX_PTR_ERROR);
2866 }
2867
2868 /* Call actual process function. */
2869 status = _nx_websocket_client_connection_status_callback_set(client_ptr, context, connection_status_callback);
2870
2871 /* Return completion status. */
2872 return(status);
2873 }
2874
2875 /**************************************************************************/
2876 /* */
2877 /* FUNCTION RELEASE */
2878 /* */
2879 /* _nx_websocket_client_connection_status_callback_set PORTABLE C */
2880 /* 6.2.0 */
2881 /* AUTHOR */
2882 /* */
2883 /* Bo Chen, Microsoft Corporation */
2884 /* */
2885 /* DESCRIPTION */
2886 /* */
2887 /* This function sets Websocket connection callback. */
2888 /* */
2889 /* INPUT */
2890 /* */
2891 /* client_ptr Pointer to WebSocket Client */
2892 /* context Context for callback */
2893 /* connection_status_callback Routine to call when connect */
2894 /* or disconnect occurs */
2895 /* */
2896 /* OUTPUT */
2897 /* */
2898 /* status Completion status */
2899 /* */
2900 /* CALLS */
2901 /* */
2902 /* None */
2903 /* */
2904 /* CALLED BY */
2905 /* */
2906 /* Application Code */
2907 /* */
2908 /* RELEASE HISTORY */
2909 /* */
2910 /* DATE NAME DESCRIPTION */
2911 /* */
2912 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
2913 /* */
2914 /**************************************************************************/
_nx_websocket_client_connection_status_callback_set(NX_WEBSOCKET_CLIENT * client_ptr,VOID * context,VOID (* connection_status_callback)(NX_WEBSOCKET_CLIENT *,VOID *,UINT))2915 UINT _nx_websocket_client_connection_status_callback_set(NX_WEBSOCKET_CLIENT *client_ptr, VOID *context,
2916 VOID (*connection_status_callback)(NX_WEBSOCKET_CLIENT *, VOID *, UINT))
2917 {
2918
2919 /* Obtain the mutex. */
2920 tx_mutex_get(&(client_ptr -> nx_websocket_client_mutex), NX_WAIT_FOREVER);
2921
2922 /* Set the context which will be passed to connection status callback. */
2923 client_ptr -> nx_websocket_client_connection_context = context;
2924
2925 /* Set the connection status callback. */
2926 client_ptr -> nx_websocket_client_connection_status_callback = connection_status_callback;
2927
2928 /* Release the mutex */
2929 tx_mutex_put(&(client_ptr -> nx_websocket_client_mutex));
2930
2931 return(NX_SUCCESS);
2932 }
2933
2934 /**************************************************************************/
2935 /* */
2936 /* FUNCTION RELEASE */
2937 /* */
2938 /* _nx_websocket_client_cleanup PORTABLE C */
2939 /* 6.2.0 */
2940 /* AUTHOR */
2941 /* */
2942 /* Bo Chen, Microsoft Corporation */
2943 /* */
2944 /* DESCRIPTION */
2945 /* */
2946 /* This function cleanups resources. */
2947 /* */
2948 /* INPUT */
2949 /* */
2950 /* client_ptr Pointer to WebSocket Client */
2951 /* */
2952 /* OUTPUT */
2953 /* */
2954 /* status Completion status */
2955 /* */
2956 /* CALLS */
2957 /* */
2958 /* None */
2959 /* */
2960 /* CALLED BY */
2961 /* */
2962 /* _nx_websocket_client_delete Delete websocket instance */
2963 /* _nx_websocket_client_data_process Process data frame */
2964 /* _nx_websocket_client_connect_response_check */
2965 /* Check connect response */
2966 /* _nx_websocket_client_connect_internal Make websocket connection */
2967 /* */
2968 /* RELEASE HISTORY */
2969 /* */
2970 /* DATE NAME DESCRIPTION */
2971 /* */
2972 /* 10-31-2022 Bo Chen Initial Version 6.2.0 */
2973 /* */
2974 /**************************************************************************/
_nx_websocket_client_cleanup(NX_WEBSOCKET_CLIENT * client_ptr)2975 void _nx_websocket_client_cleanup(NX_WEBSOCKET_CLIENT *client_ptr)
2976 {
2977
2978 /* Reset the flag for frame header found */
2979 client_ptr -> nx_websocket_client_frame_header_found = NX_FALSE;
2980
2981 /* Release the waiting list. */
2982 if (client_ptr -> nx_websocket_client_processing_packet)
2983 {
2984 nx_packet_release(client_ptr -> nx_websocket_client_processing_packet);
2985 client_ptr -> nx_websocket_client_processing_packet = NX_NULL;
2986 }
2987 }
2988