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