Having created and used uxsel, it actually turns out to be
[sgt/putty] / unix / uxnet.c
index 82b413d..0795d4d 100644 (file)
@@ -73,6 +73,8 @@ struct SockAddr_tag {
 
 static tree234 *sktree;
 
+static void uxsel_tell(Actual_Socket s);
+
 static int cmpfortree(void *av, void *bv)
 {
     Actual_Socket a = (Actual_Socket) av, b = (Actual_Socket) bv;
@@ -117,9 +119,9 @@ char *error_string(int error)
     return strerror(error);
 }
 
-SockAddr sk_namelookup(char *host, char **canonicalname)
+SockAddr sk_namelookup(const char *host, char **canonicalname)
 {
-    SockAddr ret = smalloc(sizeof(struct SockAddr_tag));
+    SockAddr ret = snew(struct SockAddr_tag);
     unsigned long a;
     struct hostent *h = NULL;
     char realhost[8192];
@@ -195,14 +197,14 @@ SockAddr sk_namelookup(char *host, char **canonicalname)
     }
     ret->address = ntohl(a);
     realhost[lenof(realhost)-1] = '\0';
-    *canonicalname = smalloc(1+strlen(realhost));
+    *canonicalname = snewn(1+strlen(realhost), char);
     strcpy(*canonicalname, realhost);
     return ret;
 }
 
-SockAddr sk_nonamelookup(char *host)
+SockAddr sk_nonamelookup(const char *host)
 {
-    SockAddr ret = smalloc(sizeof(struct SockAddr_tag));
+    SockAddr ret = snew(struct SockAddr_tag);
     ret->error = NULL;
     ret->family = AF_UNSPEC;
     strncpy(ret->hostname, host, lenof(ret->hostname));
@@ -298,34 +300,34 @@ 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);
 static char *sk_tcp_socket_error(Socket s);
 
+static struct socket_function_table tcp_fn_table = {
+    sk_tcp_plug,
+    sk_tcp_close,
+    sk_tcp_write,
+    sk_tcp_write_oob,
+    sk_tcp_flush,
+    sk_tcp_set_private_ptr,
+    sk_tcp_get_private_ptr,
+    sk_tcp_set_frozen,
+    sk_tcp_socket_error
+};
+
 Socket sk_register(void *sock, Plug plug)
 {
-    static struct socket_function_table fn_table = {
-       sk_tcp_plug,
-       sk_tcp_close,
-       sk_tcp_write,
-       sk_tcp_write_oob,
-       sk_tcp_flush,
-       sk_tcp_set_private_ptr,
-       sk_tcp_get_private_ptr,
-       sk_tcp_set_frozen,
-       sk_tcp_socket_error
-    };
-
     Actual_Socket ret;
 
     /*
      * Create Socket structure.
      */
-    ret = smalloc(sizeof(struct Socket_tag));
-    ret->fn = &fn_table;
+    ret = snew(struct Socket_tag);
+    ret->fn = &tcp_fn_table;
     ret->error = NULL;
     ret->plug = plug;
     bufchain_init(&ret->output_data);
@@ -347,6 +349,7 @@ Socket sk_register(void *sock, Plug plug)
 
     ret->oobinline = 0;
 
+    uxsel_tell(ret);
     add234(sktree, ret);
 
     return (Socket) ret;
@@ -355,18 +358,6 @@ Socket sk_register(void *sock, Plug plug)
 Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
              int nodelay, Plug plug)
 {
-    static struct socket_function_table fn_table = {
-       sk_tcp_plug,
-       sk_tcp_close,
-       sk_tcp_write,
-       sk_tcp_write_oob,
-       sk_tcp_flush,
-       sk_tcp_set_private_ptr,
-       sk_tcp_get_private_ptr,
-       sk_tcp_set_frozen,
-       sk_tcp_socket_error
-    };
-
     int s;
 #ifdef IPV6
     struct sockaddr_in6 a6;
@@ -379,8 +370,8 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
     /*
      * Create Socket structure.
      */
-    ret = smalloc(sizeof(struct Socket_tag));
-    ret->fn = &fn_table;
+    ret = snew(struct Socket_tag);
+    ret->fn = &tcp_fn_table;
     ret->error = NULL;
     ret->plug = plug;
     bufchain_init(&ret->output_data);
@@ -490,6 +481,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) ?
@@ -499,13 +495,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;
        }
@@ -518,6 +508,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
        ret->writable = 1;
     }
 
+    uxsel_tell(ret);
     add234(sktree, ret);
 
     return (Socket) ret;
