1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251875Speter * contributor license agreements.  See the NOTICE file distributed with
3251875Speter * this work for additional information regarding copyright ownership.
4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251875Speter * (the "License"); you may not use this file except in compliance with
6251875Speter * the License.  You may obtain a copy of the License at
7251875Speter *
8251875Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251875Speter *
10251875Speter * Unless required by applicable law or agreed to in writing, software
11251875Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251875Speter * See the License for the specific language governing permissions and
14251875Speter * limitations under the License.
15251875Speter */
16251875Speter
17251875Speter#include "apr_arch_networkio.h"
18251875Speter#include "apr_strings.h"
19251875Speter
20251875Speter
21251875Speterstatic apr_status_t soblock(int sd)
22251875Speter{
23251875Speter/* BeOS uses setsockopt at present for non blocking... */
24251875Speter#ifndef BEOS
25251875Speter    int fd_flags;
26251875Speter
27251875Speter    fd_flags = fcntl(sd, F_GETFL, 0);
28251875Speter#if defined(O_NONBLOCK)
29251875Speter    fd_flags &= ~O_NONBLOCK;
30251875Speter#elif defined(O_NDELAY)
31251875Speter    fd_flags &= ~O_NDELAY;
32251875Speter#elif defined(FNDELAY)
33251875Speter    fd_flags &= ~FNDELAY;
34251875Speter#else
35251875Speter#error Please teach APR how to make sockets blocking on your platform.
36251875Speter#endif
37251875Speter    if (fcntl(sd, F_SETFL, fd_flags) == -1) {
38251875Speter        return errno;
39251875Speter    }
40251875Speter#else
41251875Speter    int on = 0;
42251875Speter    if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0)
43251875Speter        return errno;
44251875Speter#endif /* BEOS */
45251875Speter    return APR_SUCCESS;
46251875Speter}
47251875Speter
48251875Speterstatic apr_status_t sononblock(int sd)
49251875Speter{
50251875Speter#ifndef BEOS
51251875Speter    int fd_flags;
52251875Speter
53251875Speter    fd_flags = fcntl(sd, F_GETFL, 0);
54251875Speter#if defined(O_NONBLOCK)
55251875Speter    fd_flags |= O_NONBLOCK;
56251875Speter#elif defined(O_NDELAY)
57251875Speter    fd_flags |= O_NDELAY;
58251875Speter#elif defined(FNDELAY)
59251875Speter    fd_flags |= FNDELAY;
60251875Speter#else
61251875Speter#error Please teach APR how to make sockets non-blocking on your platform.
62251875Speter#endif
63251875Speter    if (fcntl(sd, F_SETFL, fd_flags) == -1) {
64251875Speter        return errno;
65251875Speter    }
66251875Speter#else
67251875Speter    int on = 1;
68251875Speter    if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0)
69251875Speter        return errno;
70251875Speter#endif /* BEOS */
71251875Speter    return APR_SUCCESS;
72251875Speter}
73251875Speter
74251875Speter
75251875Speterapr_status_t apr_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
76251875Speter{
77251875Speter    apr_status_t stat;
78251875Speter
79251875Speter    /* If our new timeout is non-negative and our old timeout was
80251875Speter     * negative, then we need to ensure that we are non-blocking.
81251875Speter     * Conversely, if our new timeout is negative and we had
82251875Speter     * non-negative timeout, we must make sure our socket is blocking.
83251875Speter     * We want to avoid calling fcntl more than necessary on the
84251875Speter     * socket.
85251875Speter     */
86251875Speter    if (t >= 0 && sock->timeout < 0) {
87251875Speter        if (apr_is_option_set(sock, APR_SO_NONBLOCK) != 1) {
88251875Speter            if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS) {
89251875Speter                return stat;
90251875Speter            }
91251875Speter            apr_set_option(sock, APR_SO_NONBLOCK, 1);
92251875Speter        }
93251875Speter    }
94251875Speter    else if (t < 0 && sock->timeout >= 0) {
95251875Speter        if (apr_is_option_set(sock, APR_SO_NONBLOCK) != 0) {
96251875Speter            if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) {
97251875Speter                return stat;
98251875Speter            }
99251875Speter            apr_set_option(sock, APR_SO_NONBLOCK, 0);
100251875Speter        }
101251875Speter    }
102251875Speter    /* must disable the incomplete read support if we disable
103251875Speter     * a timeout
104251875Speter     */
105251875Speter    if (t <= 0) {
106251875Speter        sock->options &= ~APR_INCOMPLETE_READ;
107251875Speter    }
108251875Speter    sock->timeout = t;
109251875Speter    return APR_SUCCESS;
110251875Speter}
111251875Speter
112251875Speter
113251875Speterapr_status_t apr_socket_opt_set(apr_socket_t *sock,
114251875Speter                                apr_int32_t opt, apr_int32_t on)
115251875Speter{
116251875Speter    int one;
117251875Speter    apr_status_t rv;
118251875Speter
119251875Speter    if (on)
120251875Speter        one = 1;
121251875Speter    else
122251875Speter        one = 0;
123251875Speter    switch(opt) {
124251875Speter    case APR_SO_KEEPALIVE:
125251875Speter#ifdef SO_KEEPALIVE
126251875Speter        if (on != apr_is_option_set(sock, APR_SO_KEEPALIVE)) {
127251875Speter            if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, sizeof(int)) == -1) {
128251875Speter                return errno;
129251875Speter            }
130251875Speter            apr_set_option(sock, APR_SO_KEEPALIVE, on);
131251875Speter        }
132251875Speter#else
133251875Speter        return APR_ENOTIMPL;
134251875Speter#endif
135251875Speter        break;
136251875Speter    case APR_SO_DEBUG:
137251875Speter        if (on != apr_is_option_set(sock, APR_SO_DEBUG)) {
138251875Speter            if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(int)) == -1) {
139251875Speter                return errno;
140251875Speter            }
141251875Speter            apr_set_option(sock, APR_SO_DEBUG, on);
142251875Speter        }
143251875Speter        break;
144251875Speter    case APR_SO_REUSEADDR:
145251875Speter        if (on != apr_is_option_set(sock, APR_SO_REUSEADDR)) {
146251875Speter            if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) {
147251875Speter                return errno;
148251875Speter            }
149251875Speter            apr_set_option(sock, APR_SO_REUSEADDR, on);
150251875Speter        }
151251875Speter        break;
152251875Speter    case APR_SO_SNDBUF:
153251875Speter#ifdef SO_SNDBUF
154251875Speter        if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, (void *)&on, sizeof(int)) == -1) {
155251875Speter            return errno;
156251875Speter        }
157251875Speter#else
158251875Speter        return APR_ENOTIMPL;
159251875Speter#endif
160251875Speter        break;
161251875Speter    case APR_SO_RCVBUF:
162251875Speter#ifdef SO_RCVBUF
163251875Speter        if (setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVBUF, (void *)&on, sizeof(int)) == -1) {
164251875Speter            return errno;
165251875Speter        }
166251875Speter#else
167251875Speter        return APR_ENOTIMPL;
168251875Speter#endif
169251875Speter        break;
170251875Speter    case APR_SO_NONBLOCK:
171251875Speter        if (apr_is_option_set(sock, APR_SO_NONBLOCK) != on) {
172251875Speter            if (on) {
173251875Speter                if ((rv = sononblock(sock->socketdes)) != APR_SUCCESS)
174251875Speter                    return rv;
175251875Speter            }
176251875Speter            else {
177251875Speter                if ((rv = soblock(sock->socketdes)) != APR_SUCCESS)
178251875Speter                    return rv;
179251875Speter            }
180251875Speter            apr_set_option(sock, APR_SO_NONBLOCK, on);
181251875Speter        }
182251875Speter        break;
183251875Speter    case APR_SO_LINGER:
184251875Speter#ifdef SO_LINGER
185251875Speter        if (apr_is_option_set(sock, APR_SO_LINGER) != on) {
186251875Speter            struct linger li;
187251875Speter            li.l_onoff = on;
188251875Speter            li.l_linger = APR_MAX_SECS_TO_LINGER;
189251875Speter            if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) {
190251875Speter                return errno;
191251875Speter            }
192251875Speter            apr_set_option(sock, APR_SO_LINGER, on);
193251875Speter        }
194251875Speter#else
195251875Speter        return APR_ENOTIMPL;
196251875Speter#endif
197251875Speter        break;
198251875Speter    case APR_TCP_DEFER_ACCEPT:
199251875Speter#if defined(TCP_DEFER_ACCEPT)
200251875Speter        if (apr_is_option_set(sock, APR_TCP_DEFER_ACCEPT) != on) {
201251875Speter            int optlevel = IPPROTO_TCP;
202251875Speter            int optname = TCP_DEFER_ACCEPT;
203251875Speter
204251875Speter            if (setsockopt(sock->socketdes, optlevel, optname,
205251875Speter                           (void *)&on, sizeof(int)) == -1) {
206251875Speter                return errno;
207251875Speter            }
208251875Speter            apr_set_option(sock, APR_TCP_DEFER_ACCEPT, on);
209251875Speter        }
210251875Speter#else
211251875Speter        return APR_ENOTIMPL;
212251875Speter#endif
213251875Speter        break;
214251875Speter    case APR_TCP_NODELAY:
215251875Speter#if defined(TCP_NODELAY)
216251875Speter        if (apr_is_option_set(sock, APR_TCP_NODELAY) != on) {
217251875Speter            int optlevel = IPPROTO_TCP;
218251875Speter            int optname = TCP_NODELAY;
219251875Speter
220251875Speter#if APR_HAVE_SCTP
221251875Speter            if (sock->protocol == IPPROTO_SCTP) {
222251875Speter                optlevel = IPPROTO_SCTP;
223251875Speter                optname = SCTP_NODELAY;
224251875Speter            }
225251875Speter#endif
226251875Speter            if (setsockopt(sock->socketdes, optlevel, optname, (void *)&on, sizeof(int)) == -1) {
227251875Speter                return errno;
228251875Speter            }
229251875Speter            apr_set_option(sock, APR_TCP_NODELAY, on);
230251875Speter        }
231251875Speter#else
232251875Speter        /* BeOS pre-BONE has TCP_NODELAY set by default.
233251875Speter         * As it can't be turned off we might as well check if they're asking
234251875Speter         * for it to be turned on!
235251875Speter         */
236251875Speter#ifdef BEOS
237251875Speter        if (on == 1)
238251875Speter            return APR_SUCCESS;
239251875Speter        else
240251875Speter#endif
241251875Speter        return APR_ENOTIMPL;
242251875Speter#endif
243251875Speter        break;
244251875Speter    case APR_TCP_NOPUSH:
245251875Speter#if APR_TCP_NOPUSH_FLAG
246251875Speter        /* TCP_NODELAY and TCP_CORK are mutually exclusive on Linux
247251875Speter         * kernels < 2.6; on newer kernels they can be used together
248251875Speter         * and TCP_CORK takes preference, which is the desired
249251875Speter         * behaviour.  On older kernels, TCP_NODELAY must be toggled
250251875Speter         * to "off" whilst TCP_CORK is in effect. */
251251875Speter        if (apr_is_option_set(sock, APR_TCP_NOPUSH) != on) {
252251875Speter#ifndef HAVE_TCP_NODELAY_WITH_CORK
253251875Speter            int optlevel = IPPROTO_TCP;
254251875Speter            int optname = TCP_NODELAY;
255251875Speter
256251875Speter#if APR_HAVE_SCTP
257251875Speter            if (sock->protocol == IPPROTO_SCTP) {
258251875Speter                optlevel = IPPROTO_SCTP;
259251875Speter                optname = SCTP_NODELAY;
260251875Speter            }
261251875Speter#endif
262251875Speter            /* OK we're going to change some settings here... */
263251875Speter            if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1 && on) {
264251875Speter                /* Now toggle TCP_NODELAY to off, if TCP_CORK is being
265251875Speter                 * turned on: */
266251875Speter                int tmpflag = 0;
267251875Speter                if (setsockopt(sock->socketdes, optlevel, optname,
268251875Speter                               (void*)&tmpflag, sizeof(int)) == -1) {
269251875Speter                    return errno;
270251875Speter                }
271251875Speter                apr_set_option(sock, APR_RESET_NODELAY, 1);
272251875Speter                apr_set_option(sock, APR_TCP_NODELAY, 0);
273251875Speter            } else if (on) {
274251875Speter                apr_set_option(sock, APR_RESET_NODELAY, 0);
275251875Speter            }
276251875Speter#endif /* HAVE_TCP_NODELAY_WITH_CORK */
277251875Speter
278251875Speter            /* OK, now we can just set the TCP_NOPUSH flag accordingly...*/
279251875Speter            if (setsockopt(sock->socketdes, IPPROTO_TCP, APR_TCP_NOPUSH_FLAG,
280251875Speter                           (void*)&on, sizeof(int)) == -1) {
281251875Speter                return errno;
282251875Speter            }
283251875Speter            apr_set_option(sock, APR_TCP_NOPUSH, on);
284251875Speter#ifndef HAVE_TCP_NODELAY_WITH_CORK
285251875Speter            if (!on && apr_is_option_set(sock, APR_RESET_NODELAY)) {
286251875Speter                /* Now, if TCP_CORK was just turned off, turn
287251875Speter                 * TCP_NODELAY back on again if it was earlier toggled
288251875Speter                 * to off: */
289251875Speter                int tmpflag = 1;
290251875Speter                if (setsockopt(sock->socketdes, optlevel, optname,
291251875Speter                               (void*)&tmpflag, sizeof(int)) == -1) {
292251875Speter                    return errno;
293251875Speter                }
294251875Speter                apr_set_option(sock, APR_RESET_NODELAY,0);
295251875Speter                apr_set_option(sock, APR_TCP_NODELAY, 1);
296251875Speter            }
297251875Speter#endif /* HAVE_TCP_NODELAY_WITH_CORK */
298251875Speter        }
299251875Speter#else
300251875Speter        return APR_ENOTIMPL;
301251875Speter#endif
302251875Speter        break;
303251875Speter    case APR_INCOMPLETE_READ:
304251875Speter        apr_set_option(sock, APR_INCOMPLETE_READ, on);
305251875Speter        break;
306251875Speter    case APR_IPV6_V6ONLY:
307251875Speter#if APR_HAVE_IPV6 && defined(IPV6_V6ONLY)
308251875Speter        /* we don't know the initial setting of this option,
309251875Speter         * so don't check sock->options since that optimization
310251875Speter         * won't work
311251875Speter         */
312251875Speter        if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_V6ONLY,
313251875Speter                       (void *)&on, sizeof(int)) == -1) {
314251875Speter            return errno;
315251875Speter        }
316251875Speter        apr_set_option(sock, APR_IPV6_V6ONLY, on);
317251875Speter#else
318251875Speter        return APR_ENOTIMPL;
319251875Speter#endif
320251875Speter        break;
321251875Speter    default:
322251875Speter        return APR_EINVAL;
323251875Speter    }
324251875Speter
325251875Speter    return APR_SUCCESS;
326251875Speter}
327251875Speter
328251875Speter
329251875Speterapr_status_t apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
330251875Speter{
331251875Speter    *t = sock->timeout;
332251875Speter    return APR_SUCCESS;
333251875Speter}
334251875Speter
335251875Speter
336251875Speterapr_status_t apr_socket_opt_get(apr_socket_t *sock,
337251875Speter                                apr_int32_t opt, apr_int32_t *on)
338251875Speter{
339251875Speter    switch(opt) {
340251875Speter        default:
341251875Speter            *on = apr_is_option_set(sock, opt);
342251875Speter    }
343251875Speter    return APR_SUCCESS;
344251875Speter}
345251875Speter
346251875Speter
347251875Speterapr_status_t apr_socket_atmark(apr_socket_t *sock, int *atmark)
348251875Speter{
349251875Speter#ifndef BEOS_R5
350251875Speter    int oobmark;
351251875Speter
352251875Speter    if (ioctl(sock->socketdes, SIOCATMARK, (void*) &oobmark) < 0)
353251875Speter        return apr_get_netos_error();
354251875Speter
355251875Speter    *atmark = (oobmark != 0);
356251875Speter
357251875Speter    return APR_SUCCESS;
358251875Speter#else /* BEOS_R5 */
359251875Speter    return APR_ENOTIMPL;
360251875Speter#endif
361251875Speter}
362251875Speter
363251875Speterapr_status_t apr_gethostname(char *buf, apr_int32_t len, apr_pool_t *cont)
364251875Speter{
365251875Speter#ifdef BEOS_R5
366251875Speter    if (gethostname(buf, len) == 0) {
367251875Speter#else
368251875Speter    if (gethostname(buf, len) != 0) {
369251875Speter#endif
370251875Speter        buf[0] = '\0';
371251875Speter        return errno;
372251875Speter    }
373251875Speter    else if (!memchr(buf, '\0', len)) { /* buffer too small */
374251875Speter        /* note... most platforms just truncate in this condition
375251875Speter         *         linux+glibc return an error
376251875Speter         */
377251875Speter        buf[0] = '\0';
378251875Speter        return APR_ENAMETOOLONG;
379251875Speter    }
380251875Speter    return APR_SUCCESS;
381251875Speter}
382251875Speter
383251875Speter#if APR_HAS_SO_ACCEPTFILTER
384253734Speterapr_status_t apr_socket_accept_filter(apr_socket_t *sock, char *nonconst_name,
385253734Speter                                      char *nonconst_args)
386251875Speter{
387253734Speter    /* these should have been const; act like they are */
388253734Speter    const char *name = nonconst_name;
389253734Speter    const char *args = nonconst_args;
390253734Speter
391251875Speter    struct accept_filter_arg af;
392253734Speter    socklen_t optlen = sizeof(af);
393251875Speter
394253734Speter    /* FreeBSD returns an error if the filter is already set; ignore
395253734Speter     * this call if we previously set it to the same value.
396253734Speter     */
397253734Speter    if ((getsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER,
398253734Speter                    &af, &optlen)) == 0) {
399253734Speter        if (!strcmp(name, af.af_name) && !strcmp(args, af.af_arg)) {
400253734Speter            return APR_SUCCESS;
401253734Speter        }
402253734Speter    }
403253734Speter
404253734Speter    /* Uhh, at least in FreeBSD 9 the fields are declared as arrays of
405253734Speter     * these lengths; did sizeof not work in some ancient release?
406253734Speter     *
407253734Speter     * FreeBSD kernel sets the last byte to a '\0'.
408253734Speter     */
409253734Speter    apr_cpystrn(af.af_name, name, 16);
410253734Speter    apr_cpystrn(af.af_arg, args, 256 - 16);
411253734Speter
412251875Speter    if ((setsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER,
413251875Speter          &af, sizeof(af))) < 0) {
414251875Speter        return errno;
415251875Speter    }
416251875Speter    return APR_SUCCESS;
417251875Speter}
418251875Speter#endif
419