Introduce framework for authenticating with the local X server.
[u/mdw/putty] / unix / uxnet.c
index cad943a..722ab47 100644 (file)
@@ -57,12 +57,18 @@ typedef struct Socket_tag *Actual_Socket;
 
 struct SockAddr_tag {
     char *error;
-    /* address family this belongs to, AF_INET for IPv4, AF_INET6 for IPv6. */
+    /*
+     * Which address family this address belongs to. AF_INET for
+     * IPv4; AF_INET6 for IPv6; AF_UNSPEC indicates that name
+     * resolution has not been done and a simple host name is held
+     * in this SockAddr structure.
+     */
     int family;
     unsigned long address;            /* Address IPv4 style. */
 #ifdef IPV6
     struct addrinfo *ai;              /* Address IPv6 style. */
 #endif
+    char hostname[512];                       /* Store an unresolved host name. */
 };
 
 static tree234 *sktree;
@@ -194,19 +200,33 @@ SockAddr sk_namelookup(char *host, char **canonicalname)
     return ret;
 }
 
+SockAddr sk_nonamelookup(char *host)
+{
+    SockAddr ret = smalloc(sizeof(struct SockAddr_tag));
+    ret->error = NULL;
+    ret->family = AF_UNSPEC;
+    strncpy(ret->hostname, host, lenof(ret->hostname));
+    ret->hostname[lenof(ret->hostname)-1] = '\0';
+    return ret;
+}
+
 void sk_getaddr(SockAddr addr, char *buf, int buflen)
 {
 #ifdef IPV6
-    if (addr->family == AF_INET) {
+    if (addr->family == AF_INET6) {
+       FIXME; /* I don't know how to get a text form of an IPv6 address. */
+    } else
 #endif
+    if (addr->family == AF_INET) {
        struct in_addr a;
        a.s_addr = htonl(addr->address);
        strncpy(buf, inet_ntoa(a), buflen);
-#ifdef IPV6
+       buf[buflen-1] = '\0';
     } else {
-       FIXME; /* I don't know how to get a text form of an IPv6 address. */
+       assert(addr->family == AF_UNSPEC);
+       strncpy(buf, addr->hostname, buflen);
+       buf[buflen-1] = '\0';
     }
-#endif
 }
 
 int sk_hostname_is_local(char *name)
@@ -217,36 +237,42 @@ int sk_hostname_is_local(char *name)
 int sk_address_is_local(SockAddr addr)
 {
 #ifdef IPV6
-    if (addr->family == AF_INET) {
+    if (addr->family == AF_INET6) {
+       FIXME;  /* someone who can compile for IPV6 had better do this bit */
+    } else
 #endif
+    if (addr->family == AF_INET) {
        struct in_addr a;
        a.s_addr = htonl(addr->address);
        return ipv4_is_loopback(a);
-#ifdef IPV6
     } else {
-       FIXME;  /* someone who can compile for IPV6 had better do this bit */
+       assert(addr->family == AF_UNSPEC);
+       return 0;                      /* we don't know; assume not */
     }
-#endif
 }
 
 int sk_addrtype(SockAddr addr)
 {
-    return (addr->family == AF_INET ? ADDRTYPE_IPV4 : ADDRTYPE_IPV6);
+    return (addr->family == AF_INET ? ADDRTYPE_IPV4 :
+#ifdef IPV6
+           addr->family == AF_INET6 ? ADDRTYPE_IPV6 :
+#endif
+           ADDRTYPE_NAME);
 }
 
 void sk_addrcopy(SockAddr addr, char *buf)
 {
+    assert(addr->family != AF_UNSPEC);
 #ifdef IPV6
-    if (addr->family == AF_INET) {
+    if (addr->family == AF_INET6) {
+       memcpy(buf, (char*) addr->ai, 16);
+    } else
 #endif
+    if (addr->family == AF_INET) {
        struct in_addr a;
        a.s_addr = htonl(addr->address);
        memcpy(buf, (char*) &a.s_addr, 4);
-#ifdef IPV6
-    } else {
-       memcpy(buf, (char*) addr->ai, 16);
     }
-#endif
 }
 
 void sk_addr_free(SockAddr addr)
@@ -272,8 +298,8 @@ static void sk_tcp_flush(Socket s)
 }
 
 static void sk_tcp_close(Socket s);
-static int sk_tcp_write(Socket s, char *data, int len);
-static int sk_tcp_write_oob(Socket s, char *data, int len);
+static int sk_tcp_write(Socket s, const char *data, int len);
+static int sk_tcp_write_oob(Socket s, const char *data, int len);
 static void sk_tcp_set_private_ptr(Socket s, void *ptr);
 static void *sk_tcp_get_private_ptr(Socket s);
 static void sk_tcp_set_frozen(Socket s, int is_frozen);
@@ -371,6 +397,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
     /*
      * Open socket.
      */
+    assert(addr->family != AF_UNSPEC);
     s = socket(addr->family, SOCK_STREAM, 0);
     ret->s = s;
 
@@ -463,6 +490,11 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
        a.sin_port = htons((short) port);
     }
 
+    {
+       int i = 1;
+       ioctl(s, FIONBIO, &i);
+    }
+
     if ((
 #ifdef IPV6
            connect(s, ((addr->family == AF_INET6) ?
@@ -472,13 +504,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
            connect(s, (struct sockaddr *) &a, sizeof(a))
 #endif
        ) < 0) {
-       /*
-        * FIXME: We are prepared to receive EWOULDBLOCK here,
-        * because we might want the connection to be made
-        * asynchronously; but how do we actually arrange this in
-        * Unix? I forget.
-        */
-       if ( errno != EWOULDBLOCK ) {
+       if ( errno != EINPROGRESS ) {
            ret->error = error_string(errno);
            return (Socket) ret;
        }
@@ -700,7 +726,7 @@ void try_send(Actual_Socket s)
     }
 }
 
-static int sk_tcp_write(Socket sock, char *buf, int len)
+static int sk_tcp_write(Socket sock, const char *buf, int len)
 {
     Actual_Socket s = (Actual_Socket) sock;
 
@@ -718,7 +744,7 @@ static int sk_tcp_write(Socket sock, char *buf, int len)
     return bufchain_size(&s->output_data);
 }
 
-static int sk_tcp_write_oob(Socket sock, char *buf, int len)
+static int sk_tcp_write_oob(Socket sock, const char *buf, int len)
 {
     Actual_Socket s = (Actual_Socket) sock;
 
@@ -755,11 +781,6 @@ int select_result(int fd, int event)
     noise_ultralight(event);
 
     switch (event) {
-#ifdef FIXME_NONBLOCKING_CONNECTIONS
-      case FIXME:                     /* connected */
-       s->connected = s->writable = 1;
-       break;
-#endif
       case 4:                         /* exceptional */
        if (!s->oobinline) {
            /*
@@ -856,7 +877,14 @@ int select_result(int fd, int event)
        }
        break;
       case 2:                         /* writable */
-       {
+       if (!s->connected) {
+           /*
+            * select() reports a socket as _writable_ when an
+            * asynchronous connection is completed.
+            */
+           s->connected = s->writable = 1;
+           break;
+       } else {
            int bufsize_before, bufsize_after;
            s->writable = 1;
            bufsize_before = s->sending_oob + bufchain_size(&s->output_data);
@@ -961,6 +989,8 @@ static void sk_tcp_set_frozen(Socket sock, int is_frozen)
 static void set_rwx(Actual_Socket s, int *rwx)
 {
     int val = 0;
+    if (!s->connected)
+       val |= 2;                      /* write == connect */
     if (s->connected && !s->frozen)
        val |= 1 | 4;                  /* read, except */
     if (bufchain_size(&s->output_data))