Esempio n. 1
0
apr_status_t apr_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
{
    apr_status_t stat;

    /* If our new timeout is non-negative and our old timeout was
     * negative, then we need to ensure that we are non-blocking.
     * Conversely, if our new timeout is negative and we had
     * non-negative timeout, we must make sure our socket is blocking.
     * We want to avoid calling fcntl more than necessary on the
     * socket.
     */
    if (t >= 0 && sock->timeout < 0) {
        if (apr_is_option_set(sock, APR_SO_NONBLOCK) != 1) {
            if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS) {
                return stat;
            }
            apr_set_option(sock, APR_SO_NONBLOCK, 1);
        }
    } 
    else if (t < 0 && sock->timeout >= 0) {
        if (apr_is_option_set(sock, APR_SO_NONBLOCK) != 0) { 
            if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) { 
                return stat; 
            }
            apr_set_option(sock, APR_SO_NONBLOCK, 0);
        } 
    }
    /* must disable the incomplete read support if we disable
     * a timeout
     */
    if (t <= 0) {
        sock->options &= ~APR_INCOMPLETE_READ;
    }
    sock->timeout = t;
    return APR_SUCCESS;
}
Esempio n. 2
0
apr_status_t apr_socket_opt_set(apr_socket_t *sock, 
                                apr_int32_t opt, apr_int32_t on)
{
    int one;
    apr_status_t rv;

    if (on)
        one = 1;
    else
        one = 0;
    switch(opt) {
    case APR_SO_KEEPALIVE:
#ifdef SO_KEEPALIVE
        if (on != apr_is_option_set(sock, APR_SO_KEEPALIVE)) {
            if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, sizeof(int)) == -1) {
                return errno;
            }
            apr_set_option(sock, APR_SO_KEEPALIVE, on);
        }
#else
        return APR_ENOTIMPL;
#endif
        break;
    case APR_SO_DEBUG:
        if (on != apr_is_option_set(sock, APR_SO_DEBUG)) {
            if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(int)) == -1) {
                return errno;
            }
            apr_set_option(sock, APR_SO_DEBUG, on);
        }
        break;
    case APR_SO_BROADCAST:
#ifdef SO_BROADCAST
        if (on != apr_is_option_set(sock, APR_SO_BROADCAST)) {
            if (setsockopt(sock->socketdes, SOL_SOCKET, SO_BROADCAST, (void *)&one, sizeof(int)) == -1) {
                return errno;
            }
            apr_set_option(sock, APR_SO_BROADCAST, on);
        }
#else
        return APR_ENOTIMPL;
#endif
        break;
    case APR_SO_REUSEADDR:
        if (on != apr_is_option_set(sock, APR_SO_REUSEADDR)) {
            if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) {
                return errno;
            }
            apr_set_option(sock, APR_SO_REUSEADDR, on);
        }
        break;
    case APR_SO_SNDBUF:
#ifdef SO_SNDBUF
        if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, (void *)&on, sizeof(int)) == -1) {
            return errno;
        }
#else
        return APR_ENOTIMPL;
#endif
        break;
    case APR_SO_RCVBUF:
#ifdef SO_RCVBUF
        if (setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVBUF, (void *)&on, sizeof(int)) == -1) {
            return errno;
        }
#else
        return APR_ENOTIMPL;
#endif
        break;
    case APR_SO_NONBLOCK:
        if (apr_is_option_set(sock, APR_SO_NONBLOCK) != on) {
            if (on) {
                if ((rv = sononblock(sock->socketdes)) != APR_SUCCESS) 
                    return rv;
            }
            else {
                if ((rv = soblock(sock->socketdes)) != APR_SUCCESS)
                    return rv;
            }
            apr_set_option(sock, APR_SO_NONBLOCK, on);
        }
        break;
    case APR_SO_LINGER:
#ifdef SO_LINGER
        if (apr_is_option_set(sock, APR_SO_LINGER) != on) {
            struct linger li;
            li.l_onoff = on;
            li.l_linger = APR_MAX_SECS_TO_LINGER;
            if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) {
                return errno;
            }
            apr_set_option(sock, APR_SO_LINGER, on);
        }
#else
        return APR_ENOTIMPL;
#endif
        break;
    case APR_TCP_DEFER_ACCEPT:
