1 /*
2  * IRC - Internet Relay Chat, ircd/ircd_events.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 /** @file
20  * @brief Implementation of event loop mid-layer.
21  * @version $Id$
22  */
23 #include "config.h"
24 
25 #include "ircd_events.h"
26 
27 #include "ircd.h"
28 #include "ircd_alloc.h"
29 #include "ircd_log.h"
30 #include "ircd_snprintf.h"
31 #include "s_debug.h"
32 
33 /* #include <assert.h> -- Now using assert in ircd_log.h */
34 #include <signal.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 
38 #define SIGS_PER_SOCK	10	/**< number of signals to process per socket
39 				   readable event */
40 
41 #ifdef USE_KQUEUE
42 extern struct Engine engine_kqueue;
43 #define ENGINE_KQUEUE	&engine_kqueue,
44 #else
45 /** Address of kqueue engine (if used). */
46 #define ENGINE_KQUEUE
47 #endif /* USE_KQUEUE */
48 
49 #ifdef USE_DEVPOLL
50 extern struct Engine engine_devpoll;
51 #define ENGINE_DEVPOLL	&engine_devpoll,
52 #else
53 /** Address of /dev/poll engine (if used). */
54 #define ENGINE_DEVPOLL
55 #endif /* USE_DEVPOLL */
56 
57 #ifdef USE_EPOLL
58 extern struct Engine engine_epoll;
59 #define ENGINE_EPOLL &engine_epoll,
60 #else
61 /** Address of epoll engine (if used). */
62 #define ENGINE_EPOLL
63 #endif /* USE_EPOLL */
64 
65 #ifdef USE_POLL
66 extern struct Engine engine_poll;
67 /** Address of fallback (poll) engine. */
68 #define ENGINE_FALLBACK	&engine_poll,
69 #else
70 extern struct Engine engine_select;
71 /** Address of fallback (select) engine. */
72 #define ENGINE_FALLBACK	&engine_select,
73 #endif /* USE_POLL */
74 
75 /** list of engines to try */
76 static const struct Engine *evEngines[] = {
77   ENGINE_KQUEUE
78   ENGINE_EPOLL
79   ENGINE_DEVPOLL
80   ENGINE_FALLBACK
81   0
82 };
83 
84 /** Signal routines pipe data.
85  * This is used if an engine does not implement signal handling itself
86  * (when Engine::eng_signal is NULL).
87  */
88 static struct {
89   int		fd;	/**< signal routine's fd */
90   struct Socket	sock;	/**< and its struct Socket */
91 } sigInfo = { -1 };
92 
93 /** All the thread info */
94 static struct {
95   struct Generators    gens;		/**< List of all generators */
96   struct Event*	       events_free;	/**< struct Event free list */
97   unsigned int	       events_alloc;	/**< count of allocated struct Events */
98   const struct Engine* engine;		/**< core engine being used */
99 #ifdef IRCD_THREADED
100   struct GenHeader*    genq_head;	/**< head of generator event queue */
101   struct GenHeader*    genq_tail;	/**< tail of generator event queue */
102   unsigned int	       genq_count;	/**< count of generators on queue */
103 #endif
104 } evInfo = {
105   { 0, 0, 0 },
106   0, 0, 0
107 #ifdef IRCD_THREADED
108   , 0, 0, 0
109 #endif
110 };
111 
112 /** Initialize a struct GenHeader.
113  * @param[in,out] gen GenHeader to initialize.
114  * @param[in] call Callback for generated events.
115  * @param[in] data User data pointer.
116  * @param[in] next Pointer to next generator.
117  * @param[in,out] prev_p Pointer to previous pointer for this list.
118  */
119 static void
gen_init(struct GenHeader * gen,EventCallBack call,void * data,struct GenHeader * next,struct GenHeader ** prev_p)120 gen_init(struct GenHeader* gen, EventCallBack call, void* data,
121 	 struct GenHeader* next, struct GenHeader** prev_p)
122 {
123   assert(0 != gen);
124 
125   gen->gh_next = next;
126   gen->gh_prev_p = prev_p;
127 #ifdef IRCD_THREADED
128   gen->gh_qnext = 0;
129   gen->gh_qprev_p = 0;
130   gen->gh_head = 0;
131   gen->gh_tail = 0;
132 #endif
133   gen->gh_flags = GEN_ACTIVE;
134   gen->gh_ref = 0;
135   gen->gh_call = call;
136   gen->gh_data = data;
137   gen->gh_engdata.ed_int = 0;
138 
139   if (prev_p) { /* Going to link into list? */
140     if (next) /* do so */
141       next->gh_prev_p = &gen->gh_next;
142     *prev_p = gen;
143   }
144 }
145 
146 /** Execute an event.
147  * Optimizations should inline this.
148  * @param[in] event Event to execute.
149  */
150 static void
event_execute(struct Event * event)151 event_execute(struct Event* event)
152 {
153   assert(0 != event);
154   assert(0 == event->ev_prev_p); /* must be off queue first */
155   assert(event->ev_gen.gen_header->gh_flags & GEN_ACTIVE);
156 
157   if (event->ev_type == ET_DESTROY) /* turn off active flag *before* destroy */
158     event->ev_gen.gen_header->gh_flags &= ~GEN_ACTIVE;
159   if (event->ev_type == ET_ERROR) /* turn on error flag before callback */
160     event->ev_gen.gen_header->gh_flags |= GEN_ERROR;
161 
162   (*event->ev_gen.gen_header->gh_call)(event); /* execute the event */
163 
164   /* The logic here is very careful; if the event was an ET_DESTROY,
165    * then we must assume the generator is now invalid; fortunately, we
166    * don't need to do anything to it if so.  Otherwise, we decrement
167    * the reference count; if reference count goes to zero, AND we need
168    * to destroy the generator, THEN we generate a DESTROY event.
169    */
170   if (event->ev_type != ET_DESTROY)
171     gen_ref_dec(event->ev_gen.gen_header);
172 
173   event->ev_gen.gen_header = 0; /* clear event data */
174   event->ev_type = ET_DESTROY;
175 
176   event->ev_next = evInfo.events_free; /* add to free list */
177   evInfo.events_free = event;
178 }
179 
180 #ifndef IRCD_THREADED
181 /** we synchronously execute the event when not threaded */
182 #define event_add(event)	\
183 do {									      \
184   struct Event* _ev = (event);						      \
185   _ev->ev_next = 0;							      \
186   _ev->ev_prev_p = 0;							      \
187   event_execute(_ev);							      \
188 } while (0)
189 
190 #else
191 /** Add an event to the work queue.
192  * @param[in] event Event to enqueue.
193  */
194 /* This is just a placeholder; don't expect ircd to be threaded soon */
195 /* There should be locks all over the place in here */
196 static void
event_add(struct Event * event)197 event_add(struct Event* event)
198 {
199   struct GenHeader* gen;
200 
201   assert(0 != event);
202 
203   gen = event->ev_gen.gen_header;
204 
205   /* First, place event on generator's event queue */
206   event->ev_next = 0;
207   if (gen->gh_head) {
208     assert(0 != gen->gh_tail);
209 
210     event->ev_prev_p = &gen->gh_tail->ev_next;
211     gen->gh_tail->ev_next = event;
212     gen->gh_tail = event;
213   } else { /* queue was empty */
214     assert(0 == gen->gh_tail);
215 
216     event->ev_prev_p = &gen->gh_head;
217     gen->gh_head = event;
218     gen->gh_tail = event;
219   }
220 
221   /* Now, if the generator isn't on the queue yet... */
222   if (!gen->gh_qprev_p) {
223     gen->gh_qnext = 0;
224     if (evInfo.genq_head) {
225       assert(0 != evInfo.genq_tail);
226 
227       gen->gh_qprev_p = &evInfo.genq_tail->gh_qnext;
228       evInfo.genq_tail->gh_qnext = gen;
229       evInfo.genq_tail = gen;
230     } else { /* queue was empty */
231       assert(0 == evInfo.genq_tail);
232 
233       gen->gh_qprev_p = &evInfo.genq_head;
234       evInfo.genq_head = gen;
235       evInfo.genq_tail = gen;
236     }
237 
238     /* We'd also have to signal the work crew here */
239   }
240 }
241 #endif /* IRCD_THREADED */
242 
243 /** Place a timer in the correct spot on the queue.
244  * @param[in] timer Timer to enqueue.
245  */
246 static void
timer_enqueue(struct Timer * timer)247 timer_enqueue(struct Timer* timer)
248 {
249   struct GenHeader** ptr_p;
250 
251   assert(0 != timer);
252   assert(0 == timer->t_header.gh_prev_p); /* not already on queue */
253   assert(timer->t_header.gh_flags & GEN_ACTIVE); /* timer is active */
254 
255   /* Calculate expire time */
256   switch (timer->t_type) {
257   case TT_ABSOLUTE: /* no need to consider it relative */
258     timer->t_expire = timer->t_value;
259     break;
260 
261   case TT_RELATIVE: case TT_PERIODIC: /* relative timer */
262     timer->t_expire = timer->t_value + CurrentTime;
263     break;
264   }
265 
266   /* Find a slot to insert timer */
267   for (ptr_p = &evInfo.gens.g_timer; ;
268        ptr_p = &(*ptr_p)->gh_next)
269     if (!*ptr_p || timer->t_expire < ((struct Timer*)*ptr_p)->t_expire)
270       break;
271 
272   /* link it in the right place */
273   timer->t_header.gh_next = *ptr_p;
274   timer->t_header.gh_prev_p = ptr_p;
275   if (*ptr_p)
276     (*ptr_p)->gh_prev_p = &timer->t_header.gh_next;
277   *ptr_p = &timer->t_header;
278 }
279 
280 /** &Signal handler for writing signal notification to pipe.
281  * @param[in] sig Signal number that just happened.
282  */
283 static void
signal_handler(int sig)284 signal_handler(int sig)
285 {
286   unsigned char c;
287 
288   assert(sigInfo.fd >= 0);
289 
290   c = (unsigned char) sig; /* only write 1 byte to identify sig */
291 
292   write(sigInfo.fd, &c, 1);
293 }
294 
295 /** Callback for signal "socket" (really pipe) events.
296  * @param[in] event Event activity descriptor.
297  */
298 static void
signal_callback(struct Event * event)299 signal_callback(struct Event* event)
300 {
301   unsigned char sigstr[SIGS_PER_SOCK];
302   int sig, n_sigs, i;
303   struct GenHeader* ptr;
304 
305   assert(event->ev_type == ET_READ); /* readable events only */
306 
307   n_sigs = read(event->ev_gen.gen_socket->s_fd, sigstr, sizeof(sigstr));
308 
309   for (i = 0; i < n_sigs; i++) {
310     sig = (int) sigstr[i]; /* get signal */
311 
312     for (ptr = evInfo.gens.g_signal; ptr;
313 	 ptr = ptr->gh_next)
314       if (((struct Signal*)ptr)->sig_signal == sig) /* find its descriptor... */
315 	break;
316 
317     if (ptr)
318       event_generate(ET_SIGNAL, ptr, sig); /* generate signal event */
319   }
320 }
321 
322 /** Remove a generator from its queue.
323  * @param[in] arg Pointer to a GenHeader to dequeue.
324  */
325 void
gen_dequeue(void * arg)326 gen_dequeue(void* arg)
327 {
328   struct GenHeader* gen = (struct GenHeader*) arg;
329 
330   if (gen->gh_next) /* clip it out of the list */
331     gen->gh_next->gh_prev_p = gen->gh_prev_p;
332   if (gen->gh_prev_p)
333     *gen->gh_prev_p = gen->gh_next;
334 
335   gen->gh_next = 0; /* mark that it's not in the list anymore */
336   gen->gh_prev_p = 0;
337 }
338 
339 /** Initializes the event system.
340  * @param[in] max_sockets Maximum number of sockets to support.
341  */
342 void
event_init(int max_sockets)343 event_init(int max_sockets)
344 {
345   int i, p[2];
346 
347   for (i = 0; evEngines[i]; i++) { /* look for an engine... */
348     assert(0 != evEngines[i]->eng_name);
349     assert(0 != evEngines[i]->eng_init);
350 
351     if ((*evEngines[i]->eng_init)(max_sockets))
352       break; /* Found an engine that'll work */
353   }
354 
355   assert(0 != evEngines[i]);
356 
357   evInfo.engine = evEngines[i]; /* save engine */
358 
359   if (!evInfo.engine->eng_signal) { /* engine can't do signals */
360     if (pipe(p)) {
361       log_write(LS_SYSTEM, L_CRIT, 0, "Failed to open signal pipe");
362       exit(8);
363     }
364 
365     sigInfo.fd = p[1]; /* write end of pipe */
366     socket_add(&sigInfo.sock, signal_callback, 0, SS_NOTSOCK,
367 	       SOCK_EVENT_READABLE, p[0]); /* read end of pipe */
368   }
369 }
370 
371 /** Do the event loop. */
372 void
event_loop(void)373 event_loop(void)
374 {
375   assert(0 != evInfo.engine);
376   assert(0 != evInfo.engine->eng_loop);
377 
378   (*evInfo.engine->eng_loop)(&evInfo.gens);
379 }
380 
381 /** Generate an event and add it to the queue (or execute it).
382  * @param[in] type Type of event to generate.
383  * @param[in] arg Pointer to an event generator (GenHeader).
384  * @param[in] data Extra data for event.
385  */
386 void
event_generate(enum EventType type,void * arg,int data)387 event_generate(enum EventType type, void* arg, int data)
388 {
389   struct Event* ptr;
390   struct GenHeader* gen = (struct GenHeader*) arg;
391 
392   assert(0 != gen);
393 
394   /* don't create events (other than ET_DESTROY) for destroyed generators */
395   if (type != ET_DESTROY && (gen->gh_flags & GEN_DESTROY))
396     return;
397 
398   Debug((DEBUG_LIST, "Generating event type %s for generator %p (%s)",
399 	 event_to_name(type), gen, gen_flags(gen->gh_flags)));
400 
401   if ((ptr = evInfo.events_free))
402     evInfo.events_free = ptr->ev_next; /* pop one off the freelist */
403   else { /* allocate another structure */
404     ptr = (struct Event*) MyMalloc(sizeof(struct Event));
405     evInfo.events_alloc++; /* count of allocated events */
406   }
407 
408   ptr->ev_type = type; /* Record event type */
409   ptr->ev_data = data;
410 
411   ptr->ev_gen.gen_header = (struct GenHeader*) gen;
412   ptr->ev_gen.gen_header->gh_ref++;
413 
414   event_add(ptr); /* add event to queue */
415 }
416 
417 #if 0
418 /* Try to verify the timer list */
419 void
420 timer_verify(void)
421 {
422   struct Timer* ptr;
423   struct Timer** ptr_p = &evInfo.gens.g_timer;
424   time_t lasttime = 0;
425 
426   for (ptr = evInfo.gens.g_timer; ptr;
427        ptr = (struct Timer*) ptr->t_header.gh_next) {
428     /* verify timer is supposed to be in the list */
429     assert(ptr->t_header.gh_prev_p);
430     /* verify timer is correctly ordered */
431     assert((struct Timer**) ptr->t_header.gh_prev_p == ptr_p);
432     /* verify timer is active */
433     assert(ptr->t_header.gh_flags & GEN_ACTIVE);
434     /* verify timer ordering is correct */
435     assert(lasttime <= ptr->t_expire);
436 
437     lasttime = ptr->t_expire; /* store time for ordering check */
438     ptr_p = (struct Timer**) &ptr->t_header.gh_next; /* store prev pointer */
439   }
440 }
441 #endif
442 
443 /** Initialize a timer structure.
444  * @param[in,out] timer Timer to initialize.
445  * @return The pointer \a timer.
446  */
447 struct Timer*
timer_init(struct Timer * timer)448 timer_init(struct Timer* timer)
449 {
450   gen_init(&timer->t_header, 0, 0, 0, 0);
451 
452   timer->t_header.gh_flags = 0; /* turn off active flag */
453 
454   return timer; /* convenience return */
455 }
456 
457 /** Add a timer to be processed.
458  * @param[in] timer Timer to add.
459  * @param[in] call Callback for when the timer expires or is removed.
460  * @param[in] data User data pointer for the timer.
461  * @param[in] type Timer type.
462  * @param[in] value Timer expiration, duration or interval (per \a type).
463  */
464 void
timer_add(struct Timer * timer,EventCallBack call,void * data,enum TimerType type,time_t value)465 timer_add(struct Timer* timer, EventCallBack call, void* data,
466 	  enum TimerType type, time_t value)
467 {
468   assert(0 != timer);
469   assert(0 != call);
470 
471   Debug((DEBUG_LIST, "Adding timer %p; time out %Tu (type %s)", timer, value,
472 	 timer_to_name(type)));
473 
474   /* initialize a timer... */
475   timer->t_header.gh_flags |= GEN_ACTIVE;
476   if (timer->t_header.gh_flags & GEN_MARKED)
477     timer->t_header.gh_flags |= GEN_READD;
478 
479   timer->t_header.gh_ref = 0;
480   timer->t_header.gh_call = call;
481   timer->t_header.gh_data = data;
482 
483   timer->t_type = type;
484   timer->t_value = value;
485   timer->t_expire = 0;
486 
487   if (!(timer->t_header.gh_flags & GEN_MARKED))
488     timer_enqueue(timer); /* and enqueue it */
489 }
490 
491 /** Remove a timer from the processing queue.
492  * @param[in] timer Timer to remove.
493  */
494 void
timer_del(struct Timer * timer)495 timer_del(struct Timer* timer)
496 {
497   assert(0 != timer);
498 
499   timer->t_header.gh_flags &= ~GEN_READD;
500 
501   if (timer->t_header.gh_flags & GEN_MARKED)
502     return; /* timer is being used */
503 
504   Debug((DEBUG_LIST, "Deleting timer %p (type %s)", timer,
505 	 timer_to_name(timer->t_type)));
506 
507   gen_dequeue(timer);
508   event_generate(ET_DESTROY, timer, 0);
509 }
510 
511 /** Change the time a timer expires.
512  * @param[in] timer Timer to update.
513  * @param[in] type New timer type.
514  * @param[in] value New timer expiration value.
515  */
516 void
timer_chg(struct Timer * timer,enum TimerType type,time_t value)517 timer_chg(struct Timer* timer, enum TimerType type, time_t value)
518 {
519   assert(0 != timer);
520   assert(0 != value);
521   assert(TT_PERIODIC != timer->t_type);
522   assert(TT_PERIODIC != type);
523 
524   Debug((DEBUG_LIST, "Changing timer %p from type %s timeout %Tu to type %s "
525 	 "timeout %Tu", timer, timer_to_name(timer->t_type), timer->t_value,
526 	 timer_to_name(type), value));
527 
528   timer->t_type = type; /* Set the new type and value */
529   timer->t_value = value;
530   timer->t_expire = 0;
531 
532   /* If the timer expiration callback tries to change the timer
533    * expiration, flag the timer but do not dequeue it yet.
534    */
535   if (timer->t_header.gh_flags & GEN_MARKED)
536   {
537     timer->t_header.gh_flags |= GEN_READD;
538     return;
539   }
540   gen_dequeue(timer); /* remove the timer from the queue */
541   timer_enqueue(timer); /* re-queue the timer */
542 }
543 
544 /** Execute all expired timers. */
545 void
timer_run(void)546 timer_run(void)
547 {
548   struct Timer* ptr;
549 
550   /* go through queue... */
551   while ((ptr = (struct Timer*)evInfo.gens.g_timer)) {
552     if (CurrentTime < ptr->t_expire)
553       break; /* processed all pending timers */
554 
555     gen_dequeue(ptr); /* must dequeue timer here */
556     ptr->t_header.gh_flags |= (GEN_MARKED |
557 			       (ptr->t_type == TT_PERIODIC ? GEN_READD : 0));
558 
559     event_generate(ET_EXPIRE, ptr, 0); /* generate expire event */
560 
561     ptr->t_header.gh_flags &= ~GEN_MARKED;
562 
563     if (!(ptr->t_header.gh_flags & GEN_READD)) {
564       Debug((DEBUG_LIST, "Destroying timer %p", ptr));
565       event_generate(ET_DESTROY, ptr, 0);
566     } else {
567       Debug((DEBUG_LIST, "Re-enqueuing timer %p", ptr));
568       timer_enqueue(ptr); /* re-queue timer */
569       ptr->t_header.gh_flags &= ~GEN_READD;
570     }
571   }
572 }
573 
574 /** Adds a signal to the event callback system.
575  * @param[in] signal Signal event generator to use.
576  * @param[in] call Callback function to use.
577  * @param[in] data User data pointer for generator.
578  * @param[in] sig Signal number to hook.
579  */
580 void
signal_add(struct Signal * signal,EventCallBack call,void * data,int sig)581 signal_add(struct Signal* signal, EventCallBack call, void* data, int sig)
582 {
583   struct sigaction act;
584 
585   assert(0 != signal);
586   assert(0 != call);
587   assert(0 != evInfo.engine);
588 
589   /* set up struct */
590   gen_init(&signal->sig_header, call, data,
591 	   evInfo.gens.g_signal,
592 	   &evInfo.gens.g_signal);
593 
594   signal->sig_signal = sig;
595 
596   if (evInfo.engine->eng_signal)
597     (*evInfo.engine->eng_signal)(signal); /* tell engine */
598   else {
599     act.sa_handler = signal_handler; /* set up signal handler */
600     act.sa_flags = 0;
601     sigemptyset(&act.sa_mask);
602     sigaction(sig, &act, 0);
603   }
604 }
605 
606 /** Adds a socket to the event system.
607  * @param[in] sock Socket event generator to use.
608  * @param[in] call Callback function to use.
609  * @param[in] data User data pointer for the generator.
610  * @param[in] state Current socket state.
611  * @param[in] events Event interest mask for connected or connectionless sockets.
612  * @param[in] fd &Socket file descriptor.
613  * @return Zero on error, non-zero on success.
614  */
615 int
socket_add(struct Socket * sock,EventCallBack call,void * data,enum SocketState state,unsigned int events,int fd)616 socket_add(struct Socket* sock, EventCallBack call, void* data,
617 	   enum SocketState state, unsigned int events, int fd)
618 {
619   assert(0 != sock);
620   assert(0 != call);
621   assert(fd >= 0);
622   assert(0 != evInfo.engine);
623   assert(0 != evInfo.engine->eng_add);
624 
625   /* set up struct */
626   gen_init(&sock->s_header, call, data,
627 	   evInfo.gens.g_socket,
628 	   &evInfo.gens.g_socket);
629 
630   sock->s_state = state;
631   sock->s_events = events & SOCK_EVENT_MASK;
632   sock->s_fd = fd;
633 
634   return (*evInfo.engine->eng_add)(sock); /* tell engine about it */
635 }
636 
637 /** Deletes (or marks for deletion) a socket generator.
638  * @param[in] sock Event generator to clear.
639  */
640 void
socket_del(struct Socket * sock)641 socket_del(struct Socket* sock)
642 {
643   assert(0 != sock);
644   assert(!(sock->s_header.gh_flags & GEN_DESTROY));
645   assert(0 != evInfo.engine);
646   assert(0 != evInfo.engine->eng_closing);
647 
648   /* tell engine socket is going away */
649   (*evInfo.engine->eng_closing)(sock);
650 
651   sock->s_header.gh_flags |= GEN_DESTROY;
652 
653   if (!sock->s_header.gh_ref) { /* not in use; destroy right now */
654     gen_dequeue(sock);
655     event_generate(ET_DESTROY, sock, 0);
656   }
657 }
658 
659 /** Sets the socket state to something else.
660  * @param[in] sock Socket generator to update.
661  * @param[in] state New socket state.
662  */
663 void
socket_state(struct Socket * sock,enum SocketState state)664 socket_state(struct Socket* sock, enum SocketState state)
665 {
666   assert(0 != sock);
667   assert(0 != evInfo.engine);
668   assert(0 != evInfo.engine->eng_state);
669 
670   /* assertions for invalid socket state transitions */
671   assert(sock->s_state != state); /* not changing states ?! */
672   assert(sock->s_state != SS_LISTENING); /* listening socket to...?! */
673   assert(sock->s_state != SS_CONNECTED); /* connected socket to...?! */
674   /* connecting socket now connected */
675   assert(sock->s_state != SS_CONNECTING || state == SS_CONNECTED);
676   /* unconnected datagram socket now connected */
677   assert(sock->s_state != SS_DATAGRAM || state == SS_CONNECTDG);
678   /* connected datagram socket now unconnected */
679   assert(sock->s_state != SS_CONNECTDG || state == SS_DATAGRAM);
680 
681   /* Don't continue if an error occurred or the socket got destroyed */
682   if (sock->s_header.gh_flags & (GEN_DESTROY | GEN_ERROR))
683     return;
684 
685   /* tell engine we're changing socket state */
686   (*evInfo.engine->eng_state)(sock, state);
687 
688   sock->s_state = state; /* set new state */
689 }
690 
691 /** Sets the events a socket's interested in.
692  * @param[in] sock Socket generator to update.
693  * @param[in] events New event interest mask.
694  */
695 void
socket_events(struct Socket * sock,unsigned int events)696 socket_events(struct Socket* sock, unsigned int events)
697 {
698   unsigned int new_events = 0;
699 
700   assert(0 != sock);
701   assert(0 != evInfo.engine);
702   assert(0 != evInfo.engine->eng_events);
703 
704   /* Don't continue if an error occurred or the socket got destroyed */
705   if (sock->s_header.gh_flags & (GEN_DESTROY | GEN_ERROR))
706     return;
707 
708   switch (events & SOCK_ACTION_MASK) {
709   case SOCK_ACTION_SET: /* set events to given set */
710     new_events = events & SOCK_EVENT_MASK;
711     break;
712 
713   case SOCK_ACTION_ADD: /* add some events */
714     new_events = sock->s_events | (events & SOCK_EVENT_MASK);
715     break;
716 
717   case SOCK_ACTION_DEL: /* remove some events */
718     new_events = sock->s_events & ~(events & SOCK_EVENT_MASK);
719     break;
720   }
721 
722   if (sock->s_events == new_events)
723     return; /* no changes have been made */
724 
725   /* tell engine about event mask change */
726   (*evInfo.engine->eng_events)(sock, new_events);
727 
728   sock->s_events = new_events; /* set new events */
729 }
730 
731 /** Returns the current engine's name for informational purposes.
732  * @return Pointer to a static buffer containing the engine name.
733  */
734 const char*
engine_name(void)735 engine_name(void)
736 {
737   assert(0 != evInfo.engine);
738   assert(0 != evInfo.engine->eng_name);
739 
740   return evInfo.engine->eng_name;
741 }
742 
743 #ifdef DEBUGMODE
744 /* These routines pretty-print names for states and types for debug printing */
745 
746 /** Declares a struct variable containing name(s) and value(s) of \a TYPE. */
747 #define NS(TYPE) \
748 struct {	\
749   char *name;	\
750   TYPE value;	\
751 }
752 
753 /** Declares an element initialize for an NS() struct. */
754 #define NM(name)	{ #name, name }
755 
756 /** Declares end of an NS() struct array. */
757 #define NE		{ 0 }
758 
759 /** Looks up name for a socket state.
760  * @param[in] state &Socket state to look up.
761  * @return Pointer to a static buffer containing the name, or "Undefined socket state".
762  */
763 const char*
state_to_name(enum SocketState state)764 state_to_name(enum SocketState state)
765 {
766   int i;
767   NS(enum SocketState) map[] = {
768     NM(SS_CONNECTING),
769     NM(SS_LISTENING),
770     NM(SS_CONNECTED),
771     NM(SS_DATAGRAM),
772     NM(SS_CONNECTDG),
773     NM(SS_NOTSOCK),
774     NE
775   };
776 
777   for (i = 0; map[i].name; i++)
778     if (map[i].value == state)
779       return map[i].name;
780 
781   return "Undefined socket state";
782 }
783 
784 /** Looks up name for a timer type.
785  * @param[in] type &Timer type to look up.
786  * @return Pointer to a static buffer containing the name, or "Undefined timer type".
787  */
788 const char*
timer_to_name(enum TimerType type)789 timer_to_name(enum TimerType type)
790 {
791   int i;
792   NS(enum TimerType) map[] = {
793     NM(TT_ABSOLUTE),
794     NM(TT_RELATIVE),
795     NM(TT_PERIODIC),
796     NE
797   };
798 
799   for (i = 0; map[i].name; i++)
800     if (map[i].value == type)
801       return map[i].name;
802 
803   return "Undefined timer type";
804 }
805 
806 /** Looks up name for an event type.
807  * @param[in] type &Event type to look up.
808  * @return Pointer to a static buffer containing the name, or "Undefined event type".
809  */
810 const char*
event_to_name(enum EventType type)811 event_to_name(enum EventType type)
812 {
813   int i;
814   NS(enum EventType) map[] = {
815     NM(ET_READ),
816     NM(ET_WRITE),
817     NM(ET_ACCEPT),
818     NM(ET_CONNECT),
819     NM(ET_EOF),
820     NM(ET_ERROR),
821     NM(ET_SIGNAL),
822     NM(ET_EXPIRE),
823     NM(ET_DESTROY),
824     NE
825   };
826 
827   for (i = 0; map[i].name; i++)
828     if (map[i].value == type)
829       return map[i].name;
830 
831   return "Undefined event type";
832 }
833 
834 /** Constructs a string describing certain generator flags.
835  * @param[in] flags Bitwise combination of generator flags.
836  * @return Pointer to a static buffer containing the names of flags set in \a flags.
837  */
838 const char*
gen_flags(unsigned int flags)839 gen_flags(unsigned int flags)
840 {
841   int i, loc = 0;
842   static char buf[256];
843   NS(unsigned int) map[] = {
844     NM(GEN_DESTROY),
845     NM(GEN_MARKED),
846     NM(GEN_ACTIVE),
847     NM(GEN_READD),
848     NM(GEN_ERROR),
849     NE
850   };
851 
852   buf[0] = '\0';
853 
854   for (i = 0; map[i].name; i++)
855     if (map[i].value & flags) {
856       if (loc != 0)
857 	buf[loc++] = ' ';
858       loc += ircd_snprintf(0, buf + loc, sizeof(buf) - loc, "%s", map[i].name);
859       if (loc >= sizeof(buf))
860 	return buf; /* overflow case */
861     }
862 
863   return buf;
864 }
865 
866 /** Constructs a string describing certain socket flags.
867  * @param[in] flags Bitwise combination of socket flags.
868  * @return Pointer to a static buffer containing the names of flags set in \a flags.
869  */
870 const char*
sock_flags(unsigned int flags)871 sock_flags(unsigned int flags)
872 {
873   int i, loc = 0;
874   static char buf[256];
875   NS(unsigned int) map[] = {
876     NM(SOCK_EVENT_READABLE),
877     NM(SOCK_EVENT_WRITABLE),
878     NM(SOCK_ACTION_SET),
879     NM(SOCK_ACTION_ADD),
880     NM(SOCK_ACTION_DEL),
881     NE
882   };
883 
884   buf[0] = '\0';
885 
886   for (i = 0; map[i].name; i++)
887     if (map[i].value & flags) {
888       if (loc != 0)
889 	buf[loc++] = ' ';
890       loc += ircd_snprintf(0, buf + loc, sizeof(buf) - loc, "%s", map[i].name);
891       if (loc >= sizeof(buf))
892 	return buf; /* overflow case */
893     }
894 
895   return buf;
896 }
897 
898 #endif /* DEBUGMODE */
899