summaryrefslogtreecommitdiff
path: root/network_io
diff options
context:
space:
mode:
authortrawick <trawick@13f79535-47bb-0310-9956-ffa450edef68>2000-06-28 22:36:28 +0000
committertrawick <trawick@13f79535-47bb-0310-9956-ffa450edef68>2000-06-28 22:36:28 +0000
commitb825c6c300f8d2435e0378de000b82fbe701677c (patch)
treee9c756d4974b01aea934fc9cc9eef919ea74e5f5 /network_io
parenta680bcfe5d932274ef6fbe3617bce63b21553f68 (diff)
downloadlibapr-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.h2
-rw-r--r--network_io/unix/sockaddr.c40
-rw-r--r--network_io/unix/sockets.c42
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;
}