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_tcp.h"
29 #include "nx_ipv6.h"
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _nx_tcp_server_socket_unaccept PORTABLE C */
36 /* 6.1 */
37 /* AUTHOR */
38 /* */
39 /* Yuxin Zhou, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function removes the server socket from association with the */
44 /* port receiving an earlier passive connection. It is left in a */
45 /* state identical to the state after it was created. */
46 /* */
47 /* INPUT */
48 /* */
49 /* socket_ptr Pointer to new TCP socket */
50 /* */
51 /* OUTPUT */
52 /* */
53 /* status Completion status */
54 /* */
55 /* CALLS */
56 /* */
57 /* _nx_tcp_socket_receive_queue_flush Release all receive packets */
58 /* tx_mutex_get Obtain a protection mutex */
59 /* tx_mutex_put Release a protection mutex */
60 /* */
61 /* CALLED BY */
62 /* */
63 /* Application Code */
64 /* */
65 /* RELEASE HISTORY */
66 /* */
67 /* DATE NAME DESCRIPTION */
68 /* */
69 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
70 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
71 /* resulting in version 6.1 */
72 /* */
73 /**************************************************************************/
_nx_tcp_server_socket_unaccept(NX_TCP_SOCKET * socket_ptr)74 UINT _nx_tcp_server_socket_unaccept(NX_TCP_SOCKET *socket_ptr)
75 {
76
77 struct NX_TCP_LISTEN_STRUCT *listen_ptr;
78 NX_IP *ip_ptr;
79 UINT index;
80 UINT port;
81
82
83 /* Pickup the associated IP structure. */
84 ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr;
85
86 /* If trace is enabled, insert this event into the trace buffer. */
87 NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SERVER_SOCKET_UNACCEPT, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, 0, NX_TRACE_TCP_EVENTS, 0, 0);
88
89 /* Obtain the IP mutex so we can access the IP and socket data structures. */
90 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
91
92 /* Determine if the socket is in a state of disconnect. */
93 if ((socket_ptr -> nx_tcp_socket_state >= NX_TCP_CLOSE_WAIT) ||
94 ((socket_ptr -> nx_tcp_socket_state == NX_TCP_CLOSED) && (socket_ptr -> nx_tcp_socket_bound_next)))
95 {
96
97 /* If trace is enabled, insert this event into the trace buffer. */
98 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);
99
100 /* Force to the listen state. */
101 socket_ptr -> nx_tcp_socket_state = NX_TCP_LISTEN_STATE;
102
103 /* Ensure the connect information is cleared. */
104 socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version = 0;
105 #ifdef FEATURE_NX_IPV6
106 /* Zero out the IP address entry. */
107 SET_UNSPECIFIED_ADDRESS(socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_address.v6);
108 #else /* FEATURE_NX_IPV6 */
109 socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_address.v4 = 0;
110 #endif /* FEATURE_NX_IPV6 */
111
112 socket_ptr -> nx_tcp_socket_connect_port = 0;
113 }
114
115 /* Determine if the socket is in the listen state now. */
116 if (socket_ptr -> nx_tcp_socket_state != NX_TCP_LISTEN_STATE)
117 {
118
119 /* Release the IP protection. */
120 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
121
122 /* Return an error code. */
123 return(NX_NOT_LISTEN_STATE);
124 }
125
126 /* Check for a thread suspended for disconnect processing to complete. */
127 if (socket_ptr -> nx_tcp_socket_disconnect_suspended_thread)
128 {
129
130 /* Call the disconnect thread suspension cleanup routine. */
131 _nx_tcp_disconnect_cleanup(socket_ptr -> nx_tcp_socket_disconnect_suspended_thread NX_CLEANUP_ARGUMENT);
132 }
133
134 /* Remove the TCP socket form the associated port. */
135
136 /* Pickup the port number in the TCP socket structure. */
137 port = socket_ptr -> nx_tcp_socket_port;
138
139 /* Calculate the hash index in the TCP port array of the associated IP instance. */
140 index = (UINT)((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK);
141
142 /* Determine if this is the only socket bound on this port list. */
143 if (socket_ptr -> nx_tcp_socket_bound_next == socket_ptr)
144 {
145
146 /* Yes, this is the only socket on the port list. */
147
148 /* Clear the list head pointer and the next pointer in the socket. */
149 ip_ptr -> nx_ip_tcp_port_table[index] = NX_NULL;
150 socket_ptr -> nx_tcp_socket_bound_next = NX_NULL;
151 }
152 else if (socket_ptr -> nx_tcp_socket_bound_next)
153 {
154
155 /* Relink the neighbors of this TCP socket. */
156
157 /* Update the links of the adjacent sockets. */
158 (socket_ptr -> nx_tcp_socket_bound_next) -> nx_tcp_socket_bound_previous = socket_ptr -> nx_tcp_socket_bound_previous;
159 (socket_ptr -> nx_tcp_socket_bound_previous) -> nx_tcp_socket_bound_next = socket_ptr -> nx_tcp_socket_bound_next;
160
161 /* Determine if the head of the port list points to the socket being removed.
162 If so, we need to move the head pointer. */
163 if (ip_ptr -> nx_ip_tcp_port_table[index] == socket_ptr)
164 {
165
166 /* Yes, we need to move the port list head pointer. */
167 ip_ptr -> nx_ip_tcp_port_table[index] = socket_ptr -> nx_tcp_socket_bound_next;
168 }
169
170 /* Clear the next pointer in the socket to indicate it is no longer bound. */
171 socket_ptr -> nx_tcp_socket_bound_next = NX_NULL;
172 }
173 else
174 {
175
176 /* Not bound, so search through the active listen requests to see if this
177 socket is an active listen socket. */
178 listen_ptr = ip_ptr -> nx_ip_tcp_active_listen_requests;
179 if (listen_ptr)
180 {
181
182 /* Search the active listen requests for this port. */
183 do
184 {
185
186 /* Determine if we are releasing a socket that is listening. */
187 if (listen_ptr -> nx_tcp_listen_socket_ptr == socket_ptr)
188 {
189
190 /* Remove the socket from the listener. A relisten will be required to receive another
191 connection. */
192 listen_ptr -> nx_tcp_listen_socket_ptr = NX_NULL;
193 break;
194 }
195
196 /* Move to the next listen request. */
197 listen_ptr = listen_ptr -> nx_tcp_listen_next;
198 } while (listen_ptr != ip_ptr -> nx_ip_tcp_active_listen_requests);
199 }
200 }
201
202 /* If trace is enabled, insert this event into the trace buffer. */
203 NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0);
204
205 /* Adjust the socket back to default states. */
206 socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED;
207 socket_ptr -> nx_tcp_socket_client_type = NX_TRUE;
208
209 /* Socket is no longer active. Clear the timeout. */
210 socket_ptr -> nx_tcp_socket_timeout = 0;
211
212 /* The socket is off the bound list... we need to check for queued receive packets and
213 if found they need to be released. */
214 if (socket_ptr -> nx_tcp_socket_receive_queue_count)
215 {
216
217 /* Release queued receive packets. */
218 _nx_tcp_socket_receive_queue_flush(socket_ptr);
219 }
220
221 /* Release the IP protection. */
222 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
223
224 /* Return success. */
225 return(NX_SUCCESS);
226 }
227
228