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