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