bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / network_io / unix / sockopt.c
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
75 apr_status_t apr_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
76 {
77     apr_status_t stat;
78
79     /* If our timeout is positive or zero and our last timeout was
80      * negative, then we need to ensure that we are non-blocking.
81      * Conversely, if our timeout is negative and we had a positive
82      * or zero timeout, we must make sure our socket is blocking.
83      * We want to avoid calling fcntl more than necessary on the socket,
84      */
85     if (t >= 0 && sock->timeout < 0) {
86         if (apr_is_option_set(sock->netmask, APR_SO_NONBLOCK) != 1) {
87             if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS) {
88                 return stat;
89             }
90             apr_set_option(&sock->netmask, APR_SO_NONBLOCK, 1);
91         }
92     } 
93     else if (t < 0 && sock->timeout >= 0) {
94         if (apr_is_option_set(sock->netmask, APR_SO_NONBLOCK) != 0) { 
95             if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) { 
96                 return stat; 
97             }
98             apr_set_option(&sock->netmask, APR_SO_NONBLOCK, 0);
99         } 
100     }
101     /* must disable the incomplete read support if we disable
102      * a timeout
103      */
104     if (t <= 0) {
105         sock->netmask &= ~APR_INCOMPLETE_READ;
106     }
107     sock->timeout = t; 
108     apr_set_option(&sock->netmask, APR_SO_TIMEOUT, t > 0);
109     return APR_SUCCESS;
110 }
111
112
113 apr_status_t apr_socket_opt_set(apr_socket_t *sock, 
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
126         if (on != apr_is_option_set(sock->netmask, APR_SO_KEEPALIVE)) {
127             if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, sizeof(int)) == -1) {
128                 return errno;
129             }
130             apr_set_option(&sock->netmask,APR_SO_KEEPALIVE, on);
131         }
132 #else
133         return APR_ENOTIMPL;
134 #endif
135         break;
136     case APR_SO_DEBUG:
137         if (on != apr_is_option_set(sock->netmask, APR_SO_DEBUG)) {
138             if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(int)) == -1) {
139                 return errno;
140             }
141             apr_set_option(&sock->netmask, APR_SO_DEBUG, on);
142         }
143         break;
144     case APR_SO_REUSEADDR:
145         if (on != apr_is_option_set(sock->netmask, APR_SO_REUSEADDR)) {
146             if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) {
147                 return errno;
148             }
149             apr_set_option(&sock->netmask, APR_SO_REUSEADDR, on);
150         }
151         break;
152     case APR_SO_SNDBUF:
153 #ifdef SO_SNDBUF
154         if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, (void *)&on, sizeof(int)) == -1) {
155             return errno;
156         }
157 #else
158         return APR_ENOTIMPL;
159 #endif
160         break;
161     case APR_SO_RCVBUF:
162 #ifdef SO_RCVBUF
163         if (setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVBUF, (void *)&on, sizeof(int)) == -1) {
164             return errno;
165         }
166 #else
167         return APR_ENOTIMPL;
168 #endif
169         break;
170     case APR_SO_NONBLOCK:
171         if (apr_is_option_set(sock->netmask, APR_SO_NONBLOCK) != on) {
172             if (on) {
173                 if ((rv = sononblock(sock->socketdes)) != APR_SUCCESS) 
174                     return rv;
175             }
176             else {
177                 if ((rv = soblock(sock->socketdes)) != APR_SUCCESS)
178                     return rv;
179             }
180             apr_set_option(&sock->netmask, APR_SO_NONBLOCK, on);
181         }
182         break;
183     case APR_SO_LINGER:
184 #ifdef SO_LINGER
185         if (apr_is_option_set(sock->netmask, APR_SO_LINGER) != on) {
186             struct linger li;
187             li.l_onoff = on;
188             li.l_linger = APR_MAX_SECS_TO_LINGER;
189             if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) {
190                 return errno;
191             }
192             apr_set_option(&sock->netmask, APR_SO_LINGER, on);
193         }
194 #else
195         return APR_ENOTIMPL;
196 #endif
197         break;
198     case APR_SO_TIMEOUT:
199         /* XXX: To be deprecated */
200         return apr_socket_timeout_set(sock, on);
201         break;
202     case APR_TCP_NODELAY:
203 #if defined(TCP_NODELAY)
204         if (apr_is_option_set(sock->netmask, APR_TCP_NODELAY) != on) {
205             int optlevel = IPPROTO_TCP;
206             int optname = TCP_NODELAY;
207
208 #if APR_HAVE_SCTP
209             if (sock->protocol == IPPROTO_SCTP) {
210                 optlevel = IPPROTO_SCTP;
211                 optname = SCTP_NODELAY;
212             }
213 #endif
214             if (setsockopt(sock->socketdes, optlevel, optname, (void *)&on, sizeof(int)) == -1) {
215                 return errno;
216             }
217             apr_set_option(&sock->netmask, APR_TCP_NODELAY, on);
218         }
219 #else
220         /* BeOS pre-BONE has TCP_NODELAY set by default.
221          * As it can't be turned off we might as well check if they're asking
222          * for it to be turned on!
223          */
224 #ifdef BEOS
225         if (on == 1)
226             return APR_SUCCESS;
227         else
228 #endif
229         return APR_ENOTIMPL;
230 #endif
231         break;
232     case APR_TCP_NOPUSH:
233 #if APR_TCP_NOPUSH_FLAG
234         if (apr_is_option_set(sock->netmask, APR_TCP_NOPUSH) != on) {
235             int optlevel = IPPROTO_TCP;
236             int optname = TCP_NODELAY;
237
238 #if APR_HAVE_SCTP
239             if (sock->protocol == IPPROTO_SCTP) {
240                 optlevel = IPPROTO_SCTP;
241                 optname = SCTP_NODELAY;
242             }
243 #endif
244             /* OK we're going to change some settings here... */
245             /* TCP_NODELAY is mutually exclusive, so do we have it set? */
246             if (apr_is_option_set(sock->netmask, APR_TCP_NODELAY) == 1 && on) {
247                 /* If we want to set NOPUSH then if we have the TCP_NODELAY
248                  * flag set we need to switch it off...
249                  */
250                 int tmpflag = 0;
251                 if (setsockopt(sock->socketdes, optlevel, optname,
252                                (void*)&tmpflag, sizeof(int)) == -1) {
253                     return errno;
254                 }
255                 apr_set_option(&sock->netmask, APR_RESET_NODELAY, 1);
256                 apr_set_option(&sock->netmask, APR_TCP_NODELAY, 0);
257             } else if (on) {
258                 apr_set_option(&sock->netmask, APR_RESET_NODELAY, 0);
259             }
260             /* OK, now we can just set the TCP_NOPUSH flag accordingly...*/
261             if (setsockopt(sock->socketdes, IPPROTO_TCP, APR_TCP_NOPUSH_FLAG,
262                            (void*)&on, sizeof(int)) == -1) {
263                 return errno;
264             }
265             apr_set_option(&sock->netmask, APR_TCP_NOPUSH, on);
266             if (!on && apr_is_option_set(sock->netmask, APR_RESET_NODELAY)) {
267                 int tmpflag = 1;
268                 if (setsockopt(sock->socketdes, optlevel, optname,
269                                (void*)&tmpflag, sizeof(int)) == -1) {
270                     return errno;
271                 }
272                 apr_set_option(&sock->netmask, APR_RESET_NODELAY,0);
273                 apr_set_option(&sock->netmask, APR_TCP_NODELAY, 1);
274             }
275         }
276 #else
277         return APR_ENOTIMPL;
278 #endif
279         break;
280     case APR_INCOMPLETE_READ:
281         apr_set_option(&sock->netmask, APR_INCOMPLETE_READ, on);
282         break;
283     case APR_IPV6_V6ONLY:
284 #if APR_HAVE_IPV6 && defined(IPV6_V6ONLY)
285         /* we don't know the initial setting of this option,
286          * so don't check sock->netmask since that optimization
287          * won't work
288          */
289         if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_V6ONLY,
290                        (void *)&on, sizeof(int)) == -1) {
291             return errno;
292         }
293         apr_set_option(&sock->netmask, APR_IPV6_V6ONLY, on);
294 #else
295         return APR_ENOTIMPL;
296 #endif
297         break;
298     default:
299         return APR_EINVAL;
300     }
301
302     return APR_SUCCESS; 
303 }         
304
305
306 apr_status_t apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
307 {
308     *t = sock->timeout;
309     return APR_SUCCESS;
310 }
311
312
313 apr_status_t apr_socket_opt_get(apr_socket_t *sock, 
314                                 apr_int32_t opt, apr_int32_t *on)
315 {
316     switch(opt) {
317         case APR_SO_TIMEOUT:
318             /* XXX: To be deprecated */
319             *on = (apr_int32_t)sock->timeout;
320             break;
321         default:
322             *on = apr_is_option_set(sock->netmask, opt);
323     }
324     return APR_SUCCESS;
325 }
326
327
328 apr_status_t apr_socket_atmark(apr_socket_t *sock, int *atmark)
329 {
330 /* In 1.0 we rely on compile failure to assure all platforms grabbed
331  * the correct header file support for SIOCATMARK, but we don't want 
332  * to fail the build of 0.9.  Keep things good for the released branch.
333  */
334 #ifdef SIOCATMARK
335     int oobmark;
336
337     if (ioctl(sock->socketdes, SIOCATMARK, (void*) &oobmark) < 0)
338         return apr_get_netos_error();
339
340     *atmark = (oobmark != 0);
341
342     return APR_SUCCESS;
343 #else
344     return APR_ENOTIMPL;
345 #endif
346 }
347
348
349 /* deprecated */
350 apr_status_t apr_setsocketopt(apr_socket_t *sock,
351                               apr_int32_t opt, apr_int32_t on)
352 {
353     return apr_socket_opt_set(sock, opt, on);
354 }
355
356 apr_status_t apr_getsocketopt(apr_socket_t *sock,
357                               apr_int32_t opt, apr_int32_t *on)
358 {
359     return apr_socket_opt_get(sock, opt, on);
360 }
361                                            
362
363 apr_status_t apr_gethostname(char *buf, apr_int32_t len, apr_pool_t *cont)
364 {
365     if (gethostname(buf, len) == -1) {
366         buf[0] = '\0';
367         return errno;
368     }
369     else if (!memchr(buf, '\0', len)) { /* buffer too small */
370         /* note... most platforms just truncate in this condition
371          *         linux+glibc return an error
372          */
373         buf[0] = '\0';
374         return APR_ENAMETOOLONG;
375     }
376     return APR_SUCCESS;
377 }
378
379 #if APR_HAS_SO_ACCEPTFILTER
380 apr_status_t apr_socket_accept_filter(apr_socket_t *sock, char *name, 
381                                       char *args)
382 {
383     struct accept_filter_arg af;
384     strncpy(af.af_name, name, 16);
385     strncpy(af.af_arg, args, 256 - 16);
386
387     if ((setsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER,
388           &af, sizeof(af))) < 0) {
389         return errno;
390     }
391     return APR_SUCCESS;
392 }
393 #endif