Apache HTTPD
sockopt.c
Go to the documentation of this file.
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_strings.h"
19
20
21static apr_status_t soblock(int sd)
22{
23/* BeOS uses setsockopt at present for non blocking... */
24#ifndef BEOS
25 int fd_flags;
26
27 fd_flags = fcntl(sd, F_GETFL, 0);
28#if defined(O_NONBLOCK)
30#elif defined(O_NDELAY)
32#elif defined(FNDELAY)
34#else
35#error Please teach APR how to make sockets blocking on your platform.
36#endif
37 if (fcntl(sd, F_SETFL, fd_flags) == -1) {
38 return errno;
39 }
40#else
41 int on = 0;
42 if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0)
43 return errno;
44#endif /* BEOS */
45 return APR_SUCCESS;
46}
47
49{
50#ifndef BEOS
51 int fd_flags;
52
53 fd_flags = fcntl(sd, F_GETFL, 0);
54#if defined(O_NONBLOCK)
56#elif defined(O_NDELAY)
58#elif defined(FNDELAY)
60#else
61#error Please teach APR how to make sockets non-blocking on your platform.
62#endif
63 if (fcntl(sd, F_SETFL, fd_flags) == -1) {
64 return errno;
65 }
66#else
67 int on = 1;
68 if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0)
69 return errno;
70#endif /* BEOS */
71 return APR_SUCCESS;
72}
73
74
76{
78
79 /* If our new timeout is non-negative and our old timeout was
80 * negative, then we need to ensure that we are non-blocking.
81 * Conversely, if our new timeout is negative and we had
82 * non-negative timeout, we must make sure our socket is blocking.
83 * We want to avoid calling fcntl more than necessary on the
84 * socket.
85 */
86 if (t >= 0 && sock->timeout < 0) {
89 return stat;
90 }
92 }
93 }
94 else if (t < 0 && sock->timeout >= 0) {
96 if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) {
97 return stat;
98 }
100 }
101 }
102 /* must disable the incomplete read support if we disable
103 * a timeout
104 */
105 if (t <= 0) {
107 }
108 sock->timeout = t;
109 return APR_SUCCESS;
110}
111
112
115{
116 int one;
117 apr_status_t rv;
118
119 if (on)
120 one = 1;
121 else
122 one = 0;
123 switch(opt) {
124 case APR_SO_KEEPALIVE:
125#ifdef SO_KEEPALIVE
127 if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, sizeof(int)) == -1) {
128 return errno;
129 }
131 }
132#else
133 return APR_ENOTIMPL;
134#endif
135 break;
136 case APR_SO_DEBUG:
138 if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(int)) == -1) {
139 return errno;
140 }
142 }
143 break;
144 case APR_SO_BROADCAST:
145#ifdef SO_BROADCAST
147 if (setsockopt(sock->socketdes, SOL_SOCKET, SO_BROADCAST, (void *)&one, sizeof(int)) == -1) {
148 return errno;
149 }
151 }
152#else
153 return APR_ENOTIMPL;
154#endif
155 break;
156 case APR_SO_REUSEADDR:
158 if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) {
159 return errno;
160 }
162 }
163 break;
164 case APR_SO_SNDBUF:
165#ifdef SO_SNDBUF
166 if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, (void *)&on, sizeof(int)) == -1) {
167 return errno;
168 }
169#else
170 return APR_ENOTIMPL;
171#endif
172 break;
173 case APR_SO_RCVBUF:
174#ifdef SO_RCVBUF
175 if (setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVBUF, (void *)&on, sizeof(int)) == -1) {
176 return errno;
177 }
178#else
179 return APR_ENOTIMPL;
180#endif
181 break;
182 case APR_SO_NONBLOCK:
184 if (on) {
185 if ((rv = sononblock(sock->socketdes)) != APR_SUCCESS)
186 return rv;
187 }
188 else {
189 if ((rv = soblock(sock->socketdes)) != APR_SUCCESS)
190 return rv;
191 }
193 }
194 break;
195 case APR_SO_LINGER:
196#ifdef SO_LINGER
198 struct linger li;
199 li.l_onoff = on;
200 li.l_linger = APR_MAX_SECS_TO_LINGER;
201 if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) {
202 return errno;
203 }
205 }
206#else
207 return APR_ENOTIMPL;
208#endif
209 break;
211#if defined(TCP_DEFER_ACCEPT)
213 int optlevel = IPPROTO_TCP;
215
217 (void *)&on, sizeof(int)) == -1) {
218 return errno;
219 }
221 }
222#else
223 return APR_ENOTIMPL;
224#endif
225 break;
226 case APR_TCP_NODELAY:
227#if defined(TCP_NODELAY)
229 int optlevel = IPPROTO_TCP;
230 int optname = TCP_NODELAY;
231
232#if APR_HAVE_SCTP
233 if (sock->protocol == IPPROTO_SCTP) {
236 }
237#endif
238 if (setsockopt(sock->socketdes, optlevel, optname, (void *)&on, sizeof(int)) == -1) {
239 return errno;
240 }
242 }
243#else
244 /* BeOS pre-BONE has TCP_NODELAY set by default.
245 * As it can't be turned off we might as well check if they're asking
246 * for it to be turned on!
247 */
248#ifdef BEOS
249 if (on == 1)
250 return APR_SUCCESS;
251 else
252#endif
253 return APR_ENOTIMPL;
254#endif
255 break;
256 case APR_TCP_NOPUSH:
257#if APR_TCP_NOPUSH_FLAG
258 /* TCP_NODELAY and TCP_CORK are mutually exclusive on Linux
259 * kernels < 2.6; on newer kernels they can be used together
260 * and TCP_CORK takes preference, which is the desired
261 * behaviour. On older kernels, TCP_NODELAY must be toggled
262 * to "off" whilst TCP_CORK is in effect. */
264#ifndef HAVE_TCP_NODELAY_WITH_CORK
265 int optlevel = IPPROTO_TCP;
266 int optname = TCP_NODELAY;
267
268#if APR_HAVE_SCTP
269 if (sock->protocol == IPPROTO_SCTP) {
272 }
273#endif
274 /* OK we're going to change some settings here... */
276 /* Now toggle TCP_NODELAY to off, if TCP_CORK is being
277 * turned on: */
278 int tmpflag = 0;
280 (void*)&tmpflag, sizeof(int)) == -1) {
281 return errno;
282 }
285 } else if (on) {
287 }
288#endif /* HAVE_TCP_NODELAY_WITH_CORK */
289
290 /* OK, now we can just set the TCP_NOPUSH flag accordingly...*/
292 (void*)&on, sizeof(int)) == -1) {
293 return errno;
294 }
296#ifndef HAVE_TCP_NODELAY_WITH_CORK
298 /* Now, if TCP_CORK was just turned off, turn
299 * TCP_NODELAY back on again if it was earlier toggled
300 * to off: */
301 int tmpflag = 1;
303 (void*)&tmpflag, sizeof(int)) == -1) {
304 return errno;
305 }
308 }
309#endif /* HAVE_TCP_NODELAY_WITH_CORK */
310 }
311#else
312 return APR_ENOTIMPL;
313#endif
314 break;
317 break;
318 case APR_IPV6_V6ONLY:
319#if APR_HAVE_IPV6 && defined(IPV6_V6ONLY)
320 /* we don't know the initial setting of this option,
321 * so don't check sock->options since that optimization
322 * won't work
323 */
325 (void *)&on, sizeof(int)) == -1) {
326 return errno;
327 }
329#else
330 return APR_ENOTIMPL;
331#endif
332 break;
333 case APR_SO_FREEBIND:
334#if defined(IP_FREEBIND)
336 (void *)&one, sizeof(int)) == -1) {
337 return errno;
338 }
340#elif 0 /* defined(IP_BINDANY) ... */
341 /* TODO: insert FreeBSD support here, note family specific
342 * options, IP_BINDANY vs IPV6_BINDANY */
343#else
344 return APR_ENOTIMPL;
345#endif
346 break;
347 default:
348 return APR_EINVAL;
349 }
350
351 return APR_SUCCESS;
352}
353
354
360
361
364{
365 switch(opt) {
366 default:
368 }
369 return APR_SUCCESS;
370}
371
372
374{
375#ifndef BEOS_R5
376 int oobmark;
377
378 if (ioctl(sock->socketdes, SIOCATMARK, (void*) &oobmark) < 0)
379 return apr_get_netos_error();
380
381 *atmark = (oobmark != 0);
382
383 return APR_SUCCESS;
384#else /* BEOS_R5 */
385 return APR_ENOTIMPL;
386#endif
387}
388
390{
391#ifdef BEOS_R5
392 if (gethostname(buf, len) == 0) {
393#else
394 if (gethostname(buf, len) != 0) {
395#endif
396 buf[0] = '\0';
397 return errno;
398 }
399 else if (!memchr(buf, '\0', len)) { /* buffer too small */
400 /* note... most platforms just truncate in this condition
401 * linux+glibc return an error
402 */
403 buf[0] = '\0';
404 return APR_ENAMETOOLONG;
405 }
406 return APR_SUCCESS;
407}
408
409#if APR_HAS_SO_ACCEPTFILTER
411 char *nonconst_args)
412{
413 /* these should have been const; act like they are */
414 const char *name = nonconst_name;
415 const char *args = nonconst_args;
416
417 struct accept_filter_arg af;
418 socklen_t optlen = sizeof(af);
419
420 /* FreeBSD returns an error if the filter is already set; ignore
421 * this call if we previously set it to the same value.
422 */
424 &af, &optlen)) == 0) {
425 if (!strcmp(name, af.af_name) && !strcmp(args, af.af_arg)) {
426 return APR_SUCCESS;
427 }
428 }
429
430 /* Uhh, at least in FreeBSD 9 the fields are declared as arrays of
431 * these lengths; did sizeof not work in some ancient release?
432 *
433 * FreeBSD kernel sets the last byte to a '\0'.
434 */
435 apr_cpystrn(af.af_name, name, 16);
436 apr_cpystrn(af.af_arg, args, 256 - 16);
437
439 &af, sizeof(af))) < 0) {
440 return errno;
441 }
442 return APR_SUCCESS;
443}
444#endif
445
447{
448#if APR_HAVE_SOCKADDR_UN
451
452 if (socket->local_addr->family == APR_UNIX) {
453 if (!(perms & APR_FPROT_GSETID))
454 gid = -1;
455 if (fchown(socket->socketdes, uid, gid) < 0) {
456 rv = errno;
457 }
458 }
459 else
460 rv = APR_EINVAL;
461 return rv;
462#else
463 return APR_ENOTIMPL;
464#endif
465}
const char apr_size_t len
Definition ap_regex.h:187
#define ioctl
#define setsockopt
#define getsockopt
#define socket
APR Strings library.
const unsigned char * buf
Definition util_md5.h:50
#define APR_ENAMETOOLONG
Definition apr_errno.h:655
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_EINVAL
Definition apr_errno.h:711
apr_fileperms_t apr_uid_t uid
apr_fileperms_t apr_uid_t apr_gid_t gid
apr_size_t size
#define apr_get_netos_error()
Definition apr_errno.h:1222
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char apr_fileperms_t perms
#define APR_FPROT_GSETID
void * memchr(const void *s, int c, size_t n)
apr_pool_t * cont
Definition apr_getopt.h:103
apr_int32_t opt
apr_socket_t * sock
apr_interval_time_t t
int * atmark
#define APR_MAX_SECS_TO_LINGER
#define APR_UNIX
apr_int32_t apr_int32_t on
#define APR_PERMS_SET_IMPLEMENT(type)
#define APR_SO_KEEPALIVE
#define APR_SO_SNDBUF
#define APR_TCP_NODELAY
#define APR_SO_DEBUG
#define APR_SO_FREEBIND
#define APR_SO_RCVBUF
#define APR_SO_LINGER
#define APR_SO_BROADCAST
#define APR_INCOMPLETE_READ
#define APR_TCP_NOPUSH
#define APR_SO_REUSEADDR
#define APR_TCP_DEFER_ACCEPT
#define APR_SO_NONBLOCK
#define APR_RESET_NODELAY
#define APR_IPV6_V6ONLY
const char const char *const * args
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
char * name
apr_interval_time_t timeout
apr_int32_t options
#define apr_is_option_set(skt, option)
#define apr_set_option(skt, option, on)
apr_status_t apr_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
Definition sockopt.c:113
apr_status_t apr_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on)
Definition sockopt.c:362
apr_status_t apr_socket_atmark(apr_socket_t *sock, int *atmark)
Definition sockopt.c:373
static apr_status_t soblock(int sd)
Definition sockopt.c:21
apr_status_t apr_gethostname(char *buf, apr_int32_t len, apr_pool_t *cont)
Definition sockopt.c:389
static apr_status_t sononblock(int sd)
Definition sockopt.c:48
apr_status_t apr_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
Definition sockopt.c:75
apr_status_t apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
Definition sockopt.c:355
IN ULONG IN INT timeout
#define IPV6_V6ONLY
Definition sockopt.c:29