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