]> git.ipfire.org Git - thirdparty/bird.git/blob - sysdep/unix/io.c
Merge branch 'rt-accepted'
[thirdparty/bird.git] / sysdep / unix / io.c
1 /*
2 * BIRD Internet Routing Daemon -- Unix I/O
3 *
4 * (c) 1998--2004 Martin Mares <mj@ucw.cz>
5 * (c) 2004 Ondrej Filip <feela@network.cz>
6 *
7 * Can be freely distributed and used under the terms of the GNU GPL.
8 */
9
10 /* Unfortunately, some glibc versions hide parts of RFC 3542 API
11 if _GNU_SOURCE is not defined. */
12 #define _GNU_SOURCE 1
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <time.h>
17 #include <sys/time.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/fcntl.h>
21 #include <sys/uio.h>
22 #include <sys/un.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <netinet/in.h>
26 #include <netinet/icmp6.h>
27
28 #include "nest/bird.h"
29 #include "lib/lists.h"
30 #include "lib/resource.h"
31 #include "lib/timer.h"
32 #include "lib/socket.h"
33 #include "lib/event.h"
34 #include "lib/string.h"
35 #include "nest/iface.h"
36
37 #include "lib/unix.h"
38 #include "lib/sysio.h"
39
40 /* Maximum number of calls of tx handler for one socket in one
41 * select iteration. Should be small enough to not monopolize CPU by
42 * one protocol instance.
43 */
44 #define MAX_STEPS 4
45
46 /* Maximum number of calls of rx handler for all sockets in one select
47 iteration. RX callbacks are often much more costly so we limit
48 this to gen small latencies */
49 #define MAX_RX_STEPS 4
50
51 /*
52 * Tracked Files
53 */
54
55 struct rfile {
56 resource r;
57 FILE *f;
58 };
59
60 static void
61 rf_free(resource *r)
62 {
63 struct rfile *a = (struct rfile *) r;
64
65 fclose(a->f);
66 }
67
68 static void
69 rf_dump(resource *r)
70 {
71 struct rfile *a = (struct rfile *) r;
72
73 debug("(FILE *%p)\n", a->f);
74 }
75
76 static struct resclass rf_class = {
77 "FILE",
78 sizeof(struct rfile),
79 rf_free,
80 rf_dump,
81 NULL,
82 NULL
83 };
84
85 void *
86 tracked_fopen(pool *p, char *name, char *mode)
87 {
88 FILE *f = fopen(name, mode);
89
90 if (f)
91 {
92 struct rfile *r = ralloc(p, &rf_class);
93 r->f = f;
94 }
95 return f;
96 }
97
98 /**
99 * DOC: Timers
100 *
101 * Timers are resources which represent a wish of a module to call
102 * a function at the specified time. The platform dependent code
103 * doesn't guarantee exact timing, only that a timer function
104 * won't be called before the requested time.
105 *
106 * In BIRD, time is represented by values of the &bird_clock_t type
107 * which are integral numbers interpreted as a relative number of seconds since
108 * some fixed time point in past. The current time can be read
109 * from variable @now with reasonable accuracy and is monotonic. There is also
110 * a current 'absolute' time in variable @now_real reported by OS.
111 *
112 * Each timer is described by a &timer structure containing a pointer
113 * to the handler function (@hook), data private to this function (@data),
114 * time the function should be called at (@expires, 0 for inactive timers),
115 * for the other fields see |timer.h|.
116 */
117
118 #define NEAR_TIMER_LIMIT 4
119
120 static list near_timers, far_timers;
121 static bird_clock_t first_far_timer = TIME_INFINITY;
122
123 /* now must be different from 0, because 0 is a special value in timer->expires */
124 bird_clock_t now = 1, now_real;
125
126 static void
127 update_times_plain(void)
128 {
129 bird_clock_t new_time = time(NULL);
130 int delta = new_time - now_real;
131
132 if ((delta >= 0) && (delta < 60))
133 now += delta;
134 else if (now_real != 0)
135 log(L_WARN "Time jump, delta %d s", delta);
136
137 now_real = new_time;
138 }
139
140 static void
141 update_times_gettime(void)
142 {
143 struct timespec ts;
144 int rv;
145
146 rv = clock_gettime(CLOCK_MONOTONIC, &ts);
147 if (rv != 0)
148 die("clock_gettime: %m");
149
150 if (ts.tv_sec != now) {
151 if (ts.tv_sec < now)
152 log(L_ERR "Monotonic timer is broken");
153
154 now = ts.tv_sec;
155 now_real = time(NULL);
156 }
157 }
158
159 static int clock_monotonic_available;
160
161 static inline void
162 update_times(void)
163 {
164 if (clock_monotonic_available)
165 update_times_gettime();
166 else
167 update_times_plain();
168 }
169
170 static inline void
171 init_times(void)
172 {
173 struct timespec ts;
174 clock_monotonic_available = (clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
175 if (!clock_monotonic_available)
176 log(L_WARN "Monotonic timer is missing");
177 }
178
179
180 static void
181 tm_free(resource *r)
182 {
183 timer *t = (timer *) r;
184
185 tm_stop(t);
186 }
187
188 static void
189 tm_dump(resource *r)
190 {
191 timer *t = (timer *) r;
192
193 debug("(code %p, data %p, ", t->hook, t->data);
194 if (t->randomize)
195 debug("rand %d, ", t->randomize);
196 if (t->recurrent)
197 debug("recur %d, ", t->recurrent);
198 if (t->expires)
199 debug("expires in %d sec)\n", t->expires - now);
200 else
201 debug("inactive)\n");
202 }
203
204 static struct resclass tm_class = {
205 "Timer",
206 sizeof(timer),
207 tm_free,
208 tm_dump,
209 NULL,
210 NULL
211 };
212
213 /**
214 * tm_new - create a timer
215 * @p: pool
216 *
217 * This function creates a new timer resource and returns
218 * a pointer to it. To use the timer, you need to fill in
219 * the structure fields and call tm_start() to start timing.
220 */
221 timer *
222 tm_new(pool *p)
223 {
224 timer *t = ralloc(p, &tm_class);
225 return t;
226 }
227
228 static inline void
229 tm_insert_near(timer *t)
230 {
231 node *n = HEAD(near_timers);
232
233 while (n->next && (SKIP_BACK(timer, n, n)->expires < t->expires))
234 n = n->next;
235 insert_node(&t->n, n->prev);
236 }
237
238 /**
239 * tm_start - start a timer
240 * @t: timer
241 * @after: number of seconds the timer should be run after
242 *
243 * This function schedules the hook function of the timer to
244 * be called after @after seconds. If the timer has been already
245 * started, it's @expire time is replaced by the new value.
246 *
247 * You can have set the @randomize field of @t, the timeout
248 * will be increased by a random number of seconds chosen
249 * uniformly from range 0 .. @randomize.
250 *
251 * You can call tm_start() from the handler function of the timer
252 * to request another run of the timer. Also, you can set the @recurrent
253 * field to have the timer re-added automatically with the same timeout.
254 */
255 void
256 tm_start(timer *t, unsigned after)
257 {
258 bird_clock_t when;
259
260 if (t->randomize)
261 after += random() % (t->randomize + 1);
262 when = now + after;
263 if (t->expires == when)
264 return;
265 if (t->expires)
266 rem_node(&t->n);
267 t->expires = when;
268 if (after <= NEAR_TIMER_LIMIT)
269 tm_insert_near(t);
270 else
271 {
272 if (!first_far_timer || first_far_timer > when)
273 first_far_timer = when;
274 add_tail(&far_timers, &t->n);
275 }
276 }
277
278 /**
279 * tm_stop - stop a timer
280 * @t: timer
281 *
282 * This function stops a timer. If the timer is already stopped,
283 * nothing happens.
284 */
285 void
286 tm_stop(timer *t)
287 {
288 if (t->expires)
289 {
290 rem_node(&t->n);
291 t->expires = 0;
292 }
293 }
294
295 static void
296 tm_dump_them(char *name, list *l)
297 {
298 node *n;
299 timer *t;
300
301 debug("%s timers:\n", name);
302 WALK_LIST(n, *l)
303 {
304 t = SKIP_BACK(timer, n, n);
305 debug("%p ", t);
306 tm_dump(&t->r);
307 }
308 debug("\n");
309 }
310
311 void
312 tm_dump_all(void)
313 {
314 tm_dump_them("Near", &near_timers);
315 tm_dump_them("Far", &far_timers);
316 }
317
318 static inline time_t
319 tm_first_shot(void)
320 {
321 time_t x = first_far_timer;
322
323 if (!EMPTY_LIST(near_timers))
324 {
325 timer *t = SKIP_BACK(timer, n, HEAD(near_timers));
326 if (t->expires < x)
327 x = t->expires;
328 }
329 return x;
330 }
331
332 static void
333 tm_shot(void)
334 {
335 timer *t;
336 node *n, *m;
337
338 if (first_far_timer <= now)
339 {
340 bird_clock_t limit = now + NEAR_TIMER_LIMIT;
341 first_far_timer = TIME_INFINITY;
342 n = HEAD(far_timers);
343 while (m = n->next)
344 {
345 t = SKIP_BACK(timer, n, n);
346 if (t->expires <= limit)
347 {
348 rem_node(n);
349 tm_insert_near(t);
350 }
351 else if (t->expires < first_far_timer)
352 first_far_timer = t->expires;
353 n = m;
354 }
355 }
356 while ((n = HEAD(near_timers)) -> next)
357 {
358 int delay;
359 t = SKIP_BACK(timer, n, n);
360 if (t->expires > now)
361 break;
362 rem_node(n);
363 delay = t->expires - now;
364 t->expires = 0;
365 if (t->recurrent)
366 {
367 int i = t->recurrent - delay;
368 if (i < 0)
369 i = 0;
370 tm_start(t, i);
371 }
372 t->hook(t);
373 }
374 }
375
376 /**
377 * tm_parse_datetime - parse a date and time
378 * @x: datetime string
379 *
380 * tm_parse_datetime() takes a textual representation of
381 * a date and time (dd-mm-yyyy hh:mm:ss)
382 * and converts it to the corresponding value of type &bird_clock_t.
383 */
384 bird_clock_t
385 tm_parse_datetime(char *x)
386 {
387 struct tm tm;
388 int n;
389 time_t t;
390
391 if (sscanf(x, "%d-%d-%d %d:%d:%d%n", &tm.tm_mday, &tm.tm_mon, &tm.tm_year, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &n) != 6 || x[n])
392 return tm_parse_date(x);
393 tm.tm_mon--;
394 tm.tm_year -= 1900;
395 t = mktime(&tm);
396 if (t == (time_t) -1)
397 return 0;
398 return t;
399 }
400 /**
401 * tm_parse_date - parse a date
402 * @x: date string
403 *
404 * tm_parse_date() takes a textual representation of a date (dd-mm-yyyy)
405 * and converts it to the corresponding value of type &bird_clock_t.
406 */
407 bird_clock_t
408 tm_parse_date(char *x)
409 {
410 struct tm tm;
411 int n;
412 time_t t;
413
414 if (sscanf(x, "%d-%d-%d%n", &tm.tm_mday, &tm.tm_mon, &tm.tm_year, &n) != 3 || x[n])
415 return 0;
416 tm.tm_mon--;
417 tm.tm_year -= 1900;
418 tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
419 t = mktime(&tm);
420 if (t == (time_t) -1)
421 return 0;
422 return t;
423 }
424
425 static void
426 tm_format_reltime(char *x, struct tm *tm, bird_clock_t delta)
427 {
428 static char *month_names[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
429 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
430
431 if (delta < 20*3600)
432 bsprintf(x, "%02d:%02d", tm->tm_hour, tm->tm_min);
433 else if (delta < 360*86400)
434 bsprintf(x, "%s%02d", month_names[tm->tm_mon], tm->tm_mday);
435 else
436 bsprintf(x, "%d", tm->tm_year+1900);
437 }
438
439 #include "conf/conf.h"
440
441 /**
442 * tm_format_datetime - convert date and time to textual representation
443 * @x: destination buffer of size %TM_DATETIME_BUFFER_SIZE
444 * @t: time
445 *
446 * This function formats the given relative time value @t to a textual
447 * date/time representation (dd-mm-yyyy hh:mm:ss) in real time.
448 */
449 void
450 tm_format_datetime(char *x, struct timeformat *fmt_spec, bird_clock_t t)
451 {
452 const char *fmt_used;
453 struct tm *tm;
454 bird_clock_t delta = now - t;
455 t = now_real - delta;
456 tm = localtime(&t);
457
458 if (fmt_spec->fmt1 == NULL)
459 return tm_format_reltime(x, tm, delta);
460
461 if ((fmt_spec->limit == 0) || (delta < fmt_spec->limit))
462 fmt_used = fmt_spec->fmt1;
463 else
464 fmt_used = fmt_spec->fmt2;
465
466 int rv = strftime(x, TM_DATETIME_BUFFER_SIZE, fmt_used, tm);
467 if (((rv == 0) && fmt_used[0]) || (rv == TM_DATETIME_BUFFER_SIZE))
468 strcpy(x, "<too-long>");
469 }
470
471 /**
472 * DOC: Sockets
473 *
474 * Socket resources represent network connections. Their data structure (&socket)
475 * contains a lot of fields defining the exact type of the socket, the local and
476 * remote addresses and ports, pointers to socket buffers and finally pointers to
477 * hook functions to be called when new data have arrived to the receive buffer
478 * (@rx_hook), when the contents of the transmit buffer have been transmitted
479 * (@tx_hook) and when an error or connection close occurs (@err_hook).
480 *
481 * Freeing of sockets from inside socket hooks is perfectly safe.
482 */
483
484 #ifndef SOL_IP
485 #define SOL_IP IPPROTO_IP
486 #endif
487
488 #ifndef SOL_IPV6
489 #define SOL_IPV6 IPPROTO_IPV6
490 #endif
491
492 static list sock_list;
493 static struct birdsock *current_sock;
494 static struct birdsock *stored_sock;
495 static int sock_recalc_fdsets_p;
496
497 static inline sock *
498 sk_next(sock *s)
499 {
500 if (!s->n.next->next)
501 return NULL;
502 else
503 return SKIP_BACK(sock, n, s->n.next);
504 }
505
506 static void
507 sk_alloc_bufs(sock *s)
508 {
509 if (!s->rbuf && s->rbsize)
510 s->rbuf = s->rbuf_alloc = xmalloc(s->rbsize);
511 s->rpos = s->rbuf;
512 if (!s->tbuf && s->tbsize)
513 s->tbuf = s->tbuf_alloc = xmalloc(s->tbsize);
514 s->tpos = s->ttx = s->tbuf;
515 }
516
517 static void
518 sk_free_bufs(sock *s)
519 {
520 if (s->rbuf_alloc)
521 {
522 xfree(s->rbuf_alloc);
523 s->rbuf = s->rbuf_alloc = NULL;
524 }
525 if (s->tbuf_alloc)
526 {
527 xfree(s->tbuf_alloc);
528 s->tbuf = s->tbuf_alloc = NULL;
529 }
530 }
531
532 static void
533 sk_free(resource *r)
534 {
535 sock *s = (sock *) r;
536
537 sk_free_bufs(s);
538 if (s->fd >= 0)
539 {
540 close(s->fd);
541 if (s == current_sock)
542 current_sock = sk_next(s);
543 if (s == stored_sock)
544 stored_sock = sk_next(s);
545 rem_node(&s->n);
546 sock_recalc_fdsets_p = 1;
547 }
548 }
549
550 void
551 sk_reallocate(sock *s)
552 {
553 sk_free_bufs(s);
554 sk_alloc_bufs(s);
555 }
556
557 static void
558 sk_dump(resource *r)
559 {
560 sock *s = (sock *) r;
561 static char *sk_type_names[] = { "TCP<", "TCP>", "TCP", "UDP", "UDP/MC", "IP", "IP/MC", "MAGIC", "UNIX<", "UNIX", "DEL!" };
562
563 debug("(%s, ud=%p, sa=%08x, sp=%d, da=%08x, dp=%d, tos=%d, ttl=%d, if=%s)\n",
564 sk_type_names[s->type],
565 s->data,
566 s->saddr,
567 s->sport,
568 s->daddr,
569 s->dport,
570 s->tos,
571 s->ttl,
572 s->iface ? s->iface->name : "none");
573 }
574
575 static struct resclass sk_class = {
576 "Socket",
577 sizeof(sock),
578 sk_free,
579 sk_dump,
580 NULL,
581 NULL
582 };
583
584 /**
585 * sk_new - create a socket
586 * @p: pool
587 *
588 * This function creates a new socket resource. If you want to use it,
589 * you need to fill in all the required fields of the structure and
590 * call sk_open() to do the actual opening of the socket.
591 */
592 sock *
593 sk_new(pool *p)
594 {
595 sock *s = ralloc(p, &sk_class);
596 s->pool = p;
597 // s->saddr = s->daddr = IPA_NONE;
598 s->tos = s->ttl = -1;
599 s->fd = -1;
600 return s;
601 }
602
603 static void
604 sk_insert(sock *s)
605 {
606 add_tail(&sock_list, &s->n);
607 sock_recalc_fdsets_p = 1;
608 }
609
610 #ifdef IPV6
611
612 void
613 fill_in_sockaddr(struct sockaddr_in6 *sa, ip_addr a, struct iface *ifa, unsigned port)
614 {
615 memset(sa, 0, sizeof (struct sockaddr_in6));
616 sa->sin6_family = AF_INET6;
617 sa->sin6_port = htons(port);
618 sa->sin6_flowinfo = 0;
619 #ifdef HAVE_SIN_LEN
620 sa->sin6_len = sizeof(struct sockaddr_in6);
621 #endif
622 set_inaddr(&sa->sin6_addr, a);
623
624 if (ifa && ipa_has_link_scope(a))
625 sa->sin6_scope_id = ifa->index;
626 }
627
628 void
629 get_sockaddr(struct sockaddr_in6 *sa, ip_addr *a, struct iface **ifa, unsigned *port, int check)
630 {
631 if (check && sa->sin6_family != AF_INET6)
632 bug("get_sockaddr called for wrong address family (%d)", sa->sin6_family);
633 if (port)
634 *port = ntohs(sa->sin6_port);
635 memcpy(a, &sa->sin6_addr, sizeof(*a));
636 ipa_ntoh(*a);
637
638 if (ifa && ipa_has_link_scope(*a))
639 *ifa = if_find_by_index(sa->sin6_scope_id);
640 }
641
642 #else
643
644 void
645 fill_in_sockaddr(struct sockaddr_in *sa, ip_addr a, struct iface *ifa, unsigned port)
646 {
647 memset (sa, 0, sizeof (struct sockaddr_in));
648 sa->sin_family = AF_INET;
649 sa->sin_port = htons(port);
650 #ifdef HAVE_SIN_LEN
651 sa->sin_len = sizeof(struct sockaddr_in);
652 #endif
653 set_inaddr(&sa->sin_addr, a);
654 }
655
656 void
657 get_sockaddr(struct sockaddr_in *sa, ip_addr *a, struct iface **ifa, unsigned *port, int check)
658 {
659 if (check && sa->sin_family != AF_INET)
660 bug("get_sockaddr called for wrong address family (%d)", sa->sin_family);
661 if (port)
662 *port = ntohs(sa->sin_port);
663 memcpy(a, &sa->sin_addr.s_addr, sizeof(*a));
664 ipa_ntoh(*a);
665 }
666
667 #endif
668
669
670 #ifdef IPV6
671
672 /* PKTINFO handling is also standardized in IPv6 */
673 #define CMSG_RX_SPACE CMSG_SPACE(sizeof(struct in6_pktinfo))
674 #define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in6_pktinfo))
675
676 /*
677 * RFC 2292 uses IPV6_PKTINFO for both the socket option and the cmsg
678 * type, RFC 3542 changed the socket option to IPV6_RECVPKTINFO. If we
679 * don't have IPV6_RECVPKTINFO we suppose the OS implements the older
680 * RFC and we use IPV6_PKTINFO.
681 */
682 #ifndef IPV6_RECVPKTINFO
683 #define IPV6_RECVPKTINFO IPV6_PKTINFO
684 #endif
685
686 static char *
687 sysio_register_cmsgs(sock *s)
688 {
689 int ok = 1;
690 if ((s->flags & SKF_LADDR_RX) &&
691 setsockopt(s->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &ok, sizeof(ok)) < 0)
692 return "IPV6_RECVPKTINFO";
693
694 return NULL;
695 }
696
697 static void
698 sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
699 {
700 struct cmsghdr *cm;
701 struct in6_pktinfo *pi = NULL;
702
703 if (!(s->flags & SKF_LADDR_RX))
704 return;
705
706 for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
707 {
708 if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO)
709 pi = (struct in6_pktinfo *) CMSG_DATA(cm);
710 }
711
712 if (!pi)
713 {
714 s->laddr = IPA_NONE;
715 s->lifindex = 0;
716 return;
717 }
718
719 get_inaddr(&s->laddr, &pi->ipi6_addr);
720 s->lifindex = pi->ipi6_ifindex;
721 return;
722 }
723
724 /*
725 static void
726 sysio_prepare_tx_cmsgs(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
727 {
728 struct cmsghdr *cm;
729 struct in6_pktinfo *pi;
730
731 if (!(s->flags & SKF_LADDR_TX))
732 return;
733
734 msg->msg_control = cbuf;
735 msg->msg_controllen = cbuflen;
736
737 cm = CMSG_FIRSTHDR(msg);
738 cm->cmsg_level = IPPROTO_IPV6;
739 cm->cmsg_type = IPV6_PKTINFO;
740 cm->cmsg_len = CMSG_LEN(sizeof(*pi));
741
742 pi = (struct in6_pktinfo *) CMSG_DATA(cm);
743 set_inaddr(&pi->ipi6_addr, s->saddr);
744 pi->ipi6_ifindex = s->iface ? s->iface->index : 0;
745
746 msg->msg_controllen = cm->cmsg_len;
747 return;
748 }
749 */
750 #endif
751
752 static char *
753 sk_set_ttl_int(sock *s)
754 {
755 #ifdef IPV6
756 if (setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
757 return "IPV6_UNICAST_HOPS";
758 #else
759 if (setsockopt(s->fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0)
760 return "IP_TTL";
761 #ifdef CONFIG_UNIX_DONTROUTE
762 int one = 1;
763 if (s->ttl == 1 && setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0)
764 return "SO_DONTROUTE";
765 #endif
766 #endif
767 return NULL;
768 }
769
770 #define ERR(x) do { err = x; goto bad; } while(0)
771 #define WARN(x) log(L_WARN "sk_setup: %s: %m", x)
772
773 static char *
774 sk_setup(sock *s)
775 {
776 int fd = s->fd;
777 char *err = NULL;
778
779 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
780 ERR("fcntl(O_NONBLOCK)");
781 if (s->type == SK_UNIX)
782 return NULL;
783 #ifndef IPV6
784 if ((s->tos >= 0) && setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0)
785 WARN("IP_TOS");
786 #endif
787
788 #ifdef IPV6
789 int v = 1;
790 if ((s->flags & SKF_V6ONLY) && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v, sizeof(v)) < 0)
791 WARN("IPV6_V6ONLY");
792 #endif
793
794 if (s->ttl >= 0)
795 err = sk_set_ttl_int(s);
796
797 sysio_register_cmsgs(s);
798 bad:
799 return err;
800 }
801
802 /**
803 * sk_set_ttl - set transmit TTL for given socket.
804 * @s: socket
805 * @ttl: TTL value
806 *
807 * Set TTL for already opened connections when TTL was not set before.
808 * Useful for accepted connections when different ones should have
809 * different TTL.
810 *
811 * Result: 0 for success, -1 for an error.
812 */
813
814 int
815 sk_set_ttl(sock *s, int ttl)
816 {
817 char *err;
818
819 s->ttl = ttl;
820 if (err = sk_set_ttl_int(s))
821 log(L_ERR "sk_set_ttl: %s: %m", err);
822
823 return (err ? -1 : 0);
824 }
825
826 /**
827 * sk_set_min_ttl - set minimal accepted TTL for given socket.
828 * @s: socket
829 * @ttl: TTL value
830 *
831 * Can be used in TTL security implementation
832 *
833 * Result: 0 for success, -1 for an error.
834 */
835
836 int
837 sk_set_min_ttl(sock *s, int ttl)
838 {
839 int err;
840 #ifdef IPV6
841 err = sk_set_min_ttl6(s, ttl);
842 #else
843 err = sk_set_min_ttl4(s, ttl);
844 #endif
845
846 return err;
847 }
848
849 /**
850 * sk_set_md5_auth - add / remove MD5 security association for given socket.
851 * @s: socket
852 * @a: IP address of the other side
853 * @ifa: Interface for link-local IP address
854 * @passwd: password used for MD5 authentication
855 *
856 * In TCP MD5 handling code in kernel, there is a set of pairs
857 * (address, password) used to choose password according to
858 * address of the other side. This function is useful for
859 * listening socket, for active sockets it is enough to set
860 * s->password field.
861 *
862 * When called with passwd != NULL, the new pair is added,
863 * When called with passwd == NULL, the existing pair is removed.
864 *
865 * Result: 0 for success, -1 for an error.
866 */
867
868 int
869 sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd)
870 {
871 sockaddr sa;
872 fill_in_sockaddr(&sa, a, ifa, 0);
873 return sk_set_md5_auth_int(s, &sa, passwd);
874 }
875
876 int
877 sk_set_broadcast(sock *s, int enable)
878 {
879 if (setsockopt(s->fd, SOL_SOCKET, SO_BROADCAST, &enable, sizeof(enable)) < 0)
880 {
881 log(L_ERR "sk_set_broadcast: SO_BROADCAST: %m");
882 return -1;
883 }
884
885 return 0;
886 }
887
888
889 #ifdef IPV6
890
891 int
892 sk_set_ipv6_checksum(sock *s, int offset)
893 {
894 if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset)) < 0)
895 {
896 log(L_ERR "sk_set_ipv6_checksum: IPV6_CHECKSUM: %m");
897 return -1;
898 }
899
900 return 0;
901 }
902
903 int
904 sk_set_icmp_filter(sock *s, int p1, int p2)
905 {
906 /* a bit of lame interface, but it is here only for Radv */
907 struct icmp6_filter f;
908
909 ICMP6_FILTER_SETBLOCKALL(&f);
910 ICMP6_FILTER_SETPASS(p1, &f);
911 ICMP6_FILTER_SETPASS(p2, &f);
912
913 if (setsockopt(s->fd, IPPROTO_ICMPV6, ICMP6_FILTER, &f, sizeof(f)) < 0)
914 {
915 log(L_ERR "sk_setup_icmp_filter: ICMP6_FILTER: %m");
916 return -1;
917 }
918
919 return 0;
920 }
921
922 int
923 sk_setup_multicast(sock *s)
924 {
925 char *err;
926 int zero = 0;
927 int index;
928
929 ASSERT(s->iface && s->iface->addr);
930
931 index = s->iface->index;
932 if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
933 ERR("IPV6_MULTICAST_HOPS");
934 if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
935 ERR("IPV6_MULTICAST_LOOP");
936 if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index)) < 0)
937 ERR("IPV6_MULTICAST_IF");
938
939 if (err = sysio_bind_to_iface(s))
940 goto bad;
941
942 return 0;
943
944 bad:
945 log(L_ERR "sk_setup_multicast: %s: %m", err);
946 return -1;
947 }
948
949 int
950 sk_join_group(sock *s, ip_addr maddr)
951 {
952 struct ipv6_mreq mreq;
953
954 set_inaddr(&mreq.ipv6mr_multiaddr, maddr);
955
956 #ifdef CONFIG_IPV6_GLIBC_20
957 mreq.ipv6mr_ifindex = s->iface->index;
958 #else
959 mreq.ipv6mr_interface = s->iface->index;
960 #endif
961
962 if (setsockopt(s->fd, SOL_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0)
963 {
964 log(L_ERR "sk_join_group: IPV6_JOIN_GROUP: %m");
965 return -1;
966 }
967
968 return 0;
969 }
970
971 int
972 sk_leave_group(sock *s, ip_addr maddr)
973 {
974 struct ipv6_mreq mreq;
975
976 set_inaddr(&mreq.ipv6mr_multiaddr, maddr);
977
978 #ifdef CONFIG_IPV6_GLIBC_20
979 mreq.ipv6mr_ifindex = s->iface->index;
980 #else
981 mreq.ipv6mr_interface = s->iface->index;
982 #endif
983
984 if (setsockopt(s->fd, SOL_IPV6, IPV6_LEAVE_GROUP, &mreq, sizeof(mreq)) < 0)
985 {
986 log(L_ERR "sk_leave_group: IPV6_LEAVE_GROUP: %m");
987 return -1;
988 }
989
990 return 0;
991 }
992
993 #else /* IPV4 */
994
995 int
996 sk_setup_multicast(sock *s)
997 {
998 char *err;
999
1000 ASSERT(s->iface && s->iface->addr);
1001
1002 if (err = sysio_setup_multicast(s))
1003 {
1004 log(L_ERR "sk_setup_multicast: %s: %m", err);
1005 return -1;
1006 }
1007
1008 return 0;
1009 }
1010
1011 int
1012 sk_join_group(sock *s, ip_addr maddr)
1013 {
1014 char *err;
1015
1016 if (err = sysio_join_group(s, maddr))
1017 {
1018 log(L_ERR "sk_join_group: %s: %m", err);
1019 return -1;
1020 }
1021
1022 return 0;
1023 }
1024
1025 int
1026 sk_leave_group(sock *s, ip_addr maddr)
1027 {
1028 char *err;
1029
1030 if (err = sysio_leave_group(s, maddr))
1031 {
1032 log(L_ERR "sk_leave_group: %s: %m", err);
1033 return -1;
1034 }
1035
1036 return 0;
1037 }
1038
1039 #endif
1040
1041
1042 static void
1043 sk_tcp_connected(sock *s)
1044 {
1045 sockaddr lsa;
1046 int lsa_len = sizeof(lsa);
1047 if (getsockname(s->fd, (struct sockaddr *) &lsa, &lsa_len) == 0)
1048 get_sockaddr(&lsa, &s->saddr, &s->iface, &s->sport, 1);
1049
1050 s->type = SK_TCP;
1051 sk_alloc_bufs(s);
1052 s->tx_hook(s);
1053 }
1054
1055 static int
1056 sk_passive_connected(sock *s, struct sockaddr *sa, int al, int type)
1057 {
1058 int fd = accept(s->fd, sa, &al);
1059 if (fd >= 0)
1060 {
1061 sock *t = sk_new(s->pool);
1062 char *err;
1063 t->type = type;
1064 t->fd = fd;
1065 t->ttl = s->ttl;
1066 t->tos = s->tos;
1067 t->rbsize = s->rbsize;
1068 t->tbsize = s->tbsize;
1069 if (type == SK_TCP)
1070 {
1071 sockaddr lsa;
1072 int lsa_len = sizeof(lsa);
1073 if (getsockname(fd, (struct sockaddr *) &lsa, &lsa_len) == 0)
1074 get_sockaddr(&lsa, &t->saddr, &t->iface, &t->sport, 1);
1075
1076 get_sockaddr((sockaddr *) sa, &t->daddr, &t->iface, &t->dport, 1);
1077 }
1078 sk_insert(t);
1079 if (err = sk_setup(t))
1080 {
1081 log(L_ERR "Incoming connection: %s: %m", err);
1082 rfree(t);
1083 return 1;
1084 }
1085 sk_alloc_bufs(t);
1086 s->rx_hook(t, 0);
1087 return 1;
1088 }
1089 else if (errno != EINTR && errno != EAGAIN)
1090 {
1091 s->err_hook(s, errno);
1092 }
1093 return 0;
1094 }
1095
1096 /**
1097 * sk_open - open a socket
1098 * @s: socket
1099 *
1100 * This function takes a socket resource created by sk_new() and
1101 * initialized by the user and binds a corresponding network connection
1102 * to it.
1103 *
1104 * Result: 0 for success, -1 for an error.
1105 */
1106 int
1107 sk_open(sock *s)
1108 {
1109 int fd;
1110 sockaddr sa;
1111 int one = 1;
1112 int type = s->type;
1113 int has_src = ipa_nonzero(s->saddr) || s->sport;
1114 char *err;
1115
1116 switch (type)
1117 {
1118 case SK_TCP_ACTIVE:
1119 s->ttx = ""; /* Force s->ttx != s->tpos */
1120 /* Fall thru */
1121 case SK_TCP_PASSIVE:
1122 fd = socket(BIRD_PF, SOCK_STREAM, IPPROTO_TCP);
1123 break;
1124 case SK_UDP:
1125 fd = socket(BIRD_PF, SOCK_DGRAM, IPPROTO_UDP);
1126 break;
1127 case SK_IP:
1128 fd = socket(BIRD_PF, SOCK_RAW, s->dport);
1129 break;
1130 case SK_MAGIC:
1131 fd = s->fd;
1132 break;
1133 default:
1134 bug("sk_open() called for invalid sock type %d", type);
1135 }
1136 if (fd < 0)
1137 die("sk_open: socket: %m");
1138 s->fd = fd;
1139
1140 if (err = sk_setup(s))
1141 goto bad;
1142
1143 if (has_src)
1144 {
1145 int port;
1146
1147 if (type == SK_IP)
1148 port = 0;
1149 else
1150 {
1151 port = s->sport;
1152 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
1153 ERR("SO_REUSEADDR");
1154 }
1155 fill_in_sockaddr(&sa, s->saddr, s->iface, port);
1156 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
1157 ERR("bind");
1158 }
1159 fill_in_sockaddr(&sa, s->daddr, s->iface, s->dport);
1160
1161 if (s->password)
1162 {
1163 int rv = sk_set_md5_auth_int(s, &sa, s->password);
1164 if (rv < 0)
1165 goto bad_no_log;
1166 }
1167
1168 switch (type)
1169 {
1170 case SK_TCP_ACTIVE:
1171 if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
1172 sk_tcp_connected(s);
1173 else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS &&
1174 errno != ECONNREFUSED && errno != EHOSTUNREACH && errno != ENETUNREACH)
1175 ERR("connect");
1176 break;
1177 case SK_TCP_PASSIVE:
1178 if (listen(fd, 8))
1179 ERR("listen");
1180 break;
1181 case SK_MAGIC:
1182 break;
1183 default:
1184 sk_alloc_bufs(s);
1185 #ifdef IPV6
1186 #ifdef IPV6_MTU_DISCOVER
1187 {
1188 int dont = IPV6_PMTUDISC_DONT;
1189 if (setsockopt(fd, SOL_IPV6, IPV6_MTU_DISCOVER, &dont, sizeof(dont)) < 0)
1190 ERR("IPV6_MTU_DISCOVER");
1191 }
1192 #endif
1193 #else
1194 #ifdef IP_PMTUDISC
1195 {
1196 int dont = IP_PMTUDISC_DONT;
1197 if (setsockopt(fd, SOL_IP, IP_PMTUDISC, &dont, sizeof(dont)) < 0)
1198 ERR("IP_PMTUDISC");
1199 }
1200 #endif
1201 #endif
1202 }
1203
1204 sk_insert(s);
1205 return 0;
1206
1207 bad:
1208 log(L_ERR "sk_open: %s: %m", err);
1209 bad_no_log:
1210 close(fd);
1211 s->fd = -1;
1212 return -1;
1213 }
1214
1215 void
1216 sk_open_unix(sock *s, char *name)
1217 {
1218 int fd;
1219 struct sockaddr_un sa;
1220 char *err;
1221
1222 fd = socket(AF_UNIX, SOCK_STREAM, 0);
1223 if (fd < 0)
1224 ERR("socket");
1225 s->fd = fd;
1226 if (err = sk_setup(s))
1227 goto bad;
1228 unlink(name);
1229
1230 /* Path length checked in test_old_bird() */
1231 sa.sun_family = AF_UNIX;
1232 strcpy(sa.sun_path, name);
1233 if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) < 0)
1234 ERR("bind");
1235 if (listen(fd, 8))
1236 ERR("listen");
1237 sk_insert(s);
1238 return;
1239
1240 bad:
1241 log(L_ERR "sk_open_unix: %s: %m", err);
1242 die("Unable to create control socket %s", name);
1243 }
1244
1245 static inline void reset_tx_buffer(sock *s) { s->ttx = s->tpos = s->tbuf; }
1246
1247 static int
1248 sk_maybe_write(sock *s)
1249 {
1250 int e;
1251
1252 switch (s->type)
1253 {
1254 case SK_TCP:
1255 case SK_MAGIC:
1256 case SK_UNIX:
1257 while (s->ttx != s->tpos)
1258 {
1259 e = write(s->fd, s->ttx, s->tpos - s->ttx);
1260 if (e < 0)
1261 {
1262 if (errno != EINTR && errno != EAGAIN)
1263 {
1264 reset_tx_buffer(s);
1265 /* EPIPE is just a connection close notification during TX */
1266 s->err_hook(s, (errno != EPIPE) ? errno : 0);
1267 return -1;
1268 }
1269 return 0;
1270 }
1271 s->ttx += e;
1272 }
1273 reset_tx_buffer(s);
1274 return 1;
1275 case SK_UDP:
1276 case SK_IP:
1277 {
1278 if (s->tbuf == s->tpos)
1279 return 1;
1280
1281 sockaddr sa;
1282 fill_in_sockaddr(&sa, s->daddr, s->iface, s->dport);
1283
1284 struct iovec iov = {s->tbuf, s->tpos - s->tbuf};
1285 // byte cmsg_buf[CMSG_TX_SPACE];
1286
1287 struct msghdr msg = {
1288 .msg_name = &sa,
1289 .msg_namelen = sizeof(sa),
1290 .msg_iov = &iov,
1291 .msg_iovlen = 1};
1292
1293 // sysio_prepare_tx_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf));
1294 e = sendmsg(s->fd, &msg, 0);
1295
1296 if (e < 0)
1297 {
1298 if (errno != EINTR && errno != EAGAIN)
1299 {
1300 reset_tx_buffer(s);
1301 s->err_hook(s, errno);
1302 return -1;
1303 }
1304 return 0;
1305 }
1306 reset_tx_buffer(s);
1307 return 1;
1308 }
1309 default:
1310 bug("sk_maybe_write: unknown socket type %d", s->type);
1311 }
1312 }
1313
1314 int
1315 sk_rx_ready(sock *s)
1316 {
1317 fd_set rd, wr;
1318 struct timeval timo;
1319 int rv;
1320
1321 FD_ZERO(&rd);
1322 FD_ZERO(&wr);
1323 FD_SET(s->fd, &rd);
1324
1325 timo.tv_sec = 0;
1326 timo.tv_usec = 0;
1327
1328 redo:
1329 rv = select(s->fd+1, &rd, &wr, NULL, &timo);
1330
1331 if ((rv < 0) && (errno == EINTR || errno == EAGAIN))
1332 goto redo;
1333
1334 return rv;
1335 }
1336
1337 /**
1338 * sk_send - send data to a socket
1339 * @s: socket
1340 * @len: number of bytes to send
1341 *
1342 * This function sends @len bytes of data prepared in the
1343 * transmit buffer of the socket @s to the network connection.
1344 * If the packet can be sent immediately, it does so and returns
1345 * 1, else it queues the packet for later processing, returns 0
1346 * and calls the @tx_hook of the socket when the tranmission
1347 * takes place.
1348 */
1349 int
1350 sk_send(sock *s, unsigned len)
1351 {
1352 s->ttx = s->tbuf;
1353 s->tpos = s->tbuf + len;
1354 return sk_maybe_write(s);
1355 }
1356
1357 /**
1358 * sk_send_to - send data to a specific destination
1359 * @s: socket
1360 * @len: number of bytes to send
1361 * @addr: IP address to send the packet to
1362 * @port: port to send the packet to
1363 *
1364 * This is a sk_send() replacement for connection-less packet sockets
1365 * which allows destination of the packet to be chosen dynamically.
1366 */
1367 int
1368 sk_send_to(sock *s, unsigned len, ip_addr addr, unsigned port)
1369 {
1370 s->daddr = addr;
1371 s->dport = port;
1372 s->ttx = s->tbuf;
1373 s->tpos = s->tbuf + len;
1374 return sk_maybe_write(s);
1375 }
1376
1377 /*
1378 int
1379 sk_send_full(sock *s, unsigned len, struct iface *ifa,
1380 ip_addr saddr, ip_addr daddr, unsigned dport)
1381 {
1382 s->iface = ifa;
1383 s->saddr = saddr;
1384 s->daddr = daddr;
1385 s->dport = dport;
1386 s->ttx = s->tbuf;
1387 s->tpos = s->tbuf + len;
1388 return sk_maybe_write(s);
1389 }
1390 */
1391
1392 static int
1393 sk_read(sock *s)
1394 {
1395 switch (s->type)
1396 {
1397 case SK_TCP_PASSIVE:
1398 {
1399 sockaddr sa;
1400 return sk_passive_connected(s, (struct sockaddr *) &sa, sizeof(sa), SK_TCP);
1401 }
1402 case SK_UNIX_PASSIVE:
1403 {
1404 struct sockaddr_un sa;
1405 return sk_passive_connected(s, (struct sockaddr *) &sa, sizeof(sa), SK_UNIX);
1406 }
1407 case SK_TCP:
1408 case SK_UNIX:
1409 {
1410 int c = read(s->fd, s->rpos, s->rbuf + s->rbsize - s->rpos);
1411
1412 if (c < 0)
1413 {
1414 if (errno != EINTR && errno != EAGAIN)
1415 s->err_hook(s, errno);
1416 }
1417 else if (!c)
1418 s->err_hook(s, 0);
1419 else
1420 {
1421 s->rpos += c;
1422 if (s->rx_hook(s, s->rpos - s->rbuf))
1423 {
1424 /* We need to be careful since the socket could have been deleted by the hook */
1425 if (current_sock == s)
1426 s->rpos = s->rbuf;
1427 }
1428 return 1;
1429 }
1430 return 0;
1431 }
1432 case SK_MAGIC:
1433 return s->rx_hook(s, 0);
1434 default:
1435 {
1436 sockaddr sa;
1437 int e;
1438
1439 struct iovec iov = {s->rbuf, s->rbsize};
1440 byte cmsg_buf[CMSG_RX_SPACE];
1441
1442 struct msghdr msg = {
1443 .msg_name = &sa,
1444 .msg_namelen = sizeof(sa),
1445 .msg_iov = &iov,
1446 .msg_iovlen = 1,
1447 .msg_control = cmsg_buf,
1448 .msg_controllen = sizeof(cmsg_buf),
1449 .msg_flags = 0};
1450
1451 e = recvmsg(s->fd, &msg, 0);
1452
1453 if (e < 0)
1454 {
1455 if (errno != EINTR && errno != EAGAIN)
1456 s->err_hook(s, errno);
1457 return 0;
1458 }
1459 s->rpos = s->rbuf + e;
1460 get_sockaddr(&sa, &s->faddr, NULL, &s->fport, 1);
1461 sysio_process_rx_cmsgs(s, &msg);
1462
1463 s->rx_hook(s, e);
1464 return 1;
1465 }
1466 }
1467 }
1468
1469 static int
1470 sk_write(sock *s)
1471 {
1472 switch (s->type)
1473 {
1474 case SK_TCP_ACTIVE:
1475 {
1476 sockaddr sa;
1477 fill_in_sockaddr(&sa, s->daddr, s->iface, s->dport);
1478 if (connect(s->fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0 || errno == EISCONN)
1479 sk_tcp_connected(s);
1480 else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS)
1481 s->err_hook(s, errno);
1482 return 0;
1483 }
1484 default:
1485 if (s->ttx != s->tpos && sk_maybe_write(s) > 0)
1486 {
1487 s->tx_hook(s);
1488 return 1;
1489 }
1490 return 0;
1491 }
1492 }
1493
1494 void
1495 sk_dump_all(void)
1496 {
1497 node *n;
1498 sock *s;
1499
1500 debug("Open sockets:\n");
1501 WALK_LIST(n, sock_list)
1502 {
1503 s = SKIP_BACK(sock, n, n);
1504 debug("%p ", s);
1505 sk_dump(&s->r);
1506 }
1507 debug("\n");
1508 }
1509
1510 #undef ERR
1511 #undef WARN
1512
1513 /*
1514 * Main I/O Loop
1515 */
1516
1517 volatile int async_config_flag; /* Asynchronous reconfiguration/dump scheduled */
1518 volatile int async_dump_flag;
1519
1520 void
1521 io_init(void)
1522 {
1523 init_list(&near_timers);
1524 init_list(&far_timers);
1525 init_list(&sock_list);
1526 init_list(&global_event_list);
1527 krt_io_init();
1528 init_times();
1529 update_times();
1530 srandom((int) now_real);
1531 }
1532
1533 static int short_loops = 0;
1534 #define SHORT_LOOP_MAX 10
1535
1536 void
1537 io_loop(void)
1538 {
1539 fd_set rd, wr;
1540 struct timeval timo;
1541 time_t tout;
1542 int hi, events;
1543 sock *s;
1544 node *n;
1545
1546 sock_recalc_fdsets_p = 1;
1547 for(;;)
1548 {
1549 events = ev_run_list(&global_event_list);
1550 update_times();
1551 tout = tm_first_shot();
1552 if (tout <= now)
1553 {
1554 tm_shot();
1555 continue;
1556 }
1557 timo.tv_sec = events ? 0 : tout - now;
1558 timo.tv_usec = 0;
1559
1560 if (sock_recalc_fdsets_p)
1561 {
1562 sock_recalc_fdsets_p = 0;
1563 FD_ZERO(&rd);
1564 FD_ZERO(&wr);
1565 }
1566
1567 hi = 0;
1568 WALK_LIST(n, sock_list)
1569 {
1570 s = SKIP_BACK(sock, n, n);
1571 if (s->rx_hook)
1572 {
1573 FD_SET(s->fd, &rd);
1574 if (s->fd > hi)
1575 hi = s->fd;
1576 }
1577 else
1578 FD_CLR(s->fd, &rd);
1579 if (s->tx_hook && s->ttx != s->tpos)
1580 {
1581 FD_SET(s->fd, &wr);
1582 if (s->fd > hi)
1583 hi = s->fd;
1584 }
1585 else
1586 FD_CLR(s->fd, &wr);
1587 }
1588
1589 /*
1590 * Yes, this is racy. But even if the signal comes before this test
1591 * and entering select(), it gets caught on the next timer tick.
1592 */
1593
1594 if (async_config_flag)
1595 {
1596 async_config();
1597 async_config_flag = 0;
1598 continue;
1599 }
1600 if (async_dump_flag)
1601 {
1602 async_dump();
1603 async_dump_flag = 0;
1604 continue;
1605 }
1606 if (async_shutdown_flag)
1607 {
1608 async_shutdown();
1609 async_shutdown_flag = 0;
1610 continue;
1611 }
1612
1613 /* And finally enter select() to find active sockets */
1614 hi = select(hi+1, &rd, &wr, NULL, &timo);
1615
1616 if (hi < 0)
1617 {
1618 if (errno == EINTR || errno == EAGAIN)
1619 continue;
1620 die("select: %m");
1621 }
1622 if (hi)
1623 {
1624 /* guaranteed to be non-empty */
1625 current_sock = SKIP_BACK(sock, n, HEAD(sock_list));
1626
1627 while (current_sock)
1628 {
1629 sock *s = current_sock;
1630 int e;
1631 int steps;
1632
1633 steps = MAX_STEPS;
1634 if ((s->type >= SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook)
1635 do
1636 {
1637 steps--;
1638 e = sk_read(s);
1639 if (s != current_sock)
1640 goto next;
1641 }
1642 while (e && s->rx_hook && steps);
1643
1644 steps = MAX_STEPS;
1645 if (FD_ISSET(s->fd, &wr))
1646 do
1647 {
1648 steps--;
1649 e = sk_write(s);
1650 if (s != current_sock)
1651 goto next;
1652 }
1653 while (e && steps);
1654 current_sock = sk_next(s);
1655 next: ;
1656 }
1657
1658 short_loops++;
1659 if (events && (short_loops < SHORT_LOOP_MAX))
1660 continue;
1661 short_loops = 0;
1662
1663 int count = 0;
1664 current_sock = stored_sock;
1665 if (current_sock == NULL)
1666 current_sock = SKIP_BACK(sock, n, HEAD(sock_list));
1667
1668 while (current_sock && count < MAX_RX_STEPS)
1669 {
1670 sock *s = current_sock;
1671 int e;
1672
1673 if ((s->type < SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook)
1674 {
1675 count++;
1676 e = sk_read(s);
1677 if (s != current_sock)
1678 goto next2;
1679 }
1680 current_sock = sk_next(s);
1681 next2: ;
1682 }
1683
1684 stored_sock = current_sock;
1685 }
1686 }
1687 }
1688
1689 void
1690 test_old_bird(char *path)
1691 {
1692 int fd;
1693 struct sockaddr_un sa;
1694
1695 fd = socket(AF_UNIX, SOCK_STREAM, 0);
1696 if (fd < 0)
1697 die("Cannot create socket: %m");
1698 if (strlen(path) >= sizeof(sa.sun_path))
1699 die("Socket path too long");
1700 bzero(&sa, sizeof(sa));
1701 sa.sun_family = AF_UNIX;
1702 strcpy(sa.sun_path, path);
1703 if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == 0)
1704 die("I found another BIRD running.");
1705 close(fd);
1706 }
1707
1708