#if defined(TCP_DEFER_ACCEPT)
        if (apr_is_option_set(sock, APR_TCP_DEFER_ACCEPT) != on) {
            int optlevel = IPPROTO_TCP;
            int optname = TCP_DEFER_ACCEPT;

            if (setsockopt(sock->socketdes, optlevel, optname, 
                           (void *)&on, sizeof(int)) == -1) {
                return errno;
            }
            apr_set_option(sock, APR_TCP_DEFER_ACCEPT, on);
        }
#else
        return APR_ENOTIMPL;
#endif
        break;
    case APR_TCP_NODELAY:
#if defined(TCP_NODELAY)
        if (apr_is_option_set(sock, APR_TCP_NODELAY) != on) {
            int optlevel = IPPROTO_TCP;
            int optname = TCP_NODELAY;

#if APR_HAVE_SCTP
            if (sock->protocol == IPPROTO_SCTP) {
                optlevel = IPPROTO_SCTP;
                optname = SCTP_NODELAY;
            }
#endif
            if (setsockopt(sock->socketdes, optlevel, optname, (void *)&on, sizeof(int)) == -1) {
                return errno;
            }
            apr_set_option(sock, APR_TCP_NODELAY, on);
        }
#else
        /* BeOS pre-BONE has TCP_NODELAY set by default.
         * As it can't be turned off we might as well check if they're asking
         * for it to be turned on!
         */
#ifdef BEOS
        if (on == 1)
            return APR_SUCCESS;
        else
#endif
        return APR_ENOTIMPL;
#endif
        break;
    case APR_TCP_NOPUSH:
#if APR_TCP_NOPUSH_FLAG
        /* TCP_NODELAY and TCP_CORK are mutually exclusive on Linux
         * kernels < 2.6; on newer kernels they can be used together
         * and TCP_CORK takes preference, which is the desired
         * behaviour.  On older kernels, TCP_NODELAY must be toggled
         * to "off" whilst TCP_CORK is in effect. */
        if (apr_is_option_set(sock, APR_TCP_NOPUSH) != on) {
#ifndef HAVE_TCP_NODELAY_WITH_CORK
            int optlevel = IPPROTO_TCP;
            int optname = TCP_NODELAY;

#if APR_HAVE_SCTP
            if (sock->protocol == IPPROTO_SCTP) {
                optlevel = IPPROTO_SCTP;
                optname = SCTP_NODELAY;
            }
#endif
            /* OK we're going to change some settings here... */
            if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1 && on) {
                /* Now toggle TCP_NODELAY to off, if TCP_CORK is being
                 * turned on: */
                int tmpflag = 0;
                if (setsockopt(sock->socketdes, optlevel, optname,
                               (void*)&tmpflag, sizeof(int)) == -1) {
                    return errno;
                }
                apr_set_option(sock, APR_RESET_NODELAY, 1);
                apr_set_option(sock, APR_TCP_NODELAY, 0);
            } else if (on) {
                apr_set_option(sock, APR_RESET_NODELAY, 0);
            }
#endif /* HAVE_TCP_NODELAY_WITH_CORK */

            /* OK, now we can just set the TCP_NOPUSH flag accordingly...*/
            if (setsockopt(sock->socketdes, IPPROTO_TCP, APR_TCP_NOPUSH_FLAG,
                           (void*)&on, sizeof(int)) == -1) {
                return errno;
            }
            apr_set_option(sock, APR_TCP_NOPUSH, on);
#ifndef HAVE_TCP_NODELAY_WITH_CORK
            if (!on && apr_is_option_set(sock, APR_RESET_NODELAY)) {
                /* Now, if TCP_CORK was just turned off, turn
                 * TCP_NODELAY back on again if it was earlier toggled
                 * to off: */
                int tmpflag = 1;
                if (setsockopt(sock->socketdes, optlevel, optname,
                               (void*)&tmpflag, sizeof(int)) == -1) {
                    return errno;
                }
                apr_set_option(sock, APR_RESET_NODELAY,0);
                apr_set_option(sock, APR_TCP_NODELAY, 1);
            }
#endif /* HAVE_TCP_NODELAY_WITH_CORK */
        }
#else
        return APR_ENOTIMPL;
