--- network_io/unix/sockdup.c (revision 0) +++ network_io/unix/sockdup.c (revision 0) @@ -0,0 +1,134 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apr_arch_networkio.h" +#include "apr_strings.h" +#include "apr_portable.h" +#include "apr_thread_mutex.h" +#include "apr_arch_inherit.h" + +static apr_sockaddr_t *sockaddr_dup(apr_sockadddr_t *oldaddr, + apr_pool_t *p) +{ + apr_sockaddr_t *newaddr = apr_pcalloc(p, sizeof(*newaddr)); + if (!newaddr) { + return NULL; + } + newaddr->pool = p; + newaddr->hostname = apr_pstrdup(p, oldaddr->hostname); + newaddr->servname = apr_pstrdup(p, oldaddr->servname); + newaddr->port = oldaddr->port; + newaddr->family = oldaddr->family; + newaddr->salen = oldaddr->salen; + newaddr->ipaddr_len = oldaddr->ipaddr_len; + newaddr->addr_str_len = oldaddr->addr_str_len; + newaddr->ipaddr_ptr = apr_pmemdup(p, oldaddr->ipaddr_ptr, oldaddr->ipaddr_len); + newaddr->sa = apr_pmemdup(p, oldaddr->sa, oldaddr->salen); + if (oldaddr->next) { + newaddr->next = sockaddr_dup(oldaddr_next, p); + } else { + newaddr->next = NULL; + } + return newaddr; +} + +static apr_status_t sock_dup(apr_socket_t **new_socket, + apr_socket_t *old_socket, apr_pool_t *p, + int which_dup) +{ + int rv; + + if (which_dup == 2) { + if ((*new_socket) == NULL) { + /* We can't dup2 unless we have a valid new_socket */ + return APR_EINVAL; + } + rv = dup2(old_socket->socketdes, (*new_socket)->socketdes); + } else { + rv = dup(old_socket->socketdes); + } + + if (rv == -1) + return errno; + + if (which_dup == 1) { + (*new_socket) = (apr_socket_t *)apr_pcalloc(p, sizeof(apr_socket_t)); + (*new_socket)->pool = p; + (*new_socket)->socketdes = rv; + } + + (*new_socket)->type = old_socket->type; + (*new_socket)->protocol = old_socket->protocol; + (*new_socket)->local_addr = sockaddr_dup(old_socket->local_addr, p); + (*new_socket)->remote_addr = sockaddr_dup(old_socket->remote_addr, p); + (*new_socket)->timeout = old_socket->timeout; +#ifndef HAVE_POLL + (*new_socket)->connected = old_socket->connected; +#endif + (*new_socket)->local_port_unknown = old_socket->local_port_unknown; + (*new_socket)->local_interface_unknown = old_socket->local_interface_unknown; + (*new_socket)->remote_addr_unknown = old_socket->remote_addr_unknown; + + /* apr_socket_dup2() retains the original cleanup, reflecting + * the existing inherit and nocleanup flags. This means, + * that apr_socket_dup2() cannot be called against an apr_socket_t + * already closed with apr_socket_close, because the expected + * cleanup was already killed. + */ + if (which_dup == 2) { + return APR_SUCCESS; + } + + (*new_socket)->options = old_socket->options; + /* The user must call APR_DECLARE_INHERIT_SET(s) on the dupped + * apr_socket_t when desired. + */ +#ifndef WAITIO_USES_POLL + /* Start out with no pollset. apr_wait_for_io_or_timeout() will + * initialize the pollset if needed. + */ + (*new_socket)->pollset = NULL; +#endif + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_socket_dup(apr_socket_t **new_socket, + apr_socket_t *old_socket, apr_pool_t *p) +{ + return socket_dup(new_socket, old_socket, p, 1); +} + +APR_DECLARE(apr_status_t) apr_socket_dup2(apr_socket_t *new_socket, + apr_socket_t *old_socket, apr_pool_t *p) +{ + return socket_dup(&new_socket, old_socket, p, 2); +} + +APR_DECLARE(apr_status_t) apr_socket_setaside(apr_socket_t **new_socket, + apr_socket_t *old_socket, + apr_pool_t *p) +{ + *new_socket = (apr_socket_t *)apr_palloc(p, sizeof(apr_socket_t)); + memcpy(*new_socket, old_socket, sizeof(apr_socket_t)); + (*new_socket)->pool = p; + (*new_socket)->local_addr = sockaddr_dup(old_socket->local_addr, p); + (*new_socket)->remote_addr = sockaddr_dup(old_socket->remote_addr, p); + old_socket->socketdes = -1; +#ifndef WAITIO_USES_POLL + (*new_socket)->pollset = NULL; +#endif + return APR_SUCCESS; +} + * --- include/apr_network_io.h (revision 565699) +++ include/apr_network_io.h (working copy) @@ -576,6 +576,44 @@ char *buf, apr_size_t *len); /** + * Duplicate the specified socket descriptor. + * @param new_socket The structure to duplicate into. + * @param old_socket The socket to duplicate. + * @param p The pool to use for the new socket. + * @remark *new_socket must point to a valid apr_socket_t, or point to NULL. + */ +APR_DECLARE(apr_status_t) apr_socket_dup(apr_socket_t **new_socket, + apr_socket_t *old_socket, + apr_pool_t *p); + +/** + * Duplicate the specified socket descriptor and close the original + * @param new_socket The old socket that is to be closed and reused + * @param old_socket The socket to duplicate + * @param p The pool to use for the new socket + * + * @remark new_socket MUST point at a valid apr_socket_t. It cannot be NULL. + */ +APR_DECLARE(apr_status_t) apr_socket_dup2(apr_socket_t *new_socket, + apr_socket_t *old_socket, + apr_pool_t *p); + +/** + * Move the specified socket descriptor to a new pool + * @param new_socket Pointer in which to return the new apr_socket_t + * @param old_socket The socket to move + * @param p The pool to which the descriptor is to be moved + * @remark Unlike apr_socket_dup2(), this function doesn't do an + * OS dup() operation on the underlying descriptor; it just + * moves the descriptor's apr_socket_t wrapper to a new pool. + * @remark The new pool need not be an ancestor of old_socket's pool. + * @remark After calling this function, old_socket may not be used + */ +APR_DECLARE(apr_status_t) apr_socket_setaside(apr_socket_t **new_socket, + apr_socket_t *old_socket, + apr_pool_t *p); + +/** * Setup socket options for the specified socket * @param sock The socket to set up. * @param opt The option we would like to configure. One of: @@ -597,6 +635,7 @@ * * @param on Value for the option. */ + APR_DECLARE(apr_status_t) apr_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on);