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 Component                                                        */
17 /**                                                                       */
18 /**   Multiple TCP Socket/TLS Session support module                      */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 #define NX_TCPSERVER_SOURCE_CODE
24 
25 #include "nx_api.h"
26 #include "nx_tcpserver.h"
27 
28 
29 /* Define internal function prototypes. */
30 static UINT _nx_tcpserver_session_allocate(NX_TCPSERVER *server_ptr, NX_TCP_SESSION **session_pptr);
31 static UINT _nx_tcpserver_relisten(NX_TCPSERVER *server_ptr);
32 static VOID _nx_tcpserver_connect_present(NX_TCP_SOCKET *socket_ptr, UINT port);
33 static VOID _nx_tcpserver_data_present(NX_TCP_SOCKET *socket_ptr);
34 static VOID _nx_tcpserver_disconnect_present(NX_TCP_SOCKET *socket_ptr);
35 static VOID _nx_tcpserver_timeout(ULONG tcpserver_address);
36 static VOID _nx_tcpserver_connect_process(NX_TCPSERVER *server_ptr);
37 static VOID _nx_tcpserver_data_process(NX_TCPSERVER *server_ptr);
38 static VOID _nx_tcpserver_disconnect_process(NX_TCPSERVER *server_ptr);
39 static VOID _nx_tcpserver_timeout_process(NX_TCPSERVER *server_ptr);
40 static VOID _nx_tcpserver_thread_entry(ULONG tcpserver_address);
41 
42 
43 /**************************************************************************/
44 /*                                                                        */
45 /*  FUNCTION                                               RELEASE        */
46 /*                                                                        */
47 /*    _nx_tcpserver_session_allocate                       PORTABLE C     */
48 /*                                                           6.1          */
49 /*  AUTHOR                                                                */
50 /*                                                                        */
51 /*    Yuxin Zhou, Microsoft Corporation                                   */
52 /*                                                                        */
53 /*  DESCRIPTION                                                           */
54 /*                                                                        */
55 /*    This internal function allocates a free socket (and TLS session, if */
56 /*    TLS is enabled) for an incoming client request.                     */
57 /*                                                                        */
58 /*  INPUT                                                                 */
59 /*                                                                        */
60 /*    server_ptr                            Pointer to server structure   */
61 /*    session_pptr                          Pointer to allocated socket   */
62 /*                                                                        */
63 /*  OUTPUT                                                                */
64 /*                                                                        */
65 /*    status                                Completion status             */
66 /*                                                                        */
67 /*  CALLS                                                                 */
68 /*                                                                        */
69 /*    None                                                                */
70 /*                                                                        */
71 /*  CALLED BY                                                             */
72 /*                                                                        */
73 /*    _nx_tcpserver_relisten                                              */
74 /*    _nx_tcpserver_start                                                 */
75 /*    _nx_tcpserver_connect_process                                       */
76 /*                                                                        */
77 /*  RELEASE HISTORY                                                       */
78 /*                                                                        */
79 /*    DATE              NAME                      DESCRIPTION             */
80 /*                                                                        */
81 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
82 /*  09-30-2020     Yuxin Zhou               Modified comment(s), and      */
83 /*                                            fixed packet leak issue,    */
84 /*                                            resulting in version 6.1    */
85 /*                                                                        */
86 /**************************************************************************/
_nx_tcpserver_session_allocate(NX_TCPSERVER * server_ptr,NX_TCP_SESSION ** session_pptr)87 static UINT _nx_tcpserver_session_allocate(NX_TCPSERVER *server_ptr, NX_TCP_SESSION **session_pptr)
88 {
89 UINT            i;
90 NX_TCP_SOCKET  *socket_ptr;
91 
92     /* Reset. */
93     *session_pptr = NX_NULL;
94 
95     /* Loop to find unused session. */
96     for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++)
97     {
98 
99         /* Skip the listen session. */
100         if(&server_ptr -> nx_tcpserver_sessions[i] == server_ptr -> nx_tcpserver_listen_session)
101             continue;
102 
103         socket_ptr = &(server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket);
104 
105         /* A closed or listening socket is available. */
106         if((socket_ptr -> nx_tcp_socket_state == NX_TCP_CLOSED) &&
107            (socket_ptr -> nx_tcp_socket_bound_next == NX_NULL) &&
108            (socket_ptr -> nx_tcp_socket_bind_in_progress == NX_NULL))
109         {
110 
111             /* Reset expiration to zero. */
112             server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_expiration = 0;
113 
114             /* Set connection flag to false. */
115             server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_connected = NX_FALSE;
116 
117             /* Return the socket. */
118             *session_pptr = &server_ptr -> nx_tcpserver_sessions[i];
119             return NX_SUCCESS;
120         }
121     }
122 
123     return NX_TCPSERVER_FAIL;
124 }
125 
126 /**************************************************************************/
127 /*                                                                        */
128 /*  FUNCTION                                               RELEASE        */
129 /*                                                                        */
130 /*    _nx_tcpserver_relisten                               PORTABLE C     */
131 /*                                                           6.1.9        */
132 /*  AUTHOR                                                                */
133 /*                                                                        */
134 /*    Yuxin Zhou, Microsoft Corporation                                   */
135 /*                                                                        */
136 /*  DESCRIPTION                                                           */
137 /*                                                                        */
138 /*    This internal function is invoked whenever a connection is closed   */
139 /*    to re-enable listening on that closed socket/session.               */
140 /*                                                                        */
141 /*  INPUT                                                                 */
142 /*                                                                        */
143 /*    server_ptr                            Pointer to server structure   */
144 /*                                                                        */
145 /*  OUTPUT                                                                */
146 /*                                                                        */
147 /*    status                                Completion status             */
148 /*                                                                        */
149 /*  CALLS                                                                 */
150 /*                                                                        */
151 /*    _nx_tcpserver_session_allocate        Allocate socket for listening */
152 /*    nx_tcp_server_socket_relisten         Re-listen on free socket      */
153 /*                                                                        */
154 /*  CALLED BY                                                             */
155 /*                                                                        */
156 /*    _nx_tcpserver_connect_process                                       */
157 /*   _nx_tcpserver_disconnect_process                                     */
158 /*   _nx_tcpserver_timeout_process                                        */
159 /*                                                                        */
160 /*  RELEASE HISTORY                                                       */
161 /*                                                                        */
162 /*    DATE              NAME                      DESCRIPTION             */
163 /*                                                                        */
164 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
165 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
166 /*                                            resulting in version 6.1    */
167 /*  10-15-2021     Yuxin Zhou               Modified comment(s), and      */
168 /*                                            removed debug output,       */
169 /*                                            resulting in version 6.1.9  */
170 /*                                                                        */
171 /**************************************************************************/
_nx_tcpserver_relisten(NX_TCPSERVER * server_ptr)172 static UINT _nx_tcpserver_relisten(NX_TCPSERVER *server_ptr)
173 {
174 UINT            status;
175 NX_TCP_SESSION *session_ptr;
176 
177     /* Is any socket listening? */
178     if(server_ptr -> nx_tcpserver_listen_session == NX_NULL)
179     {
180 
181         /* Get a socket to listen. */
182         status = _nx_tcpserver_session_allocate(server_ptr, &session_ptr);
183         if(status)
184         {
185             return NX_TCPSERVER_FAIL;
186         }
187 
188         status = nx_tcp_server_socket_relisten(server_ptr -> nx_tcpserver_ip,
189                                                server_ptr -> nx_tcpserver_listen_port,
190                                                &session_ptr -> nx_tcp_session_socket);
191         if((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING))
192         {
193             return NX_TCPSERVER_FAIL;
194         }
195 
196         /* Store listen socket. */
197         server_ptr -> nx_tcpserver_listen_session = session_ptr;
198     }
199     else if(server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket.nx_tcp_socket_state == NX_TCP_CLOSED)
200     {
201 
202         status = nx_tcp_server_socket_relisten(server_ptr -> nx_tcpserver_ip,
203                                                server_ptr -> nx_tcpserver_listen_port,
204                                                &server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket);
205         if((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING))
206         {
207             return NX_TCPSERVER_FAIL;
208         }
209     }
210 
211     return NX_SUCCESS;
212 }
213 
214 /**************************************************************************/
215 /*                                                                        */
216 /*  FUNCTION                                               RELEASE        */
217 /*                                                                        */
218 /*    nx_tcpserver_create                                  PORTABLE C     */
219 /*                                                           6.1          */
220 /*  AUTHOR                                                                */
221 /*                                                                        */
222 /*    Yuxin Zhou, Microsoft Corporation                                   */
223 /*                                                                        */
224 /*  DESCRIPTION                                                           */
225 /*                                                                        */
226 /*    This function creates a socket server instance to handle multiple   */
227 /*    incoming TCP or TLS client connections. The server utilizes an      */
228 /*    internal thread and manages a queue of TCP sockets (and TLS         */
229 /*    sessions if enabled) that are used to handle incoming requests.     */
230 /*    The callback routines are used to handle individual requests. Each  */
231 /*    socket (and TLS session) receives identical state so that each      */
232 /*    incoming request is handled consistently.                           */
233 /*                                                                        */
234 /*    The number of available sockets and TLS sessions is determined by   */
235 /*    the size of the sessions buffer and can be found by dividing the    */
236 /*    buffer size by the size of the NX_TCP_SESSION structure.            */
237 /*                                                                        */
238 /*  INPUT                                                                 */
239 /*                                                                        */
240 /*    ip_ptr                                IP instance for this server   */
241 /*    server_ptr                            Pointer to server structure   */
242 /*    name                                  Name string for this server   */
243 /*    type_of_service                       Type of service for TCP       */
244 /*                                            sockets                     */
245 /*    fragment                              Flag to enable IP fragmenting */
246 /*    time_to_live                          Time to live value for socket */
247 /*    window_size                           Size of socket's receive      */
248 /*                                            window                      */
249 /*    new_connection                        Callback invoked for new      */
250 /*                                            client connections          */
251 /*    receive_data                          Callback invoked when data is */
252 /*                                            received from the client    */
253 /*    connection_end                        Callback invoked when a       */
254 /*                                            connection is closed        */
255 /*    connection_timeout                    Callback invoked when a       */
256 /*                                            connection times out        */
257 /*    timeout                               Timeout value for all sockets */
258 /*    stack_ptr                             Stack buffer for internal     */
259 /*                                            server thread               */
260 /*    stack_size                            Size of thread stack buffer   */
261 /*    sessions_buffer                       Buffer for per-session data   */
262 /*    buffer_size                           Size of per-session buffer,   */
263 /*                                            determines session number   */
264 /*                                                                        */
265 /*  OUTPUT                                                                */
266 /*                                                                        */
267 /*    status                                Completion status             */
268 /*                                                                        */
269 /*  CALLS                                                                 */
270 /*                                                                        */
271 /*    tx_thread_create                     Create server thread           */
272 /*    tx_event_flags_create                Create thread event flags      */
273 /*    tx_timer_create                      Create timeout timer           */
274 /*    nx_tcp_socket_create                 Create TCP sockets             */
275 /*    nx_tcp_socket_receive_notify         Set TCP notification callback  */
276 /*                                                                        */
277 /*  CALLED BY                                                             */
278 /*                                                                        */
279 /*    Application Code                                                    */
280 /*                                                                        */
281 /*  RELEASE HISTORY                                                       */
282 /*                                                                        */
283 /*    DATE              NAME                      DESCRIPTION             */
284 /*                                                                        */
285 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
286 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
287 /*                                            resulting in version 6.1    */
288 /*                                                                        */
289 /**************************************************************************/
_nx_tcpserver_create(NX_IP * ip_ptr,NX_TCPSERVER * server_ptr,CHAR * name,ULONG type_of_service,ULONG fragment,UINT time_to_live,ULONG window_size,VOID (* new_connection)(NX_TCPSERVER * server_ptr,NX_TCP_SESSION * session_ptr),VOID (* receive_data)(NX_TCPSERVER * server_ptr,NX_TCP_SESSION * session_ptr),VOID (* connection_end)(NX_TCPSERVER * server_ptr,NX_TCP_SESSION * session_ptr),VOID (* connection_timeout)(NX_TCPSERVER * server_ptr,NX_TCP_SESSION * session_ptr),ULONG timeout,VOID * stack_ptr,UINT stack_size,VOID * sessions_buffer,UINT buffer_size,UINT thread_priority,ULONG accept_wait_option)290 UINT _nx_tcpserver_create(NX_IP *ip_ptr, NX_TCPSERVER *server_ptr, CHAR *name,
291                           ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG window_size,
292                           VOID (*new_connection)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr),
293                           VOID (*receive_data)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr),
294                           VOID (*connection_end)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr),
295                           VOID (*connection_timeout)(NX_TCPSERVER *server_ptr, NX_TCP_SESSION *session_ptr),
296                           ULONG timeout, VOID *stack_ptr, UINT stack_size,
297                           VOID *sessions_buffer, UINT buffer_size, UINT thread_priority, ULONG accept_wait_option)
298 {
299 UINT            i;
300 UINT            status;
301 
302     /* Initialize server struct. */
303     server_ptr -> nx_tcpserver_ip = ip_ptr;
304     server_ptr -> nx_tcpserver_sessions = sessions_buffer;
305     server_ptr -> nx_tcpserver_sessions_count = buffer_size / sizeof(NX_TCP_SESSION);
306     server_ptr -> nx_tcpserver_listen_port = 0;
307     server_ptr -> nx_tcpserver_listen_session = NX_NULL;
308     server_ptr -> nx_tcpserver_new_connection = new_connection;
309     server_ptr -> nx_tcpserver_receive_data = receive_data;
310     server_ptr -> nx_tcpserver_connection_end = connection_end;
311     server_ptr -> nx_tcpserver_connection_timeout = connection_timeout;
312     server_ptr -> nx_tcpserver_timeout = timeout;
313     server_ptr -> nx_tcpserver_accept_wait_option = accept_wait_option;
314 
315     /* Create the tcpserver thread. */
316     status = tx_thread_create(&server_ptr -> nx_tcpserver_thread, "TCPSERVER Thread",
317                               _nx_tcpserver_thread_entry, (ULONG)server_ptr, stack_ptr,
318                               stack_size, thread_priority, thread_priority,
319                               TX_NO_TIME_SLICE, TX_DONT_START);
320 
321     /* Create the tcpserver event flags. */
322     status += tx_event_flags_create(&server_ptr -> nx_tcpserver_event_flags, "TCPSERVER Events");
323 
324     /* Create the timeout timer. */
325     status += tx_timer_create(&server_ptr -> nx_tcpserver_timer, "TCPSERVER Timer",
326                               _nx_tcpserver_timeout, (ULONG)server_ptr,
327                               (NX_IP_PERIODIC_RATE * NX_TCPSERVER_TIMEOUT_PERIOD),
328                               (NX_IP_PERIODIC_RATE * NX_TCPSERVER_TIMEOUT_PERIOD), TX_NO_ACTIVATE);
329 
330     /* Initialize buffer. */
331     memset(sessions_buffer, 0, buffer_size);
332 
333     /* Initialize TCP sockets. */
334     for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++)
335     {
336         status += nx_tcp_socket_create(ip_ptr, &server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket, name, type_of_service, fragment, time_to_live,
337                                        window_size, NX_NULL, _nx_tcpserver_disconnect_present);
338 
339         status += nx_tcp_socket_receive_notify(&server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket, _nx_tcpserver_data_present);
340 
341         server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket.nx_tcp_socket_reserved_ptr = server_ptr;
342     }
343 
344     return status;
345 }
346 
347 
348 #ifdef NX_TCPSERVER_ENABLE_TLS
349 
350 /**************************************************************************/
351 /*                                                                        */
352 /*  FUNCTION                                               RELEASE        */
353 /*                                                                        */
354 /*    _nx_tcpserver_tls_setup                              PORTABLE C     */
355 /*                                                           6.1.12       */
356 /*  AUTHOR                                                                */
357 /*                                                                        */
358 /*    Yuxin Zhou, Microsoft Corporation                                   */
359 /*                                                                        */
360 /*  DESCRIPTION                                                           */
361 /*                                                                        */
362 /*    This function configures a previously created NetX socket server    */
363 /*    instance to use TLS. The parameters are used to configure all the   */
364 /*    TLS sessions in the server with identical state so that each        */
365 /*    incoming TLS client experiences consistent behavior. The number of  */
366 /*    TLS sessions and TCP sockets is determined by the size of the       */
367 /*    sessions buffer passed into nx_tcpserver_create.                    */
368 /*                                                                        */
369 /*    The cryptographic routine table (ciphersuite table) is shared       */
370 /*    between all TLS sessions as it just contains function pointers.     */
371 /*                                                                        */
372 /*    The metadata buffer and packet reassembly buffer are divided        */
373 /*    equally between all TLS sessions. If the buffer size is not evenly  */
374 /*    divisible by the number of sessions the remainder will be unused.   */
375 /*                                                                        */
376 /*    The passed-in identity certificate is used by all sessions. During  */
377 /*    TLS operation the server identity certificate is only read from so  */
378 /*    copies are not needed for each session.                             */
379 /*                                                                        */
380 /*    The trusted certificates are added to the trusted store for each    */
381 /*    TLS session in the server. This is used for client certificate      */
382 /*    verification which is enabled if remote certificates are provided.  */
383 /*                                                                        */
384 /*    The remote certificate array and buffer is shared by default        */
385 /*    between all TLS sessions. This does mean that some sessions may     */
386 /*    block during certificate validation.                                */
387 /*                                                                        */
388 /*  INPUT                                                                 */
389 /*                                                                        */
390 /*    server_ptr                            Pointer to control block      */
391 /*    crypto_table                          TLS cryptographic routines    */
392 /*    metadata_buffer                       Cryptographic metadata buffer */
393 /*    metadata_size                         Size of metadata buffer       */
394 /*    packet_buffer                         TLS packet buffer             */
395 /*    packet_size                           Size of packet buffer         */
396 /*    identity_certificate                  TLS server certificate        */
397 /*    trusted_certificates                  TLS trusted certificates      */
398 /*    trusted_certs_num                     Number of trusted certs       */
399 /*    remote_certificates                   Remote certificates array     */
400 /*    remote_certs_num                      Number of remote certificates */
401 /*    remote_certificate_buffer             Buffer for remote certs       */
402 /*    remote_cert_buffer_size               Size of remote cert buffer    */
403 /*                                                                        */
404 /*  OUTPUT                                                                */
405 /*                                                                        */
406 /*    status                                Completion status             */
407 /*                                                                        */
408 /*  CALLS                                                                 */
409 /*                                                                        */
410 /*    nx_secure_tls_session_create          Create TLS Session            */
411 /*                                                                        */
412 /*    nx_secure_tls_session_packet_buffer_set                             */
413 /*                                          Set TLS packet buffer         */
414 /*                                                                        */
415 /*    nx_secure_tls_local_certificate_add                                 */
416 /*                                          Add local TLS identity cert   */
417 /*                                                                        */
418 /*    nx_secure_tls_session_client_verify_enable                          */
419 /*                                          Enable client cert verify     */
420 /*                                                                        */
421 /*    nx_secure_tls_trusted_certificate_add Add a trusted TLS cert        */
422 /*                                                                        */
423 /*    nx_secure_tls_remote_certificate_allocate                           */
424 /*                                          Allocate space for incoming   */
425 /*                                          client certificates           */
426 /*                                                                        */
427 /*                                                                        */
428 /*  CALLED BY                                                             */
429 /*                                                                        */
430 /*    Application Code                                                    */
431 /*                                                                        */
432 /*  RELEASE HISTORY                                                       */
433 /*                                                                        */
434 /*    DATE              NAME                      DESCRIPTION             */
435 /*                                                                        */
436 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
437 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
438 /*                                            resulting in version 6.1    */
439 /*  07-29-2022     Yuxin Zhou               Modified comment(s), and      */
440 /*                                            corrected the index of the  */
441 /*                                            remote certificate list,    */
442 /*                                            resulting in version 6.1.12 */
443 /*                                                                        */
444 /**************************************************************************/
445 
446 /* Setup TLS state per server session. */
_nx_tcpserver_tls_setup(NX_TCPSERVER * server_ptr,const NX_SECURE_TLS_CRYPTO * crypto_table,VOID * metadata_buffer,ULONG metadata_size,UCHAR * packet_buffer,UINT packet_buffer_size,NX_SECURE_X509_CERT * identity_certificate,NX_SECURE_X509_CERT * trusted_certificates[],UINT trusted_certs_num,NX_SECURE_X509_CERT * remote_certificates[],UINT remote_certs_num,UCHAR * remote_certificate_buffer,UINT remote_cert_buffer_size)447 UINT _nx_tcpserver_tls_setup(NX_TCPSERVER *server_ptr, const NX_SECURE_TLS_CRYPTO *crypto_table,
448                              VOID *metadata_buffer, ULONG metadata_size, UCHAR* packet_buffer, UINT packet_buffer_size, NX_SECURE_X509_CERT *identity_certificate,
449                              NX_SECURE_X509_CERT *trusted_certificates[], UINT trusted_certs_num, NX_SECURE_X509_CERT *remote_certificates[], UINT remote_certs_num, UCHAR *remote_certificate_buffer, UINT remote_cert_buffer_size)
450 {
451 NX_SECURE_TLS_SESSION *tls_session;
452 ULONG session_metadata_size;
453 UCHAR *session_metadata;
454 UCHAR *session_cert_buffer;
455 UINT session_cert_buffer_size = 0;
456 UINT session_pkt_buffer_size;
457 UINT num_sessions;
458 UINT i;
459 UINT cert_count;
460 UINT status;
461 
462     /* Get the number of sessions in the TCP server. */
463     num_sessions = server_ptr -> nx_tcpserver_sessions_count;
464 
465     /* Get our per-session packet buffer size. */
466     session_pkt_buffer_size = packet_buffer_size / num_sessions;
467 
468     /* Get our per-session metadata. */
469     session_metadata = metadata_buffer;
470     session_metadata_size = metadata_size / num_sessions;
471 
472     /* It's OK to have zero remote certs allocated. */
473     if(remote_certs_num > 0)
474     {
475         /* Divide the remote certificate buffer size by the total number of
476            remote certificates to get per-certificate size. */
477         session_cert_buffer_size = remote_cert_buffer_size / remote_certs_num;
478     }
479 
480     /* Loop through all sessions, initialize each one. */
481     for(i = 0; i < num_sessions; ++i)
482     {
483         /* This server instance is using TLS so mark as such. */
484         server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_using_tls = NX_TRUE;
485 
486         /* Setup per-session data. Get the session from the server structure, then initialize it. */
487         tls_session =  &(server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_tls_session);
488         status = nx_secure_tls_session_create(tls_session, crypto_table, session_metadata, session_metadata_size);
489 
490         if(status != NX_SUCCESS)
491         {
492             return(status);
493         }
494 
495         /* Allocate space for packet reassembly. */
496         status = nx_secure_tls_session_packet_buffer_set(tls_session, &packet_buffer[i * session_pkt_buffer_size],
497                                                          session_pkt_buffer_size);
498 
499         if(status != NX_SUCCESS)
500         {
501             return(status);
502         }
503 
504         /* Add identity certificate. */
505         status = nx_secure_tls_local_certificate_add(tls_session, identity_certificate);
506 
507         if(status != NX_SUCCESS)
508         {
509             return(status);
510         }
511 
512         /* See if remote certificates are provided. */
513         if(remote_certs_num > 0)
514         {
515             /* We have remote certificates to allocate so enable client certificate authentication. */
516             nx_secure_tls_session_client_verify_enable(tls_session);
517 
518             /* Add trusted certificates to each TLS session. */
519             for(cert_count = 0; cert_count < trusted_certs_num; ++cert_count)
520             {
521                 status = nx_secure_tls_trusted_certificate_add(tls_session, trusted_certificates[cert_count]);
522 
523                 if(status != NX_SUCCESS)
524                 {
525                     return(status);
526                 }
527             }
528 
529             /* Allocate remote certificates (if remote_certs_num > 0). The remote certificate
530                buffers are shared between all TLS Sessions. This is possible since they are only
531                needed for the certificate verification process and are freed immediately after. */
532             session_cert_buffer = remote_certificate_buffer;
533 
534             for(cert_count = 0; cert_count < remote_certs_num; ++cert_count)
535             {
536                 /* Allocate a remote certificate from the provided array. */
537                 status = nx_secure_tls_remote_certificate_allocate(tls_session, remote_certificates[cert_count],
538                                                                    session_cert_buffer, session_cert_buffer_size);
539 
540                 if(status != NX_SUCCESS)
541                 {
542                     return(status);
543                 }
544 
545                 /* Now get the next certificate and its buffer. */
546                 session_cert_buffer += session_cert_buffer_size;
547             }
548         }
549 
550         /* Advance metadata buffer. */
551         session_metadata = &session_metadata[session_metadata_size];
552     }
553     return(NX_SUCCESS);
554 }
555 
556 #ifdef NX_SECURE_ENABLE_ECC_CIPHERSUITE
557 /**************************************************************************/
558 /*                                                                        */
559 /*  FUNCTION                                               RELEASE        */
560 /*                                                                        */
561 /*    _nx_tcpserver_tls_ecc_setup                         PORTABLE C      */
562 /*                                                           6.1.11       */
563 /*  AUTHOR                                                                */
564 /*                                                                        */
565 /*    Yuxin Zhou, Microsoft Corporation                                   */
566 /*                                                                        */
567 /*  DESCRIPTION                                                           */
568 /*                                                                        */
569 /*    This function configures supported curve lists for NetX socket      */
570 /*    server instance using TLS.                                          */
571 /*                                                                        */
572 /*  INPUT                                                                 */
573 /*                                                                        */
574 /*    server_ptr                            Pointer to control block      */
575 /*    supported_groups                      List of supported groups      */
576 /*    supported_group_count                 Number of supported groups    */
577 /*    curves                                List of curve methods         */
578 /*                                                                        */
579 /*  OUTPUT                                                                */
580 /*                                                                        */
581 /*    status                                Completion status             */
582 /*                                                                        */
583 /*  CALLS                                                                 */
584 /*                                                                        */
585 /*    nx_secure_tls_ecc_initialize         Initializes curve lists for TLS*/
586 /*                                                                        */
587 /*  CALLED BY                                                             */
588 /*                                                                        */
589 /*    Application Code                                                    */
590 /*                                                                        */
591 /*  RELEASE HISTORY                                                       */
592 /*                                                                        */
593 /*    DATE              NAME                      DESCRIPTION             */
594 /*                                                                        */
595 /*  04-25-2022     Yuxin Zhou               Initial Version 6.1.11        */
596 /*                                                                        */
597 /**************************************************************************/
_nx_tcpserver_tls_ecc_setup(NX_TCPSERVER * server_ptr,const USHORT * supported_groups,USHORT supported_group_count,const NX_CRYPTO_METHOD ** curves)598 UINT _nx_tcpserver_tls_ecc_setup(NX_TCPSERVER *server_ptr,
599                                  const USHORT *supported_groups, USHORT supported_group_count,
600                                  const NX_CRYPTO_METHOD **curves)
601 {
602 UINT i;
603 UINT status;
604 NX_SECURE_TLS_SESSION* tls_session;
605 
606     /* Loop through all sessions, initialize each one. */
607     for (i = 0; i < server_ptr -> nx_tcpserver_sessions_count; ++i)
608     {
609 
610         tls_session = &(server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_tls_session);
611         status = nx_secure_tls_ecc_initialize(tls_session, supported_groups, supported_group_count, curves);
612         if (status != NX_SUCCESS)
613         {
614             return(status);
615         }
616     }
617 
618     return(NX_SUCCESS);
619 }
620 #endif /* NX_SECURE_ENABLE_ECC_CIPHERSUITE */
621 #endif
622 
623 /**************************************************************************/
624 /*                                                                        */
625 /*  FUNCTION                                               RELEASE        */
626 /*                                                                        */
627 /*    _nx_tcpserver_start                                  PORTABLE C     */
628 /*                                                           6.1          */
629 /*  AUTHOR                                                                */
630 /*                                                                        */
631 /*    Yuxin Zhou, Microsoft Corporation                                   */
632 /*                                                                        */
633 /*  DESCRIPTION                                                           */
634 /*                                                                        */
635 /*    This function is called by an application to start a socket server  */
636 /*    that was previously created and configured. This routine starts the */
637 /*    internal server thread and timer.                                   */
638 /*                                                                        */
639 /*  INPUT                                                                 */
640 /*                                                                        */
641 /*    server_ptr                            Pointer to server structure   */
642 /*    port                                  Port for server to listen on  */
643 /*    listen_queue_size                     Maximum number of TCP         */
644 /*                                            connections queued          */
645 /*                                                                        */
646 /*  OUTPUT                                                                */
647 /*                                                                        */
648 /*    status                                Completion status             */
649 /*                                                                        */
650 /*  CALLS                                                                 */
651 /*                                                                        */
652 /*    _nx_tcpserver_session_allocate        Allocate socket for listening */
653 /*    nx_tcp_server_socket_listen           Listen on free TCP socket     */
654 /*    tx_timer_activate                     Start timeout timer           */
655 /*    tx_thread_resume                      Start server thread           */
656 /*                                                                        */
657 /*  CALLED BY                                                             */
658 /*                                                                        */
659 /*   Application code                                                     */
660 /*                                                                        */
661 /*  RELEASE HISTORY                                                       */
662 /*                                                                        */
663 /*    DATE              NAME                      DESCRIPTION             */
664 /*                                                                        */
665 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
666 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
667 /*                                            resulting in version 6.1    */
668 /*                                                                        */
669 /**************************************************************************/
_nx_tcpserver_start(NX_TCPSERVER * server_ptr,UINT port,UINT listen_queue_size)670 UINT _nx_tcpserver_start(NX_TCPSERVER *server_ptr, UINT port, UINT listen_queue_size)
671 {
672 UINT            status;
673 NX_TCP_SESSION *session_ptr;
674 
675     /* Check whether listen is done. */
676     if(server_ptr -> nx_tcpserver_listen_port)
677         return NX_TCPSERVER_FAIL;
678 
679     /* Get a socket to listen. */
680     status = _nx_tcpserver_session_allocate(server_ptr, &session_ptr);
681     if(status)
682         return status;
683 
684     /* Listen on port. */
685     status = nx_tcp_server_socket_listen(server_ptr -> nx_tcpserver_ip, port, &session_ptr -> nx_tcp_session_socket, listen_queue_size, _nx_tcpserver_connect_present);
686     if(status)
687         return status;
688 
689     /* Store socket and port. */
690     server_ptr -> nx_tcpserver_listen_session = session_ptr;
691     server_ptr -> nx_tcpserver_listen_port = port;
692 
693     /* Activate timer. */
694     tx_timer_activate(&server_ptr -> nx_tcpserver_timer);
695 
696     /* Start thread. */
697     tx_thread_resume(&server_ptr -> nx_tcpserver_thread);
698 
699     return NX_SUCCESS;
700 }
701 
702 /**************************************************************************/
703 /*                                                                        */
704 /*  FUNCTION                                               RELEASE        */
705 /*                                                                        */
706 /*    _nx_tcpserver_connect_present                        PORTABLE C     */
707 /*                                                           6.1          */
708 /*  AUTHOR                                                                */
709 /*                                                                        */
710 /*    Yuxin Zhou, Microsoft Corporation                                   */
711 /*                                                                        */
712 /*  DESCRIPTION                                                           */
713 /*                                                                        */
714 /*    This internal function is used for the TCP listen callback passed   */
715 /*    into nx_tcp_server_socket_listen and is used to determine when an   */
716 /*    incoming request has been received and is ready for processing.     */
717 /*                                                                        */
718 /*  INPUT                                                                 */
719 /*                                                                        */
720 /*    socket_ptr                            Pointer to TCP socket         */
721 /*    port                                  Port of incoming request      */
722 /*                                                                        */
723 /*  OUTPUT                                                                */
724 /*                                                                        */
725 /*    None                                                                */
726 /*                                                                        */
727 /*  CALLS                                                                 */
728 /*                                                                        */
729 /*    tx_event_flags_set                    Set thread event flag         */
730 /*                                                                        */
731 /*  CALLED BY                                                             */
732 /*                                                                        */
733 /*   TCP stack                                                            */
734 /*                                                                        */
735 /*  RELEASE HISTORY                                                       */
736 /*                                                                        */
737 /*    DATE              NAME                      DESCRIPTION             */
738 /*                                                                        */
739 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
740 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
741 /*                                            resulting in version 6.1    */
742 /*                                                                        */
743 /**************************************************************************/
_nx_tcpserver_connect_present(NX_TCP_SOCKET * socket_ptr,UINT port)744 static VOID _nx_tcpserver_connect_present(NX_TCP_SOCKET *socket_ptr, UINT port)
745 {
746 NX_TCPSERVER *server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr;
747 
748 
749     NX_PARAMETER_NOT_USED(port);
750 
751     /* Set the connect event flag. */
752     tx_event_flags_set(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_CONNECT, TX_OR);
753 }
754 
755 /**************************************************************************/
756 /*                                                                        */
757 /*  FUNCTION                                               RELEASE        */
758 /*                                                                        */
759 /*    _nx_tcpserver_data_present                           PORTABLE C     */
760 /*                                                           6.1          */
761 /*  AUTHOR                                                                */
762 /*                                                                        */
763 /*    Yuxin Zhou, Microsoft Corporation                                   */
764 /*                                                                        */
765 /*  DESCRIPTION                                                           */
766 /*                                                                        */
767 /*    This internal function is used for the TCP receive callback passed  */
768 /*    into nx_tcp_socket_receive_notify and is used to determine when     */
769 /*    data has been received and is ready for processing.                 */
770 /*                                                                        */
771 /*  INPUT                                                                 */
772 /*                                                                        */
773 /*    socket_ptr                            Pointer to TCP socket         */
774 /*                                                                        */
775 /*  OUTPUT                                                                */
776 /*                                                                        */
777 /*    None                                                                */
778 /*                                                                        */
779 /*  CALLS                                                                 */
780 /*                                                                        */
781 /*    tx_event_flags_set                    Set thread event flag         */
782 /*                                                                        */
783 /*  CALLED BY                                                             */
784 /*                                                                        */
785 /*   TCP stack                                                            */
786 /*                                                                        */
787 /*  RELEASE HISTORY                                                       */
788 /*                                                                        */
789 /*    DATE              NAME                      DESCRIPTION             */
790 /*                                                                        */
791 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
792 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
793 /*                                            resulting in version 6.1    */
794 /*                                                                        */
795 /**************************************************************************/
_nx_tcpserver_data_present(NX_TCP_SOCKET * socket_ptr)796 static VOID _nx_tcpserver_data_present(NX_TCP_SOCKET *socket_ptr)
797 {
798 NX_TCPSERVER *server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr;
799 
800     /* Set the data event flag. */
801     tx_event_flags_set(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_DATA, TX_OR);
802 }
803 
804 /**************************************************************************/
805 /*                                                                        */
806 /*  FUNCTION                                               RELEASE        */
807 /*                                                                        */
808 /*    _nx_tcpserver_disconnect_present                     PORTABLE C     */
809 /*                                                           6.1          */
810 /*  AUTHOR                                                                */
811 /*                                                                        */
812 /*    Yuxin Zhou, Microsoft Corporation                                   */
813 /*                                                                        */
814 /*  DESCRIPTION                                                           */
815 /*                                                                        */
816 /*    This internal function is used for the TCP disconnect callback      */
817 /*    passed into nx_tcp_socket_create and is used to determine when      */
818 /*    a socket has been disconnected.                                     */
819 /*                                                                        */
820 /*  INPUT                                                                 */
821 /*                                                                        */
822 /*    socket_ptr                            Pointer to TCP socket         */
823 /*                                                                        */
824 /*  OUTPUT                                                                */
825 /*                                                                        */
826 /*    None                                                                */
827 /*                                                                        */
828 /*  CALLS                                                                 */
829 /*                                                                        */
830 /*    tx_event_flags_set                    Set thread event flag         */
831 /*                                                                        */
832 /*  CALLED BY                                                             */
833 /*                                                                        */
834 /*   TCP stack                                                            */
835 /*                                                                        */
836 /*  RELEASE HISTORY                                                       */
837 /*                                                                        */
838 /*    DATE              NAME                      DESCRIPTION             */
839 /*                                                                        */
840 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
841 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
842 /*                                            resulting in version 6.1    */
843 /*                                                                        */
844 /**************************************************************************/
_nx_tcpserver_disconnect_present(NX_TCP_SOCKET * socket_ptr)845 static VOID _nx_tcpserver_disconnect_present(NX_TCP_SOCKET *socket_ptr)
846 {
847 NX_TCPSERVER *server_ptr = socket_ptr -> nx_tcp_socket_reserved_ptr;
848 
849     /* Set the disconnect event flag. */
850     tx_event_flags_set(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_DISCONNECT, TX_OR);
851 }
852 
853 /**************************************************************************/
854 /*                                                                        */
855 /*  FUNCTION                                               RELEASE        */
856 /*                                                                        */
857 /*    _nx_tcpserver_timeout                                PORTABLE C     */
858 /*                                                           6.1          */
859 /*  AUTHOR                                                                */
860 /*                                                                        */
861 /*    Yuxin Zhou, Microsoft Corporation                                   */
862 /*                                                                        */
863 /*  DESCRIPTION                                                           */
864 /*                                                                        */
865 /*    This internal function is invoked whenever the internal timeout     */
866 /*    timer expires, and is passed into tx_timer_create as the callback.  */
867 /*                                                                        */
868 /*  INPUT                                                                 */
869 /*                                                                        */
870 /*    tcpserver_address                     Pointer to socket server      */
871 /*                                                                        */
872 /*  OUTPUT                                                                */
873 /*                                                                        */
874 /*    None                                                                */
875 /*                                                                        */
876 /*  CALLS                                                                 */
877 /*                                                                        */
878 /*    tx_event_flags_set                    Set thread event flag         */
879 /*                                                                        */
880 /*  CALLED BY                                                             */
881 /*                                                                        */
882 /*    ThreadX                                                             */
883 /*                                                                        */
884 /*  RELEASE HISTORY                                                       */
885 /*                                                                        */
886 /*    DATE              NAME                      DESCRIPTION             */
887 /*                                                                        */
888 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
889 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
890 /*                                            resulting in version 6.1    */
891 /*                                                                        */
892 /**************************************************************************/
_nx_tcpserver_timeout(ULONG tcpserver_address)893 static VOID _nx_tcpserver_timeout(ULONG tcpserver_address)
894 {
895 NX_TCPSERVER *server_ptr = (NX_TCPSERVER *)tcpserver_address;
896 
897     /* Set the timeout event flag. */
898     tx_event_flags_set(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_TIMEOUT, TX_OR);
899 }
900 
901 /**************************************************************************/
902 /*                                                                        */
903 /*  FUNCTION                                               RELEASE        */
904 /*                                                                        */
905 /*    _nx_tcpserver_connect_process                        PORTABLE C     */
906 /*                                                           6.1.11       */
907 /*  AUTHOR                                                                */
908 /*                                                                        */
909 /*    Yuxin Zhou, Microsoft Corporation                                   */
910 /*                                                                        */
911 /*  DESCRIPTION                                                           */
912 /*                                                                        */
913 /*    This internal function is invoked by the server thread whenever an  */
914 /*    incoming connection request is received. It establishes the TCP     */
915 /*    connection and if TLS is enabled, it begins the TLS handshake.      */
916 /*                                                                        */
917 /*  INPUT                                                                 */
918 /*                                                                        */
919 /*    server_ptr                            Pointer to socket server      */
920 /*                                                                        */
921 /*  OUTPUT                                                                */
922 /*                                                                        */
923 /*    None                                                                */
924 /*                                                                        */
925 /*  CALLS                                                                 */
926 /*                                                                        */
927 /*    _nx_tcpserver_session_allocate        Get socket for listening      */
928 /*    nx_tcp_server_socket_relisten         Relisten on existing socket   */
929 /*    nx_tcp_server_socket_accept           Accept incoming TCP request   */
930 /*    nx_secure_tls_session_start           Start TLS handshake           */
931 /*    nx_tcp_server_socket_unaccept         Clear accepted socket         */
932 /*    _nx_tcpserver_relisten                Re-listen on all sockets      */
933 /*                                                                        */
934 /*  CALLED BY                                                             */
935 /*                                                                        */
936 /*    _nx_tcpserver_thread_entry                                          */
937 /*                                                                        */
938 /*  RELEASE HISTORY                                                       */
939 /*                                                                        */
940 /*    DATE              NAME                      DESCRIPTION             */
941 /*                                                                        */
942 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
943 /*  09-30-2020     Yuxin Zhou               Modified comment(s), and      */
944 /*                                            fixed packet leak issue,    */
945 /*                                            resulting in version 6.1    */
946 /*  10-15-2021     Yuxin Zhou               Modified comment(s), and      */
947 /*                                            fixed TLS connection        */
948 /*                                            deadlock issue,             */
949 /*                                            resulting in version 6.1.9  */
950 /*  04-25-2022     Yuxin Zhou               Modified comment(s), and      */
951 /*                                            corrected the wait option   */
952 /*                                            of TLS connection,          */
953 /*                                            resulting in version 6.1.11 */
954 /*                                                                        */
955 /**************************************************************************/
_nx_tcpserver_connect_process(NX_TCPSERVER * server_ptr)956 static VOID _nx_tcpserver_connect_process(NX_TCPSERVER *server_ptr)
957 {
958 UINT            status;
959 NX_TCP_SESSION *session_ptr = NX_NULL;
960 
961     /* Is any socket listening? */
962     if(server_ptr -> nx_tcpserver_listen_session == NX_NULL)
963     {
964 
965         /* No. Check whether listen is done. */
966         if(server_ptr -> nx_tcpserver_listen_port == 0)
967         {
968             return;
969         }
970 
971         /* Get a socket to listen. */
972         status = _nx_tcpserver_session_allocate(server_ptr, &session_ptr);
973         if(status)
974         {
975             return;
976         }
977 
978         status = nx_tcp_server_socket_relisten(server_ptr -> nx_tcpserver_ip,
979                                                server_ptr -> nx_tcpserver_listen_port,
980                                                &session_ptr -> nx_tcp_session_socket);
981         if((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING))
982         {
983             return;
984         }
985 
986         /* Store listen socket. */
987         server_ptr -> nx_tcpserver_listen_session = session_ptr;
988     }
989     else if(server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket.nx_tcp_socket_state == NX_TCP_CLOSED)
990     {
991 
992         status = nx_tcp_server_socket_relisten(server_ptr -> nx_tcpserver_ip,
993                                                server_ptr -> nx_tcpserver_listen_port,
994                                                &session_ptr -> nx_tcp_session_socket);
995         if((status != NX_SUCCESS) && (status != NX_CONNECTION_PENDING))
996         {
997             return;
998         }
999     }
1000 
1001     /* If session is connected, just return. */
1002     if (server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_connected)
1003     {
1004         return;
1005     }
1006 
1007     /* Accept connection. */
1008     status = nx_tcp_server_socket_accept(&server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket, server_ptr -> nx_tcpserver_accept_wait_option);
1009 
1010     if(status == NX_SUCCESS)
1011     {
1012 
1013 #ifdef NX_TCPSERVER_ENABLE_TLS
1014         /* If TLS, start the TLS handshake. */
1015         if(server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_using_tls == NX_TRUE)
1016         {
1017             status = nx_secure_tls_session_start(&server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_tls_session,
1018                                                  &server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket, server_ptr -> nx_tcpserver_timeout * NX_IP_PERIODIC_RATE);
1019 
1020             if(status != NX_SUCCESS)
1021             {
1022                 nx_secure_tls_session_end(&server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_tls_session, NX_WAIT_FOREVER);
1023                 nx_tcp_socket_disconnect(&server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket, NX_NO_WAIT);
1024                 nx_tcp_server_socket_unaccept(&server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket);
1025             }
1026         }
1027 
1028         if (status == NX_SUCCESS)
1029 #endif
1030         {
1031 
1032             /* Set default expiration. */
1033             server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_expiration = server_ptr -> nx_tcpserver_timeout;
1034 
1035             if(server_ptr -> nx_tcpserver_new_connection)
1036             {
1037 
1038                 /* Invoke new connection callback. */
1039                 server_ptr -> nx_tcpserver_new_connection(server_ptr, server_ptr -> nx_tcpserver_listen_session);
1040             }
1041 
1042             /* Set connection flag to true. */
1043             server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_connected = NX_TRUE;
1044 
1045             /* Clear listen socket. */
1046             server_ptr -> nx_tcpserver_listen_session = NX_NULL;
1047         }
1048     }
1049     else
1050     {
1051         nx_tcp_server_socket_unaccept(&server_ptr -> nx_tcpserver_listen_session -> nx_tcp_session_socket);
1052     }
1053 
1054     /* Relisten */
1055     _nx_tcpserver_relisten(server_ptr);
1056 }
1057 
1058 /**************************************************************************/
1059 /*                                                                        */
1060 /*  FUNCTION                                               RELEASE        */
1061 /*                                                                        */
1062 /*    _nx_tcpserver_data_process                           PORTABLE C     */
1063 /*                                                           6.1          */
1064 /*  AUTHOR                                                                */
1065 /*                                                                        */
1066 /*    Yuxin Zhou, Microsoft Corporation                                   */
1067 /*                                                                        */
1068 /*  DESCRIPTION                                                           */
1069 /*                                                                        */
1070 /*    This internal function is invoked by the server thread whenever     */
1071 /*    data is received from the remote client. If the application passes  */
1072 /*    a receive callback to _nx_tcpserver_create, it will be invoked here.*/
1073 /*                                                                        */
1074 /*  INPUT                                                                 */
1075 /*                                                                        */
1076 /*    server_ptr                            Pointer to socket server      */
1077 /*                                                                        */
1078 /*  OUTPUT                                                                */
1079 /*                                                                        */
1080 /*    None                                                                */
1081 /*                                                                        */
1082 /*  CALLS                                                                 */
1083 /*                                                                        */
1084 /*    nx_tcpserver_receive_data             Callback to process data      */
1085 /*                                                                        */
1086 /*  CALLED BY                                                             */
1087 /*                                                                        */
1088 /*    _nx_tcpserver_thread_entry                                          */
1089 /*                                                                        */
1090 /*  RELEASE HISTORY                                                       */
1091 /*                                                                        */
1092 /*    DATE              NAME                      DESCRIPTION             */
1093 /*                                                                        */
1094 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
1095 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
1096 /*                                            resulting in version 6.1    */
1097 /*                                                                        */
1098 /**************************************************************************/
_nx_tcpserver_data_process(NX_TCPSERVER * server_ptr)1099 static VOID _nx_tcpserver_data_process(NX_TCPSERVER *server_ptr)
1100 {
1101 UINT            i;
1102 NX_TCP_SOCKET  *socket_ptr;
1103 
1104     /* Do nothing if callback is not set. */
1105     if(server_ptr -> nx_tcpserver_receive_data == NX_NULL)
1106     {
1107         return;
1108     }
1109 
1110     /* Initialize TCP sockets. */
1111     for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++)
1112     {
1113         socket_ptr = &(server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket);
1114 
1115         if(socket_ptr -> nx_tcp_socket_receive_queue_count)
1116         {
1117 
1118             /* Reset default expiration. */
1119             server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_expiration = server_ptr -> nx_tcpserver_timeout;
1120 
1121             /* Invoke receive data callback. */
1122             server_ptr -> nx_tcpserver_receive_data(server_ptr, &server_ptr -> nx_tcpserver_sessions[i]);
1123 
1124             /* Relisten */
1125             _nx_tcpserver_relisten(server_ptr);
1126         }
1127     }
1128 }
1129 
1130 /**************************************************************************/
1131 /*                                                                        */
1132 /*  FUNCTION                                               RELEASE        */
1133 /*                                                                        */
1134 /*    _nx_tcpserver_disconnect_process                     PORTABLE C     */
1135 /*                                                           6.1          */
1136 /*  AUTHOR                                                                */
1137 /*                                                                        */
1138 /*    Yuxin Zhou, Microsoft Corporation                                   */
1139 /*                                                                        */
1140 /*  DESCRIPTION                                                           */
1141 /*                                                                        */
1142 /*    This internal function is invoked by the server thread whenever     */
1143 /*    a socket is disconnected. If the application passes  a disconnect   */
1144 /*    callback to _nx_tcpserver_create, it will be invoked here.          */
1145 /*                                                                        */
1146 /*  INPUT                                                                 */
1147 /*                                                                        */
1148 /*    server_ptr                            Pointer to socket server      */
1149 /*                                                                        */
1150 /*  OUTPUT                                                                */
1151 /*                                                                        */
1152 /*    None                                                                */
1153 /*                                                                        */
1154 /*  CALLS                                                                 */
1155 /*                                                                        */
1156 /*    nx_tcpserver_connection_end           Callback for disconnections   */
1157 /*    _nx_tcpserver_relisten                Re-listen on free sockets     */
1158 /*                                                                        */
1159 /*  CALLED BY                                                             */
1160 /*                                                                        */
1161 /*    _nx_tcpserver_thread_entry                                          */
1162 /*                                                                        */
1163 /*  RELEASE HISTORY                                                       */
1164 /*                                                                        */
1165 /*    DATE              NAME                      DESCRIPTION             */
1166 /*                                                                        */
1167 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
1168 /*  09-30-2020     Yuxin Zhou               Modified comment(s), and      */
1169 /*                                            fixed packet leak issue,    */
1170 /*                                            resulting in version 6.1    */
1171 /*                                                                        */
1172 /**************************************************************************/
_nx_tcpserver_disconnect_process(NX_TCPSERVER * server_ptr)1173 static VOID _nx_tcpserver_disconnect_process(NX_TCPSERVER *server_ptr)
1174 {
1175 UINT            i;
1176 NX_TCP_SOCKET  *socket_ptr;
1177 
1178     /* Do nothing if callback is not set. */
1179     if(server_ptr -> nx_tcpserver_connection_end == NX_NULL)
1180     {
1181         return;
1182     }
1183 
1184     /* Initialize TCP sockets. */
1185     for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++)
1186     {
1187         socket_ptr = &(server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket);
1188 
1189         if((socket_ptr -> nx_tcp_socket_state > NX_TCP_ESTABLISHED) ||
1190            ((socket_ptr -> nx_tcp_socket_state < NX_TCP_SYN_SENT) &&
1191              server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_expiration))
1192         {
1193 
1194             /* Invoke disconnect callback. */
1195             server_ptr -> nx_tcpserver_connection_end(server_ptr, &server_ptr -> nx_tcpserver_sessions[i]);
1196 
1197             /* Reset epiration of session. */
1198             server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_expiration = 0;
1199 
1200             /* Set connection flag to false. */
1201             server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_connected = NX_FALSE;
1202 
1203             /* Relisten */
1204             _nx_tcpserver_relisten(server_ptr);
1205         }
1206     }
1207 }
1208 
1209 /**************************************************************************/
1210 /*                                                                        */
1211 /*  FUNCTION                                               RELEASE        */
1212 /*                                                                        */
1213 /*    _nx_tcpserver_timeout_process                        PORTABLE C     */
1214 /*                                                           6.1          */
1215 /*  AUTHOR                                                                */
1216 /*                                                                        */
1217 /*    Yuxin Zhou, Microsoft Corporation                                   */
1218 /*                                                                        */
1219 /*  DESCRIPTION                                                           */
1220 /*                                                                        */
1221 /*    This internal function is invoked by the server thread whenever     */
1222 /*    a timeout event is encountered (triggered by the timeout timer).    */
1223 /*    If the application passes  a disconnect callback to                 */
1224 /*    _nx_tcpserver_create, it will be invoked here.                      */
1225 /*                                                                        */
1226 /*  INPUT                                                                 */
1227 /*                                                                        */
1228 /*    server_ptr                            Pointer to socket server      */
1229 /*                                                                        */
1230 /*  OUTPUT                                                                */
1231 /*                                                                        */
1232 /*    None                                                                */
1233 /*                                                                        */
1234 /*  CALLS                                                                 */
1235 /*                                                                        */
1236 /*    nx_tcpserver_connection_timeout       Callback to process timeout   */
1237 /*    _nx_tcpserver_relisten                Re-listen on free sockets     */
1238 /*                                                                        */
1239 /*  CALLED BY                                                             */
1240 /*                                                                        */
1241 /*    _nx_tcpserver_thread_entry                                          */
1242 /*                                                                        */
1243 /*  RELEASE HISTORY                                                       */
1244 /*                                                                        */
1245 /*    DATE              NAME                      DESCRIPTION             */
1246 /*                                                                        */
1247 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
1248 /*  09-30-2020     Yuxin Zhou               Modified comment(s), and      */
1249 /*                                            fixed packet leak issue,    */
1250 /*                                            resulting in version 6.1    */
1251 /*                                                                        */
1252 /**************************************************************************/
_nx_tcpserver_timeout_process(NX_TCPSERVER * server_ptr)1253 static VOID _nx_tcpserver_timeout_process(NX_TCPSERVER *server_ptr)
1254 {
1255 UINT            i;
1256 NX_TCP_SESSION *session_ptr;
1257 
1258     /* Do nothing if callback is not set. */
1259     if(server_ptr -> nx_tcpserver_connection_timeout == NX_NULL)
1260     {
1261         return;
1262     }
1263 
1264     /* Initialize TCP sockets. */
1265     for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++)
1266     {
1267         session_ptr = &server_ptr -> nx_tcpserver_sessions[i];
1268 
1269         /* Skip socket that is not used. */
1270         if(session_ptr -> nx_tcp_session_socket.nx_tcp_socket_state == NX_TCP_CLOSED)
1271         {
1272             continue;
1273         }
1274 
1275         /* Skip socket that is already timeout. */
1276         if(session_ptr -> nx_tcp_session_expiration == 0)
1277         {
1278             continue;
1279         }
1280 
1281         /* Is the session timeout? */
1282         if(session_ptr -> nx_tcp_session_expiration > NX_TCPSERVER_TIMEOUT_PERIOD)
1283             session_ptr -> nx_tcp_session_expiration -= NX_TCPSERVER_TIMEOUT_PERIOD;
1284         else
1285         {
1286 
1287             session_ptr -> nx_tcp_session_expiration = 0;
1288 
1289             /* Invoke timeout callback. */
1290             server_ptr -> nx_tcpserver_connection_timeout(server_ptr, &server_ptr -> nx_tcpserver_sessions[i]);
1291 
1292             /* Set connection flag to false. */
1293             session_ptr -> nx_tcp_session_connected = NX_FALSE;
1294 
1295             /* Relisten */
1296             _nx_tcpserver_relisten(server_ptr);
1297         }
1298     }
1299 }
1300 
1301 /**************************************************************************/
1302 /*                                                                        */
1303 /*  FUNCTION                                               RELEASE        */
1304 /*                                                                        */
1305 /*    _nx_tcpserver_thread_entry                           PORTABLE C     */
1306 /*                                                           6.1          */
1307 /*  AUTHOR                                                                */
1308 /*                                                                        */
1309 /*    Yuxin Zhou, Microsoft Corporation                                   */
1310 /*                                                                        */
1311 /*  DESCRIPTION                                                           */
1312 /*                                                                        */
1313 /*    This internal function is the entry point for the socket server     */
1314 /*    thread. It continually loops, checking the event flags and          */
1315 /*    dispatching processing when events are encountered.                 */
1316 /*                                                                        */
1317 /*  INPUT                                                                 */
1318 /*                                                                        */
1319 /*    tcpserver_address                     Pointer to socket server      */
1320 /*                                                                        */
1321 /*  OUTPUT                                                                */
1322 /*                                                                        */
1323 /*    None                                                                */
1324 /*                                                                        */
1325 /*  CALLS                                                                 */
1326 /*                                                                        */
1327 /*    _nx_tcpserver_connect_process         Process new connection        */
1328 /*    _nx_tcpserver_data_process            Process received data         */
1329 /*    _nx_tcpserver_disconnect_process      Process disconnection event   */
1330 /*    _nx_tcpserver_timeout_process         Process server timeout        */
1331 /*                                                                        */
1332 /*  CALLED BY                                                             */
1333 /*                                                                        */
1334 /*    ThreadX                                                             */
1335 /*                                                                        */
1336 /*  RELEASE HISTORY                                                       */
1337 /*                                                                        */
1338 /*    DATE              NAME                      DESCRIPTION             */
1339 /*                                                                        */
1340 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
1341 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
1342 /*                                            resulting in version 6.1    */
1343 /*                                                                        */
1344 /**************************************************************************/
_nx_tcpserver_thread_entry(ULONG tcpserver_address)1345 static VOID _nx_tcpserver_thread_entry(ULONG tcpserver_address)
1346 {
1347 ULONG           events;
1348 UINT            status;
1349 NX_TCPSERVER   *server_ptr = (NX_TCPSERVER *)tcpserver_address;
1350 
1351 
1352     /* Loop to process events. */
1353     while(1)
1354     {
1355         status = tx_event_flags_get(&server_ptr -> nx_tcpserver_event_flags, NX_TCPSERVER_ANY_EVENT, TX_OR_CLEAR, &events, TX_WAIT_FOREVER);
1356 
1357         /* Check the return status. */
1358         if(status)
1359         {
1360 
1361             /* If an error occurs, simply continue the loop. */
1362             continue;
1363         }
1364 
1365         /* Otherwise, an event is present. Process according to the event. */
1366 
1367         /* Check for a connect event. */
1368         if(events & NX_TCPSERVER_CONNECT)
1369         {
1370 
1371             /* Call the connect processing. */
1372             _nx_tcpserver_connect_process(server_ptr);
1373         }
1374 
1375 
1376         /* Check for a data event. */
1377         if(events & NX_TCPSERVER_DATA)
1378         {
1379 
1380             /* Call the receive data processing. */
1381             _nx_tcpserver_data_process(server_ptr);
1382         }
1383 
1384 
1385         /* Check for a disconnect event. */
1386         if(events & NX_TCPSERVER_DISCONNECT)
1387         {
1388 
1389             /* Call the disconnect processing. */
1390             _nx_tcpserver_disconnect_process(server_ptr);
1391         }
1392 
1393 
1394         /* Check for a timeout event. */
1395         if(events & NX_TCPSERVER_TIMEOUT)
1396         {
1397 
1398             /* Call the disconnect processing. */
1399             _nx_tcpserver_timeout_process(server_ptr);
1400         }
1401 
1402     }
1403 }
1404 
1405 
1406 /**************************************************************************/
1407 /*                                                                        */
1408 /*  FUNCTION                                               RELEASE        */
1409 /*                                                                        */
1410 /*    _nx_tcpserver_stop                                   PORTABLE C     */
1411 /*                                                           6.1          */
1412 /*  AUTHOR                                                                */
1413 /*                                                                        */
1414 /*    Yuxin Zhou, Microsoft Corporation                                   */
1415 /*                                                                        */
1416 /*  DESCRIPTION                                                           */
1417 /*                                                                        */
1418 /*    This function is called by an application to stop a currently       */
1419 /*    running socket server. It shuts down the server thread and stops    */
1420 /*    listening on all internal TCP sockets.                              */
1421 /*                                                                        */
1422 /*  INPUT                                                                 */
1423 /*                                                                        */
1424 /*    server_ptr                            Pointer to server structure   */
1425 /*                                                                        */
1426 /*  OUTPUT                                                                */
1427 /*                                                                        */
1428 /*    status                                Completion status             */
1429 /*                                                                        */
1430 /*  CALLS                                                                 */
1431 /*                                                                        */
1432 /*    tx_thread_suspend                     Stop server thread            */
1433 /*    tx_timer_deactivate                   Stop server timeout timer     */
1434 /*    nx_tcp_server_socket_unlisten         Stop listening on TCP socket  */
1435 /*                                                                        */
1436 /*  CALLED BY                                                             */
1437 /*                                                                        */
1438 /*   Application code                                                     */
1439 /*                                                                        */
1440 /*  RELEASE HISTORY                                                       */
1441 /*                                                                        */
1442 /*    DATE              NAME                      DESCRIPTION             */
1443 /*                                                                        */
1444 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
1445 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
1446 /*                                            resulting in version 6.1    */
1447 /*                                                                        */
1448 /**************************************************************************/
_nx_tcpserver_stop(NX_TCPSERVER * server_ptr)1449 UINT _nx_tcpserver_stop(NX_TCPSERVER *server_ptr)
1450 {
1451 UINT status;
1452 
1453     /* Check whether listen is done. */
1454     if(server_ptr -> nx_tcpserver_listen_port == 0)
1455         return NX_TCPSERVER_FAIL;
1456 
1457     /* Suspend thread. */
1458     tx_thread_suspend(&server_ptr -> nx_tcpserver_thread);
1459 
1460     /* Deactivate timer. */
1461     tx_timer_deactivate(&server_ptr -> nx_tcpserver_timer);
1462 
1463     /* Unlisten. */
1464     status = nx_tcp_server_socket_unlisten(server_ptr -> nx_tcpserver_ip, server_ptr -> nx_tcpserver_listen_port);
1465 
1466     if(status == NX_SUCCESS)
1467     {
1468 
1469         /* Clear. */
1470         server_ptr -> nx_tcpserver_listen_port = 0;
1471         server_ptr -> nx_tcpserver_listen_session = NX_NULL;
1472     }
1473 
1474     return status;
1475 }
1476 
1477 /**************************************************************************/
1478 /*                                                                        */
1479 /*  FUNCTION                                               RELEASE        */
1480 /*                                                                        */
1481 /*    _nx_tcpserver_delete                                 PORTABLE C     */
1482 /*                                                           6.1          */
1483 /*  AUTHOR                                                                */
1484 /*                                                                        */
1485 /*    Yuxin Zhou, Microsoft Corporation                                   */
1486 /*                                                                        */
1487 /*  DESCRIPTION                                                           */
1488 /*                                                                        */
1489 /*    This function is called by an application to clean up a previously  */
1490 /*    created socket server. It cleans up the server thread and closes    */
1491 /*    deletes all internal TCP sockets and TLS sessions.                  */
1492 /*                                                                        */
1493 /*  INPUT                                                                 */
1494 /*                                                                        */
1495 /*    server_ptr                            Pointer to server structure   */
1496 /*                                                                        */
1497 /*  OUTPUT                                                                */
1498 /*                                                                        */
1499 /*    status                                Completion status             */
1500 /*                                                                        */
1501 /*  CALLS                                                                 */
1502 /*                                                                        */
1503 /*    tx_thread_terminate                   Stop server thread            */
1504 /*    tx_thread_delete                      Stop server timeout timer     */
1505 /*    tx_event_flags_delete                 Delete server event flags     */
1506 /*    tx_timer_deactivate                   Deactivate timeout timer      */
1507 /*    tx_timer_delete                       Delete timeout timer          */
1508 /*    nx_tcp_socket_disconnect              Disconnect TCP sockets        */
1509 /*    nx_tcp_server_socket_unaccept         Stop listening on TCP sockets */
1510 /*    nx_tcp_socket_delete                  Delete TCP socket             */
1511 /*                                                                        */
1512 /*  CALLED BY                                                             */
1513 /*                                                                        */
1514 /*   Application code                                                     */
1515 /*                                                                        */
1516 /*  RELEASE HISTORY                                                       */
1517 /*                                                                        */
1518 /*    DATE              NAME                      DESCRIPTION             */
1519 /*                                                                        */
1520 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
1521 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
1522 /*                                            resulting in version 6.1    */
1523 /*                                                                        */
1524 /**************************************************************************/
_nx_tcpserver_delete(NX_TCPSERVER * server_ptr)1525 UINT _nx_tcpserver_delete(NX_TCPSERVER *server_ptr)
1526 {
1527 UINT            i;
1528 NX_TCP_SOCKET  *socket_ptr;
1529 
1530     /* Terminate server thread. */
1531     tx_thread_terminate(&server_ptr -> nx_tcpserver_thread);
1532 
1533     /* Delete server thread. */
1534     tx_thread_delete(&server_ptr -> nx_tcpserver_thread);
1535 
1536     /* Delete the event flag group */
1537     tx_event_flags_delete(&server_ptr -> nx_tcpserver_event_flags);
1538 
1539     /* Deactivate and delete timer. */
1540     tx_timer_deactivate(&server_ptr -> nx_tcpserver_timer);
1541     tx_timer_delete(&server_ptr -> nx_tcpserver_timer);
1542 
1543     /* Delete all opened sockets. */
1544     for(i = 0; i < server_ptr -> nx_tcpserver_sessions_count; i++)
1545     {
1546 
1547         /* Get socket pointer. */
1548         socket_ptr = &server_ptr -> nx_tcpserver_sessions[i].nx_tcp_session_socket;
1549 
1550         /* Disconnect the socket. */
1551         nx_tcp_socket_disconnect(socket_ptr, NX_NO_WAIT);
1552 
1553         /* unaccept the socket. */
1554         nx_tcp_server_socket_unaccept(socket_ptr);
1555 
1556         /* Delete the socket. */
1557         nx_tcp_socket_delete(socket_ptr);
1558     }
1559 
1560     /* Return successful compeletion. */
1561     return NX_SUCCESS;
1562 }
1563