Added uxsel.c, into which I've moved those parts of the uxnet.c
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 29 Mar 2003 16:47:06 +0000 (16:47 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 29 Mar 2003 16:47:06 +0000 (16:47 +0000)
functionality that deal with selectable fds in general. The idea is
that pty.c will stop passing its fd straight to pterm.c and hand it
to this module instead, and pterm.c will start requesting a general
list of fds from this module rather than expecting a single one from
pty.c, with the ultimate aim of pterm.c being able to form the basis
of a Unix PuTTY as well as pterm proper.

git-svn-id: svn://svn.tartarus.org/sgt/putty@3015 cda61777-01e9-0310-a592-d414129be87e

Recipe
unix/unix.h
unix/uxnet.c
unix/uxplink.c
unix/uxsel.c [new file with mode: 0644]

diff --git a/Recipe b/Recipe
index ddc18a1..1040bb9 100644 (file)
--- a/Recipe
+++ b/Recipe
@@ -115,7 +115,8 @@ SFTP     = sftp int64 logging
 # Pageant or PuTTYgen).
 WINMISC  = misc version winstore settings tree234 winnet proxy cmdline
          + windefs winmisc
-UXMISC   = misc version uxstore settings tree234 uxnet proxy cmdline uxmisc
+UXMISC   = misc version uxstore settings tree234 uxsel uxnet proxy cmdline
+         + uxmisc
 MACMISC  = misc version macstore settings tree234 macnet mtcpnet otnet proxy
          + macmisc macabout
 
index b003ac7..9fd1569 100644 (file)
@@ -61,10 +61,14 @@ char *x_get_default(const char *key);
 /* Things uxstore.c provides to pterm.c */
 void provide_xrm_string(char *string);
 
-/* Things uxnet.c provides to the front end */
+/* The interface used by uxsel.c */
+void uxsel_init(void);
+typedef int (*uxsel_callback_fn)(int fd, int event);
+void uxsel_set(int fd, int rwx, uxsel_callback_fn callback);
+void uxsel_del(int fd);
 int select_result(int fd, int event);
-int first_socket(int *state, int *rwx);
-int next_socket(int *state, int *rwx);
+int first_fd(int *state, int *rwx);
+int next_fd(int *state, int *rwx);
 
 /* uxcfg.c */
 struct controlbox;
index 9dd4aa6..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;
@@ -347,6 +349,7 @@ Socket sk_register(void *sock, Plug plug)
 
     ret->oobinline = 0;
 
+    uxsel_tell(ret);
     add234(sktree, ret);
 
     return (Socket) ret;
@@ -505,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;
@@ -623,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;
@@ -632,6 +637,7 @@ 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);
@@ -729,6 +735,7 @@ void try_send(Actual_Socket s)
            }
        }
     }
+    uxsel_tell(s);
 }
 
 static int sk_tcp_write(Socket sock, const char *buf, int len)
