]> git.ipfire.org Git - thirdparty/bird.git/blame - sysdep/unix/io.c
NEWS and version update.
[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
c37e7851
OZ
413static void
414tm_format_reltime(char *x, struct tm *tm, bird_clock_t delta)
913f7dc9 415{
c37e7851
OZ
416 static char *month_names[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
417 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
913f7dc9 418
c37e7851
OZ
419 if (delta < 20*3600)
420 bsprintf(x, "%02d:%02d", tm->tm_hour, tm->tm_min);
421 else if (delta < 360*86400)
422 bsprintf(x, "%s%02d", month_names[tm->tm_mon], tm->tm_mday);
423 else
424 bsprintf(x, "%d", tm->tm_year+1900);
913f7dc9
MM
425}
426
c37e7851
OZ
427#include "conf/conf.h"
428
525fa2c1
MM
429/**
430 * tm_format_datetime - convert date and time to textual representation
431 * @x: destination buffer of size %TM_DATETIME_BUFFER_SIZE
432 * @t: time
433 *
fd91ae33
OZ
434 * This function formats the given relative time value @t to a textual
435 * date/time representation (dd-mm-yyyy hh:mm:ss) in real time.
525fa2c1 436 */
7a88832e 437void
c37e7851 438tm_format_datetime(char *x, struct timeformat *fmt_spec, bird_clock_t t)
7a88832e 439{
c37e7851 440 const char *fmt_used;
7a88832e 441 struct tm *tm;
fd91ae33
OZ
442 bird_clock_t delta = now - t;
443 t = now_real - delta;
7a88832e 444 tm = localtime(&t);
7a88832e 445
c37e7851
OZ
446 if (fmt_spec->fmt1 == NULL)
447 return tm_format_reltime(x, tm, delta);
afa8937a 448
c37e7851
OZ
449 if ((fmt_spec->limit == 0) || (delta < fmt_spec->limit))
450 fmt_used = fmt_spec->fmt1;
afa8937a 451 else
c37e7851
OZ
452 fmt_used = fmt_spec->fmt2;
453
454 int rv = strftime(x, TM_DATETIME_BUFFER_SIZE, fmt_used, tm);
455 if (((rv == 0) && fmt_used[0]) || (rv == TM_DATETIME_BUFFER_SIZE))
456 strcpy(x, "<too-long>");
afa8937a
MM
457}
458
525fa2c1
MM
459/**
460 * DOC: Sockets
461 *
462 * Socket resources represent network connections. Their data structure (&socket)
463 * contains a lot of fields defining the exact type of the socket, the local and
464 * remote addresses and ports, pointers to socket buffers and finally pointers to
465 * hook functions to be called when new data have arrived to the receive buffer
466 * (@rx_hook), when the contents of the transmit buffer have been transmitted
467 * (@tx_hook) and when an error or connection close occurs (@err_hook).
468 *
38a608c5 469 * Freeing of sockets from inside socket hooks is perfectly safe.
b5d9ee5c
MM
470 */
471
abae6e9c
MM
472#ifndef SOL_IP
473#define SOL_IP IPPROTO_IP
474#endif
475
b1a1faba
OF
476#ifndef SOL_IPV6
477#define SOL_IPV6 IPPROTO_IPV6
478#endif
479
b5d9ee5c 480static list sock_list;
38a608c5 481static struct birdsock *current_sock;
ea89da38 482static struct birdsock *stored_sock;
38a608c5
MM
483static int sock_recalc_fdsets_p;
484
485static inline sock *
486sk_next(sock *s)
487{
488 if (!s->n.next->next)
489 return NULL;
490 else
491 return SKIP_BACK(sock, n, s->n.next);
492}
b5d9ee5c
MM
493
494static void
4da25acb 495sk_alloc_bufs(sock *s)
b5d9ee5c 496{
4da25acb
MM
497 if (!s->rbuf && s->rbsize)
498 s->rbuf = s->rbuf_alloc = xmalloc(s->rbsize);
499 s->rpos = s->rbuf;
500 if (!s->tbuf && s->tbsize)
501 s->tbuf = s->tbuf_alloc = xmalloc(s->tbsize);
502 s->tpos = s->ttx = s->tbuf;
503}
b5d9ee5c 504
4da25acb
MM
505static void
506sk_free_bufs(sock *s)
507{
38a608c5 508 if (s->rbuf_alloc)
4da25acb
MM
509 {
510 xfree(s->rbuf_alloc);
511 s->rbuf = s->rbuf_alloc = NULL;
512 }
38a608c5 513 if (s->tbuf_alloc)
4da25acb
MM
514 {
515 xfree(s->tbuf_alloc);
516 s->tbuf = s->tbuf_alloc = NULL;
517 }
518}
519
520static void
521sk_free(resource *r)
522{
523 sock *s = (sock *) r;
524
525 sk_free_bufs(s);
b5d9ee5c 526 if (s->fd >= 0)
320f4173
MM
527 {
528 close(s->fd);
38a608c5
MM
529 if (s == current_sock)
530 current_sock = sk_next(s);
ea89da38
OZ
531 if (s == stored_sock)
532 stored_sock = sk_next(s);
320f4173 533 rem_node(&s->n);
38a608c5 534 sock_recalc_fdsets_p = 1;
320f4173 535 }
b5d9ee5c
MM
536}
537
4da25acb
MM
538void
539sk_reallocate(sock *s)
540{
541 sk_free_bufs(s);
542 sk_alloc_bufs(s);
543}
544
b5d9ee5c
MM
545static void
546sk_dump(resource *r)
547{
548 sock *s = (sock *) r;
b93abffa 549 static char *sk_type_names[] = { "TCP<", "TCP>", "TCP", "UDP", "UDP/MC", "IP", "IP/MC", "MAGIC", "UNIX<", "UNIX", "DEL!" };
b5d9ee5c
MM
550
551 debug("(%s, ud=%p, sa=%08x, sp=%d, da=%08x, dp=%d, tos=%d, ttl=%d, if=%s)\n",
552 sk_type_names[s->type],
553 s->data,
554 s->saddr,
555 s->sport,
556 s->daddr,
557 s->dport,
558 s->tos,
559 s->ttl,
560 s->iface ? s->iface->name : "none");
561}
562
563static struct resclass sk_class = {
564 "Socket",
565 sizeof(sock),
566 sk_free,
567 sk_dump
568};
569
525fa2c1
MM
570/**
571 * sk_new - create a socket
572 * @p: pool
573 *
574 * This function creates a new socket resource. If you want to use it,
575 * you need to fill in all the required fields of the structure and
576 * call sk_open() to do the actual opening of the socket.
577 */
b5d9ee5c
MM
578sock *
579sk_new(pool *p)
580{
581 sock *s = ralloc(p, &sk_class);
582 s->pool = p;
daeeb8e9 583 // s->saddr = s->daddr = IPA_NONE;
b5d9ee5c 584 s->tos = s->ttl = -1;
b5d9ee5c
MM
585 s->fd = -1;
586 return s;
587}
588
38a608c5
MM
589static void
590sk_insert(sock *s)
591{
592 add_tail(&sock_list, &s->n);
593 sock_recalc_fdsets_p = 1;
594}
b5d9ee5c 595
4f22c981
MM
596#ifdef IPV6
597
4f22c981
MM
598void
599fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port)
600{
b1a1faba 601 memset (sa, 0, sizeof (struct sockaddr_in6));
4f22c981
MM
602 sa->sin6_family = AF_INET6;
603 sa->sin6_port = htons(port);
604 sa->sin6_flowinfo = 0;
b1a1faba
OF
605#ifdef HAVE_SIN_LEN
606 sa->sin6_len = sizeof(struct sockaddr_in6);
607#endif
4f22c981
MM
608 set_inaddr(&sa->sin6_addr, a);
609}
610
061ab802
OZ
611static inline void
612fill_in_sockifa(sockaddr *sa, struct iface *ifa)
613{
614 sa->sin6_scope_id = ifa ? ifa->index : 0;
615}
616
4f22c981 617void
b1a1faba 618get_sockaddr(struct sockaddr_in6 *sa, ip_addr *a, unsigned *port, int check)
4f22c981 619{
b1a1faba
OF
620 if (check && sa->sin6_family != AF_INET6)
621 bug("get_sockaddr called for wrong address family (%d)", sa->sin6_family);
4f22c981
MM
622 if (port)
623 *port = ntohs(sa->sin6_port);
624 memcpy(a, &sa->sin6_addr, sizeof(*a));
625 ipa_ntoh(*a);
626}
627
628#else
629
4cf45766 630void
4f22c981 631fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port)
b5d9ee5c 632{
b1a1faba 633 memset (sa, 0, sizeof (struct sockaddr_in));
b5d9ee5c
MM
634 sa->sin_family = AF_INET;
635 sa->sin_port = htons(port);
b1a1faba
OF
636#ifdef HAVE_SIN_LEN
637 sa->sin_len = sizeof(struct sockaddr_in);
638#endif
b5d9ee5c
MM
639 set_inaddr(&sa->sin_addr, a);
640}
641
061ab802
OZ
642static inline void
643fill_in_sockifa(sockaddr *sa, struct iface *ifa)
644{
645}
646
af847acc 647void
b1a1faba 648get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port, int check)
b5d9ee5c 649{
b1a1faba
OF
650 if (check && sa->sin_family != AF_INET)
651 bug("get_sockaddr called for wrong address family (%d)", sa->sin_family);
af847acc
MM
652 if (port)
653 *port = ntohs(sa->sin_port);
b5d9ee5c 654 memcpy(a, &sa->sin_addr.s_addr, sizeof(*a));
dce26783 655 ipa_ntoh(*a);
b5d9ee5c
MM
656}
657
4f22c981
MM
658#endif
659
a39b165e
OZ
660static char *
661sk_set_ttl_int(sock *s)
662{
663 int one = 1;
664#ifdef IPV6
f9c799a0 665 if (setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
a39b165e
OZ
666 return "IPV6_UNICAST_HOPS";
667#else
668 if (setsockopt(s->fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0)
669 return "IP_TTL";
670#ifdef CONFIG_UNIX_DONTROUTE
671 if (s->ttl == 1 && setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0)
672 return "SO_DONTROUTE";
673#endif
674#endif
675 return NULL;
676}
677
38a608c5
MM
678#define ERR(x) do { err = x; goto bad; } while(0)
679#define WARN(x) log(L_WARN "sk_setup: %s: %m", x)
680
b5d9ee5c
MM
681static char *
682sk_setup(sock *s)
683{
684 int fd = s->fd;
b5d9ee5c
MM
685 char *err;
686
687 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
688 ERR("fcntl(O_NONBLOCK)");
b93abffa
MM
689 if (s->type == SK_UNIX)
690 return NULL;
a39b165e 691#ifndef IPV6
b5d9ee5c 692 if ((s->tos >= 0) && setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0)
f782b72c 693 WARN("IP_TOS");
b5d9ee5c 694#endif
789772ed
OZ
695
696#ifdef IPV6
697 int v = 1;
698 if ((s->flags & SKF_V6ONLY) && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v, sizeof(v)) < 0)
699 WARN("IPV6_V6ONLY");
700#endif
701
a39b165e
OZ
702 if (s->ttl >= 0)
703 err = sk_set_ttl_int(s);
704 else
705 err = NULL;
706
b5d9ee5c
MM
707bad:
708 return err;
709}
710
a39b165e
OZ
711/**
712 * sk_set_ttl - set TTL for given socket.
713 * @s: socket
714 * @ttl: TTL value
715 *
716 * Set TTL for already opened connections when TTL was not set before.
717 * Useful for accepted connections when different ones should have
718 * different TTL.
719 *
720 * Result: 0 for success, -1 for an error.
721 */
722
723int
724sk_set_ttl(sock *s, int ttl)
725{
726 char *err;
727
728 s->ttl = ttl;
729 if (err = sk_set_ttl_int(s))
730 log(L_ERR "sk_set_ttl: %s: %m", err);
731
732 return (err ? -1 : 0);
733}
734
d51aa281 735
d51aa281
OZ
736/**
737 * sk_set_md5_auth - add / remove MD5 security association for given socket.
738 * @s: socket
739 * @a: IP address of the other side
740 * @passwd: password used for MD5 authentication
741 *
742 * In TCP MD5 handling code in kernel, there is a set of pairs
743 * (address, password) used to choose password according to
744 * address of the other side. This function is useful for
745 * listening socket, for active sockets it is enough to set
746 * s->password field.
747 *
748 * When called with passwd != NULL, the new pair is added,
749 * When called with passwd == NULL, the existing pair is removed.
750 *
751 * Result: 0 for success, -1 for an error.
752 */
753
754int
755sk_set_md5_auth(sock *s, ip_addr a, char *passwd)
756{
757 sockaddr sa;
758 fill_in_sockaddr(&sa, a, 0);
759 return sk_set_md5_auth_int(s, &sa, passwd);
760}
761
f9c799a0
OZ
762int
763sk_set_broadcast(sock *s, int enable)
764{
765 if (setsockopt(s->fd, SOL_SOCKET, SO_BROADCAST, &enable, sizeof(enable)) < 0)
4ac7c834
OZ
766 {
767 log(L_ERR "sk_set_broadcast: SO_BROADCAST: %m");
768 return -1;
769 }
770
771 return 0;
f9c799a0
OZ
772}
773
774
775#ifdef IPV6
776
4ac7c834
OZ
777int
778sk_set_ipv6_checksum(sock *s, int offset)
779{
780 if (setsockopt(s->fd, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset)) < 0)
781 {
782 log(L_ERR "sk_set_ipv6_checksum: IPV6_CHECKSUM: %m");
783 return -1;
784 }
785
786 return 0;
787}
788
f9c799a0
OZ
789int
790sk_setup_multicast(sock *s)
791{
792 char *err;
793 int zero = 0;
794 int index;
795
796 ASSERT(s->iface && s->iface->addr);
797
798 index = s->iface->index;
799 if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
800 ERR("IPV6_MULTICAST_HOPS");
801 if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
802 ERR("IPV6_MULTICAST_LOOP");
803 if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index)) < 0)
804 ERR("IPV6_MULTICAST_IF");
805
806 return 0;
807
808bad:
809 log(L_ERR "sk_setup_multicast: %s: %m", err);
810 return -1;
811}
812
813int
814sk_join_group(sock *s, ip_addr maddr)
815{
816 struct ipv6_mreq mreq;
817
818 set_inaddr(&mreq.ipv6mr_multiaddr, maddr);
819
820#ifdef CONFIG_IPV6_GLIBC_20
821 mreq.ipv6mr_ifindex = s->iface->index;
822#else
823 mreq.ipv6mr_interface = s->iface->index;
824#endif
825
861f223a 826 if (setsockopt(s->fd, SOL_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0)
f9c799a0 827 {
861f223a 828 log(L_ERR "sk_join_group: IPV6_JOIN_GROUP: %m");
f9c799a0
OZ
829 return -1;
830 }
831
832 return 0;
833}
834
835int
836sk_leave_group(sock *s, ip_addr maddr)
837{
838 struct ipv6_mreq mreq;
839
840 set_inaddr(&mreq.ipv6mr_multiaddr, maddr);
841
842#ifdef CONFIG_IPV6_GLIBC_20
843 mreq.ipv6mr_ifindex = s->iface->index;
844#else
845 mreq.ipv6mr_interface = s->iface->index;
846#endif
847
861f223a 848 if (setsockopt(s->fd, SOL_IPV6, IPV6_LEAVE_GROUP, &mreq, sizeof(mreq)) < 0)
f9c799a0 849 {
861f223a 850 log(L_ERR "sk_leave_group: IPV6_LEAVE_GROUP: %m");
f9c799a0
OZ
851 return -1;
852 }
853
854 return 0;
855}
856
857#else /* IPV4 */
858
859int
860sk_setup_multicast(sock *s)
861{
862 char *err;
863
864 ASSERT(s->iface && s->iface->addr);
865
866 if (err = sysio_setup_multicast(s))
867 {
868 log(L_ERR "sk_setup_multicast: %s: %m", err);
869 return -1;
870 }
871
872 return 0;
873}
874
875int
876sk_join_group(sock *s, ip_addr maddr)
877{
878 char *err;
879
880 if (err = sysio_join_group(s, maddr))
881 {
882 log(L_ERR "sk_join_group: %s: %m", err);
883 return -1;
884 }
885
886 return 0;
887}
888
889int
890sk_leave_group(sock *s, ip_addr maddr)
891{
892 char *err;
893
894 if (err = sysio_leave_group(s, maddr))
895 {
896 log(L_ERR "sk_leave_group: %s: %m", err);
897 return -1;
898 }
899
900 return 0;
901}
902
903#endif
904
d51aa281 905
b93abffa 906static void
b5d9ee5c
MM
907sk_tcp_connected(sock *s)
908{
b5d9ee5c
MM
909 s->type = SK_TCP;
910 sk_alloc_bufs(s);
320f4173 911 s->tx_hook(s);
b5d9ee5c
MM
912}
913
b93abffa
MM
914static int
915sk_passive_connected(sock *s, struct sockaddr *sa, int al, int type)
916{
917 int fd = accept(s->fd, sa, &al);
918 if (fd >= 0)
919 {
920 sock *t = sk_new(s->pool);
921 char *err;
922 t->type = type;
923 t->fd = fd;
e1ddd993
MM
924 t->ttl = s->ttl;
925 t->tos = s->tos;
926 t->rbsize = s->rbsize;
927 t->tbsize = s->tbsize;
928 if (type == SK_TCP)
cf31112f
OZ
929 {
930 sockaddr lsa;
931 int lsa_len = sizeof(lsa);
932 if (getsockname(fd, (struct sockaddr *) &lsa, &lsa_len) == 0)
933 get_sockaddr(&lsa, &t->saddr, &t->sport, 1);
934
935 get_sockaddr((sockaddr *) sa, &t->daddr, &t->dport, 1);
936 }
38a608c5 937 sk_insert(t);
b93abffa
MM
938 if (err = sk_setup(t))
939 {
940 log(L_ERR "Incoming connection: %s: %m", err);
e1ddd993
MM
941 rfree(t);
942 return 1;
b93abffa
MM
943 }
944 sk_alloc_bufs(t);
e1ddd993 945 s->rx_hook(t, 0);
b93abffa
MM
946 return 1;
947 }
948 else if (errno != EINTR && errno != EAGAIN)
949 {
950 log(L_ERR "accept: %m");
c025b852 951 s->err_hook(s, errno);
b93abffa
MM
952 }
953 return 0;
954}
955
525fa2c1
MM
956/**
957 * sk_open - open a socket
958 * @s: socket
959 *
960 * This function takes a socket resource created by sk_new() and
961 * initialized by the user and binds a corresponding network connection
962 * to it.
963 *
964 * Result: 0 for success, -1 for an error.
965 */
b5d9ee5c
MM
966int
967sk_open(sock *s)
968{
93a786cb 969 int fd;
4f22c981 970 sockaddr sa;
b5d9ee5c
MM
971 int one = 1;
972 int type = s->type;
973 int has_src = ipa_nonzero(s->saddr) || s->sport;
b5d9ee5c
MM
974 char *err;
975
976 switch (type)
977 {
978 case SK_TCP_ACTIVE:
320f4173
MM
979 s->ttx = ""; /* Force s->ttx != s->tpos */
980 /* Fall thru */
b5d9ee5c 981 case SK_TCP_PASSIVE:
4f22c981 982 fd = socket(BIRD_PF, SOCK_STREAM, IPPROTO_TCP);
b5d9ee5c
MM
983 break;
984 case SK_UDP:
4f22c981 985 fd = socket(BIRD_PF, SOCK_DGRAM, IPPROTO_UDP);
b5d9ee5c
MM
986 break;
987 case SK_IP:
4f22c981 988 fd = socket(BIRD_PF, SOCK_RAW, s->dport);
b5d9ee5c 989 break;
b4b3b39e
MM
990 case SK_MAGIC:
991 fd = s->fd;
992 break;
b5d9ee5c 993 default:
b4b3b39e 994 bug("sk_open() called for invalid sock type %d", type);
b5d9ee5c
MM
995 }
996 if (fd < 0)
997 die("sk_open: socket: %m");
998 s->fd = fd;
999
1000 if (err = sk_setup(s))
1001 goto bad;
38a608c5 1002
b5d9ee5c
MM
1003 if (has_src)
1004 {
1005 int port;
1006
f9c799a0 1007 if (type == SK_IP)
b5d9ee5c
MM
1008 port = 0;
1009 else
1010 {
1011 port = s->sport;
1012 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
1013 ERR("SO_REUSEADDR");
1014 }
1015 fill_in_sockaddr(&sa, s->saddr, port);
061ab802 1016 fill_in_sockifa(&sa, s->iface);
b5d9ee5c
MM
1017 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
1018 ERR("bind");
1019 }
1020 fill_in_sockaddr(&sa, s->daddr, s->dport);
d51aa281
OZ
1021
1022 if (s->password)
1023 {
1024 int rv = sk_set_md5_auth_int(s, &sa, s->password);
1025 if (rv < 0)
1026 goto bad_no_log;
1027 }
1028
b5d9ee5c
MM
1029 switch (type)
1030 {
1031 case SK_TCP_ACTIVE:
1032 if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
1033 sk_tcp_connected(s);
9cbf43eb
MM
1034 else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS &&
1035 errno != ECONNREFUSED && errno != EHOSTUNREACH)
b5d9ee5c
MM
1036 ERR("connect");
1037 break;
1038 case SK_TCP_PASSIVE:
1039 if (listen(fd, 8))
1040 ERR("listen");
1041 break;
4f22c981
MM
1042 case SK_MAGIC:
1043 break;
1044 default:
320f4173 1045 sk_alloc_bufs(s);
4f22c981
MM
1046#ifdef IPV6
1047#ifdef IPV6_MTU_DISCOVER
1048 {
1049 int dont = IPV6_PMTUDISC_DONT;
1050 if (setsockopt(fd, SOL_IPV6, IPV6_MTU_DISCOVER, &dont, sizeof(dont)) < 0)
1051 ERR("IPV6_MTU_DISCOVER");
1052 }
1053#endif
1054#else
1055#ifdef IP_PMTUDISC
1056 {
1057 int dont = IP_PMTUDISC_DONT;
1058 if (setsockopt(fd, SOL_IP, IP_PMTUDISC, &dont, sizeof(dont)) < 0)
1059 ERR("IP_PMTUDISC");
1060 }
1061#endif
1062#endif
b5d9ee5c
MM
1063 }
1064
38a608c5 1065 sk_insert(s);
b5d9ee5c
MM
1066 return 0;
1067
1068bad:
1069 log(L_ERR "sk_open: %s: %m", err);
d51aa281 1070bad_no_log:
b5d9ee5c
MM
1071 close(fd);
1072 s->fd = -1;
1073 return -1;
1074}
1075
b93abffa
MM
1076int
1077sk_open_unix(sock *s, char *name)
1078{
1079 int fd;
1080 struct sockaddr_un sa;
1081 char *err;
1082
1083 fd = socket(AF_UNIX, SOCK_STREAM, 0);
1084 if (fd < 0)
1085 die("sk_open_unix: socket: %m");
1086 s->fd = fd;
1087 if (err = sk_setup(s))
1088 goto bad;
1089 unlink(name);
68fa95cf
OZ
1090
1091 if (strlen(name) >= sizeof(sa.sun_path))
1092 die("sk_open_unix: path too long");
1093
b93abffa 1094 sa.sun_family = AF_UNIX;
97c6fa02 1095 strcpy(sa.sun_path, name);
0b3bf4b1 1096 if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) < 0)
b93abffa
MM
1097 ERR("bind");
1098 if (listen(fd, 8))
1099 ERR("listen");
38a608c5 1100 sk_insert(s);
b93abffa
MM
1101 return 0;
1102
1103bad:
1104 log(L_ERR "sk_open_unix: %s: %m", err);
1105 close(fd);
1106 s->fd = -1;
1107 return -1;
1108}
1109
b5d9ee5c
MM
1110static int
1111sk_maybe_write(sock *s)
1112{
1113 int e;
1114
1115 switch (s->type)
1116 {
1117 case SK_TCP:
b4b3b39e 1118 case SK_MAGIC:
b93abffa 1119 case SK_UNIX:
b5d9ee5c
MM
1120 while (s->ttx != s->tpos)
1121 {
1122 e = write(s->fd, s->ttx, s->tpos - s->ttx);
1123 if (e < 0)
1124 {
1125 if (errno != EINTR && errno != EAGAIN)
1126 {
c025b852
OF
1127 s->ttx = s->tpos; /* empty tx buffer */
1128 s->err_hook(s, errno);
b5d9ee5c
MM
1129 return -1;
1130 }
1131 return 0;
1132 }
1133 s->ttx += e;
1134 }
1135 s->ttx = s->tpos = s->tbuf;
1136 return 1;
1137 case SK_UDP:
b5d9ee5c 1138 case SK_IP:
b5d9ee5c 1139 {
4f22c981 1140 sockaddr sa;
b5d9ee5c
MM
1141
1142 if (s->tbuf == s->tpos)
1143 return 1;
b1a1faba 1144
061ab802
OZ
1145 fill_in_sockaddr(&sa, s->faddr, s->fport);
1146 fill_in_sockifa(&sa, s->iface);
b5d9ee5c
MM
1147 e = sendto(s->fd, s->tbuf, s->tpos - s->tbuf, 0, (struct sockaddr *) &sa, sizeof(sa));
1148 if (e < 0)
1149 {
1150 if (errno != EINTR && errno != EAGAIN)
1151 {
c025b852
OF
1152 s->ttx = s->tpos; /* empty tx buffer */
1153 s->err_hook(s, errno);
b5d9ee5c
MM
1154 return -1;
1155 }
1156 return 0;
1157 }
1158 s->tpos = s->tbuf;
1159 return 1;
1160 }
1161 default:
08c69a77 1162 bug("sk_maybe_write: unknown socket type %d", s->type);
b5d9ee5c
MM
1163 }
1164}
1165
ea89da38
OZ
1166int
1167sk_rx_ready(sock *s)
1168{
1169 fd_set rd, wr;
1170 struct timeval timo;
1171 int rv;
1172
1173 FD_ZERO(&rd);
1174 FD_ZERO(&wr);
1175 FD_SET(s->fd, &rd);
1176
1177 timo.tv_sec = 0;
1178 timo.tv_usec = 0;
1179
1180 redo:
1181 rv = select(s->fd+1, &rd, &wr, NULL, &timo);
1182
1183 if ((rv < 0) && (errno == EINTR || errno == EAGAIN))
1184 goto redo;
1185
1186 return rv;
1187}
1188
525fa2c1
MM
1189/**
1190 * sk_send - send data to a socket
1191 * @s: socket
1192 * @len: number of bytes to send
1193 *
1194 * This function sends @len bytes of data prepared in the
1195 * transmit buffer of the socket @s to the network connection.
1196 * If the packet can be sent immediately, it does so and returns
1197 * 1, else it queues the packet for later processing, returns 0
1198 * and calls the @tx_hook of the socket when the tranmission
1199 * takes place.
1200 */
b5d9ee5c
MM
1201int
1202sk_send(sock *s, unsigned len)
1203{
1204 s->faddr = s->daddr;
1205 s->fport = s->dport;
1206 s->ttx = s->tbuf;
1207 s->tpos = s->tbuf + len;
1208 return sk_maybe_write(s);
1209}
1210
525fa2c1
MM
1211/**
1212 * sk_send_to - send data to a specific destination
1213 * @s: socket
1214 * @len: number of bytes to send
1215 * @addr: IP address to send the packet to
1216 * @port: port to send the packet to
1217 *
2e9b2421 1218 * This is a sk_send() replacement for connection-less packet sockets
525fa2c1
MM
1219 * which allows destination of the packet to be chosen dynamically.
1220 */
b5d9ee5c
MM
1221int
1222sk_send_to(sock *s, unsigned len, ip_addr addr, unsigned port)
1223{
1224 s->faddr = addr;
1225 s->fport = port;
1226 s->ttx = s->tbuf;
1227 s->tpos = s->tbuf + len;
1228 return sk_maybe_write(s);
1229}
1230
1231static int
1232sk_read(sock *s)
1233{
1234 switch (s->type)
1235 {
b5d9ee5c
MM
1236 case SK_TCP_PASSIVE:
1237 {
4f22c981 1238 sockaddr sa;
b93abffa
MM
1239 return sk_passive_connected(s, (struct sockaddr *) &sa, sizeof(sa), SK_TCP);
1240 }
1241 case SK_UNIX_PASSIVE:
1242 {
1243 struct sockaddr_un sa;
1244 return sk_passive_connected(s, (struct sockaddr *) &sa, sizeof(sa), SK_UNIX);
b5d9ee5c
MM
1245 }
1246 case SK_TCP:
b93abffa 1247 case SK_UNIX:
b5d9ee5c
MM
1248 {
1249 int c = read(s->fd, s->rpos, s->rbuf + s->rbsize - s->rpos);
1250
1251 if (c < 0)
1252 {
1253 if (errno != EINTR && errno != EAGAIN)
c025b852 1254 s->err_hook(s, errno);
b5d9ee5c
MM
1255 }
1256 else if (!c)
c025b852 1257 s->err_hook(s, 0);
b5d9ee5c
MM
1258 else
1259 {
1260 s->rpos += c;
1261 if (s->rx_hook(s, s->rpos - s->rbuf))
38a608c5
MM
1262 {
1263 /* We need to be careful since the socket could have been deleted by the hook */
1264 if (current_sock == s)
1265 s->rpos = s->rbuf;
1266 }
b5d9ee5c
MM
1267 return 1;
1268 }
1269 return 0;
1270 }
b4b3b39e
MM
1271 case SK_MAGIC:
1272 return s->rx_hook(s, 0);
b5d9ee5c
MM
1273 default:
1274 {
4f22c981 1275 sockaddr sa;
b5d9ee5c
MM
1276 int al = sizeof(sa);
1277 int e = recvfrom(s->fd, s->rbuf, s->rbsize, 0, (struct sockaddr *) &sa, &al);
1278
1279 if (e < 0)
1280 {
1281 if (errno != EINTR && errno != EAGAIN)
c025b852 1282 s->err_hook(s, errno);
b5d9ee5c
MM
1283 return 0;
1284 }
1285 s->rpos = s->rbuf + e;
b1a1faba 1286 get_sockaddr(&sa, &s->faddr, &s->fport, 1);
b5d9ee5c
MM
1287 s->rx_hook(s, e);
1288 return 1;
1289 }
1290 }
1291}
1292
38a608c5 1293static int
b5d9ee5c
MM
1294sk_write(sock *s)
1295{
320f4173
MM
1296 switch (s->type)
1297 {
1298 case SK_TCP_ACTIVE:
1299 {
1300 sockaddr sa;
1301 fill_in_sockaddr(&sa, s->daddr, s->dport);
09e4117c 1302 if (connect(s->fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0 || errno == EISCONN)
320f4173
MM
1303 sk_tcp_connected(s);
1304 else if (errno != EINTR && errno != EAGAIN && errno != EINPROGRESS)
c025b852 1305 s->err_hook(s, errno);
38a608c5 1306 return 0;
320f4173 1307 }
320f4173 1308 default:
38a608c5
MM
1309 if (s->ttx != s->tpos && sk_maybe_write(s) > 0)
1310 {
1311 s->tx_hook(s);
1312 return 1;
1313 }
1314 return 0;
320f4173 1315 }
b5d9ee5c
MM
1316}
1317
1318void
1319sk_dump_all(void)
1320{
1321 node *n;
1322 sock *s;
1323
1324 debug("Open sockets:\n");
1325 WALK_LIST(n, sock_list)
1326 {
1327 s = SKIP_BACK(sock, n, n);
1328 debug("%p ", s);
1329 sk_dump(&s->r);
1330 }
1331 debug("\n");
1332}
1333
1334#undef ERR
f782b72c 1335#undef WARN
b5d9ee5c
MM
1336
1337/*
1338 * Main I/O Loop
1339 */
1340
4c9dd1e4
MM
1341volatile int async_config_flag; /* Asynchronous reconfiguration/dump scheduled */
1342volatile int async_dump_flag;
1343
b5d9ee5c
MM
1344void
1345io_init(void)
1346{
1347 init_list(&near_timers);
1348 init_list(&far_timers);
1349 init_list(&sock_list);
e8f73195 1350 init_list(&global_event_list);
7e5f5ffd 1351 krt_io_init();
fd91ae33
OZ
1352 init_times();
1353 update_times();
1354 srandom((int) now_real);
b5d9ee5c
MM
1355}
1356
ea89da38
OZ
1357static int short_loops = 0;
1358#define SHORT_LOOP_MAX 10
1359
b5d9ee5c
MM
1360void
1361io_loop(void)
1362{
1363 fd_set rd, wr;
1364 struct timeval timo;
1365 time_t tout;
30770df2 1366 int hi, events;
b5d9ee5c 1367 sock *s;
38a608c5 1368 node *n;
b5d9ee5c 1369
38a608c5 1370 sock_recalc_fdsets_p = 1;
b5d9ee5c
MM
1371 for(;;)
1372 {
30770df2 1373 events = ev_run_list(&global_event_list);
fd91ae33 1374 update_times();
b5d9ee5c
MM
1375 tout = tm_first_shot();
1376 if (tout <= now)
1377 {
1378 tm_shot();
1379 continue;
1380 }
30770df2
MM
1381 timo.tv_sec = events ? 0 : tout - now;
1382 timo.tv_usec = 0;
b5d9ee5c 1383
38a608c5
MM
1384 if (sock_recalc_fdsets_p)
1385 {
1386 sock_recalc_fdsets_p = 0;
1387 FD_ZERO(&rd);
1388 FD_ZERO(&wr);
1389 }
1390
b5d9ee5c
MM
1391 hi = 0;
1392 WALK_LIST(n, sock_list)
1393 {
1394 s = SKIP_BACK(sock, n, n);
1395 if (s->rx_hook)
1396 {
1397 FD_SET(s->fd, &rd);
1398 if (s->fd > hi)
1399 hi = s->fd;
1400 }
38a608c5
MM
1401 else
1402 FD_CLR(s->fd, &rd);
b5d9ee5c
MM
1403 if (s->tx_hook && s->ttx != s->tpos)
1404 {
1405 FD_SET(s->fd, &wr);
1406 if (s->fd > hi)
1407 hi = s->fd;
1408 }
38a608c5
MM
1409 else
1410 FD_CLR(s->fd, &wr);
b5d9ee5c
MM
1411 }
1412
4c9dd1e4
MM
1413 /*
1414 * Yes, this is racy. But even if the signal comes before this test
1415 * and entering select(), it gets caught on the next timer tick.
1416 */
1417
1418 if (async_config_flag)
1419 {
1420 async_config();
1421 async_config_flag = 0;
f4aabcee 1422 continue;
4c9dd1e4
MM
1423 }
1424 if (async_dump_flag)
1425 {
1426 async_dump();
1427 async_dump_flag = 0;
f4aabcee
MM
1428 continue;
1429 }
1430 if (async_shutdown_flag)
1431 {
1432 async_shutdown();
1433 async_shutdown_flag = 0;
1434 continue;
4c9dd1e4
MM
1435 }
1436
1437 /* And finally enter select() to find active sockets */
b5d9ee5c 1438 hi = select(hi+1, &rd, &wr, NULL, &timo);
ea89da38 1439
b5d9ee5c
MM
1440 if (hi < 0)
1441 {
1442 if (errno == EINTR || errno == EAGAIN)
1443 continue;
1444 die("select: %m");
1445 }
1446 if (hi)
1447 {
ea89da38
OZ
1448 /* guaranteed to be non-empty */
1449 current_sock = SKIP_BACK(sock, n, HEAD(sock_list));
1450
38a608c5 1451 while (current_sock)
b5d9ee5c 1452 {
38a608c5
MM
1453 sock *s = current_sock;
1454 int e;
ea89da38
OZ
1455 int steps;
1456
1457 steps = MAX_STEPS;
1458 if ((s->type >= SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook)
38a608c5
MM
1459 do
1460 {
4323099d 1461 steps--;
38a608c5
MM
1462 e = sk_read(s);
1463 if (s != current_sock)
1464 goto next;
1465 }
4323099d
OZ
1466 while (e && s->rx_hook && steps);
1467
1468 steps = MAX_STEPS;
38a608c5
MM
1469 if (FD_ISSET(s->fd, &wr))
1470 do
1471 {
4323099d 1472 steps--;
38a608c5
MM
1473 e = sk_write(s);
1474 if (s != current_sock)
1475 goto next;
1476 }
4323099d 1477 while (e && steps);
38a608c5
MM
1478 current_sock = sk_next(s);
1479 next: ;
b5d9ee5c 1480 }
ea89da38
OZ
1481
1482 short_loops++;
1483 if (events && (short_loops < SHORT_LOOP_MAX))
1484 continue;
1485 short_loops = 0;
1486
1487 int count = 0;
1488 current_sock = stored_sock;
1489 if (current_sock == NULL)
1490 current_sock = SKIP_BACK(sock, n, HEAD(sock_list));
1491
1492 while (current_sock && count < MAX_RX_STEPS)
1493 {
1494 sock *s = current_sock;
1495 int e;
1496 int steps;
1497
1498 if ((s->type < SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook)
1499 {
1500 count++;
1501 e = sk_read(s);
1502 if (s != current_sock)
1503 goto next2;
1504 }
1505 current_sock = sk_next(s);
1506 next2: ;
1507 }
1508
1509 stored_sock = current_sock;
b5d9ee5c
MM
1510 }
1511 }
1512}
41c8976e
OF
1513
1514void
1515test_old_bird(char *path)
1516{
1517 int fd;
1518 struct sockaddr_un sa;
1519
1520 fd = socket(AF_UNIX, SOCK_STREAM, 0);
1521
1522 if (fd < 0)
1523 die("Cannot create socket: %m");
1524 bzero(&sa, sizeof(sa));
1525 sa.sun_family = AF_UNIX;
1526 strcpy(sa.sun_path, path);
1527 if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == 0)
1528 die("I found another BIRD running.");
1529 close(fd);
1530}
1531
1532