]> jfr.im git - irc/rqf/shadowircd.git/blob - libratbox/src/devpoll.c
Fix up grammar in ShadowIRCd MOTD for great good!
[irc/rqf/shadowircd.git] / libratbox / src / 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
23 * USA
24 *
25 */
26 #include <libratbox_config.h>
27 #include <ratbox_lib.h>
28 #include <commio-int.h>
29 #include <fcntl.h>
30
31 #if defined(HAVE_DEVPOLL) && (HAVE_SYS_DEVPOLL_H)
32 #include <sys/devpoll.h>
33
34 static int dpfd;
35 static int maxfd;
36 static short *fdmask;
37 static void devpoll_update_events(rb_fde_t *, short, PF *);
38 static void devpoll_write_update(int, int);
39
40
41 int
42 rb_setup_fd_devpoll(rb_fde_t *F)
43 {
44 return 0;
45 }
46
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 rb_lib_log("devpoll_write_update: dpfd write failed %d: %s", errno,
69 strerror(errno));
70 /* Done! */
71 }
72
73 static void
74 devpoll_update_events(rb_fde_t *F, short filter, PF * handler)
75 {
76 int update_required = 0;
77 int fd = rb_get_fd(F);
78 int cur_mask = fdmask[fd];
79 PF *cur_handler;
80 fdmask[fd] = 0;
81 switch (filter)
82 {
83 case RB_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 RB_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 return;
103 break;
104 }
105
106 if(cur_handler == NULL && handler != NULL)
107 update_required++;
108 else if(cur_handler != NULL && handler == NULL)
109 update_required++;
110 if(cur_mask != fdmask[fd])
111 update_required++;
112 if(update_required)
113 {
114 /*
115 * Ok, we can call devpoll_write_update() here now to re-build the
116 * fd struct. If we end up with nothing on this fd, it won't write
117 * anything.
118 */
119 if(fdmask[fd])
120 {
121 devpoll_write_update(fd, POLLREMOVE);
122 devpoll_write_update(fd, fdmask[fd]);
123 }
124 else
125 devpoll_write_update(fd, POLLREMOVE);
126 }
127 }
128
129
130
131
132
133 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
134 /* Public functions */
135
136
137 /*
138 * rb_init_netio
139 *
140 * This is a needed exported function which will be called to initialise
141 * the network loop code.
142 */
143 int
144 rb_init_netio_devpoll(void)
145 {
146 dpfd = open("/dev/poll", O_RDWR);
147 if(dpfd < 0)
148 {
149 return errno;
150 }
151 maxfd = getdtablesize() - 2; /* This makes more sense than HARD_FDLIMIT */
152 fdmask = rb_malloc(sizeof(fdmask) * maxfd + 1);
153 rb_open(dpfd, RB_FD_UNKNOWN, "/dev/poll file descriptor");
154 return 0;
155 }
156
157 /*
158 * rb_setselect
159 *
160 * This is a needed exported function which will be called to register
161 * and deregister interest in a pending IO state for a given FD.
162 */
163 void
164 rb_setselect_devpoll(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
165 {
166 lrb_assert(IsFDOpen(F));
167
168 if(type & RB_SELECT_READ)
169 {
170 devpoll_update_events(F, RB_SELECT_READ, handler);
171 F->read_handler = handler;
172 F->read_data = client_data;
173 }
174 if(type & RB_SELECT_WRITE)
175 {
176 devpoll_update_events(F, RB_SELECT_WRITE, handler);
177 F->write_handler = handler;
178 F->write_data = client_data;
179 }
180 }
181
182 /*
183 * Check all connections for new connections and input data that is to be
184 * processed. Also check for connections with data queued and whether we can
185 * write it out.
186 */
187
188 /*
189 * rb_select
190 *
191 * Called to do the new-style IO, courtesy of squid (like most of this
192 * new IO code). This routine handles the stuff we've hidden in
193 * rb_setselect and fd_table[] and calls callbacks for IO ready
194 * events.
195 */
196
197 int
198 rb_select_devpoll(long delay)
199 {
200 int num, i;
201 struct pollfd pollfds[maxfd];
202 struct dvpoll dopoll;
203
204 do
205 {
206 for(;;)
207 {
208 dopoll.dp_timeout = delay;
209 dopoll.dp_nfds = maxfd;
210 dopoll.dp_fds = &pollfds[0];
211 num = ioctl(dpfd, DP_POLL, &dopoll);
212 if(num >= 0)
213 break;
214 if(rb_ignore_errno(errno))
215 break;
216 rb_set_time();
217 return RB_ERROR;
218 }
219
220 rb_set_time();
221 if(num == 0)
222 continue;
223
224 for(i = 0; i < num; i++)
225 {
226 int fd = dopoll.dp_fds[i].fd;
227 PF *hdl = NULL;
228 rb_fde_t *F = rb_find_fd(fd);
229 if((dopoll.dp_fds[i].revents & (POLLRDNORM | POLLIN | POLLHUP |
230 POLLERR))
231 && (dopoll.dp_fds[i].events & (POLLRDNORM | POLLIN)))
232 {
233 if((hdl = F->read_handler) != NULL)
234 {
235 F->read_handler = NULL;
236 hdl(F, F->read_data);
237 /*
238 * this call used to be with a NULL pointer, BUT
239 * in the devpoll case we only want to update the
240 * poll set *if* the handler changes state (active ->
241 * NULL or vice versa.)
242 */
243 devpoll_update_events(F, RB_SELECT_READ, F->read_handler);
244 }
245 }
246
247 if(!IsFDOpen(F))
248 continue; /* Read handler closed us..go on to do something more useful */
249 if((dopoll.dp_fds[i].revents & (POLLWRNORM | POLLOUT | POLLHUP |
250 POLLERR))
251 && (dopoll.dp_fds[i].events & (POLLWRNORM | POLLOUT)))
252 {
253 if((hdl = F->write_handler) != NULL)
254 {
255 F->write_handler = NULL;
256 hdl(F, F->write_data);
257 /* See above similar code in the read case */
258 devpoll_update_events(F,
259 RB_SELECT_WRITE, F->write_handler);
260 }
261
262 }
263 }
264 return RB_OK;
265 }
266 while(0);
267 /* XXX Get here, we broke! */
268 return 0;
269 }
270
271 #else /* /dev/poll not supported */
272 int
273 rb_init_netio_devpoll(void)
274 {
275 return ENOSYS;
276 }
277
278 void
279 rb_setselect_devpoll(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
280 {
281 errno = ENOSYS;
282 return;
283 }
284
285 int
286 rb_select_devpoll(long delay)
287 {
288 errno = ENOSYS;
289 return -1;
290 }
291
292 int
293 rb_setup_fd_devpoll(rb_fde_t *F)
294 {
295 errno = ENOSYS;
296 return -1;
297 }
298 #endif