]> jfr.im git - irc/rqf/shadowircd.git/blob - libratbox/src/select.c
Fix up grammar in ShadowIRCd MOTD for great good!
[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 */
26 #define FD_SETSIZE 65535
27 #include <libratbox_config.h>
28 #include <ratbox_lib.h>
29 #include <commio-int.h>
30
31 #if defined(HAVE_SELECT) || defined(_WIN32)
32
33 #ifdef _WIN32
34 #define MY_FD_SET(x, y) FD_SET((SOCKET)x, y)
35 #define MY_FD_CLR(x, y) FD_CLR((SOCKET)x, y)
36 #else
37 #define MY_FD_SET(x, y) FD_SET(x, y)
38 #define MY_FD_CLR(x, y) FD_CLR(x, y)
39 #endif
40
41 #ifdef HAVE_SYS_SELECT_H
42 #include <sys/select.h>
43 #endif
44 /*
45 * Note that this is only a single list - multiple lists is kinda pointless
46 * under select because the list size is a function of the highest FD :-)
47 * -- adrian
48 */
49
50 static fd_set select_readfds;
51 static fd_set select_writefds;
52
53 /*
54 * You know, I'd rather have these local to rb_select but for some
55 * reason my gcc decides that I can't modify them at all..
56 * -- adrian
57 */
58 static fd_set tmpreadfds;
59 static fd_set tmpwritefds;
60
61 static int rb_maxfd = -1;
62 static void select_update_selectfds(rb_fde_t *F, short event, PF * handler);
63
64 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
65 /* Private functions */
66
67 /*
68 * set and clear entries in the select array ..
69 */
70 static void
71 select_update_selectfds(rb_fde_t *F, short event, PF * handler)
72 {
73 /* Update the read / write set */
74 if(event & RB_SELECT_READ)
75 {
76 if(handler)
77 {
78 MY_FD_SET(F->fd, &select_readfds);
79 F->pflags |= RB_SELECT_READ;
80 }
81 else
82 {
83 MY_FD_CLR(F->fd, &select_readfds);
84 F->pflags &= ~RB_SELECT_READ;
85 }
86 }
87
88 if(event & RB_SELECT_WRITE)
89 {
90 if(handler)
91 {
92 MY_FD_SET(F->fd, &select_writefds);
93 F->pflags |= RB_SELECT_WRITE;
94 }
95 else
96 {
97 MY_FD_CLR(F->fd, &select_writefds);
98 F->pflags &= ~RB_SELECT_WRITE;
99 }
100 }
101
102 if(F->pflags & (RB_SELECT_READ | RB_SELECT_WRITE))
103 {
104 if(F->fd > rb_maxfd)
105 {
106 rb_maxfd = F->fd;
107 }
108 }
109 else if(F->fd <= rb_maxfd)
110 {
111 while(rb_maxfd >= 0 && !FD_ISSET(rb_maxfd, &select_readfds)
112 && !FD_ISSET(rb_maxfd, &select_writefds))
113 rb_maxfd--;
114 }
115 }
116
117
118 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
119 /* Public functions */
120
121 int
122 rb_setup_fd_select(rb_fde_t *F)
123 {
124 return 0;
125 }
126
127
128 /*
129 * rb_init_netio
130 *
131 * This is a needed exported function which will be called to initialise
132 * the network loop code.
133 */
134 extern int rb_maxconnections;
135 int
136 rb_init_netio_select(void)
137 {
138 if(rb_maxconnections > FD_SETSIZE)
139 rb_maxconnections = FD_SETSIZE; /* override this */
140 FD_ZERO(&select_readfds);
141 FD_ZERO(&select_writefds);
142 return 0;
143 }
144
145 /*
146 * rb_setselect
147 *
148 * This is a needed exported function which will be called to register
149 * and deregister interest in a pending IO state for a given FD.
150 */
151 void
152 rb_setselect_select(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
153 {
154 lrb_assert(IsFDOpen(F));
155
156 if(type & RB_SELECT_READ)
157 {
158 F->read_handler = handler;
159 F->read_data = client_data;
160 select_update_selectfds(F, RB_SELECT_READ, handler);
161 }
162 if(type & RB_SELECT_WRITE)
163 {
164 F->write_handler = handler;
165 F->write_data = client_data;
166 select_update_selectfds(F, RB_SELECT_WRITE, handler);
167 }
168 }
169
170 /*
171 * Check all connections for new connections and input data that is to be
172 * processed. Also check for connections with data queued and whether we can
173 * write it out.
174 */
175
176 /*
177 * rb_select
178 *
179 * Do IO events
180 */
181
182 int
183 rb_select_select(long delay)
184 {
185 int num;
186 int fd;
187 PF *hdl;
188 rb_fde_t *F;
189 struct timeval to;
190
191 /* Copy over the read/write sets so we don't have to rebuild em */
192 memcpy(&tmpreadfds, &select_readfds, sizeof(fd_set));
193 memcpy(&tmpwritefds, &select_writefds, sizeof(fd_set));
194
195 for(;;)
196 {
197 to.tv_sec = 0;
198 to.tv_usec = delay * 1000;
199 num = select(rb_maxfd + 1, &tmpreadfds, &tmpwritefds, NULL, &to);
200 if(num >= 0)
201 break;
202 if(rb_ignore_errno(errno))
203 continue;
204 rb_set_time();
205 /* error! */
206 return -1;
207 /* NOTREACHED */
208 }
209 rb_set_time();
210
211 if(num == 0)
212 return 0;
213
214 /* XXX we *could* optimise by falling out after doing num fds ... */
215 for(fd = 0; fd < rb_maxfd + 1; fd++)
216 {
217 F = rb_find_fd(fd);
218 if(F == NULL)
219 continue;
220 if(FD_ISSET(fd, &tmpreadfds))
221 {
222 hdl = F->read_handler;
223 F->read_handler = NULL;
224 if(hdl)
225 hdl(F, F->read_data);
226 }
227
228 if(!IsFDOpen(F))
229 continue; /* Read handler closed us..go on */
230
231 if(FD_ISSET(fd, &tmpwritefds))
232 {
233 hdl = F->write_handler;
234 F->write_handler = NULL;
235 if(hdl)
236 hdl(F, F->write_data);
237 }
238
239 if(F->read_handler == NULL)
240 select_update_selectfds(F, RB_SELECT_READ, NULL);
241 if(F->write_handler == NULL)
242 select_update_selectfds(F, RB_SELECT_WRITE, NULL);
243 }
244 return 0;
245 }
246
247 #else /* select not supported..what sort of garbage is this? */
248 int
249 rb_init_netio_select(void)
250 {
251 return ENOSYS;
252 }
253
254 void
255 rb_setselect_select(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
256 {
257 errno = ENOSYS;
258 return;
259 }
260
261 int
262 rb_select_select(long delay)
263 {
264 errno = ENOSYS;
265 return -1;
266 }
267
268 int
269 rb_setup_fd_select(rb_fde_t *F)
270 {
271 errno = ENOSYS;
272 return -1;
273 }
274
275 #endif