diff options
author | trawick <trawick@13f79535-47bb-0310-9956-ffa450edef68> | 2000-06-28 22:36:28 +0000 |
---|---|---|
committer | trawick <trawick@13f79535-47bb-0310-9956-ffa450edef68> | 2000-06-28 22:36:28 +0000 |
commit | b825c6c300f8d2435e0378de000b82fbe701677c (patch) | |
tree | e9c756d4974b01aea934fc9cc9eef919ea74e5f5 /network_io | |
parent | a680bcfe5d932274ef6fbe3617bce63b21553f68 (diff) | |
download | libapr-b825c6c300f8d2435e0378de000b82fbe701677c.tar.gz |
APR network_io for Unix:
Defer/avoid getsockname() whenever possible.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@60280 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'network_io')
-rw-r--r-- | network_io/unix/networkio.h | 2 | ||||
-rw-r--r-- | network_io/unix/sockaddr.c | 40 | ||||
-rw-r--r-- | network_io/unix/sockets.c | 42 |
3 files changed, 74 insertions, 10 deletions
diff --git a/network_io/unix/networkio.h b/network_io/unix/networkio.h index 6dccfaad8..af28dc7c7 100644 --- a/network_io/unix/networkio.h +++ b/network_io/unix/networkio.h @@ -126,6 +126,8 @@ struct ap_socket_t { #ifndef HAVE_POLL int connected; #endif + int local_port_unknown; + int local_interface_unknown; }; struct ap_pollfd_t { diff --git a/network_io/unix/sockaddr.c b/network_io/unix/sockaddr.c index f17a16b9b..1a912d7f6 100644 --- a/network_io/unix/sockaddr.c +++ b/network_io/unix/sockaddr.c @@ -70,8 +70,32 @@ ap_status_t ap_set_remote_port(ap_socket_t *sock, ap_uint32_t port) +static ap_status_t get_local_addr(ap_socket_t *sock) +{ + socklen_t namelen = sizeof(*sock->local_addr); + + if (getsockname(sock->socketdes, (struct sockaddr *)sock->local_addr, + &namelen) < 0) { + return errno; + } + else { + sock->local_port_unknown = sock->local_interface_unknown = 0; + return APR_SUCCESS; + } +} + + + ap_status_t ap_get_local_port(ap_uint32_t *port, ap_socket_t *sock) { + if (sock->local_port_unknown) { + ap_status_t rv = get_local_addr(sock); + + if (rv != APR_SUCCESS) { + return rv; + } + } + *port = ntohs(sock->local_addr->sin_port); return APR_SUCCESS; } @@ -130,6 +154,14 @@ ap_status_t ap_set_remote_ipaddr(ap_socket_t *sock, const char *addr) ap_status_t ap_get_local_ipaddr(char **addr, ap_socket_t *sock) { + if (sock->local_interface_unknown) { + ap_status_t rv = get_local_addr(sock); + + if (rv != APR_SUCCESS) { + return rv; + } + } + *addr = ap_pstrdup(sock->cntxt, inet_ntoa(sock->local_addr->sin_addr)); return APR_SUCCESS; } @@ -147,6 +179,14 @@ ap_status_t ap_get_remote_ipaddr(char **addr, ap_socket_t *sock) #if APR_HAVE_NETINET_IN_H ap_status_t ap_get_local_name(struct sockaddr_in **name, ap_socket_t *sock) { + if (sock->local_port_unknown || sock->local_interface_unknown) { + ap_status_t rv = get_local_addr(sock); + + if (rv != APR_SUCCESS) { + return rv; + } + } + *name = sock->local_addr; return APR_SUCCESS; } diff --git a/network_io/unix/sockets.c b/network_io/unix/sockets.c index 5445248b5..764d6861a 100644 --- a/network_io/unix/sockets.c +++ b/network_io/unix/sockets.c @@ -115,8 +115,12 @@ ap_status_t ap_bind(ap_socket_t *sock) { if (bind(sock->socketdes, (struct sockaddr *)sock->local_addr, sock->addr_len) == -1) return errno; - else + else { + if (sock->local_addr->sin_port == 0) { /* no need for ntohs() when comparing w/ 0 */ + sock->local_port_unknown = 1; /* kernel got us an ephemeral port */ + } return APR_SUCCESS; + } } ap_status_t ap_listen(ap_socket_t *sock, ap_int32_t backlog) @@ -151,9 +155,22 @@ ap_status_t ap_accept(ap_socket_t **new, ap_socket_t *sock, ap_pool_t *connectio return errno; } - if (getsockname((*new)->socketdes, (struct sockaddr *)(*new)->local_addr, - &((*new)->addr_len)) < 0) { - return errno; + *(*new)->local_addr = *sock->local_addr; + + if (sock->local_port_unknown) { + /* not likely for a listening socket, but theoretically possible :) */ + (*new)->local_port_unknown = 1; + } + + if (sock->local_interface_unknown || + sock->local_addr->sin_addr.s_addr == 0) { + /* If the interface address inside the listening socket's local_addr wasn't + * up-to-date, we don't know local interface of the connected socket either. + * + * If the listening socket was not bound to a specific interface, we + * don't know the local_addr of the connected socket. + */ + (*new)->local_interface_unknown = 1; } ap_register_cleanup((*new)->cntxt, (void *)(*new), @@ -197,8 +214,16 @@ ap_status_t ap_connect(ap_socket_t *sock, char *hostname) return errno; } else { - socklen_t namelen = sizeof(*sock->local_addr); - getsockname(sock->socketdes, (struct sockaddr *)sock->local_addr, &namelen); + if (sock->local_addr->sin_port == 0) { + /* connect() got us an ephemeral port */ + sock->local_port_unknown = 1; + } + if (sock->local_addr->sin_addr.s_addr == 0) { + /* not bound to specific local interface; connect() had to assign + * one for the socket + */ + sock->local_interface_unknown = 1; + } #ifndef HAVE_POLL sock->connected=1; #endif @@ -240,11 +265,8 @@ ap_status_t ap_put_os_sock(ap_socket_t **sock, ap_os_sock_t *thesock, (*sock)->addr_len = sizeof(*(*sock)->local_addr); (*sock)->timeout = -1; - if (getsockname(*thesock, (struct sockaddr *)(*sock)->local_addr, - &((*sock)->addr_len)) < 0) { - return errno; - } } + (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1; (*sock)->socketdes = *thesock; return APR_SUCCESS; } |