#endif
        break;
    case APR_INCOMPLETE_READ:
        apr_set_option(sock, APR_INCOMPLETE_READ, on);
        break;
    case APR_IPV6_V6ONLY:
#if APR_HAVE_IPV6 && defined(IPV6_V6ONLY)
        /* we don't know the initial setting of this option,
         * so don't check sock->options since that optimization
         * won't work
         */
        if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_V6ONLY,
                       (void *)&on, sizeof(int)) == -1) {
            return errno;
        }
        apr_set_option(sock, APR_IPV6_V6ONLY, on);
#else
        return APR_ENOTIMPL;
#endif
        break;
    default:
        return APR_EINVAL;
    }

    return APR_SUCCESS; 
}         
Esempio n. 3
0
/** Drain and close the socket
 * @param sd        socket to close
 * @param l         logger
 * @return          -1: socket to close is invalid
 *                  -1: some kind of error occured (!WIN32)
 *                  SOCKET_ERROR: some kind of error occured  (WIN32)
 *                  0: success
 * @remark          Does not change errno
 */
int jk_shutdown_socket(jk_sock_t sd, jk_logger_t *l)
{
    char dummy[512];
    char buf[DUMP_SINFO_BUF_SZ];
    char *sb = NULL;
    int rc = 0;
    size_t rd = 0;
    size_t rp = 0;
    int save_errno;
    int timeout = MS_TO_LINGER;
    time_t start = time(NULL);

    JK_TRACE_ENTER(l);

    if (!IS_VALID_SOCKET(sd)) {
        JK_TRACE_EXIT(l);
        return -1;
    }

    save_errno = errno;
    if (JK_IS_DEBUG_LEVEL(l)) {
        sb = jk_dump_sinfo(sd, buf, sizeof(buf));
        jk_log(l, JK_LOG_DEBUG, "About to shutdown socket %d [%s]",
               sd, sb);
    }
    /* Shut down the socket for write, which will send a FIN
     * to the peer.
     */
    if (shutdown(sd, SHUT_WR)) {
        rc = jk_close_socket(sd, l);
        if (JK_IS_DEBUG_LEVEL(l))
            jk_log(l, JK_LOG_DEBUG,
                   "Failed sending SHUT_WR for socket %d [%s]",
                   sd, sb);
        errno = save_errno;
        JK_TRACE_EXIT(l);
        return rc;
    }

    do {
        rp = 0;
        if (jk_is_input_event(sd, timeout, l)) {
            /* Do a restartable read on the socket
             * draining out all the data currently in the socket buffer.
             */
            int num = 0;
            do {
                num++;
#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
                rc = recv(sd, &dummy[0], sizeof(dummy), 0);
                if (JK_IS_SOCKET_ERROR(rc))
                    JK_GET_SOCKET_ERRNO();
#else
                rc = read(sd, &dummy[0], sizeof(dummy));
#endif
                if (rc > 0)
                    rp += rc;
            } while (JK_IS_SOCKET_ERROR(rc) && (errno == EINTR || errno == EAGAIN) && num < MAX_READ_RETRY);

            if (rc < 0) {
                /* Read failed.
                 * Bail out from the loop.
                 */
                break;
            }
        }
        else {
            /* Error or timeout (reason is logged within jk_is_input_event)
             * Exit the drain loop
             */
            break;
        }
        rd += rp;
        if (rp < sizeof(dummy)) {
            if (timeout > MS_TO_LINGER_LAST) {
                /* Try one last time with a short timeout
                */
                timeout = MS_TO_LINGER_LAST;
                continue;
            }
            /* We have read less then size of buffer
             * It's a good chance there will be no more data
             * to read.
             */
            if ((rc = sononblock(sd))) {
                rc = jk_close_socket(sd, l);
                if (JK_IS_DEBUG_LEVEL(l))
                    jk_log(l, JK_LOG_DEBUG,
                           "error setting socket %d [%s] to nonblocking",
                           sd, sb);
                errno = save_errno;
                JK_TRACE_EXIT(l);
                return rc;
            }
            if (JK_IS_DEBUG_LEVEL(l))
                jk_log(l, JK_LOG_DEBUG,
                       "shutting down the read side of socket %d [%s]",
                       sd, sb);
            shutdown(sd, SHUT_RD);
            break;
        }
        timeout = MS_TO_LINGER;
    } while ((rd < MAX_LINGER_BYTES) && (difftime(time(NULL), start) < MAX_SECS_TO_LINGER));

    rc = jk_close_socket(sd, l);
    if (JK_IS_DEBUG_LEVEL(l))
        jk_log(l, JK_LOG_DEBUG,
               "Shutdown socket %d [%s] and read %d lingering bytes in %d sec.",
               sd, sb, rd, (int)difftime(time(NULL), start));
    errno = save_errno;
    JK_TRACE_EXIT(l);
    return rc;
}
Esempio n. 4
0
/** Non-blocking socket connect
 * @param sd       socket to connect
 * @param addr     address to connect to
 * @param source   optional source address
 * @param timeout  connect timeout in seconds
 *                 (<=0: no timeout=blocking)
 * @param l        logger
 * @return         -1: some kind of error occured
 *                 0: success
 */
