#define ipv4_is_loopback(addr) \
((p_ntohl(addr.s_addr) & 0xFF000000L) == 0x7F000000L)
+/*
+ * We used to typedef struct Socket_tag *Socket.
+ *
+ * Since we have made the networking abstraction slightly more
+ * abstract, Socket no longer means a tcp socket (it could mean
+ * an ssl socket). So now we must use Actual_Socket when we know
+ * we are talking about a tcp socket.
+ */
+typedef struct Socket_tag *Actual_Socket;
+
struct Socket_tag {
const struct socket_function_table *fn;
/* the above variable absolutely *must* be the first in this structure */
int sending_oob;
int oobinline;
int pending_error; /* in case send() returns error */
+ /*
+ * We sometimes need pairs of Socket structures to be linked:
+ * if we are listening on the same IPv6 and v4 port, for
+ * example. So here we define `parent' and `child' pointers to
+ * track this link.
+ */
+ Actual_Socket parent, child;
};
-/*
- * We used to typedef struct Socket_tag *Socket.
- *
- * Since we have made the networking abstraction slightly more
- * abstract, Socket no longer means a tcp socket (it could mean
- * an ssl socket). So now we must use Actual_Socket when we know
- * we are talking about a tcp socket.
- */
-typedef struct Socket_tag *Actual_Socket;
-
struct SockAddr_tag {
char *error;
/*
unsigned long a;
struct hostent *h = NULL;
char realhost[8192];
+ int ret_family;
+ int err;
/* Clear the structure and default to IPv4. */
memset(ret, 0, sizeof(struct SockAddr_tag));
address_family == ADDRTYPE_IPV6 ? AF_INET6 :
#endif
AF_UNSPEC);
+ ret_family = AF_UNSPEC;
*realhost = '\0';
if ((a = p_inet_addr(host)) == (unsigned long) INADDR_NONE) {
* it will fallback to IPv4. */
typedef int (CALLBACK * FGETADDRINFO) (const char *nodename,
const char *servname,
- const struct addrinfo *
- hints,
- struct addrinfo ** res);
+ const struct addrinfo *hints,
+ struct addrinfo **res);
FGETADDRINFO fGetAddrInfo = NULL;
HINSTANCE dllWSHIP6 = LoadLibrary("wship6.dll");
* Use fGetAddrInfo when it's available
*/
if (fGetAddrInfo) {
- struct addrinfo hints;
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = ret->family;
- if (fGetAddrInfo(host, NULL, &hints, &ret->ai) == 0)
- ret->family = ret->ai->ai_family;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = ret->family;
+ if ((err = fGetAddrInfo(host, NULL, &hints, &ret->ai)) == 0)
+ ret_family = ret->ai->ai_family;
} else
#endif
{
* Otherwise use the IPv4-only gethostbyname...
* (NOTE: we don't use gethostbyname as a fallback!)
*/
- if (ret->family == 0) {
- if ( (h = p_gethostbyname(host)) )
- ret->family = AF_INET;
- }
+ if ( (h = p_gethostbyname(host)) )
+ ret_family = AF_INET;
+ else
+ err = p_WSAGetLastError();
}
- if (ret->family == AF_UNSPEC) {
- DWORD err = p_WSAGetLastError();
+ if (ret_family == AF_UNSPEC) {
ret->error = (err == WSAENETDOWN ? "Network is down" :
- err ==
- WSAHOST_NOT_FOUND ? "Host does not exist" : err
- == WSATRY_AGAIN ? "Host not found" :
+ err == WSAHOST_NOT_FOUND ? "Host does not exist" :
+ err == WSATRY_AGAIN ? "Host not found" :
#ifndef NO_IPV6
fGetAddrInfo ? "getaddrinfo: unknown error" :
#endif
"gethostbyname: unknown error");
} else {
ret->error = NULL;
+ ret->family = ret_family;
#ifndef NO_IPV6
/* If we got an address info use that... */
ret->frozen_readable = 0;
ret->localhost_only = 0; /* unused, but best init anyway */
ret->pending_error = 0;
+ ret->parent = ret->child = NULL;
ret->s = (SOCKET)sock;
ret->frozen_readable = 0;
ret->localhost_only = 0; /* unused, but best init anyway */
ret->pending_error = 0;
+ ret->parent = ret->child = NULL;
/*
* Open socket.
}
Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only,
- int address_family)
+ int orig_address_family)
{
static const struct socket_function_table fn_table = {
sk_tcp_plug,
int retcode;
int on = 1;
+ int address_family;
+
/*
* Create Socket structure.
*/
ret->frozen_readable = 0;
ret->localhost_only = local_host_only;
ret->pending_error = 0;
+ ret->parent = ret->child = NULL;
/*
* Translate address_family from platform-independent constants
* into local reality.
*/
- address_family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
+ address_family = (orig_address_family == ADDRTYPE_IPV4 ? AF_INET :
#ifndef NO_IPV6
- address_family == ADDRTYPE_IPV6 ? AF_INET6 :
+ orig_address_family == ADDRTYPE_IPV6 ? AF_INET6 :
#endif
AF_UNSPEC);
-
-#ifndef NO_IPV6
- /* Let's default to IPv6, this shouldn't hurt anybody
- * If the stack supports IPv6 it will also allow IPv4 connections. */
- if (address_family == AF_UNSPEC) address_family = AF_INET6;
-#else
- /* No other choice, default to IPv4 */
- if (address_family == AF_UNSPEC) address_family = AF_INET;
-#endif
+
+ /*
+ * Our default, if passed the `don't care' value
+ * ADDRTYPE_UNSPEC, is to listen on IPv4. If IPv6 is supported,
+ * we will also set up a second socket listening on IPv6, but
+ * the v4 one is primary since that ought to work even on
+ * non-v6-supporting systems.
+ */
+ if (address_family == AF_UNSPEC) address_family = AF_INET;
/*
* Open socket.
}
if (err) {
+ p_closesocket(s);
ret->error = winsock_error_string(err);
return (Socket) ret;
}
* window, or an EventSelect on an event object. */
errstr = do_select(s, 1);
if (errstr) {
+ p_closesocket(s);
ret->error = errstr;
return (Socket) ret;
}
add234(sktree, ret);
+#ifndef NO_IPV6
+ /*
+ * If we were given ADDRTYPE_UNSPEC, we must also create an
+ * IPv6 listening socket and link it to this one.
+ */
+ if (address_family == AF_INET && orig_address_family == ADDRTYPE_UNSPEC) {
+ Actual_Socket other;
+
+ other = (Actual_Socket) sk_newlistener(srcaddr, port, plug,
+ local_host_only, ADDRTYPE_IPV6);
+
+ if (other) {
+ if (!other->error) {
+ other->parent = ret;
+ ret->child = other;
+ } else {
+ sfree(other);
+ }
+ }
+ }
+#endif
+
return (Socket) ret;
}
extern char *do_select(SOCKET skt, int startup);
Actual_Socket s = (Actual_Socket) sock;
+ if (s->child)
+ sk_tcp_close((Socket)s->child);
+
del234(sktree, s);
do_select(s->s, 0);
p_closesocket(s->s);