@@ -770,7 +777,7 @@ static int sk_tcp_write_oob(Socket sock, const 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;
@@ -888,6 +895,7 @@ int select_result(int fd, int event)
             * asynchronous connection is completed.
             */
            s->connected = s->writable = 1;
+           uxsel_tell(s);
            break;
        } else {
            int bufsize_before, bufsize_after;
@@ -983,44 +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)
-       val |= 2;                      /* write == connect */
+       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)
index e71e644..a62d34e 100644 (file)
@@ -273,9 +273,9 @@ int main(int argc, char **argv)
 {
     int sending;
     int portnumber = -1;
-    int *sklist;
-    int socket;
-    int i, skcount, sksize, socketstate;
+    int *fdlist;
+    int fd;
+    int i, fdcount, fdsize, fdstate;
     int connopen;
     int exitcode;
     int errors;
@@ -283,8 +283,8 @@ int main(int argc, char **argv)
 
     ssh_get_line = console_get_line;
 
-    sklist = NULL;
-    skcount = sksize = 0;
+    fdlist = NULL;
+    fdcount = fdsize = 0;
     /*
      * Initialise port and protocol to sensible defaults. (These
      * will be overridden by more or less anything.)
@@ -559,6 +559,7 @@ int main(int argc, char **argv)
     putty_signal(SIGWINCH, sigwinch);
 
     sk_init();
+    uxsel_init();
 
     /*
      * Start up the connection.
@@ -623,31 +624,31 @@ int main(int argc, char **argv)
            FD_SET_MAX(2, maxfd, wset);
        }
 
-       /* Count the currently active sockets. */
+       /* Count the currently active fds. */
        i = 0;
-       for (socket = first_socket(&socketstate, &rwx); socket >= 0;
-            socket = next_socket(&socketstate, &rwx)) i++;
+       for (fd = first_fd(&fdstate, &rwx); fd >= 0;
+            fd = next_fd(&fdstate, &rwx)) i++;
 
-       /* Expand the sklist buffer if necessary. */
-       if (i > sksize) {
-           sksize = i + 16;
-           sklist = sresize(sklist, sksize, int);
+       /* Expand the fdlist buffer if necessary. */
+       if (i > fdsize) {
+           fdsize = i + 16;
+           fdlist = sresize(fdlist, fdsize, int);
        }
 
        /*
-        * Add all currently open sockets to the select sets, and
-        * store them in sklist as well.
+        * Add all currently open fds to the select sets, and store
+        * them in fdlist as well.
         */
-       skcount = 0;
-       for (socket = first_socket(&socketstate, &rwx); socket >= 0;
-            socket = next_socket(&socketstate, &rwx)) {
-           sklist[skcount++] = socket;
+       fdcount = 0;
+       for (fd = first_fd(&fdstate, &rwx); fd >= 0;
+            fd = next_fd(&fdstate, &rwx)) {
+           fdlist[fdcount++] = fd;
            if (rwx & 1)
-               FD_SET_MAX(socket, maxfd, rset);
+               FD_SET_MAX(fd, maxfd, rset);
            if (rwx & 2)
-               FD_SET_MAX(socket, maxfd, wset);
+               FD_SET_MAX(fd, maxfd, wset);
            if (rwx & 4)
-               FD_SET_MAX(socket, maxfd, xset);
+               FD_SET_MAX(fd, maxfd, xset);
        }
 
        do {
@@ -659,19 +660,19 @@ int main(int argc, char **argv)
            exit(1);
        }
 
-       for (i = 0; i < skcount; i++) {
-           socket = sklist[i];
+       for (i = 0; i < fdcount; i++) {
+           fd = fdlist[i];
             /*
              * We must process exceptional notifications before
              * ordinary readability ones, or we may go straight
              * past the urgent marker.
              */
-           if (FD_ISSET(socket, &xset))
-               select_result(socket, 4);
-           if (FD_ISSET(socket, &rset))
-               select_result(socket, 1);
-           if (FD_ISSET(socket, &wset))
-               select_result(socket, 2);
+           if (FD_ISSET(fd, &xset))
+               select_result(fd, 4);
+           if (FD_ISSET(fd, &rset))
+               select_result(fd, 1);
+           if (FD_ISSET(fd, &wset))
+               select_result(fd, 2);
        }
 
        if (FD_ISSET(signalpipe[0], &rset)) {
diff --git a/unix/uxsel.c b/unix/uxsel.c
new file mode 100644 (file)
index 0000000..aaedc02
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * uxsel.c
+ * 
+ * This module is a sort of all-purpose interchange for file
+ * descriptors. At one end it talks to uxnet.c and pty.c and
+ * anything else which might have one or more fds that need
+ * select()-type things doing to them during an extended program
+ * run; at the other end it talks to pterm.c or uxplink.c or
+ * anything else which might have its own means of actually doing
+ * those select()-type things.
+ */
+
+#include <assert.h>
+
+#include "putty.h"
+#include "tree234.h"
+
+struct fd {
+    int fd;
+    int rwx;                          /* 4=except 2=write 1=read */
+    uxsel_callback_fn callback;
+};
+
+static tree234 *fds;
+
+static int uxsel_fd_cmp(void *av, void *bv)
+{
+    struct fd *a = (struct fd *)av;
+    struct fd *b = (struct fd *)bv;
+    if (a->fd < b->fd)
+       return -1;
+    if (a->fd > b->fd)
+       return +1;
+    return 0;
+}
+static int uxsel_fd_findcmp(void *av, void *bv)
+{
+    int *a = (int *)av;
+    struct fd *b = (struct fd *)bv;
+    if (*a < b->fd)
+       return -1;
+    if (*a > b->fd)
+       return +1;
+    return 0;
+}
+
+void uxsel_init(void)
+{
+    fds = newtree234(uxsel_fd_cmp);
+}
+
+/*
+ * Here is the interface to fd-supplying modules. They supply an
+ * fd, a set of read/write/execute states, and a callback function
+ * for when the fd satisfies one of those states. Repeated calls to
+ * uxsel_set on the same fd are perfectly legal and serve to change
+ * the rwx state (typically you only want to select an fd for
+ * writing when you actually have pending data you want to write to
+ * it!).
+ */
+
+void uxsel_set(int fd, int rwx, uxsel_callback_fn callback)
+{
+    struct fd *newfd = snew(struct fd);
+    struct fd *oldfd;
+
+    newfd->fd = fd;
+    newfd->rwx = rwx;
+    newfd->callback = callback;
+
+    oldfd = find234(fds, newfd, NULL);
+    if (oldfd) {
+       del234(fds, oldfd);
+       sfree(oldfd);
+    }
+
+    add234(fds, newfd);
+}
+
+void uxsel_del(int fd)
+{
+    struct fd *oldfd = find234(fds, &fd, uxsel_fd_findcmp);
+    if (oldfd) {
+       del234(fds, oldfd);
+       sfree(oldfd);
+    }
+}
+
+/*
+ * And here is the interface to select-functionality-supplying
+ * modules. 
+ */
+
+int next_fd(int *state, int *rwx)
+{
+    struct fd *fd;
+    fd = index234(fds, (*state)++);
+    if (fd) {
+       *rwx = fd->rwx;
+       return fd->fd;
+    } else
+       return -1;
+}
+
+int first_fd(int *state, int *rwx)
+{
+    *state = 0;
+    return next_fd(state, rwx);
+}
+
+int select_result(int fd, int event)
+{
+    struct fd *fdstruct = find234(fds, &fd, uxsel_fd_findcmp);
+    assert(fdstruct != NULL);
+    return fdstruct->callback(fd, event);
+}