0ff9ea38 |
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()-type things doing to them during an extended program |
8 | * 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; |
74aca06d |
22 | int id; /* for uxsel_input_remove */ |
0ff9ea38 |
23 | }; |
24 | |
25 | static tree234 *fds; |
26 | |
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 | } |
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 | |
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 | |
63 | void uxsel_set(int fd, int rwx, uxsel_callback_fn callback) |
64 | { |
65 | struct fd *newfd = snew(struct fd); |
66 | struct fd *oldfd; |
67 | |
68 | newfd->fd = fd; |
69 | newfd->rwx = rwx; |
70 | newfd->callback = callback; |
71 | |
72 | oldfd = find234(fds, newfd, NULL); |
73 | if (oldfd) { |
74aca06d |
74 | uxsel_input_remove(oldfd->id); |
0ff9ea38 |
75 | del234(fds, oldfd); |
76 | sfree(oldfd); |
77 | } |
78 | |
79 | add234(fds, newfd); |
74aca06d |
80 | newfd->id = uxsel_input_add(fd, rwx); |
0ff9ea38 |
81 | } |
82 | |
83 | void uxsel_del(int fd) |
84 | { |
85 | struct fd *oldfd = find234(fds, &fd, uxsel_fd_findcmp); |
86 | if (oldfd) { |
74aca06d |
87 | uxsel_input_remove(oldfd->id); |
0ff9ea38 |
88 | del234(fds, oldfd); |
89 | sfree(oldfd); |
90 | } |
91 | } |
92 | |
93 | /* |
94 | * And here is the interface to select-functionality-supplying |
95 | * modules. |
96 | */ |
97 | |
98 | int next_fd(int *state, int *rwx) |
99 | { |
100 | struct fd *fd; |
101 | fd = index234(fds, (*state)++); |
102 | if (fd) { |
103 | *rwx = fd->rwx; |
104 | return fd->fd; |
105 | } else |
106 | return -1; |
107 | } |
108 | |
109 | int first_fd(int *state, int *rwx) |
110 | { |
111 | *state = 0; |
112 | return next_fd(state, rwx); |
113 | } |
114 | |
115 | int select_result(int fd, int event) |
116 | { |
117 | struct fd *fdstruct = find234(fds, &fd, uxsel_fd_findcmp); |
7718480a |
118 | /* |
119 | * Apparently this can sometimes be NULL. Can't see how, but I |
120 | * assume it means I need to ignore the event since it's on an |
121 | * fd I've stopped being interested in. Sigh. |
122 | */ |
123 | if (fdstruct) |
124 | return fdstruct->callback(fd, event); |
125 | else |
126 | return 1; |
0ff9ea38 |
127 | } |