static int nb_connect(jk_sock_t sd, jk_sockaddr_t *addr, jk_sockaddr_t *source,
                      int timeout, jk_logger_t *l)
{
    int rc = 0;
    char buf[64];

    JK_TRACE_ENTER(l);

    if (source != NULL) {
        if (bind(sd, (const struct sockaddr *)&source->sa.sin, source->salen)) {
            JK_GET_SOCKET_ERRNO();
            jk_log(l, JK_LOG_ERROR,
                   "error during source bind on socket %d [%s] (errno=%d)",
                   sd, jk_dump_hinfo(source, buf, sizeof(buf)), errno);
        }
    }
    if (timeout > 0) {
        if (sononblock(sd)) {
            JK_TRACE_EXIT(l);
            return -1;
        }
    }
    do {
        rc = connect(sd, (const struct sockaddr *)&addr->sa.sin, addr->salen);
    } while (rc == -1 && errno == EINTR);

    if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY)
                   && (timeout > 0)) {
        fd_set wfdset;
        struct timeval tv;
        socklen_t rclen = (socklen_t)sizeof(rc);

        FD_ZERO(&wfdset);
        FD_SET(sd, &wfdset);
        tv.tv_sec = timeout / 1000;
        tv.tv_usec = (timeout % 1000) * 1000;
        rc = select(sd + 1, NULL, &wfdset, NULL, &tv);
        if (rc <= 0) {
            /* Save errno */
            int err = errno;
            soblock(sd);
            errno = err;
            JK_TRACE_EXIT(l);
            return -1;
        }
        rc = 0;
#ifdef SO_ERROR
        if (!FD_ISSET(sd, &wfdset) ||
            (getsockopt(sd, SOL_SOCKET, SO_ERROR,
                        (char *)&rc, &rclen) < 0) || rc) {
            if (rc)
                errno = rc;
            rc = -1;
        }
#endif /* SO_ERROR */
    }
    /* Not sure we can be already connected */
    if (rc == -1 && errno == EISCONN)
        rc = 0;
    soblock(sd);
    JK_TRACE_EXIT(l);
    return rc;
}
Esempio n. 5
0
/** Non-blocking socket connect
 * @param sd       socket to connect
 * @param addr     address to connect to
 * @param source   optional source address
 * @param timeout  connect timeout in seconds
 *                 (<=0: no timeout=blocking)
 * @param l        logger
 * @return         -1: some kind of error occured
 *                 SOCKET_ERROR: no timeout given and error
 *                               during blocking connect
 *                 0: success
 */
