diff options
-rw-r--r-- | include/arch/win32/networkio.h | 2 | ||||
-rw-r--r-- | network_io/win32/networkio.h | 2 | ||||
-rw-r--r-- | network_io/win32/sockaddr.c | 39 | ||||
-rw-r--r-- | network_io/win32/sockets.c | 54 |
4 files changed, 85 insertions, 12 deletions
diff --git a/include/arch/win32/networkio.h b/include/arch/win32/networkio.h index 8f1437ef5..296127288 100644 --- a/include/arch/win32/networkio.h +++ b/include/arch/win32/networkio.h @@ -66,6 +66,8 @@ struct ap_socket_t { size_t addr_len; ap_interval_time_t timeout; ap_int32_t disconnected; + int local_port_unknown; + int local_interface_unknown; }; struct ap_pollfd_t { diff --git a/network_io/win32/networkio.h b/network_io/win32/networkio.h index 8f1437ef5..296127288 100644 --- a/network_io/win32/networkio.h +++ b/network_io/win32/networkio.h @@ -66,6 +66,8 @@ struct ap_socket_t { size_t addr_len; ap_interval_time_t timeout; ap_int32_t disconnected; + int local_port_unknown; + int local_interface_unknown; }; struct ap_pollfd_t { diff --git a/network_io/win32/sockaddr.c b/network_io/win32/sockaddr.c index 553b02084..d4c724338 100644 --- a/network_io/win32/sockaddr.c +++ b/network_io/win32/sockaddr.c @@ -58,6 +58,21 @@ #include "apr_strings.h" #include <string.h> +static ap_status_t get_local_addr(ap_socket_t *sock) +{ + size_t namelen = sizeof(*sock->local_addr); + + if (getsockname(sock->sock, (struct sockaddr *)sock->local_addr, + &namelen) < 0) { + return WSAGetLastError(); + } + else { + sock->local_port_unknown = sock->local_interface_unknown = 0; + return APR_SUCCESS; + } +} + + ap_status_t ap_set_local_port(ap_socket_t *sock, ap_uint32_t port) { @@ -77,6 +92,14 @@ ap_status_t ap_set_remote_port(ap_socket_t *sock, ap_uint32_t port) 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; } @@ -131,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; } @@ -146,6 +177,14 @@ ap_status_t ap_get_remote_ipaddr(char **addr, ap_socket_t *sock) 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/win32/sockets.c b/network_io/win32/sockets.c index 6c64a36e9..3a5cf8445 100644 --- a/network_io/win32/sockets.c +++ b/network_io/win32/sockets.c @@ -150,8 +150,12 @@ ap_status_t ap_bind(ap_socket_t *sock) if (bind(sock->sock, (struct sockaddr *)sock->local_addr, sock->addr_len) == -1) { return WSAGetLastError(); } - else + else { + if (sock->local_addr->sin_port == 0) { + sock->local_port_unknown = 1; /* ephemeral port */ + } return APR_SUCCESS; + } } ap_status_t ap_listen(ap_socket_t *sock, ap_int32_t backlog) @@ -185,6 +189,24 @@ ap_status_t ap_accept(ap_socket_t **new, ap_socket_t *sock, ap_pool_t *connectio return WSAGetLastError(); } + *(*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), socket_cleanup, ap_null_cleanup); return APR_SUCCESS; @@ -218,20 +240,27 @@ ap_status_t ap_connect(ap_socket_t *sock, char *hostname) sock->remote_addr->sin_family = AF_INET; if (connect(sock->sock, (const struct sockaddr *)sock->remote_addr, - sock->addr_len) == 0) { - return APR_SUCCESS; - } - else { + sock->addr_len) == SOCKET_ERROR) { lasterror = WSAGetLastError(); - if (lasterror == WSAEWOULDBLOCK) { - FD_ZERO(&temp); - FD_SET(sock->sock, &temp); - if (select(sock->sock+1, NULL, &temp, NULL, NULL) == 1) { - return APR_SUCCESS; - } + if (lasterror != WSAEWOULDBLOCK) { + return lasterror; } - return lasterror; + /* wait for the connect to complete */ + FD_ZERO(&temp); + FD_SET(sock->sock, &temp); + if (select(sock->sock+1, NULL, &temp, NULL, NULL) == SOCKET_ERROR) { + return WSAGetLastError(); + } + } + /* connect was OK .. amazing */ + if (sock->local_addr->sin_port == 0) { + sock->local_port_unknown = 1; } + if (sock->local_addr->sin_addr.s_addr == 0) { + /* must be using free-range port */ + sock->local_interface_unknown = 1; + } + return APR_SUCCESS; } ap_status_t ap_get_socketdata(void **data, const char *key, ap_socket_t *socket) @@ -273,6 +302,7 @@ ap_status_t ap_put_os_sock(ap_socket_t **sock, ap_os_sock_t *thesock, (*sock)->timeout = -1; (*sock)->disconnected = 0; } + (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1; (*sock)->sock = *thesock; return APR_SUCCESS; } |