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 /**   Transmission Control Protocol (TCP)                                 */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define NX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 
27 #include "nx_api.h"
28 #include "nx_ip.h"
29 #include "nx_tcp.h"
30 #include "tx_thread.h"
31 
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _nx_tcp_server_socket_accept                        PORTABLE C      */
38 /*                                                           6.1          */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Yuxin Zhou, Microsoft Corporation                                   */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*    This function sets up the server socket after an active connection  */
46 /*    request was received.                                               */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    socket_ptr                            Pointer to new TCP socket     */
51 /*    wait_option                           Suspension option             */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    status                                Completion status             */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    _nx_tcp_packet_send_syn               Send SYN message              */
60 /*    _nx_tcp_socket_thread_suspend         Suspend thread for connection */
61 /*    tx_mutex_get                          Obtain a protection mutex     */
62 /*    tx_mutex_put                          Release a protection mutex    */
63 /*    NX_RAND                               Random number for sequence    */
64 /*                                                                        */
65 /*  CALLED BY                                                             */
66 /*                                                                        */
67 /*    Application Code                                                    */
68 /*                                                                        */
69 /*  RELEASE HISTORY                                                       */
70 /*                                                                        */
71 /*    DATE              NAME                      DESCRIPTION             */
72 /*                                                                        */
73 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
74 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
75 /*                                            resulting in version 6.1    */
76 /*                                                                        */
77 /**************************************************************************/
_nx_tcp_server_socket_accept(NX_TCP_SOCKET * socket_ptr,ULONG wait_option)78 UINT  _nx_tcp_server_socket_accept(NX_TCP_SOCKET *socket_ptr, ULONG wait_option)
79 {
80 
81 NX_IP *ip_ptr;
82 
83 
84     /* Pickup the associated IP structure.  */
85     ip_ptr =  socket_ptr -> nx_tcp_socket_ip_ptr;
86 
87     /* If trace is enabled, insert this event into the trace buffer.  */
88     NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SERVER_SOCKET_ACCEPT, ip_ptr, socket_ptr, wait_option, socket_ptr -> nx_tcp_socket_state, NX_TRACE_TCP_EVENTS, 0, 0);
89 
90     /* Check if the socket has already made a connection, return successful outcome to accept(). */
91     if (socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED)
92     {
93         return(NX_SUCCESS);
94     }
95 
96     /* Determine if the socket is still in the listen state or has sent a SYN packet out already
97        from a previous accept() call on this socket.  */
98     if ((socket_ptr -> nx_tcp_socket_state != NX_TCP_LISTEN_STATE) && (socket_ptr -> nx_tcp_socket_state != NX_TCP_SYN_RECEIVED))
99     {
100 
101         /* Socket has either been closed or in the process of closing*/
102         return(NX_NOT_LISTEN_STATE);
103     }
104 
105 
106     /* Obtain the IP mutex so we can initiate accept processing for this socket.  */
107     tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
108 
109     if (socket_ptr -> nx_tcp_socket_state == NX_TCP_LISTEN_STATE)
110     {
111 
112         /* Setup the initial sequence number.  */
113         if (socket_ptr -> nx_tcp_socket_tx_sequence == 0)
114         {
115             socket_ptr -> nx_tcp_socket_tx_sequence =  (((ULONG)NX_RAND()) << NX_SHIFT_BY_16) & 0xFFFFFFFF;
116             socket_ptr -> nx_tcp_socket_tx_sequence |= (ULONG)NX_RAND();
117         }
118         else
119         {
120             socket_ptr -> nx_tcp_socket_tx_sequence =  socket_ptr -> nx_tcp_socket_tx_sequence + ((ULONG)(((ULONG)0x10000))) + ((ULONG)NX_RAND());
121         }
122 
123         /* Ensure the rx window size logic is reset.  */
124         socket_ptr -> nx_tcp_socket_rx_window_current =    socket_ptr -> nx_tcp_socket_rx_window_default;
125         socket_ptr -> nx_tcp_socket_rx_window_last_sent =  socket_ptr -> nx_tcp_socket_rx_window_default;
126 
127         /* If trace is enabled, insert this event into the trace buffer.  */
128         NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_SYN_RECEIVED, NX_TRACE_INTERNAL_EVENTS, 0, 0);
129 
130         /* Move the TCP state to Sequence Received, the next state of a passive open.  */
131         socket_ptr -> nx_tcp_socket_state =  NX_TCP_SYN_RECEIVED;
132 
133         /* Clear the FIN received flag.  */
134         socket_ptr -> nx_tcp_socket_fin_received =  NX_FALSE;
135         socket_ptr -> nx_tcp_socket_fin_acked =  NX_FALSE;
136 
137         /* Determine if the listen command has completed.  This can be detected by checking
138            to see if the socket is bound.  If it is bound and still in the listen state, then
139            we know that this service is being called after a client connection request was
140            received.  */
141         if (socket_ptr -> nx_tcp_socket_bound_next)
142         {
143 
144             /* Send a SYN message back to establish the connection, but increment the ACK first.  */
145             socket_ptr -> nx_tcp_socket_rx_sequence++;
146 
147             /* Increment the sequence number.  */
148             socket_ptr -> nx_tcp_socket_tx_sequence++;
149 
150             /* Setup a timeout so the connection attempt can be sent again.  */
151 
152             socket_ptr -> nx_tcp_socket_timeout =          socket_ptr -> nx_tcp_socket_timeout_rate;
153             socket_ptr -> nx_tcp_socket_timeout_retries =  0;
154 
155             /* CLEANUP: Clean up any existing socket data before making a new connection. */
156             socket_ptr -> nx_tcp_socket_tx_window_congestion = 0;
157             socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0;
158             socket_ptr -> nx_tcp_socket_packets_sent = 0;
159             socket_ptr -> nx_tcp_socket_bytes_sent = 0;
160             socket_ptr -> nx_tcp_socket_packets_received = 0;
161             socket_ptr -> nx_tcp_socket_bytes_received = 0;
162             socket_ptr -> nx_tcp_socket_retransmit_packets = 0;
163             socket_ptr -> nx_tcp_socket_checksum_errors = 0;
164             socket_ptr -> nx_tcp_socket_transmit_sent_head  =  NX_NULL;
165             socket_ptr -> nx_tcp_socket_transmit_sent_tail  =  NX_NULL;
166             socket_ptr -> nx_tcp_socket_transmit_sent_count =  0;
167             socket_ptr -> nx_tcp_socket_receive_queue_count =  0;
168             socket_ptr -> nx_tcp_socket_receive_queue_head  =  NX_NULL;
169             socket_ptr -> nx_tcp_socket_receive_queue_tail  =  NX_NULL;
170 
171             /* Send the SYN+ACK message.  */
172             _nx_tcp_packet_send_syn(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1));
173         }
174         else
175         {
176             socket_ptr -> nx_tcp_socket_timeout = 0;
177         }
178     }
179 
180     /* Determine if the wait option is specified.  If so, suspend the calling thread.
181        Otherwise, return an in progress status.  */
182     if ((wait_option) && (_tx_thread_current_ptr != &(ip_ptr -> nx_ip_thread)))
183     {
184 
185         /* Suspend the thread on this socket's receive queue.  */
186         _nx_tcp_socket_thread_suspend(&(socket_ptr -> nx_tcp_socket_connect_suspended_thread), _nx_tcp_connect_cleanup,
187                                       socket_ptr, &(ip_ptr -> nx_ip_protection), wait_option);
188 
189         /* Check if the socket connection has failed.  */
190         if (_tx_thread_current_ptr -> tx_thread_suspend_status)
191         {
192 
193             /* If trace is enabled, insert this event into the trace buffer.  */
194             NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_LISTEN_STATE, NX_TRACE_INTERNAL_EVENTS, 0, 0);
195 
196             /* Yes, socket connection has failed.  Return to the
197                listen state so it can be tried again.  */
198             socket_ptr -> nx_tcp_socket_state =  NX_TCP_LISTEN_STATE;
199 
200             /* Socket is not active. Clear the timeout. */
201             socket_ptr -> nx_tcp_socket_timeout =  0;
202         }
203 
204         /* If not, just return the status.  */
205         return(_tx_thread_current_ptr -> tx_thread_suspend_status);
206     }
207     else
208     {
209 
210         /* No suspension is request, just release protection and return to the caller.  */
211 
212         /* Release the IP protection.  */
213         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
214 
215         /* Return in-progress completion status.  */
216         return(NX_IN_PROGRESS);
217     }
218 }
219 
220