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