1 /*
2 * uxsel.c
3 *
4 * This module is a sort of all-purpose interchange for file
5 * descriptors. At one end it talks to uxnet.c and pty.c and
6 * anything else which might have one or more fds that need
7 * select() or poll()-type things doing to them during an extended
8 * program run; at the other end it talks to pterm.c or uxplink.c or
9 * anything else which might have its own means of actually doing
10 * those select()-type things.
11 */
12
13 #include <assert.h>
14
15 #include "putty.h"
16 #include "tree234.h"
17
18 struct fd {
19 int fd;
20 int rwx; /* 4=except 2=write 1=read */
21 uxsel_callback_fn callback;
22 uxsel_id *id; /* for uxsel_input_remove */
23 };
24
25 static tree234 *fds;
26
uxsel_fd_cmp(void * av,void * bv)27 static int uxsel_fd_cmp(void *av, void *bv)
28 {
29 struct fd *a = (struct fd *)av;
30 struct fd *b = (struct fd *)bv;
31 if (a->fd < b->fd)
32 return -1;
33 if (a->fd > b->fd)
34 return +1;
35 return 0;
36 }
uxsel_fd_findcmp(void * av,void * bv)37 static int uxsel_fd_findcmp(void *av, void *bv)
38 {
39 int *a = (int *)av;
40 struct fd *b = (struct fd *)bv;
41 if (*a < b->fd)
42 return -1;
43 if (*a > b->fd)
44 return +1;
45 return 0;
46 }
47
uxsel_init(void)48 void uxsel_init(void)
49 {
50 fds = newtree234(uxsel_fd_cmp);
51 }
52
53 /*
54 * Here is the interface to fd-supplying modules. They supply an
55 * fd, a set of read/write/execute states, and a callback function
56 * for when the fd satisfies one of those states. Repeated calls to
57 * uxsel_set on the same fd are perfectly legal and serve to change
58 * the rwx state (typically you only want to select an fd for
59 * writing when you actually have pending data you want to write to
60 * it!).
61 */
62
uxsel_set(int fd,int rwx,uxsel_callback_fn callback)63 void uxsel_set(int fd, int rwx, uxsel_callback_fn callback)
64 {
65 struct fd *newfd;
66
67 assert(fd >= 0);
68
69 uxsel_del(fd);
70
71 if (rwx) {
72 newfd = snew(struct fd);
73 newfd->fd = fd;
74 newfd->rwx = rwx;
75 newfd->callback = callback;
76 newfd->id = uxsel_input_add(fd, rwx);
77 add234(fds, newfd);
78 }
79 }
80
uxsel_del(int fd)81 void uxsel_del(int fd)
82 {
83 struct fd *oldfd = find234(fds, &fd, uxsel_fd_findcmp);
84 if (oldfd) {
85 if (oldfd->id)
86 uxsel_input_remove(oldfd->id);
87 del234(fds, oldfd);
88 sfree(oldfd);
89 }
90 }
91
92 /*
93 * And here is the interface to select-functionality-supplying
94 * modules.
95 */
96
next_fd(int * state,int * rwx)97 int next_fd(int *state, int *rwx)
98 {
99 struct fd *fd;
100 fd = index234(fds, (*state)++);
101 if (fd) {
102 *rwx = fd->rwx;
103 return fd->fd;
104 } else
105 return -1;
106 }
107
first_fd(int * state,int * rwx)108 int first_fd(int *state, int *rwx)
109 {
110 *state = 0;
111 return next_fd(state, rwx);
112 }
113
select_result(int fd,int event)114 void select_result(int fd, int event)
115 {
116 struct fd *fdstruct = find234(fds, &fd, uxsel_fd_findcmp);
117
118 noise_ultralight(NOISE_SOURCE_IOID, fd);
119
120 /*
121 * Apparently this can sometimes be NULL. Can't see how, but I
122 * assume it means I need to ignore the event since it's on an
123 * fd I've stopped being interested in. Sigh.
124 */
125 if (fdstruct)
126 fdstruct->callback(fd, event);
127 }
128