]> jfr.im git - solanum.git/blob - librb/src/sigio.c
Revert "Accept expired certificates"
[solanum.git] / librb / src / sigio.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * sigio.c: Linux Realtime SIGIO 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 Aaron Sethman <androsyn@ratbox.org>
9 * Copyright (C) 2002 ircd-ratbox development team
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
24 * USA
25 *
26 */
27
28 #ifndef _GNU_SOURCE
29 #define _GNU_SOURCE 1 /* Needed for F_SETSIG */
30 #endif
31
32 #include <librb_config.h>
33 #include <rb_lib.h>
34 #include <commio-int.h>
35 #include <event-int.h>
36 #include <fcntl.h> /* Yes this needs to be before the ifdef */
37
38 #if defined(HAVE_SYS_POLL_H) && defined(F_SETSIG)
39 #define USING_SIGIO
40 #endif
41
42 #ifdef USING_SIGIO
43
44 #include <signal.h>
45 #include <sys/poll.h>
46
47 #ifdef USE_TIMER_CREATE
48 #define SIGIO_SCHED_EVENT 1
49 #endif
50
51 #define RTSIGIO SIGRTMIN
52 #define RTSIGTIM (SIGRTMIN+1)
53
54
55 struct _pollfd_list
56 {
57 struct pollfd *pollfds;
58 int maxindex; /* highest FD number */
59 int allocated;
60 };
61
62 typedef struct _pollfd_list pollfd_list_t;
63
64 pollfd_list_t pollfd_list;
65 static int can_do_event = 0;
66 static int sigio_is_screwed = 0; /* We overflowed our sigio queue */
67 static sigset_t our_sigset;
68
69
70 /*
71 * rb_init_netio
72 *
73 * This is a needed exported function which will be called to initialise
74 * the network loop code.
75 */
76 int
77 rb_init_netio_sigio(void)
78 {
79 int fd;
80 pollfd_list.pollfds = rb_malloc(rb_getmaxconnect() * (sizeof(struct pollfd)));
81 pollfd_list.allocated = rb_getmaxconnect();
82 for(fd = 0; fd < rb_getmaxconnect(); fd++)
83 {
84 pollfd_list.pollfds[fd].fd = -1;
85 }
86
87 pollfd_list.maxindex = 0;
88
89 sigio_is_screwed = 1; /* Start off with poll first.. */
90
91 sigemptyset(&our_sigset);
92 sigaddset(&our_sigset, RTSIGIO);
93 sigaddset(&our_sigset, SIGIO);
94 #ifdef SIGIO_SCHED_EVENT
95 sigaddset(&our_sigset, RTSIGTIM);
96 #endif
97 sigprocmask(SIG_BLOCK, &our_sigset, NULL);
98 return 0;
99 }
100
101 static inline void
102 resize_pollarray(int fd)
103 {
104 if(rb_unlikely(fd >= pollfd_list.allocated))
105 {
106 int x, old_value = pollfd_list.allocated;
107 pollfd_list.allocated += 1024;
108 pollfd_list.pollfds =
109 rb_realloc(pollfd_list.pollfds,
110 pollfd_list.allocated * (sizeof(struct pollfd)));
111 memset(&pollfd_list.pollfds[old_value + 1], 0, sizeof(struct pollfd) * 1024);
112 for(x = old_value + 1; x < pollfd_list.allocated; x++)
113 {
114 pollfd_list.pollfds[x].fd = -1;
115 }
116 }
117 }
118
119
120 /*
121 * void setup_sigio_fd(int fd)
122 *
123 * Input: File descriptor
124 * Output: None
125 * Side Effect: Sets the FD up for SIGIO
126 */
127
128 int
129 rb_setup_fd_sigio(rb_fde_t *F)
130 {
131 int flags = 0;
132 int fd = F->fd;
133 flags = fcntl(fd, F_GETFL, 0);
134 if(flags == -1)
135 return 0;
136 /* if set async, clear it so we can reset it in the kernel :/ */
137 if(flags & O_ASYNC)
138 {
139 flags &= ~O_ASYNC;
140 fcntl(fd, F_SETFL, flags);
141 }
142
143 flags |= O_ASYNC | O_NONBLOCK;
144
145 if(fcntl(fd, F_SETFL, flags) == -1)
146 return 0;
147
148 if(fcntl(fd, F_SETSIG, RTSIGIO) == -1)
149 return 0;
150 if(fcntl(fd, F_SETOWN, getpid()) == -1)
151 return 0;
152
153 return 1;
154 }
155
156 /*
157 * rb_setselect
158 *
159 * This is a needed exported function which will be called to register
160 * and deregister interest in a pending IO state for a given FD.
161 */
162 void
163 rb_setselect_sigio(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
164 {
165 if(F == NULL)
166 return;
167
168 if(type & RB_SELECT_READ)
169 {
170 F->read_handler = handler;
171 F->read_data = client_data;
172 if(handler != NULL)
173 F->pflags |= POLLRDNORM;
174 else
175 F->pflags &= ~POLLRDNORM;
176 }
177 if(type & RB_SELECT_WRITE)
178 {
179 F->write_handler = handler;
180 F->write_data = client_data;
181 if(handler != NULL)
182 F->pflags |= POLLWRNORM;
183 else
184 F->pflags &= ~POLLWRNORM;
185 }
186
187 resize_pollarray(F->fd);
188
189 if(F->pflags <= 0)
190 {
191 pollfd_list.pollfds[F->fd].events = 0;
192 pollfd_list.pollfds[F->fd].fd = -1;
193 if(F->fd == pollfd_list.maxindex)
194 {
195 while(pollfd_list.maxindex >= 0
196 && pollfd_list.pollfds[pollfd_list.maxindex].fd == -1)
197 pollfd_list.maxindex--;
198 }
199 }
200 else
201 {
202 pollfd_list.pollfds[F->fd].events = F->pflags;
203 pollfd_list.pollfds[F->fd].fd = F->fd;
204 if(F->fd > pollfd_list.maxindex)
205 pollfd_list.maxindex = F->fd;
206 }
207
208 }
209
210
211
212 /* int rb_select(long delay)
213 * Input: The maximum time to delay.
214 * Output: Returns -1 on error, 0 on success.
215 * Side-effects: Deregisters future interest in IO and calls the handlers
216 * if an event occurs for an FD.
217 * Comments: Check all connections for new connections and input data
218 * that is to be processed. Also check for connections with data queued
219 * and whether we can write it out.
220 * Called to do the new-style IO, courtesy of squid (like most of this
221 * new IO code). This routine handles the stuff we've hidden in
222 * rb_setselect and fd_table[] and calls callbacks for IO ready
223 * events.
224 */
225 int
226 rb_select_sigio(long delay)
227 {
228 int num = 0;
229 int revents = 0;
230 int sig;
231 int fd;
232 int ci;
233 PF *hdl;
234 rb_fde_t *F;
235 void *data;
236 siginfo_t si;
237
238 struct timespec timeout;
239 if(rb_sigio_supports_event() || delay >= 0)
240 {
241 timeout.tv_sec = (delay / 1000);
242 timeout.tv_nsec = (delay % 1000) * 1000000;
243 }
244
245 for(;;)
246 {
247 if(!sigio_is_screwed)
248 {
249 if(can_do_event || delay < 0)
250 {
251 sig = sigwaitinfo(&our_sigset, &si);
252 }
253 else
254 sig = sigtimedwait(&our_sigset, &si, &timeout);
255
256 if(sig > 0)
257 {
258
259 if(sig == SIGIO)
260 {
261 rb_lib_log
262 ("Kernel RT Signal queue overflowed. Is ulimit -i too small(or perhaps /proc/sys/kernel/rtsig-max on old kernels)");
263 sigio_is_screwed = 1;
264 break;
265 }
266 #ifdef SIGIO_SCHED_EVENT
267 if(sig == RTSIGTIM && can_do_event)
268 {
269 struct ev_entry *ev = (struct ev_entry *)si.si_ptr;
270 if(ev == NULL)
271 continue;
272 rb_run_one_event(ev);
273 continue;
274 }
275 #endif
276 fd = si.si_fd;
277 pollfd_list.pollfds[fd].revents |= si.si_band;
278 revents = pollfd_list.pollfds[fd].revents;
279 num++;
280 F = rb_find_fd(fd);
281 if(F == NULL)
282 continue;
283
284 if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
285 {
286 hdl = F->read_handler;
287 data = F->read_data;
288 F->read_handler = NULL;
289 F->read_data = NULL;
290 if(hdl)
291 hdl(F, data);
292 }
293
294 if(revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))
295 {
296 hdl = F->write_handler;
297 data = F->write_data;
298 F->write_handler = NULL;
299 F->write_data = NULL;
300 if(hdl)
301 hdl(F, data);
302 }
303 }
304 else
305 break;
306
307 }
308 else
309 break;
310 }
311
312 if(!sigio_is_screwed) /* We don't need to proceed */
313 {
314 rb_set_time();
315 return 0;
316 }
317
318 signal(RTSIGIO, SIG_IGN);
319 signal(RTSIGIO, SIG_DFL);
320 sigio_is_screwed = 0;
321
322
323 num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, delay);
324 rb_set_time();
325 if(num < 0)
326 {
327 if(!rb_ignore_errno(errno))
328 return RB_OK;
329 else
330 return RB_ERROR;
331 }
332 if(num == 0)
333 return RB_OK;
334
335 /* XXX we *could* optimise by falling out after doing num fds ... */
336 for(ci = 0; ci < pollfd_list.maxindex + 1; ci++)
337 {
338 if(((revents = pollfd_list.pollfds[ci].revents) == 0)
339 || (pollfd_list.pollfds[ci].fd) == -1)
340 continue;
341 fd = pollfd_list.pollfds[ci].fd;
342 F = rb_find_fd(fd);
343 if(F == NULL)
344 continue;
345 if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
346 {
347 hdl = F->read_handler;
348 data = F->read_data;
349 F->read_handler = NULL;
350 F->read_data = NULL;
351 if(hdl)
352 hdl(F, data);
353 }
354
355 if(IsFDOpen(F) && (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)))
356 {
357 hdl = F->write_handler;
358 data = F->write_data;
359 F->write_handler = NULL;
360 F->write_data = NULL;
361 if(hdl)
362 hdl(F, data);
363 }
364 if(F->read_handler == NULL)
365 rb_setselect_sigio(F, RB_SELECT_READ, NULL, NULL);
366 if(F->write_handler == NULL)
367 rb_setselect_sigio(F, RB_SELECT_WRITE, NULL, NULL);
368
369 }
370
371 return 0;
372 }
373
374 #if defined(SIGIO_SCHED_EVENT)
375 void
376 rb_sigio_init_event(void)
377 {
378 rb_sigio_supports_event();
379 }
380
381
382 int
383 rb_sigio_supports_event(void)
384 {
385 timer_t timer;
386 struct sigevent ev;
387 if(can_do_event == 1)
388 return 1;
389 if(can_do_event == -1)
390 return 0;
391
392 ev.sigev_signo = SIGVTALRM;
393 ev.sigev_notify = SIGEV_SIGNAL;
394 if(timer_create(CLOCK_REALTIME, &ev, &timer) != 0)
395 {
396 can_do_event = -1;
397 return 0;
398 }
399 timer_delete(timer);
400 can_do_event = 1;
401 return 1;
402 }
403
404 int
405 rb_sigio_sched_event(struct ev_entry *event, int when)
406 {
407 timer_t *id;
408 struct sigevent ev;
409 struct itimerspec ts;
410 if(can_do_event <= 0)
411 return 0;
412
413 memset(&ev, 0, sizeof(ev));
414 event->comm_ptr = rb_malloc(sizeof(timer_t));
415 id = event->comm_ptr;
416 ev.sigev_notify = SIGEV_SIGNAL;
417 ev.sigev_signo = RTSIGTIM;
418 ev.sigev_value.sival_ptr = event;
419
420 if(timer_create(CLOCK_REALTIME, &ev, id) < 0)
421 {
422 rb_lib_log("timer_create: %s\n", strerror(errno));
423 return 0;
424 }
425 memset(&ts, 0, sizeof(ts));
426 ts.it_value.tv_sec = when;
427 ts.it_value.tv_nsec = 0;
428 if(event->frequency != 0)
429 ts.it_interval = ts.it_value;
430
431 if(timer_settime(*id, 0, &ts, NULL) < 0)
432 {
433 rb_lib_log("timer_settime: %s\n", strerror(errno));
434 return 0;
435 }
436 return 1;
437 }
438
439 void
440 rb_sigio_unsched_event(struct ev_entry *event)
441 {
442 if(can_do_event <= 0)
443 return;
444 timer_delete(*((timer_t *) event->comm_ptr));
445 rb_free(event->comm_ptr);
446 event->comm_ptr = NULL;
447 }
448 #endif /* SIGIO_SCHED_EVENT */
449
450 #else
451
452 int
453 rb_init_netio_sigio(void)
454 {
455 return ENOSYS;
456 }
457
458 void
459 rb_setselect_sigio(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
460 {
461 errno = ENOSYS;
462 return;
463 }
464
465 int
466 rb_select_sigio(long delay)
467 {
468 errno = ENOSYS;
469 return -1;
470 }
471
472 int
473 rb_setup_fd_sigio(rb_fde_t *F)
474 {
475 errno = ENOSYS;
476 return -1;
477 }
478
479 #endif
480
481 #if !defined(USING_SIGIO) || !defined(SIGIO_SCHED_EVENT)
482 void
483 rb_sigio_init_event(void)
484 {
485 return;
486 }
487
488 int
489 rb_sigio_sched_event(struct ev_entry *event __attribute__((unused)), int when __attribute__((unused)))
490 {
491 errno = ENOSYS;
492 return -1;
493 }
494
495 void
496 rb_sigio_unsched_event(struct ev_entry *event __attribute__((unused)))
497 {
498 return;
499 }
500
501 int
502 rb_sigio_supports_event(void)
503 {
504 errno = ENOSYS;
505 return 0;
506 }
507 #endif /* !USING_SIGIO || !SIGIO_SCHED_EVENT */