static int nb_connect(jk_sock_t sd, jk_sockaddr_t *addr, jk_sockaddr_t *source,
                      int timeout, jk_logger_t *l)
{
    int rc;
    char buf[64];

    JK_TRACE_ENTER(l);

    if (source != NULL) {
        if (bind(sd, (const struct sockaddr *)&source->sa.sin, source->salen)) {
            JK_GET_SOCKET_ERRNO();
            jk_log(l, JK_LOG_ERROR,
                   "error during source bind on socket %d [%s] (errno=%d)",
                   sd, jk_dump_hinfo(source, buf, sizeof(buf)), errno);
        }
    }
    if (timeout <= 0) {
        rc = connect(sd, (const struct sockaddr *)&addr->sa.sin, addr->salen);
        JK_TRACE_EXIT(l);
        return rc;
    }

    if ((rc = sononblock(sd))) {
        JK_TRACE_EXIT(l);
        return -1;
    }
    if (JK_IS_SOCKET_ERROR(connect(sd, (const struct sockaddr *)&addr->sa.sin, addr->salen))) {
        struct timeval tv;
        fd_set wfdset, efdset;

        if ((rc = WSAGetLastError()) != WSAEWOULDBLOCK) {
            soblock(sd);
            WSASetLastError(rc);
            JK_TRACE_EXIT(l);
            return -1;
        }
        /* wait for the connect to complete or timeout */
        FD_ZERO(&wfdset);
        FD_SET(sd, &wfdset);
        FD_ZERO(&efdset);
        FD_SET(sd, &efdset);

        tv.tv_sec = timeout / 1000;
        tv.tv_usec = (timeout % 1000) * 1000;

        rc = select((int)sd + 1, NULL, &wfdset, &efdset, &tv);
        if (JK_IS_SOCKET_ERROR(rc) || rc == 0) {
            rc = WSAGetLastError();
            soblock(sd);
            WSASetLastError(rc);
            JK_TRACE_EXIT(l);
            return -1;
        }
        /* Evaluate the efdset */
        if (FD_ISSET(sd, &efdset)) {
            /* The connect failed. */
            int rclen = (int)sizeof(rc);
            if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (char*) &rc, &rclen))
                rc = 0;
            soblock(sd);
            if (rc)
                WSASetLastError(rc);
            JK_TRACE_EXIT(l);
            return -1;
        }
    }
    soblock(sd);
    JK_TRACE_EXIT(l);
    return 0;
}
Esempio n. 6
0
apr_status_t apr_socket_opt_set(apr_socket_t *sock, 
                                apr_int32_t opt, apr_int32_t on)
{
    int one;
    apr_status_t rv;

    if (on)
        one = 1;
    else
        one = 0;
    switch(opt) {
    case APR_SO_KEEPALIVE:
#ifdef SO_KEEPALIVE
        if (on != apr_is_option_set(sock->netmask, APR_SO_KEEPALIVE)) {
            if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, sizeof(int)) == -1) {
                return errno;
            }
            apr_set_option(&sock->netmask,APR_SO_KEEPALIVE, on);
        }
#else
        return APR_ENOTIMPL;
#endif
        break;
    case APR_SO_DEBUG:
        if (on != apr_is_option_set(sock->netmask, APR_SO_DEBUG)) {
            if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(int)) == -1) {
                return errno;
            }
            apr_set_option(&sock->netmask, APR_SO_DEBUG, on);
        }
        break;
    case APR_SO_REUSEADDR:
        if (on != apr_is_option_set(sock->netmask, APR_SO_REUSEADDR)) {
            if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) {
                return errno;
            }
            apr_set_option(&sock->netmask, APR_SO_REUSEADDR, on);
        }
        break;
    case APR_SO_SNDBUF:
#ifdef SO_SNDBUF
        if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, (void *)&on, sizeof(int)) == -1) {
            return errno;
        }
#else
        return APR_ENOTIMPL;
#endif
        break;
    case APR_SO_RCVBUF:
#ifdef SO_RCVBUF
        if (setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVBUF, (void *)&on, sizeof(int)) == -1) {
            return errno;
        }
#else
        return APR_ENOTIMPL;
#endif
        break;
    case APR_SO_NONBLOCK:
        if (apr_is_option_set(sock->netmask, APR_SO_NONBLOCK) != on) {
            if (on) {
                if ((rv = sononblock(sock->socketdes)) != APR_SUCCESS) 
                    return rv;
            }
            else {
                if ((rv = soblock(sock->socketdes)) != APR_SUCCESS)
                    return rv;
            }
            apr_set_option(&sock->netmask, APR_SO_NONBLOCK, on);
        }
        break;
    case APR_SO_LINGER:
#ifdef SO_LINGER
        if (apr_is_option_set(sock->netmask, APR_SO_LINGER) != on) {
            struct linger li;
            li.l_onoff = on;
            li.l_linger = APR_MAX_SECS_TO_LINGER;
            if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) {
                return errno;
            }
            apr_set_option(&sock->netmask, APR_SO_LINGER, on);
        }
