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