Author: Kev <klmitch@mit.edu>
[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 /* Figure out what bits indicate errors */
62 #ifdef POLLHUP
63 #  define POLLERRORS (POLLHUP|POLLERR)
64 #else
65 #  define POLLERRORS POLLERR
66 #endif
67
68 static struct Socket** sockList;
69 static struct pollfd* pollfdList;
70 static unsigned int poll_count;
71 static unsigned int poll_max;
72
73 static int errors = 0;
74 static struct Timer clear_error;
75
76 /* decrements the error count once per hour */
77 static void
78 error_clear(struct Event* ev)
79 {
80   if (!--errors) /* remove timer when error count reaches 0 */
81     timer_del(ev_timer(ev));
82 }
83
84 /* initialize the poll engine */
85 static int
86 engine_init(int max_sockets)
87 {
88   int i;
89
90   /* allocate necessary memory */
91   sockList = (struct Socket**) MyMalloc(sizeof(struct Socket*) * max_sockets);
92   pollfdList = (struct pollfd*) MyMalloc(sizeof(struct pollfd) * max_sockets);
93
94   /* initialize the data */
95   for (i = 0; i < max_sockets; i++) {
96     sockList[i] = 0;
97     pollfdList[i].fd = -1;
98     pollfdList[i].events = 0;
99     pollfdList[i].revents = 0;
100   }
101
102   poll_count = 0; /* nothing in set */
103   poll_max = max_sockets; /* number of sockets allocated */
104
105   return 1;
106 }
107
108 /* Figure out what events go with a given state */
109 static unsigned int
110 state_to_events(enum SocketState state, unsigned int events)
111 {
112   switch (state) {
113   case SS_CONNECTING: /* connecting socket */
114     return SOCK_EVENT_WRITABLE;
115     break;
116
117   case SS_LISTENING: /* listening socket */
118   case SS_NOTSOCK: /* our signal socket */
119     return SOCK_EVENT_READABLE;
120     break;
121
122   case SS_CONNECTED: case SS_DATAGRAM: case SS_CONNECTDG:
123     return events; /* ordinary socket */
124     break;
125   }
126
127   /*NOTREACHED*/
128   return 0;
129 }
130
131 /* Toggle bits in the pollfd structs correctly */
132 static void
133 set_or_clear(int idx, unsigned int clear, unsigned int set)
134 {
135   if ((clear ^ set) & SOCK_EVENT_READABLE) { /* readable has changed */
136     if (set & SOCK_EVENT_READABLE) /* it's set */
137       pollfdList[idx].events |= POLLREADFLAGS;
138     else /* clear it */
139       pollfdList[idx].events &= ~POLLREADFLAGS;
140   }
141
142   if ((clear ^ set) & SOCK_EVENT_WRITABLE) { /* writable has changed */
143     if (set & SOCK_EVENT_WRITABLE) /* it's set */
144       pollfdList[idx].events |= POLLWRITEFLAGS;
145     else /* clear it */
146       pollfdList[idx].events &= ~POLLWRITEFLAGS;
147   }
148 }
149
150 /* add a socket to be listened on */
151 static int
152 engine_add(struct Socket* sock)
153 {
154   int i;
155
156   assert(0 != sock);
157
158   for (i = 0; sockList[i] && i < poll_count; i++) /* Find an empty slot */
159     ;
160
161   Debug((DEBUG_ENGINE, "poll: Looking at slot %d, contents %p", i,
162          sockList[i]));
163
164   if (i >= poll_count) { /* ok, need to allocate another off the list */
165     if (poll_count >= poll_max) { /* bounds-check... */
166       log_write(LS_SYSTEM, L_ERROR, 0,
167                 "Attempt to add socket %d (> %d) to event engine", sock->s_fd,
168                 poll_max);
169       return 0;
170     }
171
172     i = poll_count++;
173     Debug((DEBUG_ENGINE, "poll: Allocating a new slot: %d", i));
174   }
175
176   s_ed_int(sock) = i; /* set engine data */
177   sockList[i] = sock; /* enter socket into data structures */
178   pollfdList[i].fd = s_fd(sock);
179
180   Debug((DEBUG_ENGINE, "poll: Adding socket %d to engine on %d [%p], state %s",
181          s_fd(sock), s_ed_int(sock), sock, state_to_name(s_state(sock))));
182
183   /* set the appropriate bits */
184   set_or_clear(i, 0, state_to_events(s_state(sock), s_events(sock)));
185
186   return 1; /* success */
187 }
188
189 /* socket switching to new state */
190 static void
191 engine_state(struct Socket* sock, enum SocketState new_state)
192 {
193   assert(0 != sock);
194   assert(sock == sockList[s_ed_int(sock)]);
195   assert(s_fd(sock) == pollfdList[s_ed_int(sock)].fd);
196
197   Debug((DEBUG_ENGINE, "poll: Changing state for socket %p to %s", sock,
198          state_to_name(new_state)));
199
200   /* set the correct events */
201   set_or_clear(s_ed_int(sock),
202                state_to_events(s_state(sock), s_events(sock)), /* old state */
203                state_to_events(new_state, s_events(sock))); /* new state */
204 }
205
206 /* socket events changing */
207 static void
208 engine_events(struct Socket* sock, unsigned int new_events)
209 {
210   assert(0 != sock);
211   assert(sock == sockList[s_ed_int(sock)]);
212   assert(s_fd(sock) == pollfdList[s_ed_int(sock)].fd);
213
214   Debug((DEBUG_ENGINE, "poll: Changing event mask for socket %p to [%s]", sock,
215          sock_flags(new_events)));
216
217   /* set the correct events */
218   set_or_clear(s_ed_int(sock),
219                state_to_events(s_state(sock), s_events(sock)), /* old events */
220                state_to_events(s_state(sock), new_events)); /* new events */
221 }
222
223 /* socket going away */
224 static void
225 engine_delete(struct Socket* sock)
226 {
227   assert(0 != sock);
228   assert(sock == sockList[s_ed_int(sock)]);
229   assert(s_fd(sock) == pollfdList[s_ed_int(sock)].fd);
230
231   Debug((DEBUG_ENGINE, "poll: Deleting socket %d (%d) [%p], state %s",
232          s_fd(sock), s_ed_int(sock), sock, state_to_name(s_state(sock))));
233
234   /* clear the events */
235   pollfdList[s_ed_int(sock)].fd = -1;
236   pollfdList[s_ed_int(sock)].events = 0;
237
238   /* zero the socket list entry */
239   sockList[s_ed_int(sock)] = 0;
240
241   /* update poll_count */
242   while (poll_count > 0 && sockList[poll_count - 1] == 0)
243     poll_count--;
244 }
245
246 /* socket event loop */
247 static void
248 engine_loop(struct Generators* gen)
249 {
250   int wait;
251   int nfds;
252   int i;
253   int errcode;
254   size_t codesize;
255   struct Socket *sock;
256
257   while (running) {
258     wait = timer_next(gen) ? (timer_next(gen) - CurrentTime) * 1000 : -1;
259
260     Debug((DEBUG_INFO, "poll: delay: %Tu (%Tu) %d", timer_next(gen),
261            CurrentTime, wait));
262
263     /* check for active files */
264     nfds = poll(pollfdList, poll_count, wait);
265
266     CurrentTime = time(0); /* set current time... */
267
268     if (nfds < 0) {
269       if (errno != EINTR) { /* ignore poll interrupts */
270         /* Log the poll error */
271         log_write(LS_SOCKET, L_ERROR, 0, "poll() error: %m");
272         if (!errors++)
273           timer_add(&clear_error, error_clear, 0, TT_PERIODIC,
274                     ERROR_EXPIRE_TIME);
275         else if (errors > POLL_ERROR_THRESHOLD) /* too many errors... */
276           server_restart("too many poll errors");
277       }
278       /* old code did a sleep(1) here; with usage these days,
279        * that may be too expensive
280        */
281       continue;
282     }
283
284     for (i = 0; nfds && i < poll_count; i++) {
285       if (!(sock = sockList[i])) /* skip empty socket elements */
286         continue;
287
288       assert(s_fd(sock) == pollfdList[i].fd);
289
290       gen_ref_inc(sock); /* can't have it going away on us */
291
292       Debug((DEBUG_ENGINE, "poll: Checking socket %p (fd %d, index %d, "
293              "state %s, events %s", sock, s_fd(sock), i,
294              state_to_name(s_state(sock)), sock_flags(s_events(sock))));
295
296       if (s_state(sock) != SS_NOTSOCK) {
297         errcode = 0; /* check for errors on socket */
298         codesize = sizeof(errcode);
299         if (getsockopt(s_fd(sock), SOL_SOCKET, SO_ERROR, &errcode,
300                        &codesize) < 0)
301           errcode = errno; /* work around Solaris implementation */
302
303         if (errcode) { /* an error occurred; generate an event */
304           Debug((DEBUG_ENGINE, "poll: Error %d on fd %d (index %d), socket %p",
305                  errcode, s_fd(sock), i, sock));
306           event_generate(ET_ERROR, sock, errcode);
307           gen_ref_dec(sock); /* careful not to leak ref counts */
308           nfds--;
309           continue;
310         }
311       }
312
313       switch (s_state(sock)) {
314       case SS_CONNECTING:
315         if (pollfdList[i].revents & POLLWRITEFLAGS) { /* connect completed */
316           Debug((DEBUG_ENGINE, "poll: Connection completed"));
317           event_generate(ET_CONNECT, sock, 0);
318           nfds--;
319         }
320         break;
321
322       case SS_LISTENING:
323         if (pollfdList[i].revents & POLLREADFLAGS) { /* ready for accept */
324           Debug((DEBUG_ENGINE, "poll: Ready for accept"));
325           event_generate(ET_ACCEPT, sock, 0);
326           nfds--;
327         }
328         break;
329
330       case SS_NOTSOCK:
331         if (pollfdList[i].revents & POLLREADFLAGS) { /* data on socket */
332           /* can't peek; it's not a socket */
333           Debug((DEBUG_ENGINE, "poll: non-socket readable"));
334           event_generate(ET_READ, sock, 0);
335           nfds--;
336         }
337         break;
338
339       case SS_CONNECTED:
340         if (pollfdList[i].revents & POLLREADFLAGS) { /* data on socket */
341           char c;
342
343           switch (recv(s_fd(sock), &c, 1, MSG_PEEK)) { /* check EOF */
344           case -1: /* error occurred?!? */
345             if (errno == EAGAIN) {
346               Debug((DEBUG_ENGINE, "poll: Resource temporarily unavailable?"));
347               continue;
348             }
349             Debug((DEBUG_ENGINE, "poll: Uncaught error!"));
350             event_generate(ET_ERROR, sock, errno);
351             break;
352
353           case 0: /* EOF from client */
354             Debug((DEBUG_ENGINE, "poll: EOF from client"));
355             event_generate(ET_EOF, sock, 0);
356             break;
357
358           default: /* some data can be read */
359             Debug((DEBUG_ENGINE, "poll: Data to be read"));
360             event_generate(ET_READ, sock, 0);
361             break;
362           }
363         }
364         if (pollfdList[i].revents & POLLWRITEFLAGS) { /* socket writable */
365           Debug((DEBUG_ENGINE, "poll: Data can be written"));
366           event_generate(ET_WRITE, sock, 0);
367         }
368         if (pollfdList[i].revents & (POLLREADFLAGS | POLLWRITEFLAGS))
369           nfds--;
370         break;
371
372       case SS_DATAGRAM: case SS_CONNECTDG:
373         if (pollfdList[i].revents & POLLREADFLAGS) { /* socket readable */
374           Debug((DEBUG_ENGINE, "poll: Datagram to be read"));
375           event_generate(ET_READ, sock, 0);
376         }
377         if (pollfdList[i].revents & POLLWRITEFLAGS) { /* socket writable */
378           Debug((DEBUG_ENGINE, "poll: Datagram can be written"));
379           event_generate(ET_WRITE, sock, 0);
380         }
381         if (pollfdList[i].revents & (POLLREADFLAGS | POLLWRITEFLAGS))
382           nfds--;
383         break;
384       }
385
386       gen_ref_dec(sock); /* we're done with it */
387     }
388
389     timer_run(); /* execute any pending timers */
390   }
391 }
392
393 struct Engine engine_poll = {
394   "poll()",             /* Engine name */
395   engine_init,          /* Engine initialization function */
396   0,                    /* Engine signal registration function */
397   engine_add,           /* Engine socket registration function */
398   engine_state,         /* Engine socket state change function */
399   engine_events,        /* Engine socket events mask function */
400   engine_delete,        /* Engine socket deletion function */
401   engine_loop           /* Core engine event loop */
402 };