diff --git a/Recipe b/Recipe index ddc18a1e..1040bb99 100644 --- 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 diff --git a/unix/unix.h b/unix/unix.h index b003ac74..9fd15699 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -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; diff --git a/unix/uxnet.c b/unix/uxnet.c index 9dd4aa62..0795d4d2 100644 --- a/unix/uxnet.c +++ b/unix/uxnet.c @@ -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) diff --git a/unix/uxplink.c b/unix/uxplink.c index e71e6446..a62d34eb 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -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 index 00000000..aaedc022 --- /dev/null +++ b/unix/uxsel.c @@ -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 + +#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); +}