# 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
/* 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;
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;
ret->oobinline = 0;
+ uxsel_tell(ret);
add234(sktree, ret);
return (Socket) ret;
ret->writable = 1;
}
+ uxsel_tell(ret);
add234(sktree, ret);
return (Socket) ret;
return (Socket) ret;
}
+ uxsel_tell(ret);
add234(sktree, ret);
return (Socket) ret;
{
Actual_Socket s = (Actual_Socket) sock;
+ uxsel_del(s->s);
del234(sktree, s);
close(s->s);
sfree(s);
}
}
}
+ uxsel_tell(s);
}
static int sk_tcp_write(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;
* asynchronous connection is completed.
*/
s->connected = s->writable = 1;
+ uxsel_tell(s);
break;
} else {
int bufsize_before, bufsize_after;
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)
{
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;
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.)
putty_signal(SIGWINCH, sigwinch);
sk_init();
+ uxsel_init();
/*
* Start up the connection.
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 {
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)) {
--- /dev/null
+/*
+ * 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);
+}