@@ -525,18 +516,6 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
 
 Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
 {
-    static struct socket_function_table fn_table = {
-       sk_tcp_plug,
-       sk_tcp_close,
-       sk_tcp_write,
-       sk_tcp_write_oob,
-       sk_tcp_flush,
-       sk_tcp_set_private_ptr,
-       sk_tcp_get_private_ptr,
-       sk_tcp_set_frozen,
-       sk_tcp_socket_error
-    };
-
     int s;
 #ifdef IPV6
     struct sockaddr_in6 a6;
@@ -550,8 +529,8 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
     /*
      * Create Socket structure.
      */
-    ret = smalloc(sizeof(struct Socket_tag));
-    ret->fn = &fn_table;
+    ret = snew(struct Socket_tag);
+    ret->fn = &tcp_fn_table;
     ret->error = NULL;
     ret->plug = plug;
     bufchain_init(&ret->output_data);
@@ -648,6 +627,7 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
        return (Socket) ret;
     }
 
+    uxsel_tell(ret);
     add234(sktree, ret);
 
     return (Socket) ret;
@@ -657,11 +637,41 @@ static void sk_tcp_close(Socket sock)
 {
     Actual_Socket s = (Actual_Socket) sock;
 
+    uxsel_del(s->s);
     del234(sktree, s);
     close(s->s);
     sfree(s);
 }
 
+int sk_getxdmdata(void *sock, unsigned long *ip, int *port)
+{
+    Actual_Socket s = (Actual_Socket) sock;
+    struct sockaddr_in addr;
+    socklen_t addrlen;
+
+    /*
+     * We must check that this socket really _is_ an Actual_Socket.
+     */
+    if (s->fn != &tcp_fn_table)
+       return 0;                      /* failure */
+
+    /*
+     * If we ever implement connecting to a local X server through
+     * a Unix socket, we return 0xFFFFFFFF for the IP address and
+     * our current pid for the port. Bizarre, but such is life.
+     */
+
+    addrlen = sizeof(addr);
+    if (getsockname(s->s, (struct sockaddr *)&addr, &addrlen) < 0 ||
+       addr.sin_family != AF_INET)
+       return 0;
+
+    *ip = ntohl(addr.sin_addr.s_addr);
+    *port = ntohs(addr.sin_port);
+
+    return 1;
+}
+
 /*
  * The function which tries to send on a socket once it's deemed
  * writable.
@@ -725,9 +735,10 @@ void try_send(Actual_Socket s)
            }
        }
     }
+    uxsel_tell(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;
 
@@ -745,7 +756,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;
 
@@ -766,7 +777,7 @@ static int sk_tcp_write_oob(Socket sock, char *buf, int len)
     return s->sending_oob;
 }
 
-int select_result(int fd, int event)
+static int net_select_result(int fd, int event)
 {
     int ret;
     int err;
@@ -782,11 +793,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) {
            /*
@@ -883,7 +889,15 @@ 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;
+           uxsel_tell(s);
+           break;
+       } else {
            int bufsize_before, bufsize_after;
            s->writable = 1;
            bufsize_before = s->sending_oob + bufchain_size(&s->output_data);
@@ -977,42 +991,21 @@ static void sk_tcp_set_frozen(Socket sock, int is_frozen)
        recv(s->s, &c, 1, MSG_PEEK);
     }
     s->frozen_readable = 0;
+    uxsel_tell(s);
 }
 
-/*
- * For Unix select()-based frontends: enumerate all sockets
- * currently active, and state whether we currently wish to receive
- * select events on them for reading, writing and exceptional
- * status.
- */
-static void set_rwx(Actual_Socket s, int *rwx)
+static void uxsel_tell(Actual_Socket s)
 {
-    int val = 0;
+    int rwx = 0;
+    if (!s->connected)
+       rwx |= 2;                      /* write == connect */
     if (s->connected && !s->frozen)
-       val |= 1 | 4;                  /* read, except */
+       rwx |= 1 | 4;                  /* read, except */
     if (bufchain_size(&s->output_data))
-       val |= 2;                      /* write */
+       rwx |= 2;                      /* write */
     if (s->listener)
-       val |= 1;                      /* read == accept */
-    *rwx = val;
-}
-
-int first_socket(int *state, int *rwx)
-{
-    Actual_Socket s;
-    *state = 0;
-    s = index234(sktree, (*state)++);
-    if (s)
-       set_rwx(s, rwx);
-    return s ? s->s : -1;
-}
-
-int next_socket(int *state, int *rwx)
-{
-    Actual_Socket s = index234(sktree, (*state)++);
-    if (s)
-       set_rwx(s, rwx);
-    return s ? s->s : -1;
+       rwx |= 1;                      /* read == accept */
+    uxsel_set(s->s, rwx, net_select_result);
 }
 
 int net_service_lookup(char *service)