#else
        return APR_ENOTIMPL;
#endif
        break;
    case APR_SO_TIMEOUT:
        /* XXX: To be deprecated */
        return apr_socket_timeout_set(sock, on);
        break;
    case APR_TCP_NODELAY:
#if defined(TCP_NODELAY)
        if (apr_is_option_set(sock->netmask, APR_TCP_NODELAY) != on) {
            int optlevel = IPPROTO_TCP;
            int optname = TCP_NODELAY;

#if APR_HAVE_SCTP
            if (sock->protocol == IPPROTO_SCTP) {
                optlevel = IPPROTO_SCTP;
                optname = SCTP_NODELAY;
            }
#endif
            if (setsockopt(sock->socketdes, optlevel, optname, (void *)&on, sizeof(int)) == -1) {
                return errno;
            }
            apr_set_option(&sock->netmask, APR_TCP_NODELAY, on);
        }
#else
        /* BeOS pre-BONE has TCP_NODELAY set by default.
         * As it can't be turned off we might as well check if they're asking
         * for it to be turned on!
         */
#ifdef BEOS
        if (on == 1)
            return APR_SUCCESS;
        else
#endif
        return APR_ENOTIMPL;
#endif
        break;
    case APR_TCP_NOPUSH:
#if APR_TCP_NOPUSH_FLAG
        if (apr_is_option_set(sock->netmask, APR_TCP_NOPUSH) != on) {
            int optlevel = IPPROTO_TCP;
            int optname = TCP_NODELAY;

#if APR_HAVE_SCTP
            if (sock->protocol == IPPROTO_SCTP) {
                optlevel = IPPROTO_SCTP;
                optname = SCTP_NODELAY;
            }
#endif
            /* OK we're going to change some settings here... */
            /* TCP_NODELAY is mutually exclusive, so do we have it set? */
            if (apr_is_option_set(sock->netmask, APR_TCP_NODELAY) == 1 && on) {
                /* If we want to set NOPUSH then if we have the TCP_NODELAY
                 * flag set we need to switch it off...
                 */
                int tmpflag = 0;
                if (setsockopt(sock->socketdes, optlevel, optname,
                               (void*)&tmpflag, sizeof(int)) == -1) {
                    return errno;
                }
                apr_set_option(&sock->netmask, APR_RESET_NODELAY, 1);
                apr_set_option(&sock->netmask, APR_TCP_NODELAY, 0);
            } else if (on) {
                apr_set_option(&sock->netmask, APR_RESET_NODELAY, 0);
            }
            /* OK, now we can just set the TCP_NOPUSH flag accordingly...*/
            if (setsockopt(sock->socketdes, IPPROTO_TCP, APR_TCP_NOPUSH_FLAG,
                           (void*)&on, sizeof(int)) == -1) {
                return errno;
            }
            apr_set_option(&sock->netmask, APR_TCP_NOPUSH, on);
            if (!on && apr_is_option_set(sock->netmask, APR_RESET_NODELAY)) {
                int tmpflag = 1;
                if (setsockopt(sock->socketdes, optlevel, optname,
                               (void*)&tmpflag, sizeof(int)) == -1) {
                    return errno;
                }
                apr_set_option(&sock->netmask, APR_RESET_NODELAY,0);
                apr_set_option(&sock->netmask, APR_TCP_NODELAY, 1);
            }
        }
#else
        return APR_ENOTIMPL;
#endif
        break;
    case APR_INCOMPLETE_READ:
        apr_set_option(&sock->netmask, APR_INCOMPLETE_READ, on);
        break;
    case APR_IPV6_V6ONLY:
#if APR_HAVE_IPV6 && defined(IPV6_V6ONLY)
        /* we don't know the initial setting of this option,
         * so don't check sock->netmask since that optimization
         * won't work
         */
        if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_V6ONLY,
                       (void *)&on, sizeof(int)) == -1) {
            return errno;
        }
        apr_set_option(&sock->netmask, APR_IPV6_V6ONLY, on);
#else
        return APR_ENOTIMPL;
#endif
        break;
    default:
        return APR_EINVAL;
    }

    return APR_SUCCESS; 
}