summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/arch/win32/networkio.h2
-rw-r--r--network_io/win32/networkio.h2
-rw-r--r--network_io/win32/sockaddr.c39
-rw-r--r--network_io/win32/sockets.c54
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;
}