Fixes to improve portability (especially to OS X, Solaris, OpenBSD).
[ircu2.10.12-pk.git] / ircd / engine_poll.c
1 /*
2  * IRC - Internet Relay Chat, ircd/engine_poll.c
3  * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 1, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  * $Id$
20  */
21 #include "config.h"
22
23 #include "ircd_events.h"
24
25 #include "ircd.h"
26 #include "ircd_alloc.h"
27 #include "ircd_log.h"
28 #include "s_debug.h"
29
30 #include <assert.h>
31 #include <errno.h>
32 #include <sys/poll.h>
33 #include <sys/socket.h>
34 #include <sys/types.h>
35 #include <time.h>
36 #include <unistd.h>
37
38 #define POLL_ERROR_THRESHOLD    20      /* after 20 poll errors, restart */
39 #define ERROR_EXPIRE_TIME       3600    /* expire errors after an hour */
40
41 /* Figure out what bits to set for read */
42 #if defined(POLLMSG) && defined(POLLIN) && defined(POLLRDNORM)
43 #  define POLLREADFLAGS (POLLMSG|POLLIN|POLLRDNORM)
44 #elif defined(POLLIN) && defined(POLLRDNORM)
45 #  define POLLREADFLAGS (POLLIN|POLLRDNORM)
46 #elif defined(POLLIN)
47 #  define POLLREADFLAGS POLLIN
48 #elif defined(POLLRDNORM)
49 #  define POLLREADFLAGS POLLRDNORM
50 #endif
51
52 /* Figure out what bits to set for write */
53 #if defined(POLLOUT) && defined(POLLWRNORM)
54 #  define POLLWRITEFLAGS (POLLOUT|POLLWRNORM)
55 #elif defined(POLLOUT)
56 #  define POLLWRITEFLAGS POLLOUT
57 #elif defined(POLLWRNORM)
58 #  define POLLWRITEFLAGS POLLWRNORM
59 #endif
60
61 static struct Socket** sockList;
62 static struct pollfd* pollfdList;
63 static unsigned int poll_count;
64 static unsigned int poll_max;
65
66 static int errors = 0;
67 static struct Timer clear_error;
68
69 /* decrements the error count once per hour */
70 static void
71 error_clear(struct Event* ev)
72 {
73   if (!--errors) /* remove timer when error count reaches 0 */
74     timer_del(ev_timer(ev));
75 }
76
77 /* initialize the poll engine */
78 static int
79 engine_init(int max_sockets)
80 {
81   int i;
82
83   /* allocate necessary memory */
84   sockList = (struct Socket**) MyMalloc(sizeof(struct Socket*) * max_sockets);
85   pollfdList = (struct pollfd*) MyMalloc(sizeof(struct pollfd) * max_sockets);
86
87   /* initialize the data */
88   for (i = 0; i < max_sockets; i++) {
89     sockList[i] = 0;
90     pollfdList[i].fd = -1;
91     pollfdList[i].events = 0;
92     pollfdList[i].revents = 0;
93   }
94
95   poll_count = 0; /* nothing in set */
96   poll_max = max_sockets; /* number of sockets allocated */
97
98   return 1;
99 }
100
101 /* Figure out what events go with a given state */
102 static unsigned int
103 state_to_events(enum SocketState state, unsigned int events)
104 {
105   switch (state) {
106   case SS_CONNECTING: /* connecting socket */
107     return SOCK_EVENT_WRITABLE;
108     break;
109
110   case SS_LISTENING: /* listening socket */
111   case SS_NOTSOCK: /* our signal socket */
112     return SOCK_EVENT_READABLE;
113     break;
114
115   case SS_CONNECTED: case SS_DATAGRAM: case SS_CONNECTDG:
116     return events; /* ordinary socket */
117     break;
118   }
119
120   /*NOTREACHED*/
121   return 0;
122 }
123
124 /* Toggle bits in the pollfd structs correctly */
125 static void
126 set_or_clear(int idx, unsigned int clear, unsigned int set)
127 {
128   if ((clear ^ set) & SOCK_EVENT_READABLE) { /* readable has changed */
129     if (set & SOCK_EVENT_READABLE) /* it's set */
130       pollfdList[idx].events |= POLLREADFLAGS;
131     else /* clear it */
132       pollfdList[idx].events &= ~POLLREADFLAGS;
133   }
134
135   if ((clear ^ set) & SOCK_EVENT_WRITABLE) { /* writable has changed */
136     if (set & SOCK_EVENT_WRITABLE) /* it's set */
137       pollfdList[idx].events |= POLLWRITEFLAGS;
138     else /* clear it */
139       pollfdList[idx].events &= ~POLLWRITEFLAGS;
140   }
141 }
142
143 /* add a socket to be listened on */
144 static int
145 engine_add(struct Socket* sock)
146 {
147   int i;
148
149   assert(0 != sock);
150
151   for (i = 0; sockList[i] && i < poll_count; i++) /* Find an empty slot */
152     ;
153
154   Debug((DEBUG_ENGINE, "poll: Looking at slot %d, contents %p", i,
155          sockList[i]));
156
157   if (i >= poll_count) { /* ok, need to allocate another off the list */
158     if (poll_count >= poll_max) { /* bounds-check... */
159       log_write(LS_SYSTEM, L_ERROR, 0,
160                 "Attempt to add socket %d (> %d) to event engine", sock->s_fd,
161                 poll_max);
162       return 0;
163     }
164
165     i = poll_count++;
166     Debug((DEBUG_ENGINE, "poll: Allocating a new slot: %d", i));
167   }
168
169   s_ed_int(sock) = i; /* set engine data */
170   sockList[i] = sock; /* enter socket into data structures */
171   pollfdList[i].fd = s_fd(sock);
172
173   Debug((DEBUG_ENGINE, "poll: Adding socket %d to engine on %d [%p], state %s",
174          s_fd(sock), s_ed_int(sock), sock, state_to_name(s_state(sock))));
175
176   /* set the appropriate bits */
177   set_or_clear(i, 0, state_to_events(s_state(sock), s_events(sock)));
178
179   return 1; /* success */
180 }
181
182 /* socket switching to new state */
183 static void
184 engine_state(struct Socket* sock, enum SocketState new_state)
185 {
186   assert(0 != sock);
187   assert(sock == sockList[s_ed_int(sock)]);
188   assert(s_fd(sock) == pollfdList[s_ed_int(sock)].fd);
189
190   Debug((DEBUG_ENGINE, "poll: Changing state for socket %p to %s", sock,
191          state_to_name(new_state)));
192
193   /* set the correct events */
194   set_or_clear(s_ed_int(sock),
195                state_to_events(s_state(sock), s_events(sock)), /* old state */
196                state_to_events(new_state, s_events(sock))); /* new state */
197 }
198
199 /* socket events changing */
200 static void
201 engine_events(struct Socket* sock, unsigned int new_events)
202 {
203   assert(0 != sock);
204   assert(sock == sockList[s_ed_int(sock)]);
205   assert(s_fd(sock) == pollfdList[s_ed_int(sock)].fd);
206
207   Debug((DEBUG_ENGINE, "poll: Changing event mask for socket %p to [%s]", sock,
208          sock_flags(new_events)));
209
210   /* set the correct events */
211   set_or_clear(s_ed_int(sock),
212                state_to_events(s_state(sock), s_events(sock)), /* old events */
213                state_to_events(s_state(sock), new_events)); /* new events */
214 }
215
216 /* socket going away */
217 static void
218 engine_delete(struct Socket* sock)
219 {
220   assert(0 != sock);
221   assert(sock == sockList[s_ed_int(sock)]);
222   assert(s_fd(sock) == pollfdList[s_ed_int(sock)].fd);
223
224   Debug((DEBUG_ENGINE, "poll: Deleting socket %d (%d) [%p], state %s",
225          s_fd(sock), s_ed_int(sock), sock, state_to_name(s_state(sock))));
226
227   /* clear the events */
228   pollfdList[s_ed_int(sock)].fd = -1;
229   pollfdList[s_ed_int(sock)].events = 0;
230
231   /* zero the socket list entry */
232   sockList[s_ed_int(sock)] = 0;
233
234   /* update poll_count */
235   while (poll_count > 0 && sockList[poll_count - 1] == 0)
236     poll_count--;
237 }
238
239 /* socket event loop */
240 static void
241 engine_loop(struct Generators* gen)
242 {
243   int wait;
244   int nfds;
245   int i;
246   int errcode;
247   socklen_t codesize;
248   struct Socket *sock;
249
250   while (running) {
251     wait = timer_next(gen) ? (timer_next(gen) - CurrentTime) * 1000 : -1;
252
253     Debug((DEBUG_INFO, "poll: delay: %Tu (%Tu) %d", timer_next(gen),
254            CurrentTime, wait));
255
256     /* check for active files */
257     nfds = poll(pollfdList, poll_count, wait);
258
259     CurrentTime = time(0); /* set current time... */
260
261     if (nfds < 0) {
262       if (errno != EINTR) { /* ignore poll interrupts */
263         /* Log the poll error */
264         log_write(LS_SOCKET, L_ERROR, 0, "poll() error: %m");
265         if (!errors++)
266           timer_add(timer_init(&clear_error), error_clear, 0, TT_PERIODIC,
267                     ERROR_EXPIRE_TIME);
268         else if (errors > POLL_ERROR_THRESHOLD) /* too many errors... */
269           server_restart("too many poll errors");
270       }
271       /* old code did a sleep(1) here; with usage these days,
272        * that may be too expensive
273        */
274       continue;
275     }
276
277     for (i = 0; nfds && i < poll_count; i++) {
278       if (!(sock = sockList[i])) /* skip empty socket elements */
279         continue;
280
281       assert(s_fd(sock) == pollfdList[i].fd);
282
283       gen_ref_inc(sock); /* can't have it going away on us */
284
285       Debug((DEBUG_ENGINE, "poll: Checking socket %p (fd %d, index %d, "
286              "state %s, events %s", sock, s_fd(sock), i,
287              state_to_name(s_state(sock)), sock_flags(s_events(sock))));
288
289       if (s_state(sock) != SS_NOTSOCK) {
290         errcode = 0; /* check for errors on socket */
291         codesize = sizeof(errcode);
292         if (getsockopt(s_fd(sock), SOL_SOCKET, SO_ERROR, &errcode,
293                        &codesize) < 0)
294           errcode = errno; /* work around Solaris implementation */
295
296         if (errcode) { /* an error occurred; generate an event */
297           Debug((DEBUG_ENGINE, "poll: Error %d on fd %d (index %d), socket %p",
298                  errcode, s_fd(sock), i, sock));
299           event_generate(ET_ERROR, sock, errcode);
300           gen_ref_dec(sock); /* careful not to leak ref counts */
301           nfds--;
302           continue;
303         }
304       }
305
306 #ifdef POLLHUP
307       if (pollfdList[i].revents & POLLHUP) { /* hang-up on socket */
308         Debug((DEBUG_ENGINE, "poll: EOF from client (POLLHUP)"));
309         event_generate(ET_EOF, sock, 0);
310         nfds--;
311         continue;
312       }
313 #endif /* POLLHUP */
314
315       switch (s_state(sock)) {
316       case SS_CONNECTING:
317         if (pollfdList[i].revents & POLLWRITEFLAGS) { /* connect completed */
318           Debug((DEBUG_ENGINE, "poll: Connection completed"));
319           event_generate(ET_CONNECT, sock, 0);
320           nfds--;
321         }
322         break;
323
324       case SS_LISTENING:
325         if (pollfdList[i].revents & POLLREADFLAGS) { /* ready for accept */
326           Debug((DEBUG_ENGINE, "poll: Ready for accept"));
327           event_generate(ET_ACCEPT, sock, 0);
328           nfds--;
329         }
330         break;
331
332       case SS_NOTSOCK:
333         if (pollfdList[i].revents & POLLREADFLAGS) { /* data on socket */
334           /* can't peek; it's not a socket */
335           Debug((DEBUG_ENGINE, "poll: non-socket readable"));
336           event_generate(ET_READ, sock, 0);
337           nfds--;
338         }
339         break;
340
341       case SS_CONNECTED:
342         if (pollfdList[i].revents & POLLREADFLAGS) { /* data on socket */
343           char c;
344
345           switch (recv(s_fd(sock), &c, 1, MSG_PEEK)) { /* check EOF */
346           case -1: /* error occurred?!? */
347             if (errno == EAGAIN) {
348               Debug((DEBUG_ENGINE, "poll: Resource temporarily unavailable?"));
349               continue;
350             }
351             Debug((DEBUG_ENGINE, "poll: Uncaught error!"));
352             event_generate(ET_ERROR, sock, errno);
353             break;
354
355           case 0: /* EOF from client */
356             Debug((DEBUG_ENGINE, "poll: EOF from client"));
357             event_generate(ET_EOF, sock, 0);
358             break;
359
360           default: /* some data can be read */
361             Debug((DEBUG_ENGINE, "poll: Data to be read"));
362             event_generate(ET_READ, sock, 0);
363             break;
364           }
365         }
366         if (pollfdList[i].revents & POLLWRITEFLAGS) { /* socket writable */
367           Debug((DEBUG_ENGINE, "poll: Data can be written"));
368           event_generate(ET_WRITE, sock, 0);
369         }
370         if (pollfdList[i].revents & (POLLREADFLAGS | POLLWRITEFLAGS))
371           nfds--;
372         break;
373
374       case SS_DATAGRAM: case SS_CONNECTDG:
375         if (pollfdList[i].revents & POLLREADFLAGS) { /* socket readable */
376           Debug((DEBUG_ENGINE, "poll: Datagram to be read"));
377           event_generate(ET_READ, sock, 0);
378         }
379         if (pollfdList[i].revents & POLLWRITEFLAGS) { /* socket writable */
380           Debug((DEBUG_ENGINE, "poll: Datagram can be written"));
381           event_generate(ET_WRITE, sock, 0);
382         }
383         if (pollfdList[i].revents & (POLLREADFLAGS | POLLWRITEFLAGS))
384           nfds--;
385         break;
386       }
387
388       gen_ref_dec(sock); /* we're done with it */
389     }
390
391     timer_run(); /* execute any pending timers */
392   }
393 }
394
395 struct Engine engine_poll = {
396   "poll()",             /* Engine name */
397   engine_init,          /* Engine initialization function */
398   0,                    /* Engine signal registration function */
399   engine_add,           /* Engine socket registration function */
400   engine_state,         /* Engine socket state change function */
401   engine_events,        /* Engine socket events mask function */
402   engine_delete,        /* Engine socket deletion function */
403   engine_loop           /* Core engine event loop */
404 };