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