apr  1.7.0
About: APR (Apache Portable Runtime) project offers software libraries that provide a predictable and consistent interface to underlying platform-specific implementations (APR core library).
  Fossies Dox: apr-1.7.0.tar.bz2  ("inofficial" and yet experimental doxygen-generated source code documentation)  

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 
21 static 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)
29  fd_flags &= ~O_NONBLOCK;
30 #elif defined(O_NDELAY)
31  fd_flags &= ~O_NDELAY;
32 #elif defined(FNDELAY)
33  fd_flags &= ~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 
48 static apr_status_t sononblock(int sd)
49 {
50 #ifndef BEOS
51  int fd_flags;
52 
53  fd_flags = fcntl(sd, F_GETFL, 0);
54 #if defined(O_NONBLOCK)
55  fd_flags |= O_NONBLOCK;
56 #elif defined(O_NDELAY)
57  fd_flags |= O_NDELAY;
58 #elif defined(FNDELAY)
59  fd_flags |= 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 {
77  apr_status_t stat;
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) {
88  if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS) {
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 
114  apr_int32_t opt, apr_int32_t on)
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;
214  int optname = TCP_DEFER_ACCEPT;
215 
216  if (setsockopt(sock->socketdes, optlevel, optname,
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) {
234  optlevel = IPPROTO_SCTP;
235  optname = SCTP_NODELAY;
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) {
270  optlevel = IPPROTO_SCTP;
271  optname = SCTP_NODELAY;
272  }
273 #endif
274  /* OK we're going to change some settings here... */
275  if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1 && on) {
276  /* Now toggle TCP_NODELAY to off, if TCP_CORK is being
277  * turned on: */
278  int tmpflag = 0;
279  if (setsockopt(sock->socketdes, optlevel, optname,
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...*/
291  if (setsockopt(sock->socketdes, IPPROTO_TCP, APR_TCP_NOPUSH_FLAG,
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;
302  if (setsockopt(sock->socketdes, optlevel, optname,
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;
315  case APR_INCOMPLETE_READ:
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  */
324  if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_V6ONLY,
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)
335  if (setsockopt(sock->socketdes, SOL_IP, 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 
356 {
357  *t = sock->timeout;
358  return APR_SUCCESS;
359 }
360 
361 
363  apr_int32_t opt, apr_int32_t *on)
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
410 apr_status_t apr_socket_accept_filter(apr_socket_t *sock, char *nonconst_name,
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  */
423  if ((getsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER,
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 
438  if ((setsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER,
439  &af, sizeof(af))) < 0) {
440  return errno;
441  }
442  return APR_SUCCESS;
443 }
444 #endif
445 
447 {
448 #if APR_HAVE_SOCKADDR_UN
450  apr_socket_t *socket = (apr_socket_t *)thesocket;
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 }
APR_SO_RCVBUF
#define APR_SO_RCVBUF
Definition: apr_network_io.h:73
sononblock
static apr_status_t sononblock(int sd)
Definition: sockopt.c:48
socket
#define socket
Definition: apr_arch_os2calls.h:41
t
apr_interval_time_t t
Definition: apr_network_io.h:735
APR_EINVAL
#define APR_EINVAL
Definition: apr_errno.h:711
APR_SO_KEEPALIVE
#define APR_SO_KEEPALIVE
Definition: apr_network_io.h:68
APR_INCOMPLETE_READ
#define APR_INCOMPLETE_READ
Definition: apr_network_io.h:92
apr_socket_opt_get
apr_status_t apr_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on)
Definition: sockopt.c:362
APR_ENAMETOOLONG
#define APR_ENAMETOOLONG
Definition: apr_errno.h:655
APR_UNIX
#define APR_UNIX
Definition: apr_network_io.h:208
APR_FPROT_GSETID
#define APR_FPROT_GSETID
Definition: apr_file_info.h:84
timeout
IN ULONG IN INT timeout
Definition: apr_arch_misc.h:477
APR_ENOTIMPL
#define APR_ENOTIMPL
Definition: apr_errno.h:476
apr_socket_t::socketdes
int socketdes
Definition: apr_arch_networkio.h:39
APR_TCP_NOPUSH
#define APR_TCP_NOPUSH
Definition: apr_network_io.h:80
apr_strings.h
APR Strings library.
sock
apr_socket_t * sock
Definition: apr_network_io.h:403
IPV6_V6ONLY
#define IPV6_V6ONLY
Definition: sockopt.c:29
APR_SO_BROADCAST
#define APR_SO_BROADCAST
Definition: apr_network_io.h:130
gid
apr_fileperms_t apr_uid_t apr_gid_t gid
Definition: apr_global_mutex.h:159
apr_gethostname
apr_status_t apr_gethostname(char *buf, apr_int32_t len, apr_pool_t *cont)
Definition: sockopt.c:389
setsockopt
#define setsockopt
Definition: apr_arch_os2calls.h:54
APR_IPV6_V6ONLY
#define APR_IPV6_V6ONLY
Definition: apr_network_io.h:118
APR_TCP_DEFER_ACCEPT
#define APR_TCP_DEFER_ACCEPT
Definition: apr_network_io.h:123
apr_get_netos_error
#define apr_get_netos_error()
Definition: apr_errno.h:1222
APR_SO_DEBUG
#define APR_SO_DEBUG
Definition: apr_network_io.h:69
APR_SO_SNDBUF
#define APR_SO_SNDBUF
Definition: apr_network_io.h:72
on
apr_int32_t apr_int32_t on
Definition: apr_network_io.h:721
APR_SO_FREEBIND
#define APR_SO_FREEBIND
Definition: apr_network_io.h:133
APR_MAX_SECS_TO_LINGER
#define APR_MAX_SECS_TO_LINGER
Definition: apr_network_io.h:50
atmark
int * atmark
Definition: apr_network_io.h:774
APR_SO_LINGER
#define APR_SO_LINGER
Definition: apr_network_io.h:67
soblock
static apr_status_t soblock(int sd)
Definition: sockopt.c:21
len
const char apr_ssize_t int apr_size_t * len
Definition: apr_encode.h:162
perms
const char apr_fileperms_t perms
Definition: apr_file_io.h:333
buf
char * buf
Definition: apr_errno.h:52
ioctl
#define ioctl
Definition: apr_arch_os2calls.h:50
apr_socket_t::timeout
apr_interval_time_t timeout
Definition: apr_arch_networkio.h:44
apr_interval_time_t
apr_int64_t apr_interval_time_t
Definition: apr_time.h:55
cont
apr_pool_t * cont
Definition: apr_getopt.h:103
apr_socket_t
Definition: apr_arch_networkio.h:37
apr_socket_opt_set
apr_status_t apr_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
Definition: sockopt.c:113
apr_pool_t
Definition: apr_pools.c:577
apr_set_option
#define apr_set_option(skt, option, on)
Definition: apr_arch_networkio.h:136
apr_socket_timeout_set
apr_status_t apr_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
Definition: sockopt.c:75
APR_PERMS_SET_IMPLEMENT
APR_PERMS_SET_IMPLEMENT(socket)
Definition: sockopt.c:446
APR_RESET_NODELAY
#define APR_RESET_NODELAY
Definition: apr_network_io.h:81
APR_SO_REUSEADDR
#define APR_SO_REUSEADDR
Definition: apr_network_io.h:71
name
const char ** name
Definition: apr_network_io.h:492
apr_status_t
int apr_status_t
Definition: apr_errno.h:44
APR_SUCCESS
#define APR_SUCCESS
Definition: apr_errno.h:225
apr_is_option_set
#define apr_is_option_set(skt, option)
Definition: apr_arch_networkio.h:133
APR_SO_NONBLOCK
#define APR_SO_NONBLOCK
Definition: apr_network_io.h:70
args
const char const char *const * args
Definition: apr_thread_proc.h:634
opt
apr_int32_t opt
Definition: apr_network_io.h:721
getsockopt
#define getsockopt
Definition: apr_arch_os2calls.h:49
memchr
void * memchr(const void *s, int c, size_t n)
Definition: apr_strings.c:216
apr_socket_t::protocol
int protocol
Definition: apr_arch_networkio.h:41
apr_socket_timeout_get
apr_status_t apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
Definition: sockopt.c:355
apr_socket_atmark
apr_status_t apr_socket_atmark(apr_socket_t *sock, int *atmark)
Definition: sockopt.c:373
uid
apr_fileperms_t apr_uid_t uid
Definition: apr_global_mutex.h:159
apr_socket_t::options
apr_int32_t options
Definition: apr_arch_networkio.h:49
APR_TCP_NODELAY
#define APR_TCP_NODELAY
Definition: apr_network_io.h:75