]> git.ipfire.org Git - thirdparty/bird.git/blob - sysdep/unix/io.c
Fixed a bunch of FIXME's by removing them :)
[thirdparty/bird.git] / sysdep / unix / io.c
1 /*
2 * BIRD Internet Routing Daemon -- Unix I/O
3 *
4 * (c) 1998--1999 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/time.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <sys/fcntl.h>
16 #include <sys/un.h>
17 #include <unistd.h>
18 #include <errno.h>
19
20 #include "nest/bird.h"
21 #include "lib/lists.h"
22 #include "lib/resource.h"
23 #include "lib/timer.h"
24 #include "lib/socket.h"
25 #include "lib/event.h"
26 #include "lib/string.h"
27 #include "nest/iface.h"
28
29 #include "lib/unix.h"
30 #include "lib/sysio.h"
31
32 /*
33 * Random Numbers
34 */
35
36 u32
37 random_u32(void)
38 {
39 long int rand_low, rand_high;
40
41 rand_low = random();
42 rand_high = random();
43 return (rand_low & 0xffff) | ((rand_high & 0xffff) << 16);
44 }
45
46 /*
47 * Tracked Files
48 */
49
50 struct rfile {
51 resource r;
52 FILE *f;
53 };
54
55 static void
56 rf_free(resource *r)
57 {
58 struct rfile *a = (struct rfile *) r;
59
60 fclose(a->f);
61 }
62
63 static void
64 rf_dump(resource *r)
65 {
66 struct rfile *a = (struct rfile *) r;
67
68 debug("(FILE *%p)\n", a->f);
69 }
70
71 static struct resclass rf_class = {
72 "FILE",
73 sizeof(struct rfile),
74 rf_free,
75 rf_dump
76 };
77
78 void *
79 tracked_fopen(pool *p, char *name, char *mode)
80 {
81 FILE *f = fopen(name, mode);
82
83 if (f)
84 {
85 struct rfile *r = ralloc(p, &rf_class);
86 r->f = f;
87 }
88 return f;
89 }
90
91 /*
92 * Timers
93 */
94
95 #define NEAR_TIMER_LIMIT 4
96
97 static list near_timers, far_timers;
98 static bird_clock_t first_far_timer = TIME_INFINITY;
99
100 bird_clock_t now;
101
102 static void
103 tm_free(resource *r)
104 {
105 timer *t = (timer *) r;
106
107 tm_stop(t);
108 }
109
110 static void
111 tm_dump(resource *r)
112 {
113 timer *t = (timer *) r;
114
115 debug("(code %p, data %p, ", t->hook, t->data);
116 if (t->randomize)
117 debug("rand %d, ", t->randomize);
118 if (t->recurrent)
119 debug("recur %d, ", t->recurrent);
120 if (t->expires)
121 debug("expires in %d sec)\n", t->expires - now);
122 else
123 debug("inactive)\n");
124 }
125
126 static struct resclass tm_class = {
127 "Timer",
128 sizeof(timer),
129 tm_free,
130 tm_dump
131 };
132
133 timer *
134 tm_new(pool *p)
135 {
136 timer *t = ralloc(p, &tm_class);
137 t->hook = NULL;
138 t->data = NULL;
139 t->randomize = 0;
140 t->expires = 0;
141 return t;
142 }
143
144 static inline void
145 tm_insert_near(timer *t)
146 {
147 node *n = HEAD(near_timers);
148
149 while (n->next && (SKIP_BACK(timer, n, n)->expires < t->expires))
150 n = n->next;
151 insert_node(&t->n, n->prev);
152 }
153
154 void
155 tm_start(timer *t, unsigned after)
156 {
157 bird_clock_t when;
158
159 if (t->randomize)
160 after += random() % (t->randomize + 1);
161 when = now + after;
162 if (t->expires == when)
163 return;
164 if (t->expires)
165 rem_node(&t->n);
166 t->expires = when;
167 if (after <= NEAR_TIMER_LIMIT)
168 tm_insert_near(t);
169 else
170 {
171 if (!first_far_timer || first_far_timer > when)
172 first_far_timer = when;
173 add_tail(&far_timers, &t->n);
174 }
175 }
176
177 void
178 tm_stop(timer *t)
179 {
180 if (t->expires)
181 {
182 rem_node(&t->n);
183 t->expires = 0;
184 }
185 }
186
187 static void
188 tm_dump_them(char *name, list *l)
189 {
190 node *n;
191 timer *t;
192
193 debug("%s timers:\n", name);
194 WALK_LIST(n, *l)
195 {
196 t = SKIP_BACK(timer, n, n);
197 debug("%p ", t);
198 tm_dump(&t->r);
199 }
200 debug("\n");
201 }
202
203 void
204 tm_dump_all(void)
205 {
206 tm_dump_them("Near", &near_timers);
207 tm_dump_them("Far", &far_timers);
208 }
209
210 static inline time_t
211 tm_first_shot(void)
212 {
213 time_t x = first_far_timer;
214
215 if (!EMPTY_LIST(near_timers))
216 {
217 timer *t = SKIP_BACK(timer, n, HEAD(near_timers));
218 if (t->expires < x)
219 x = t->expires;
220 }
221 return x;
222 }
223
224 static void
225 tm_shot(void)
226 {
227 timer *t;
228 node *n, *m;
229
230 if (first_far_timer <= now)
231 {
232 bird_clock_t limit = now + NEAR_TIMER_LIMIT;
233 first_far_timer = TIME_INFINITY;
234 n = HEAD(far_timers);
235 while (m = n->next)
236 {
237 t = SKIP_BACK(timer, n, n);
238 if (t->expires <= limit)
239 {
240 rem_node(n);
241 tm_insert_near(t);
242 }
243 else if (t->expires < first_far_timer)
244 first_far_timer = t->expires;
245 n = m;
246 }
247 }
248 while ((n = HEAD(near_timers)) -> next)
249 {
250 int delay;
251 t = SKIP_BACK(timer, n, n);
252 if (t->expires > now)
253 break;
254 rem_node(n);
255 delay = t->expires - now;
256 t->expires = 0;
257 if (t->recurrent)
258 {
259 int i = t->recurrent - delay;
260 if (i < 0)
261 i = 0;
262 tm_start(t, i);
263 }
264 t->hook(t);
265 }
266 }
267
268 bird_clock_t
269 tm_parse_date(char *x)
270 {
271 struct tm tm;
272 int n;
273 time_t t;
274
275 if (sscanf(x, "%d-%d-%d%n", &tm.tm_mday, &tm.tm_mon, &tm.tm_year, &n) != 3 || x[n])
276 return 0;
277 tm.tm_mon--;
278 tm.tm_year -= 1900;
279 tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
280 t = mktime(&tm);
281 if (t == (time_t) -1)
282 return 0;
283 return t;
284 }
285
286 void
287 tm_format_date(char *x, bird_clock_t t)
288 {
289 struct tm *tm;
290
291 tm = localtime(&t);
292 sprintf(x, "%02d-%02d-%04d", tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900);
293 }
294
295 void
296 tm_format_datetime(char *x, bird_clock_t t)
297 {
298 struct tm *tm;
299
300 tm = localtime(&t);
301 if (strftime(x, TM_DATETIME_BUFFER_SIZE, "%d-%m-%Y %H:%M:%S", tm) == TM_DATETIME_BUFFER_SIZE)
302 strcpy(x, "<too-long>");
303 }
304
305 void
306 tm_format_reltime(char *x, bird_clock_t t)
307 {
308 struct tm *tm;
309 bird_clock_t delta = now - t;
310 static char *month_names[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
311
312 tm = localtime(&t);
313 if (delta < 0)
314 strcpy(x, "?fut?");
315 else if (delta < 20*3600)
316 bsprintf(x, "%02d:%02d", tm->tm_hour, tm->tm_min);
317 else if (delta < 360*86400)
318 bsprintf(x, "%s%02d", month_names[tm->tm_mon], tm->tm_mday);
319 else
320 bsprintf(x, "%d", tm->tm_year+1900);
321 }
322
323 /*
324 * Sockets
325 */
326
327 #ifndef SOL_IP
328 #define SOL_IP IPPROTO_IP
329 #endif
330
331 static list sock_list;
332
333 static void
334 sk_free(resource *r)
335 {
336 sock *s = (sock *) r;
337
338 if (s->fd >= 0)
339 rem_node(&s->n);
340 }
341
342 static void
343 sk_dump(resource *r)
344 {
345 sock *s = (sock *) r;
346 static char *sk_type_names[] = { "TCP<", "TCP>", "TCP", "UDP", "UDP/MC", "IP", "IP/MC", "MAGIC", "UNIX<", "UNIX", "DEL!" };
347
348 debug("(%s, ud=%p, sa=%08x, sp=%d, da=%08x, dp=%d, tos=%d, ttl=%d, if=%s)\n",
349 sk_type_names[s->type],
350 s->data,
351 s->saddr,
352 s->sport,
353 s->daddr,
354 s->dport,
355 s->tos,
356 s->ttl,
357 s->iface ? s->iface->name : "none");
358 }
359
360 static struct resclass sk_class = {
361 "Socket",
362 sizeof(sock),
363 sk_free,
364 sk_dump
365 };
366
367 sock *
368 sk_new(pool *p)
369 {
370 sock *s = ralloc(p, &sk_class);
371 s->pool = p;
372 s->data = NULL;
373 s->saddr = s->daddr = IPA_NONE;
374 s->sport = s->dport = 0;
375 s->tos = s->ttl = -1;
376 s->iface = NULL;
377 s->rbuf = NULL;
378 s->rx_hook = NULL;
379 s->rbsize = 0;
380 s->tbuf = NULL;
381 s->tx_hook = NULL;
382 s->tbsize = 0;
383 s->err_hook = NULL;
384 s->fd = -1;
385 return s;
386 }
387
388 #define ERR(x) do { err = x; goto bad; } while(0)
389 #define WARN(x) log(L_WARN "sk_setup: %s: %m", x)
390
391 #ifdef IPV6
392
393 void
394 fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port)
395 {
396 sa->sin6_family = AF_INET6;
397 sa->sin6_port = htons(port);
398 sa->sin6_flowinfo = 0;
399 set_inaddr(&sa->sin6_addr, a);
400 }
401
402 void
403 get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port)
404 {
405 if (sa->sin6_family != AF_INET6)
406 bug("get_sockaddr called for wrong address family");
407 if (port)
408 *port = ntohs(sa->sin6_port);
409 memcpy(a, &sa->sin6_addr, sizeof(*a));
410 ipa_ntoh(*a);
411 }
412
413 #else
414
415 void
416 fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port)
417 {
418 sa->sin_family = AF_INET;
419 sa->sin_port = htons(port);
420 set_inaddr(&sa->sin_addr, a);
421 }
422
423 void
424 get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port)
425 {
426 if (sa->sin_family != AF_INET)
427 bug("get_sockaddr called for wrong address family");
428 if (port)
429 *port = ntohs(sa->sin_port);
430 memcpy(a, &sa->sin_addr.s_addr, sizeof(*a));
431 ipa_ntoh(*a);
432 }
433
434 #endif
435
436 static char *
437 sk_setup(sock *s)
438 {
439 int fd = s->fd;
440 int one = 1;
441 char *err;
442
443 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
444 ERR("fcntl(O_NONBLOCK)");
445 if (s->type == SK_UNIX)
446 return NULL;
447 #ifdef IPV6
448 if (s->ttl >= 0 && s->type != SK_UDP_MC && s->type != SK_IP_MC &&
449 setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
450 ERR("IPV6_UNICAST_HOPS");
451 #else
452 if ((s->tos >= 0) && setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0)
453 WARN("IP_TOS");
454 if (s->ttl >= 0)
455 {
456 if (setsockopt(fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0)
457 ERR("IP_TTL");
458 if (setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0)
459 ERR("SO_DONTROUTE");
460 }
461 #endif
462 /* FIXME: Set send/receive buffers? */
463 /* FIXME: Set keepalive for TCP connections? */
464 err = NULL;
465 bad:
466 return err;
467 }
468
469 static void
470 sk_alloc_bufs(sock *s)
471 {
472 if (!s->rbuf && s->rbsize)
473 s->rbuf = mb_alloc(s->pool, s->rbsize);
474 s->rpos = s->rbuf;
475 if (!s->tbuf && s->tbsize)
476 s->tbuf = mb_alloc(s->pool, s->tbsize);
477 s->tpos = s->ttx = s->tbuf;
478 }
479
480 static void
481 sk_tcp_connected(sock *s)
482 {
483 s->rx_hook(s, 0);
484 s->type = SK_TCP;
485 sk_alloc_bufs(s);
486 }
487
488 static int
489 sk_passive_connected(sock *s, struct sockaddr *sa, int al, int type)
490 {
491 int fd = accept(s->fd, sa, &al);
492 if (fd >= 0)
493 {
494 sock *t = sk_new(s->pool);
495 char *err;
496 t->type = type;
497 t->fd = fd;
498 add_tail(&sock_list, &t->n);
499 s->rx_hook(t, 0);
500 if (err = sk_setup(t))
501 {
502 log(L_ERR "Incoming connection: %s: %m", err);
503 s->err_hook(s, errno);
504 return 0;
505 }
506 sk_alloc_bufs(t);
507 return 1;
508 }
509 else if (errno != EINTR && errno != EAGAIN)
510 {
511 log(L_ERR "accept: %m");
512 s->err_hook(s, errno);
513 }
514 return 0;
515 }
516
517 int
518 sk_open(sock *s)
519 {
520 int fd, e;
521 sockaddr sa;
522 int one = 1;
523 int type = s->type;
524 int has_src = ipa_nonzero(s->saddr) || s->sport;
525 char *err;
526
527 switch (type)
528 {
529 case SK_TCP_ACTIVE:
530 case SK_TCP_PASSIVE:
531 fd = socket(BIRD_PF, SOCK_STREAM, IPPROTO_TCP);
532 break;
533 case SK_UDP:
534 case SK_UDP_MC:
535 fd = socket(BIRD_PF, SOCK_DGRAM, IPPROTO_UDP);
536 break;
537 case SK_IP:
538 case SK_IP_MC:
539 fd = socket(BIRD_PF, SOCK_RAW, s->dport);
540 break;
541 case SK_MAGIC:
542 fd = s->fd;
543 break;
544 default:
545 bug("sk_open() called for invalid sock type %d", type);
546 }
547 if (fd < 0)
548 die("sk_open: socket: %m");
549 s->fd = fd;
550
551 if (err = sk_setup(s))
552 goto bad;
553 switch (type)
554 {
555 case SK_UDP:
556 case SK_IP:
557 if (s->iface) /* It's a broadcast socket */
558 #ifdef IPV6
559 bug("IPv6 has no broadcasts");
560 #else
561 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0)
562 ERR("SO_BROADCAST");
563 #endif
564 break;
565 case SK_UDP_MC:
566 case SK_IP_MC:
567 {
568 #ifdef IPV6
569 /* Fortunately, IPv6 socket interface is recent enough and therefore standardized */
570 ASSERT(s->iface && s->iface->addr);
571 if (ipa_nonzero(s->daddr))
572 {
573 int t = s->iface->index;
574 int zero = 0;
575 if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
576 ERR("IPV6_MULTICAST_HOPS");
577 if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
578 ERR("IPV6_MULTICAST_LOOP");
579 if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_IF, &t, sizeof(t)) < 0)
580 ERR("IPV6_MULTICAST_IF");
581 }
582 if (has_src)
583 {
584 struct ipv6_mreq mreq;
585 set_inaddr(&mreq.ipv6mr_multiaddr, s->daddr);
586 mreq.ipv6mr_ifindex = s->iface->index;
587 if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
588 ERR("IPV6_ADD_MEMBERSHIP");
589 }
590 #else
591 /* With IPv4 there are zillions of different socket interface variants. Ugh. */
592 ASSERT(s->iface && s->iface->addr);
593 if (err = sysio_mcast_join(s))
594 goto bad;
595 #endif
596 break;
597 }
598 }
599 if (has_src)
600 {
601 int port;
602
603 if (type == SK_IP || type == SK_IP_MC)
604 port = 0;
605 else
606 {
607 port = s->sport;
608 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
609 ERR("SO_REUSEADDR");
610 }
611 fill_in_sockaddr(&sa, s->saddr, port);
612 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
613 ERR("bind");
614 }
615 fill_in_sockaddr(&sa, s->daddr, s->dport);
616 switch (type)
617 {
618 case SK_TCP_ACTIVE:
619 if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
620 sk_tcp_connected(s);
621 else if (errno != EINTR && errno != EAGAIN)
622 ERR("connect");
623 break;
624 case SK_TCP_PASSIVE:
625 if (listen(fd, 8))
626 ERR("listen");
627 break;
628 case SK_MAGIC:
629 break;
630 default:
631 #ifdef IPV6
632 #ifdef IPV6_MTU_DISCOVER
633 {
634 int dont = IPV6_PMTUDISC_DONT;
635 if (setsockopt(fd, SOL_IPV6, IPV6_MTU_DISCOVER, &dont, sizeof(dont)) < 0)
636 ERR("IPV6_MTU_DISCOVER");
637 }
638 #endif
639 #else
640 #ifdef IP_PMTUDISC
641 {
642 int dont = IP_PMTUDISC_DONT;
643 if (setsockopt(fd, SOL_IP, IP_PMTUDISC, &dont, sizeof(dont)) < 0)
644 ERR("IP_PMTUDISC");
645 }
646 #endif
647 #endif
648 }
649
650 sk_alloc_bufs(s);
651 add_tail(&sock_list, &s->n);
652 return 0;
653
654 bad:
655 log(L_ERR "sk_open: %s: %m", err);
656 close(fd);
657 s->fd = -1;
658 return -1;
659 }
660
661 int
662 sk_open_unix(sock *s, char *name)
663 {
664 int fd;
665 struct sockaddr_un sa;
666 char *err;
667
668 fd = socket(AF_UNIX, SOCK_STREAM, 0);
669 if (fd < 0)
670 die("sk_open_unix: socket: %m");
671 s->fd = fd;
672 if (err = sk_setup(s))
673 goto bad;
674 unlink(name);
675 sa.sun_family = AF_UNIX;
676 strcpy(sa.sun_path, name);
677 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
678 ERR("bind");
679 if (listen(fd, 8))
680 ERR("listen");
681 sk_alloc_bufs(s);
682 add_tail(&sock_list, &s->n);
683 return 0;
684
685 bad:
686 log(L_ERR "sk_open_unix: %s: %m", err);
687 close(fd);
688 s->fd = -1;
689 return -1;
690 }
691
692 static int
693 sk_maybe_write(sock *s)
694 {
695 int e;
696
697 switch (s->type)
698 {
699 case SK_TCP:
700 case SK_MAGIC:
701 case SK_UNIX:
702 while (s->ttx != s->tpos)
703 {
704 e = write(s->fd, s->ttx, s->tpos - s->ttx);
705 if (e < 0)
706 {
707 if (errno != EINTR && errno != EAGAIN)
708 {
709 log(L_ERR "write: %m");
710 s->err_hook(s, errno);
711 return -1;
712 }
713 return 0;
714 }
715 s->ttx += e;
716 }
717 s->ttx = s->tpos = s->tbuf;
718 return 1;
719 case SK_UDP:
720 case SK_UDP_MC:
721 case SK_IP:
722 case SK_IP_MC:
723 {
724 sockaddr sa;
725
726 if (s->tbuf == s->tpos)
727 return 1;
728 fill_in_sockaddr(&sa, s->faddr, s->fport);
729 e = sendto(s->fd, s->tbuf, s->tpos - s->tbuf, 0, (struct sockaddr *) &sa, sizeof(sa));
730 if (e < 0)
731 {
732 if (errno != EINTR && errno != EAGAIN)
733 {
734 log(L_ERR "sendto: %m");
735 s->err_hook(s, errno);
736 return -1;
737 }
738 return 0;
739 }
740 s->tpos = s->tbuf;
741 return 1;
742 }
743 default:
744 bug("sk_maybe_write: unknown socket type %d", s->type);
745 }
746 }
747
748 int
749 sk_send(sock *s, unsigned len)
750 {
751 s->faddr = s->daddr;
752 s->fport = s->dport;
753 s->ttx = s->tbuf;
754 s->tpos = s->tbuf + len;
755 return sk_maybe_write(s);
756 }
757
758 int
759 sk_send_to(sock *s, unsigned len, ip_addr addr, unsigned port)
760 {
761 s->faddr = addr;
762 s->fport = port;
763 s->ttx = s->tbuf;
764 s->tpos = s->tbuf + len;
765 return sk_maybe_write(s);
766 }
767
768 static int
769 sk_read(sock *s)
770 {
771 switch (s->type)
772 {
773 case SK_TCP_ACTIVE:
774 {
775 sockaddr sa;
776 fill_in_sockaddr(&sa, s->daddr, s->dport);
777 if (connect(s->fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
778 sk_tcp_connected(s);
779 else if (errno != EINTR && errno != EAGAIN)
780 {
781 log(L_ERR "connect: %m");
782 s->err_hook(s, errno);
783 }
784 return 0;
785 }
786 case SK_TCP_PASSIVE:
787 {
788 sockaddr sa;
789 return sk_passive_connected(s, (struct sockaddr *) &sa, sizeof(sa), SK_TCP);
790 }
791 case SK_UNIX_PASSIVE:
792 {
793 struct sockaddr_un sa;
794 return sk_passive_connected(s, (struct sockaddr *) &sa, sizeof(sa), SK_UNIX);
795 }
796 case SK_TCP:
797 case SK_UNIX:
798 {
799 int c = read(s->fd, s->rpos, s->rbuf + s->rbsize - s->rpos);
800
801 if (c < 0)
802 {
803 if (errno != EINTR && errno != EAGAIN)
804 {
805 log(L_ERR "read: %m");
806 s->err_hook(s, errno);
807 }
808 }
809 else if (!c)
810 s->err_hook(s, 0);
811 else
812 {
813 s->rpos += c;
814 if (s->rx_hook(s, s->rpos - s->rbuf))
815 s->rpos = s->rbuf;
816 return 1;
817 }
818 return 0;
819 }
820 case SK_MAGIC:
821 return s->rx_hook(s, 0);
822 default:
823 {
824 sockaddr sa;
825 int al = sizeof(sa);
826 int e = recvfrom(s->fd, s->rbuf, s->rbsize, 0, (struct sockaddr *) &sa, &al);
827
828 if (e < 0)
829 {
830 if (errno != EINTR && errno != EAGAIN)
831 {
832 log(L_ERR "recvfrom: %m");
833 s->err_hook(s, errno);
834 }
835 return 0;
836 }
837 s->rpos = s->rbuf + e;
838 get_sockaddr(&sa, &s->faddr, &s->fport);
839 s->rx_hook(s, e);
840 return 1;
841 }
842 }
843 }
844
845 static void
846 sk_write(sock *s)
847 {
848 while (s->ttx != s->tbuf && sk_maybe_write(s) > 0)
849 s->tx_hook(s);
850 }
851
852 void
853 sk_dump_all(void)
854 {
855 node *n;
856 sock *s;
857
858 debug("Open sockets:\n");
859 WALK_LIST(n, sock_list)
860 {
861 s = SKIP_BACK(sock, n, n);
862 debug("%p ", s);
863 sk_dump(&s->r);
864 }
865 debug("\n");
866 }
867
868 #undef ERR
869 #undef WARN
870
871 /*
872 * Main I/O Loop
873 */
874
875 volatile int async_config_flag; /* Asynchronous reconfiguration/dump scheduled */
876 volatile int async_dump_flag;
877
878 void
879 io_init(void)
880 {
881 init_list(&near_timers);
882 init_list(&far_timers);
883 init_list(&sock_list);
884 init_list(&global_event_list);
885 krt_io_init();
886 now = time(NULL);
887 srandom((int) now);
888 }
889
890 void
891 io_loop(void)
892 {
893 fd_set rd, wr;
894 struct timeval timo;
895 time_t tout;
896 int hi, events;
897 sock *s;
898 node *n, *p;
899
900 FD_ZERO(&rd);
901 FD_ZERO(&wr);
902 for(;;)
903 {
904 events = ev_run_list(&global_event_list);
905 now = time(NULL);
906 tout = tm_first_shot();
907 if (tout <= now)
908 {
909 tm_shot();
910 continue;
911 }
912 timo.tv_sec = events ? 0 : tout - now;
913 timo.tv_usec = 0;
914
915 hi = 0;
916 WALK_LIST(n, sock_list)
917 {
918 s = SKIP_BACK(sock, n, n);
919 if (s->rx_hook)
920 {
921 FD_SET(s->fd, &rd);
922 if (s->fd > hi)
923 hi = s->fd;
924 }
925 if (s->tx_hook && s->ttx != s->tpos)
926 {
927 FD_SET(s->fd, &wr);
928 if (s->fd > hi)
929 hi = s->fd;
930 }
931 }
932
933 /*
934 * Yes, this is racy. But even if the signal comes before this test
935 * and entering select(), it gets caught on the next timer tick.
936 */
937
938 if (async_config_flag)
939 {
940 async_config();
941 async_config_flag = 0;
942 continue;
943 }
944 if (async_dump_flag)
945 {
946 async_dump();
947 async_dump_flag = 0;
948 continue;
949 }
950 if (async_shutdown_flag)
951 {
952 async_shutdown();
953 async_shutdown_flag = 0;
954 continue;
955 }
956
957 /* And finally enter select() to find active sockets */
958
959 hi = select(hi+1, &rd, &wr, NULL, &timo);
960 if (hi < 0)
961 {
962 if (errno == EINTR || errno == EAGAIN)
963 continue;
964 die("select: %m");
965 }
966 if (hi)
967 {
968 WALK_LIST_DELSAFE(n, p, sock_list)
969 {
970 s = SKIP_BACK(sock, n, n);
971 if (FD_ISSET(s->fd, &rd))
972 {
973 FD_CLR(s->fd, &rd);
974 while (sk_read(s))
975 ;
976 }
977 if (s->type != SK_DELETED && FD_ISSET(s->fd, &wr))
978 {
979 FD_CLR(s->fd, &wr);
980 sk_write(s);
981 }
982 if (s->type == SK_DELETED)
983 rfree(s);
984 }
985 }
986 }
987 }