xref: /aosp_15_r20/external/cronet/third_party/apache-portable-runtime/src/network_io/win32/sockopt.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "apr_arch_networkio.h"
18 #include "apr_arch_misc.h" /* apr_os_level */
19 #include "apr_network_io.h"
20 #include "apr_general.h"
21 #include "apr_strings.h"
22 #include <string.h>
23 
24 /* IPV6_V6ONLY is missing from pre-Windows 2008 SDK as well as MinGW
25  * (at least up through 1.0.16).
26  * Runtime support is a separate issue.
27  */
28 #ifndef IPV6_V6ONLY
29 #define IPV6_V6ONLY 27
30 #endif
31 
soblock(SOCKET sd)32 static apr_status_t soblock(SOCKET sd)
33 {
34     u_long zero = 0;
35 
36     if (ioctlsocket(sd, FIONBIO, &zero) == SOCKET_ERROR) {
37         return apr_get_netos_error();
38     }
39     return APR_SUCCESS;
40 }
41 
sononblock(SOCKET sd)42 static apr_status_t sononblock(SOCKET sd)
43 {
44     u_long one = 1;
45 
46     if (ioctlsocket(sd, FIONBIO, &one) == SOCKET_ERROR) {
47         return apr_get_netos_error();
48     }
49     return APR_SUCCESS;
50 }
51 
52 
apr_socket_timeout_set(apr_socket_t * sock,apr_interval_time_t t)53 APR_DECLARE(apr_status_t) apr_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
54 {
55     apr_status_t stat;
56 
57     if (t == 0) {
58         /* Set the socket non-blocking if it was previously blocking */
59         if (sock->timeout != 0) {
60             if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS)
61                 return stat;
62         }
63     }
64     else if (t > 0) {
65         /* Set the socket to blocking if it was previously non-blocking */
66         if (sock->timeout == 0 || apr_is_option_set(sock, APR_SO_NONBLOCK)) {
67             if ((stat = soblock(sock->socketdes)) != APR_SUCCESS)
68                 return stat;
69             apr_set_option(sock, APR_SO_NONBLOCK, 0);
70         }
71         /* Reset socket timeouts if the new timeout differs from the old timeout */
72         if (sock->timeout != t)
73         {
74             /* Win32 timeouts are in msec, represented as int */
75             sock->timeout_ms = (int)apr_time_as_msec(t);
76             setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVTIMEO,
77                        (char *) &sock->timeout_ms,
78                        sizeof(sock->timeout_ms));
79             setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDTIMEO,
80                        (char *) &sock->timeout_ms,
81                        sizeof(sock->timeout_ms));
82         }
83     }
84     else if (t < 0) {
85         int zero = 0;
86         /* Set the socket to blocking with infinite timeouts */
87         if ((stat = soblock(sock->socketdes)) != APR_SUCCESS)
88             return stat;
89         setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVTIMEO,
90                    (char *) &zero, sizeof(zero));
91         setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDTIMEO,
92                    (char *) &zero, sizeof(zero));
93     }
94     sock->timeout = t;
95     return APR_SUCCESS;
96 }
97 
98 
apr_socket_opt_set(apr_socket_t * sock,apr_int32_t opt,apr_int32_t on)99 APR_DECLARE(apr_status_t) apr_socket_opt_set(apr_socket_t *sock,
100                                              apr_int32_t opt, apr_int32_t on)
101 {
102     int one;
103     apr_status_t stat;
104 
105     one = on ? 1 : 0;
106 
107     switch (opt) {
108     case APR_SO_KEEPALIVE:
109         if (on != apr_is_option_set(sock, APR_SO_KEEPALIVE)) {
110             if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE,
111                            (void *)&one, sizeof(int)) == -1) {
112                 return apr_get_netos_error();
113             }
114             apr_set_option(sock, APR_SO_KEEPALIVE, on);
115         }
116         break;
117     case APR_SO_DEBUG:
118         if (on != apr_is_option_set(sock, APR_SO_DEBUG)) {
119             if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG,
120                            (void *)&one, sizeof(int)) == -1) {
121                 return apr_get_netos_error();
122             }
123             apr_set_option(sock, APR_SO_DEBUG, on);
124         }
125         break;
126     case APR_SO_SNDBUF:
127         if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF,
128                        (void *)&on, sizeof(int)) == -1) {
129             return apr_get_netos_error();
130         }
131         break;
132     case APR_SO_RCVBUF:
133         if (setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVBUF,
134                        (void *)&on, sizeof(int)) == -1) {
135             return apr_get_netos_error();
136         }
137         break;
138     case APR_SO_BROADCAST:
139         if (on != apr_is_option_set(sock, APR_SO_BROADCAST)) {
140            if (setsockopt(sock->socketdes, SOL_SOCKET, SO_BROADCAST,
141                            (void *)&one, sizeof(int)) == -1) {
142                 return apr_get_netos_error();
143             }
144             apr_set_option(sock, APR_SO_BROADCAST, on);
145         }
146         break;
147     case APR_SO_REUSEADDR:
148         if (on != apr_is_option_set(sock, APR_SO_REUSEADDR)) {
149             if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR,
150                            (void *)&one, sizeof(int)) == -1) {
151                 return apr_get_netos_error();
152             }
153             apr_set_option(sock, APR_SO_REUSEADDR, on);
154         }
155         break;
156     case APR_SO_NONBLOCK:
157         if (apr_is_option_set(sock, APR_SO_NONBLOCK) != on) {
158             if (on) {
159                 if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS)
160                     return stat;
161             }
162             else {
163                 if ((stat = soblock(sock->socketdes)) != APR_SUCCESS)
164                     return stat;
165             }
166             apr_set_option(sock, APR_SO_NONBLOCK, on);
167         }
168         break;
169     case APR_SO_LINGER:
170     {
171         if (apr_is_option_set(sock, APR_SO_LINGER) != on) {
172             struct linger li;
173             li.l_onoff = on;
174             li.l_linger = APR_MAX_SECS_TO_LINGER;
175             if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER,
176                            (char *) &li, sizeof(struct linger)) == -1) {
177                 return apr_get_netos_error();
178             }
179             apr_set_option(sock, APR_SO_LINGER, on);
180         }
181         break;
182     }
183     case APR_TCP_DEFER_ACCEPT:
184 #if defined(TCP_DEFER_ACCEPT)
185         if (apr_is_option_set(sock, APR_TCP_DEFER_ACCEPT) != on) {
186             int optlevel = IPPROTO_TCP;
187             int optname = TCP_DEFER_ACCEPT;
188 
189             if (setsockopt(sock->socketdes, optlevel, optname,
190                            (void *)&on, sizeof(int)) == -1) {
191                 return apr_get_netos_error();
192             }
193             apr_set_option(sock, APR_TCP_DEFER_ACCEPT, on);
194         }
195 #else
196         return APR_ENOTIMPL;
197 #endif
198     case APR_TCP_NODELAY:
199         if (apr_is_option_set(sock, APR_TCP_NODELAY) != on) {
200             int optlevel = IPPROTO_TCP;
201             int optname = TCP_NODELAY;
202 
203 #if APR_HAVE_SCTP
204             if (sock->protocol == IPPROTO_SCTP) {
205                 optlevel = IPPROTO_SCTP;
206                 optname = SCTP_NODELAY;
207             }
208 #endif
209             if (setsockopt(sock->socketdes, optlevel, optname,
210                            (void *)&on, sizeof(int)) == -1) {
211                 return apr_get_netos_error();
212             }
213             apr_set_option(sock, APR_TCP_NODELAY, on);
214         }
215         break;
216     case APR_IPV6_V6ONLY:
217 #if APR_HAVE_IPV6
218         if (apr_os_level < APR_WIN_VISTA &&
219             sock->local_addr->family == AF_INET6) {
220             /* apr_set_option() called at socket creation */
221             if (on) {
222                 return APR_SUCCESS;
223             }
224             else {
225                 return APR_ENOTIMPL;
226             }
227         }
228         /* we don't know the initial setting of this option,
229          * so don't check sock->options since that optimization
230          * won't work
231          */
232         if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_V6ONLY,
233                        (void *)&on, sizeof(int)) == -1) {
234             return apr_get_netos_error();
235         }
236         apr_set_option(sock, APR_IPV6_V6ONLY, on);
237 #else
238         return APR_ENOTIMPL;
239 #endif
240         break;
241     default:
242         return APR_EINVAL;
243         break;
244     }
245     return APR_SUCCESS;
246 }
247 
248 
apr_socket_timeout_get(apr_socket_t * sock,apr_interval_time_t * t)249 APR_DECLARE(apr_status_t) apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
250 {
251     *t = sock->timeout;
252     return APR_SUCCESS;
253 }
254 
255 
apr_socket_opt_get(apr_socket_t * sock,apr_int32_t opt,apr_int32_t * on)256 APR_DECLARE(apr_status_t) apr_socket_opt_get(apr_socket_t *sock,
257                                              apr_int32_t opt, apr_int32_t *on)
258 {
259     switch (opt) {
260     case APR_SO_DISCONNECTED:
261         *on = sock->disconnected;
262         break;
263     case APR_SO_KEEPALIVE:
264     case APR_SO_DEBUG:
265     case APR_SO_REUSEADDR:
266     case APR_SO_NONBLOCK:
267     case APR_SO_LINGER:
268     default:
269         *on = apr_is_option_set(sock, opt);
270         break;
271     }
272     return APR_SUCCESS;
273 }
274 
275 
apr_socket_atmark(apr_socket_t * sock,int * atmark)276 APR_DECLARE(apr_status_t) apr_socket_atmark(apr_socket_t *sock, int *atmark)
277 {
278     u_long oobmark;
279 
280     if (ioctlsocket(sock->socketdes, SIOCATMARK, (void*) &oobmark) < 0)
281         return apr_get_netos_error();
282 
283     *atmark = (oobmark != 0);
284 
285     return APR_SUCCESS;
286 }
287 
288 
apr_gethostname(char * buf,int len,apr_pool_t * cont)289 APR_DECLARE(apr_status_t) apr_gethostname(char *buf, int len,
290                                           apr_pool_t *cont)
291 {
292     if (gethostname(buf, len) == -1) {
293         buf[0] = '\0';
294         return apr_get_netos_error();
295     }
296     else if (!memchr(buf, '\0', len)) { /* buffer too small */
297         buf[0] = '\0';
298         return APR_ENAMETOOLONG;
299     }
300     return APR_SUCCESS;
301 }
302 
303