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