]> jfr.im git - irc/rqf/shadowircd.git/blob - libratbox/src/select.c
Copied libratbox and related stuff from shadowircd upstream.
[irc/rqf/shadowircd.git] / libratbox / src / select.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * select.c: select() compatible network routines.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
8 * Copyright (C) 2002-2005 ircd-ratbox development team
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
23 * USA
24 *
25 * $Id: select.c 26092 2008-09-19 15:13:52Z androsyn $
26 */
27 #define FD_SETSIZE 65535
28 #include <libratbox_config.h>
29 #include <ratbox_lib.h>
30 #include <commio-int.h>
31
32 #if defined(HAVE_SELECT) || defined(_WIN32)
33
34 #ifdef _WIN32
35 #define MY_FD_SET(x, y) FD_SET((SOCKET)x, y)
36 #define MY_FD_CLR(x, y) FD_CLR((SOCKET)x, y)
37 #else
38 #define MY_FD_SET(x, y) FD_SET(x, y)
39 #define MY_FD_CLR(x, y) FD_CLR(x, y)
40 #endif
41
42 #ifdef HAVE_SYS_SELECT_H
43 #include <sys/select.h>
44 #endif
45 /*
46 * Note that this is only a single list - multiple lists is kinda pointless
47 * under select because the list size is a function of the highest FD :-)
48 * -- adrian
49 */
50
51 static fd_set select_readfds;
52 static fd_set select_writefds;
53
54 /*
55 * You know, I'd rather have these local to rb_select but for some
56 * reason my gcc decides that I can't modify them at all..
57 * -- adrian
58 */
59 static fd_set tmpreadfds;
60 static fd_set tmpwritefds;
61
62 static int rb_maxfd = -1;
63 static void select_update_selectfds(rb_fde_t *F, short event, PF * handler);
64
65 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
66 /* Private functions */
67
68 /*
69 * set and clear entries in the select array ..
70 */
71 static void
72 select_update_selectfds(rb_fde_t *F, short event, PF * handler)
73 {
74 /* Update the read / write set */
75 if(event & RB_SELECT_READ)
76 {
77 if(handler)
78 {
79 MY_FD_SET(F->fd, &select_readfds);
80 F->pflags |= RB_SELECT_READ;
81 }
82 else
83 {
84 MY_FD_CLR(F->fd, &select_readfds);
85 F->pflags &= ~RB_SELECT_READ;
86 }
87 }
88
89 if(event & RB_SELECT_WRITE)
90 {
91 if(handler)
92 {
93 MY_FD_SET(F->fd, &select_writefds);
94 F->pflags |= RB_SELECT_WRITE;
95 }
96 else
97 {
98 MY_FD_CLR(F->fd, &select_writefds);
99 F->pflags &= ~RB_SELECT_WRITE;
100 }
101 }
102
103 if(F->pflags & (RB_SELECT_READ | RB_SELECT_WRITE))
104 {
105 if(F->fd > rb_maxfd)
106 {
107 rb_maxfd = F->fd;
108 }
109 }
110 else if(F->fd <= rb_maxfd)
111 {
112 while(rb_maxfd >= 0 && !FD_ISSET(rb_maxfd, &select_readfds)
113 && !FD_ISSET(rb_maxfd, &select_writefds))
114 rb_maxfd--;
115 }
116 }
117
118
119 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
120 /* Public functions */
121
122 int
123 rb_setup_fd_select(rb_fde_t *F)
124 {
125 return 0;
126 }
127
128
129 /*
130 * rb_init_netio
131 *
132 * This is a needed exported function which will be called to initialise
133 * the network loop code.
134 */
135 extern int rb_maxconnections;
136 int
137 rb_init_netio_select(void)
138 {
139 if(rb_maxconnections > FD_SETSIZE)
140 rb_maxconnections = FD_SETSIZE; /* override this */
141 FD_ZERO(&select_readfds);
142 FD_ZERO(&select_writefds);
143 return 0;
144 }
145
146 /*
147 * rb_setselect
148 *
149 * This is a needed exported function which will be called to register
150 * and deregister interest in a pending IO state for a given FD.
151 */
152 void
153 rb_setselect_select(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
154 {
155 lrb_assert(IsFDOpen(F));
156
157 if(type & RB_SELECT_READ)
158 {
159 F->read_handler = handler;
160 F->read_data = client_data;
161 select_update_selectfds(F, RB_SELECT_READ, handler);
162 }
163 if(type & RB_SELECT_WRITE)
164 {
165 F->write_handler = handler;
166 F->write_data = client_data;
167 select_update_selectfds(F, RB_SELECT_WRITE, handler);
168 }
169 }
170
171 /*
172 * Check all connections for new connections and input data that is to be
173 * processed. Also check for connections with data queued and whether we can
174 * write it out.
175 */
176
177 /*
178 * rb_select
179 *
180 * Do IO events
181 */
182
183 int
184 rb_select_select(long delay)
185 {
186 int num;
187 int fd;
188 PF *hdl;
189 rb_fde_t *F;
190 struct timeval to;
191
192 /* Copy over the read/write sets so we don't have to rebuild em */
193 memcpy(&tmpreadfds, &select_readfds, sizeof(fd_set));
194 memcpy(&tmpwritefds, &select_writefds, sizeof(fd_set));
195
196 for(;;)
197 {
198 to.tv_sec = 0;
199 to.tv_usec = delay * 1000;
200 num = select(rb_maxfd + 1, &tmpreadfds, &tmpwritefds, NULL, &to);
201 if(num >= 0)
202 break;
203 if(rb_ignore_errno(errno))
204 continue;
205 rb_set_time();
206 /* error! */
207 return -1;
208 /* NOTREACHED */
209 }
210 rb_set_time();
211
212 if(num == 0)
213 return 0;
214
215 /* XXX we *could* optimise by falling out after doing num fds ... */
216 for(fd = 0; fd < rb_maxfd + 1; fd++)
217 {
218 F = rb_find_fd(fd);
219 if(F == NULL)
220 continue;
221 if(FD_ISSET(fd, &tmpreadfds))
222 {
223 hdl = F->read_handler;
224 F->read_handler = NULL;
225 if(hdl)
226 hdl(F, F->read_data);
227 }
228
229 if(!IsFDOpen(F))
230 continue; /* Read handler closed us..go on */
231
232 if(FD_ISSET(fd, &tmpwritefds))
233 {
234 hdl = F->write_handler;
235 F->write_handler = NULL;
236 if(hdl)
237 hdl(F, F->write_data);
238 }
239
240 if(F->read_handler == NULL)
241 select_update_selectfds(F, RB_SELECT_READ, NULL);
242 if(F->write_handler == NULL)
243 select_update_selectfds(F, RB_SELECT_WRITE, NULL);
244 }
245 return 0;
246 }
247
248 #else /* select not supported..what sort of garbage is this? */
249 int
250 rb_init_netio_select(void)
251 {
252 return ENOSYS;
253 }
254
255 void
256 rb_setselect_select(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
257 {
258 errno = ENOSYS;
259 return;
260 }
261
262 int
263 rb_select_select(long delay)
264 {
265 errno = ENOSYS;
266 return -1;
267 }
268
269 int
270 rb_setup_fd_select(rb_fde_t *F)
271 {
272 errno = ENOSYS;
273 return -1;
274 }
275
276 #endif