Various changes related to the Subversion migration.
[u/mdw/putty] / winnet.c
index 25cfc19..bcb22bf 100644 (file)
--- a/winnet.c
+++ b/winnet.c
@@ -47,8 +47,8 @@
 #include "network.h"
 #include "tree234.h"
 
-#ifdef IPV6
 #include <ws2tcpip.h>
+#ifdef IPV6
 #include <tpipv6.h>
 #endif
 
@@ -168,6 +168,10 @@ DECL_WINSOCK_FUNCTION(static, int, ioctlsocket,
 DECL_WINSOCK_FUNCTION(static, SOCKET, accept,
                      (SOCKET, struct sockaddr FAR *, int FAR *));
 DECL_WINSOCK_FUNCTION(static, int, recv, (SOCKET, char FAR *, int, int));
+DECL_WINSOCK_FUNCTION(static, int, WSAIoctl,
+                     (SOCKET, DWORD, LPVOID, DWORD, LPVOID, DWORD,
+                      LPDWORD, LPWSAOVERLAPPED,
+                      LPWSAOVERLAPPED_COMPLETION_ROUTINE));
 
 static HMODULE winsock_module;
 
@@ -210,6 +214,7 @@ void sk_init(void)
     GET_WINSOCK_FUNCTION(ioctlsocket);
     GET_WINSOCK_FUNCTION(accept);
     GET_WINSOCK_FUNCTION(recv);
+    GET_WINSOCK_FUNCTION(WSAIoctl);
 
     if (p_WSAStartup(winsock_ver, &wsadata)) {
        fatalbox("Unable to initialise WinSock");
@@ -232,6 +237,8 @@ void sk_cleanup(void)
        for (i = 0; (s = index234(sktree, i)) != NULL; i++) {
            p_closesocket(s->s);
        }
+       freetree234(sktree);
+       sktree = NULL;
     }
 
     p_WSACleanup();
@@ -490,6 +497,37 @@ int sk_hostname_is_local(char *name)
     return !strcmp(name, "localhost");
 }
 
+static INTERFACE_INFO local_interfaces[16];
+static int n_local_interfaces;       /* 0=not yet, -1=failed, >0=number */
+
+static int ipv4_is_local_addr(struct in_addr addr)
+{
+    if (ipv4_is_loopback(addr))
+       return 1;                      /* loopback addresses are local */
+    if (!n_local_interfaces) {
+       SOCKET s = p_socket(AF_INET, SOCK_DGRAM, 0);
+       DWORD retbytes;
+
+       if (p_WSAIoctl &&
+           p_WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0,
+                      local_interfaces, sizeof(local_interfaces),
+                      &retbytes, NULL, NULL) == 0)
+           n_local_interfaces = retbytes / sizeof(INTERFACE_INFO);
+       else
+           logevent(NULL, "Unable to get list of local IP addresses");
+    }
+    if (n_local_interfaces > 0) {
+       int i;
+       for (i = 0; i < n_local_interfaces; i++) {
+           SOCKADDR_IN *address =
+               (SOCKADDR_IN *)&local_interfaces[i].iiAddress;
+           if (address->sin_addr.s_addr == addr.s_addr)
+               return 1;              /* this address is local */
+       }
+    }
+    return 0;                 /* this address is not local */
+}
+
 int sk_address_is_local(SockAddr addr)
 {
 #ifdef IPV6
@@ -500,7 +538,7 @@ int sk_address_is_local(SockAddr addr)
     if (addr->family == AF_INET) {
        struct in_addr a;
        a.s_addr = p_htonl(addr->address);
-       return ipv4_is_loopback(a);
+       return ipv4_is_local_addr(a);
     } else {
        assert(addr->family == AF_UNSPEC);
        return 0;                      /* we don't know; assume not */
@@ -620,7 +658,7 @@ Socket sk_register(void *sock, Plug plug)
 }
 
 Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
-             int nodelay, Plug plug)
+             int nodelay, int keepalive, Plug plug)
 {
     static const struct socket_function_table fn_table = {
        sk_tcp_plug,
@@ -684,6 +722,11 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
        p_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b));
     }
 
+    if (keepalive) {
+       BOOL b = TRUE;
+       p_setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b));
+    }
+
     /*
      * Bind to local address.
      */
@@ -1200,7 +1243,7 @@ int select_result(WPARAM wParam, LPARAM lParam)
                    break;
            }
 
-           if (s->localhost_only && !ipv4_is_loopback(isa.sin_addr)) {
+           if (s->localhost_only && !ipv4_is_local_addr(isa.sin_addr)) {
                p_closesocket(t);      /* dodgy WinSock let nonlocal through */
            } else if (plug_accepting(s->plug, (void*)t)) {
                p_closesocket(t);      /* denied or error */
@@ -1319,3 +1362,11 @@ int net_service_lookup(char *service)
     else
        return 0;
 }
+
+SockAddr platform_get_x11_unix_address(int displaynum, char **canonicalname)
+{
+    SockAddr ret = snew(struct SockAddr_tag);
+    memset(ret, 0, sizeof(struct SockAddr_tag));
+    ret->error = "unix sockets not supported on this platform";
+    return ret;
+}