]> jfr.im git - irc/rqf/shadowircd.git/blob - libcharybdis/devpoll.c
[svn] - apparently setting KE_LENGTH to 128 is fine.
[irc/rqf/shadowircd.git] / libcharybdis / devpoll.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * s_bsd_devpoll.c: /dev/poll 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
24 *
25 * $Id: devpoll.c 3354 2007-04-03 09:21:31Z nenolod $
26 */
27
28 #include "config.h"
29
30 #include "stdinc.h"
31 #include <sys/devpoll.h>
32
33 #include "libcharybdis.h"
34
35 #define POLL_LENGTH 1024
36
37 static void devpoll_update_events(int, short, PF *);
38 static int dpfd;
39 static short fdmask[POLL_LENGTH];
40 static void devpoll_update_events(int, short, PF *);
41 static void devpoll_write_update(int, int);
42
43 /* #define NOTYET 1 */
44
45 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
46 /* Private functions */
47
48 /*
49 * Write an update to the devpoll filter.
50 * See, we end up having to do a seperate (?) remove before we do an
51 * add of a new polltype, so we have to have this function seperate from
52 * the others.
53 */
54 static void
55 devpoll_write_update(int fd, int events)
56 {
57 struct pollfd pollfds[1]; /* Just to be careful */
58 int retval;
59
60 /* Build the pollfd entry */
61 pollfds[0].revents = 0;
62 pollfds[0].fd = fd;
63 pollfds[0].events = events;
64
65 /* Write the thing to our poll fd */
66 retval = write(dpfd, &pollfds[0], sizeof(struct pollfd));
67 if(retval != sizeof(struct pollfd))
68 libcharybdis_log("devpoll_write_update: dpfd write failed %d: %s", errno, strerror(errno));
69 /* Done! */
70 }
71
72 void
73 devpoll_update_events(int fd, short filter, PF * handler)
74 {
75 int update_required = 0;
76 int cur_mask = fdmask[fd];
77 PF *cur_handler;
78 fdmask[fd] = 0;
79 fde_t *F = comm_locate_fd(fd);
80
81 switch (filter)
82 {
83 case COMM_SELECT_READ:
84 cur_handler = F->read_handler;
85 if(handler)
86 fdmask[fd] |= POLLRDNORM;
87 else
88 fdmask[fd] &= ~POLLRDNORM;
89 if(F->write_handler)
90 fdmask[fd] |= POLLWRNORM;
91 break;
92 case COMM_SELECT_WRITE:
93 cur_handler = F->write_handler;
94 if(handler)
95 fdmask[fd] |= POLLWRNORM;
96 else
97 fdmask[fd] &= ~POLLWRNORM;
98 if(F->read_handler)
99 fdmask[fd] |= POLLRDNORM;
100 break;
101 default:
102 #ifdef NOTYET
103 libcharybdis_log("devpoll_update_events called with unknown filter: %hd", filter);
104 #endif
105 return;
106 break;
107 }
108
109 if(cur_handler == NULL && handler != NULL)
110 update_required++;
111 else if(cur_handler != NULL && handler == NULL)
112 update_required++;
113 if(cur_mask != fdmask[fd])
114 update_required++;
115 if(update_required)
116 {
117 /*
118 * Ok, we can call devpoll_write_update() here now to re-build the
119 * fd struct. If we end up with nothing on this fd, it won't write
120 * anything.
121 */
122 if(fdmask[fd])
123 {
124 devpoll_write_update(fd, POLLREMOVE);
125 devpoll_write_update(fd, fdmask[fd]);
126 }
127 else
128 devpoll_write_update(fd, POLLREMOVE);
129 }
130 }
131
132
133
134
135
136 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
137 /* Public functions */
138
139
140 /*
141 * init_netio
142 *
143 * This is a needed exported function which will be called to initialise
144 * the network loop code.
145 */
146 void
147 init_netio(void)
148 {
149 memset(&fdmask, 0, sizeof(fdmask));
150 dpfd = open("/dev/poll", O_RDWR);
151 if(dpfd < 0)
152 {
153 fprintf(stderr,
154 "init_netio: Couldn't open /dev/poll - %d: %s\n",
155 errno, strerror(errno));
156 exit(115); /* Whee! */
157 }
158 }
159
160 /*
161 * comm_setselect
162 *
163 * This is a needed exported function which will be called to register
164 * and deregister interest in a pending IO state for a given FD.
165 */
166 void
167 comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
168 void *client_data, time_t timeout)
169 {
170 fde_t *F = comm_locate_fd(fd);
171 s_assert(fd >= 0);
172 s_assert(F->flags.open);
173
174 /* Update the list, even though we're not using it .. */
175 F->list = list;
176
177 if(type & COMM_SELECT_READ)
178 {
179 devpoll_update_events(fd, COMM_SELECT_READ, handler);
180 F->read_handler = handler;
181 F->read_data = client_data;
182 }
183 if(type & COMM_SELECT_WRITE)
184 {
185 devpoll_update_events(fd, COMM_SELECT_WRITE, handler);
186 F->write_handler = handler;
187 F->write_data = client_data;
188 }
189 if(timeout)
190 F->timeout = CurrentTime + (timeout / 1000);
191 }
192
193 /*
194 * Check all connections for new connections and input data that is to be
195 * processed. Also check for connections with data queued and whether we can
196 * write it out.
197 */
198
199 /*
200 * comm_select
201 *
202 * Called to do the new-style IO, courtesy of squid (like most of this
203 * new IO code). This routine handles the stuff we've hidden in
204 * comm_setselect and fd_table[] and calls callbacks for IO ready
205 * events.
206 */
207
208 int
209 comm_select(unsigned long delay)
210 {
211 int num, i;
212 struct pollfd pollfds[POLL_LENGTH];
213 struct dvpoll dopoll;
214
215 do
216 {
217 for (;;)
218 {
219 dopoll.dp_timeout = delay;
220 dopoll.dp_nfds = POLL_LENGTH;
221 dopoll.dp_fds = &pollfds[0];
222 num = ioctl(dpfd, DP_POLL, &dopoll);
223 if(num >= 0)
224 break;
225 if(ignoreErrno(errno))
226 break;
227 set_time();
228 return COMM_ERROR;
229 }
230
231 set_time();
232 if(num == 0)
233 continue;
234
235 for (i = 0; i < num; i++)
236 {
237 int fd = dopoll.dp_fds[i].fd;
238 PF *hdl = NULL;
239 fde_t *F = comm_locate_fd(fd);
240 if((dopoll.dp_fds[i].
241 revents & (POLLRDNORM | POLLIN | POLLHUP |
242 POLLERR))
243 && (dopoll.dp_fds[i].events & (POLLRDNORM | POLLIN)))
244 {
245 if((hdl = F->read_handler) != NULL)
246 {
247 F->read_handler = NULL;
248 hdl(fd, F->read_data);
249 /*
250 * this call used to be with a NULL pointer, BUT
251 * in the devpoll case we only want to update the
252 * poll set *if* the handler changes state (active ->
253 * NULL or vice versa.)
254 */
255 devpoll_update_events(fd,
256 COMM_SELECT_READ, F->read_handler);
257 }
258 else
259 libcharybdis_log("comm_select: Unhandled read event: fdmask: %x",
260 fdmask[fd]);
261 }
262
263 if(F->flags.open == 0)
264 continue; /* Read handler closed us..go on to do something more useful */
265 if((dopoll.dp_fds[i].
266 revents & (POLLWRNORM | POLLOUT | POLLHUP |
267 POLLERR))
268 && (dopoll.dp_fds[i].events & (POLLWRNORM | POLLOUT)))
269 {
270 if((hdl = F->write_handler) != NULL)
271 {
272 F->write_handler = NULL;
273 hdl(fd, F->write_data);
274 /* See above similar code in the read case */
275 devpoll_update_events(fd,
276 COMM_SELECT_WRITE, F->write_handler);
277 }
278 else
279 libcharybdis_log("comm_select: Unhandled write event: fdmask: %x",
280 fdmask[fd]);
281
282 }
283 if(dopoll.dp_fds[i].revents & POLLNVAL)
284 {
285 libcharybdis_log("revents was Invalid for %d", fd);
286 }
287 }
288 return COMM_OK;
289 }
290 while (0);
291 /* XXX Get here, we broke! */
292 return 0;
293 }
294