Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / io.c @ 4f22c981

History | View | Annotate | Download (17.4 KB)

1
/*
2
 *        BIRD Internet Routing Daemon -- Unix I/O
3
 *
4
 *        (c) 1998--1999 Martin Mares <mj@ucw.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8

    
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <string.h>
12
#include <sys/time.h>
13
#include <sys/types.h>
14
#include <sys/socket.h>
15
#include <sys/fcntl.h>
16
#include <unistd.h>
17
#include <errno.h>
18

    
19
#ifndef HAVE_STRUCT_IP_MREQN
20
#include <net/if.h>
21
#endif
22

    
23
#include "nest/bird.h"
24
#include "lib/lists.h"
25
#include "lib/resource.h"
26
#include "lib/timer.h"
27
#include "lib/socket.h"
28
#include "lib/event.h"
29
#include "nest/iface.h"
30

    
31
#ifdef IPV6
32
#include <linux/in6.h>                        /* FIXMEv6: glibc variant? */
33
#endif
34

    
35
#include "lib/unix.h"
36

    
37
/*
38
 *        Timers
39
 */
40

    
41
#define NEAR_TIMER_LIMIT 4
42

    
43
#ifdef TIME_T_IS_64BIT
44
#define TIME_INFINITY 0x7fffffffffffffff
45
#else
46
#ifdef TIME_T_IS_SIGNED
47
#define TIME_INFINITY 0x7fffffff
48
#else
49
#define TIME_INFINITY 0xffffffff
50
#endif
51
#endif
52

    
53
static list near_timers, far_timers;
54
static bird_clock_t first_far_timer = TIME_INFINITY;
55

    
56
bird_clock_t now;
57

    
58
static void
59
tm_free(resource *r)
60
{
61
  timer *t = (timer *) r;
62

    
63
  tm_stop(t);
64
}
65

    
66
static void
67
tm_dump(resource *r)
68
{
69
  timer *t = (timer *) r;
70

    
71
  debug("(code %p, data %p, ", t->hook, t->data);
72
  if (t->randomize)
73
    debug("rand %d, ", t->randomize);
74
  if (t->recurrent)
75
    debug("recur %d, ", t->recurrent);
76
  if (t->expires)
77
    debug("expires in %d sec)\n", t->expires - now);
78
  else
79
    debug("inactive)\n");
80
}
81

    
82
static struct resclass tm_class = {
83
  "Timer",
84
  sizeof(timer),
85
  tm_free,
86
  tm_dump
87
};
88

    
89
timer *
90
tm_new(pool *p)
91
{
92
  timer *t = ralloc(p, &tm_class);
93
  t->hook = NULL;
94
  t->data = NULL;
95
  t->randomize = 0;
96
  t->expires = 0;
97
  return t;
98
}
99

    
100
static inline void
101
tm_insert_near(timer *t)
102
{
103
  node *n = HEAD(near_timers);
104

    
105
  while (n->next && (SKIP_BACK(timer, n, n)->expires < t->expires))
106
    n = n->next;
107
  insert_node(&t->n, n->prev);
108
}
109

    
110
void
111
tm_start(timer *t, unsigned after)
112
{
113
  bird_clock_t when;
114

    
115
  if (t->randomize)
116
    after += random() % (t->randomize + 1);
117
  when = now + after;
118
  if (t->expires == when)
119
    return;
120
  if (t->expires)
121
    rem_node(&t->n);
122
  t->expires = when;
123
  if (after <= NEAR_TIMER_LIMIT)
124
    tm_insert_near(t);
125
  else
126
    {
127
      if (!first_far_timer || first_far_timer > when)
128
        first_far_timer = when;
129
      add_tail(&far_timers, &t->n);
130
    }
131
}
132

    
133
void
134
tm_stop(timer *t)
135
{
136
  if (t->expires)
137
    {
138
      rem_node(&t->n);
139
      t->expires = 0;
140
    }
141
}
142

    
143
static void
144
tm_dump_them(char *name, list *l)
145
{
146
  node *n;
147
  timer *t;
148

    
149
  debug("%s timers:\n", name);
150
  WALK_LIST(n, *l)
151
    {
152
      t = SKIP_BACK(timer, n, n);
153
      debug("%p ", t);
154
      tm_dump(&t->r);
155
    }
156
  debug("\n");
157
}
158

    
159
void
160
tm_dump_all(void)
161
{
162
  tm_dump_them("Near", &near_timers);
163
  tm_dump_them("Far", &far_timers);
164
}
165

    
166
static inline time_t
167
tm_first_shot(void)
168
{
169
  time_t x = first_far_timer;
170

    
171
  if (!EMPTY_LIST(near_timers))
172
    {
173
      timer *t = SKIP_BACK(timer, n, HEAD(near_timers));
174
      if (t->expires < x)
175
        x = t->expires;
176
    }
177
  return x;
178
}
179

    
180
static void
181
tm_shot(void)
182
{
183
  timer *t;
184
  node *n, *m;
185

    
186
  if (first_far_timer <= now)
187
    {
188
      bird_clock_t limit = now + NEAR_TIMER_LIMIT;
189
      first_far_timer = TIME_INFINITY;
190
      n = HEAD(far_timers);
191
      while (m = n->next)
192
        {
193
          t = SKIP_BACK(timer, n, n);
194
          if (t->expires <= limit)
195
            {
196
              rem_node(n);
197
              tm_insert_near(t);
198
            }
199
          else if (t->expires < first_far_timer)
200
            first_far_timer = t->expires;
201
          n = m;
202
        }
203
    }
204
  while ((n = HEAD(near_timers)) -> next)
205
    {
206
      int delay;
207
      t = SKIP_BACK(timer, n, n);
208
      if (t->expires > now)
209
        break;
210
      rem_node(n);
211
      delay = t->expires - now;
212
      t->expires = 0;
213
      if (t->recurrent)
214
        {
215
          int i = t->recurrent - delay;
216
          if (i < 0)
217
            i = 0;
218
          tm_start(t, i);
219
        }
220
      t->hook(t);
221
    }
222
}
223

    
224
bird_clock_t
225
tm_parse_date(char *x)
226
{
227
  struct tm tm;
228
  int n;
229
  time_t t;
230

    
231
  if (sscanf(x, "%d-%d-%d%n", &tm.tm_mday, &tm.tm_mon, &tm.tm_year, &n) != 3 || x[n])
232
    return 0;
233
  tm.tm_mon--;
234
  tm.tm_year -= 1900;
235
  tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
236
  t = mktime(&tm);
237
  if (t == (time_t) -1)
238
    return 0;
239
  return t;
240
}
241

    
242
void
243
tm_format_date(char *x, bird_clock_t t)
244
{
245
  struct tm *tm;
246

    
247
  tm = localtime(&t);
248
  sprintf(x, "%02d-%02d-%04d", tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900);
249
}
250

    
251
/*
252
 *        Sockets
253
 */
254

    
255
#ifndef SOL_IP
256
#define SOL_IP IPPROTO_IP
257
#endif
258

    
259
static list sock_list;
260

    
261
static void
262
sk_free(resource *r)
263
{
264
  sock *s = (sock *) r;
265

    
266
  if (s->fd >= 0)
267
    rem_node(&s->n);
268
}
269

    
270
static void
271
sk_dump(resource *r)
272
{
273
  sock *s = (sock *) r;
274
  static char *sk_type_names[] = { "TCP<", "TCP>", "TCP", "UDP", "UDP/MC", "IP", "IP/MC", "MAGIC" };
275

    
276
  debug("(%s, ud=%p, sa=%08x, sp=%d, da=%08x, dp=%d, tos=%d, ttl=%d, if=%s)\n",
277
        sk_type_names[s->type],
278
        s->data,
279
        s->saddr,
280
        s->sport,
281
        s->daddr,
282
        s->dport,
283
        s->tos,
284
        s->ttl,
285
        s->iface ? s->iface->name : "none");
286
}
287

    
288
static struct resclass sk_class = {
289
  "Socket",
290
  sizeof(sock),
291
  sk_free,
292
  sk_dump
293
};
294

    
295
sock *
296
sk_new(pool *p)
297
{
298
  sock *s = ralloc(p, &sk_class);
299
  s->pool = p;
300
  s->data = NULL;
301
  s->saddr = s->daddr = IPA_NONE;
302
  s->sport = s->dport = 0;
303
  s->tos = s->ttl = -1;
304
  s->iface = NULL;
305
  s->rbuf = NULL;
306
  s->rx_hook = NULL;
307
  s->rbsize = 0;
308
  s->tbuf = NULL;
309
  s->tx_hook = NULL;
310
  s->tbsize = 0;
311
  s->err_hook = NULL;
312
  s->fd = -1;
313
  return s;
314
}
315

    
316
#define ERR(x) do { err = x; goto bad; } while(0)
317

    
318
#ifdef IPV6
319

    
320
static inline void
321
set_inaddr(struct in6_addr *ia, ip_addr a)
322
{
323
  ipa_hton(a);
324
  memcpy(ia, &a, sizeof(a));
325
}
326

    
327
void
328
fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port)
329
{
330
  sa->sin6_family = AF_INET6;
331
  sa->sin6_port = htons(port);
332
  sa->sin6_flowinfo = 0;
333
  set_inaddr(&sa->sin6_addr, a);
334
}
335

    
336
void
337
get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port)
338
{
339
  if (sa->sin6_family != AF_INET6)
340
    bug("get_sockaddr called for wrong address family");
341
  if (port)
342
    *port = ntohs(sa->sin6_port);
343
  memcpy(a, &sa->sin6_addr, sizeof(*a));
344
  ipa_ntoh(*a);
345
}
346

    
347
#else
348

    
349
static inline void
350
set_inaddr(struct in_addr *ia, ip_addr a)
351
{
352
  ipa_hton(a);
353
  memcpy(&ia->s_addr, &a, sizeof(a));
354
}
355

    
356
void
357
fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port)
358
{
359
  sa->sin_family = AF_INET;
360
  sa->sin_port = htons(port);
361
  set_inaddr(&sa->sin_addr, a);
362
}
363

    
364
void
365
get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port)
366
{
367
  if (sa->sin_family != AF_INET)
368
    bug("get_sockaddr called for wrong address family");
369
  if (port)
370
    *port = ntohs(sa->sin_port);
371
  memcpy(a, &sa->sin_addr.s_addr, sizeof(*a));
372
  ipa_ntoh(*a);
373
}
374

    
375
#endif
376

    
377
static char *
378
sk_setup(sock *s)
379
{
380
  int fd = s->fd;
381
  int one = 1;
382
  char *err;
383

    
384
  if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
385
    ERR("fcntl(O_NONBLOCK)");
386
#ifdef IPV6
387
  if (s->ttl >= 0 && s->type != SK_UDP_MC && s->type != SK_IP_MC &&
388
      setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
389
    ERR("IPV6_UNICAST_HOPS");
390
#else
391
  if ((s->tos >= 0) && setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0)
392
    ERR("IP_TOS");
393
  if (s->ttl >= 0)
394
    {
395
      if (setsockopt(fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0)
396
        ERR("IP_TTL");
397
      if (setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0)
398
        ERR("SO_DONTROUTE");
399
    }
400
#endif
401
  /* FIXME: Set send/receive buffers? */
402
  /* FIXME: Set keepalive for TCP connections? */
403
  err = NULL;
404
bad:
405
  return err;
406
}
407

    
408
static void
409
sk_alloc_bufs(sock *s)
410
{
411
  if (!s->rbuf && s->rbsize)
412
    s->rbuf = mb_alloc(s->pool, s->rbsize);
413
  s->rpos = s->rbuf;
414
  if (!s->tbuf && s->tbsize)
415
    s->tbuf = mb_alloc(s->pool, s->tbsize);
416
  s->tpos = s->ttx = s->tbuf;
417
}
418

    
419
void
420
sk_tcp_connected(sock *s)
421
{
422
  s->rx_hook(s, 0);
423
  s->type = SK_TCP;
424
  sk_alloc_bufs(s);
425
}
426

    
427
int
428
sk_open(sock *s)
429
{
430
  int fd, e;
431
  sockaddr sa;
432
  int zero = 0;
433
  int one = 1;
434
  int type = s->type;
435
  int has_src = ipa_nonzero(s->saddr) || s->sport;
436
  int has_dest = ipa_nonzero(s->daddr);
437
  char *err;
438

    
439
  switch (type)
440
    {
441
    case SK_TCP_ACTIVE:
442
    case SK_TCP_PASSIVE:
443
      fd = socket(BIRD_PF, SOCK_STREAM, IPPROTO_TCP);
444
      break;
445
    case SK_UDP:
446
    case SK_UDP_MC:
447
      fd = socket(BIRD_PF, SOCK_DGRAM, IPPROTO_UDP);
448
      break;
449
    case SK_IP:
450
    case SK_IP_MC:
451
      fd = socket(BIRD_PF, SOCK_RAW, s->dport);
452
      break;
453
    case SK_MAGIC:
454
      fd = s->fd;
455
      break;
456
    default:
457
      bug("sk_open() called for invalid sock type %d", type);
458
    }
459
  if (fd < 0)
460
    die("sk_open: socket: %m");
461
  s->fd = fd;
462

    
463
  if (err = sk_setup(s))
464
    goto bad;
465
  switch (type)
466
    {
467
    case SK_UDP:
468
    case SK_IP:
469
      if (s->iface)                        /* It's a broadcast socket */
470
#ifdef IPV6
471
        bug("IPv6 has no broadcasts");
472
#else
473
        if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0)
474
          ERR("SO_BROADCAST");
475
#endif
476
      break;
477
    case SK_UDP_MC:
478
    case SK_IP_MC:
479
      {
480
#ifdef IPV6
481
        /* Fortunately, IPv6 socket interface is recent enough and therefore standardized */
482
        ASSERT(s->iface && s->iface->addr);
483
        if (has_dest)
484
          {
485
            int t = s->iface->index;
486
            if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
487
              ERR("IPV6_MULTICAST_HOPS");
488
            if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
489
              ERR("IPV6_MULTICAST_LOOP");
490
            if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_IF, &t, sizeof(t)) < 0)
491
              ERR("IPV6_MULTICAST_IF");
492
          }
493
        if (has_src)
494
          {
495
            struct ipv6_mreq mreq;
496
            set_inaddr(&mreq.ipv6mr_multiaddr, s->daddr);
497
            mreq.ipv6mr_ifindex = s->iface->index;
498
            if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
499
              ERR("IPV6_ADD_MEMBERSHIP");
500
          }
501
#else
502
        /* With IPv4 there are zillions of different socket interface variants. Ugh. */
503
#ifdef HAVE_STRUCT_IP_MREQN
504
        struct ip_mreqn mreq;
505
#define mreq_add mreq
506
        ASSERT(s->iface && s->iface->addr);
507
        mreq.imr_ifindex = s->iface->index;
508
        set_inaddr(&mreq.imr_address, s->iface->addr->ip);
509
#else
510
        struct in_addr mreq;
511
        struct ip_mreq mreq_add;
512
        ASSERT(s->iface && s->iface->addr);
513
        set_inaddr(&mreq, s->iface->addr->ip);
514
#ifdef SO_BINDTODEVICE
515
        {
516
          struct ifreq ifr;
517
          strcpy(ifr.ifr_name, s->iface->name);
518
          if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0)
519
            ERR("SO_BINDTODEVICE");
520
          mreq_add.imr_interface.s_addr = INADDR_ANY;
521
        }
522
#else
523
#error Multicasts not supported on PtP devices                /* FIXME: Solve it somehow? */
524
        mreq_add.imr_interface = mreq;
525
#endif
526
#endif
527
        set_inaddr(&mreq_add.imr_multiaddr, s->daddr);
528
        if (has_dest)
529
          {
530
            if (
531
#ifdef IP_DEFAULT_MULTICAST_TTL
532
                s->ttl != IP_DEFAULT_MULTICAST_TTL &&
533
#endif
534
                setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &s->ttl, sizeof(s->ttl)) < 0)
535
              ERR("IP_MULTICAST_TTL");
536
            if (
537
#ifdef IP_DEFAULT_MULTICAST_LOOP
538
                IP_DEFAULT_MULTICAST_LOOP &&
539
#endif
540
                setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
541
              ERR("IP_MULTICAST_LOOP");
542
            /* This defines where should we send _outgoing_ multicasts */
543
            if (setsockopt(fd, SOL_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)) < 0)
544
              ERR("IP_MULTICAST_IF");
545
        }
546
      /* And this one sets interface for _receiving_ multicasts from */
547
      if (has_src && setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq_add, sizeof(mreq_add)) < 0)
548
        ERR("IP_ADD_MEMBERSHIP");
549
#endif
550
      break;
551
      }
552
    }
553
  if (has_src)
554
    {
555
      int port;
556

    
557
      if (type == SK_IP || type == SK_IP_MC)
558
        port = 0;
559
      else
560
        {
561
          port = s->sport;
562
          if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
563
            ERR("SO_REUSEADDR");
564
        }
565
      fill_in_sockaddr(&sa, s->saddr, port);
566
      if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
567
        ERR("bind");
568
    }
569
  fill_in_sockaddr(&sa, s->daddr, s->dport);
570
  switch (type)
571
    {
572
    case SK_TCP_ACTIVE:
573
      if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
574
        sk_tcp_connected(s);
575
      else if (errno != EINTR && errno != EAGAIN)
576
        ERR("connect");
577
      break;
578
    case SK_TCP_PASSIVE:
579
      if (listen(fd, 8))
580
        ERR("listen");
581
      break;
582
    case SK_MAGIC:
583
      break;
584
    default:
585
#ifdef IPV6
586
#ifdef IPV6_MTU_DISCOVER
587
      {
588
        int dont = IPV6_PMTUDISC_DONT;
589
        if (setsockopt(fd, SOL_IPV6, IPV6_MTU_DISCOVER, &dont, sizeof(dont)) < 0)
590
          ERR("IPV6_MTU_DISCOVER");
591
      }
592
#endif
593
#else
594
#ifdef IP_PMTUDISC
595
      {
596
        int dont = IP_PMTUDISC_DONT;
597
        if (setsockopt(fd, SOL_IP, IP_PMTUDISC, &dont, sizeof(dont)) < 0)
598
          ERR("IP_PMTUDISC");
599
      }
600
#endif
601
#endif
602
    }
603

    
604
  sk_alloc_bufs(s);
605
  add_tail(&sock_list, &s->n);
606
  return 0;
607

    
608
bad:
609
  log(L_ERR "sk_open: %s: %m", err);
610
  close(fd);
611
  s->fd = -1;
612
  return -1;
613
}
614

    
615
static int
616
sk_maybe_write(sock *s)
617
{
618
  int e;
619

    
620
  switch (s->type)
621
    {
622
    case SK_TCP:
623
    case SK_MAGIC:
624
      while (s->ttx != s->tpos)
625
        {
626
          e = write(s->fd, s->ttx, s->tpos - s->ttx);
627
          if (e < 0)
628
            {
629
              if (errno != EINTR && errno != EAGAIN)
630
                {
631
                  log(L_ERR "write: %m");
632
                  s->err_hook(s, errno);
633
                  return -1;
634
                }
635
              return 0;
636
            }
637
          s->ttx += e;
638
        }
639
      s->ttx = s->tpos = s->tbuf;
640
      return 1;
641
    case SK_UDP:
642
    case SK_UDP_MC:
643
    case SK_IP:
644
    case SK_IP_MC:
645
      {
646
        sockaddr sa;
647

    
648
        if (s->tbuf == s->tpos)
649
          return 1;
650
        fill_in_sockaddr(&sa, s->faddr, s->fport);
651
        e = sendto(s->fd, s->tbuf, s->tpos - s->tbuf, 0, (struct sockaddr *) &sa, sizeof(sa));
652
        if (e < 0)
653
          {
654
            if (errno != EINTR && errno != EAGAIN)
655
              {
656
                log(L_ERR "sendto: %m");
657
                s->err_hook(s, errno);
658
                return -1;
659
              }
660
            return 0;
661
          }
662
        s->tpos = s->tbuf;
663
        return 1;
664
      }
665
    default:
666
      bug("sk_maybe_write: unknown socket type %d", s->type);
667
    }
668
}
669

    
670
int
671
sk_send(sock *s, unsigned len)
672
{
673
  s->faddr = s->daddr;
674
  s->fport = s->dport;
675
  s->ttx = s->tbuf;
676
  s->tpos = s->tbuf + len;
677
  return sk_maybe_write(s);
678
}
679

    
680
int
681
sk_send_to(sock *s, unsigned len, ip_addr addr, unsigned port)
682
{
683
  s->faddr = addr;
684
  s->fport = port;
685
  s->ttx = s->tbuf;
686
  s->tpos = s->tbuf + len;
687
  return sk_maybe_write(s);
688
}
689

    
690
static int
691
sk_read(sock *s)
692
{
693
  switch (s->type)
694
    {
695
    case SK_TCP_ACTIVE:
696
      {
697
        sockaddr sa;
698
        fill_in_sockaddr(&sa, s->daddr, s->dport);
699
        if (connect(s->fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
700
          sk_tcp_connected(s);
701
        else if (errno != EINTR && errno != EAGAIN)
702
          {
703
            log(L_ERR "connect: %m");
704
            s->err_hook(s, errno);
705
          }
706
        return 0;
707
      }
708
    case SK_TCP_PASSIVE:
709
      {
710
        sockaddr sa;
711
        int al = sizeof(sa);
712
        int fd = accept(s->fd, (struct sockaddr *) &sa, &al);
713
        if (fd >= 0)
714
          {
715
            sock *t = sk_new(s->pool);
716
            char *err;
717
            t->type = SK_TCP;
718
            t->fd = fd;
719
            add_tail(&sock_list, &t->n);
720
            s->rx_hook(t, 0);
721
            if (err = sk_setup(t))
722
              {
723
                log(L_ERR "Incoming connection: %s: %m", err);
724
                s->err_hook(s, errno);
725
                return 0;
726
              }
727
            sk_alloc_bufs(t);
728
            return 1;
729
          }
730
        else if (errno != EINTR && errno != EAGAIN)
731
          {
732
            log(L_ERR "accept: %m");
733
            s->err_hook(s, errno);
734
          }
735
        return 0;
736
      }
737
    case SK_TCP:
738
      {
739
        int c = read(s->fd, s->rpos, s->rbuf + s->rbsize - s->rpos);
740

    
741
        if (c < 0)
742
          {
743
            if (errno != EINTR && errno != EAGAIN)
744
              {
745
                log(L_ERR "read: %m");
746
                s->err_hook(s, errno);
747
              }
748
          }
749
        else if (!c)
750
          s->err_hook(s, 0);
751
        else
752
          {
753
            s->rpos += c;
754
            if (s->rx_hook(s, s->rpos - s->rbuf))
755
              s->rpos = s->rbuf;
756
            return 1;
757
          }
758
        return 0;
759
      }
760
    case SK_MAGIC:
761
      return s->rx_hook(s, 0);
762
    default:
763
      {
764
        sockaddr sa;
765
        int al = sizeof(sa);
766
        int e = recvfrom(s->fd, s->rbuf, s->rbsize, 0, (struct sockaddr *) &sa, &al);
767

    
768
        if (e < 0)
769
          {
770
            if (errno != EINTR && errno != EAGAIN)
771
              {
772
                log(L_ERR "recvfrom: %m");
773
                s->err_hook(s, errno);
774
              }
775
            return 0;
776
          }
777
        s->rpos = s->rbuf + e;
778
        get_sockaddr(&sa, &s->faddr, &s->fport);
779
        s->rx_hook(s, e);
780
        return 1;
781
      }
782
    }
783
}
784

    
785
static void
786
sk_write(sock *s)
787
{
788
  while (s->ttx != s->tbuf && sk_maybe_write(s) > 0)
789
    s->tx_hook(s);
790
}
791

    
792
void
793
sk_dump_all(void)
794
{
795
  node *n;
796
  sock *s;
797

    
798
  debug("Open sockets:\n");
799
  WALK_LIST(n, sock_list)
800
    {
801
      s = SKIP_BACK(sock, n, n);
802
      debug("%p ", s);
803
      sk_dump(&s->r);
804
    }
805
  debug("\n");
806
}
807

    
808
#undef ERR
809

    
810
/*
811
 *        Main I/O Loop
812
 */
813

    
814
volatile int async_config_flag;                /* Asynchronous reconfiguration/dump scheduled */
815
volatile int async_dump_flag;
816

    
817
void
818
io_init(void)
819
{
820
  init_list(&near_timers);
821
  init_list(&far_timers);
822
  init_list(&sock_list);
823
  init_list(&global_event_list);
824
  krt_io_init();
825
  now = time(NULL);
826
}
827

    
828
void
829
io_loop(void)
830
{
831
  fd_set rd, wr;
832
  struct timeval timo;
833
  time_t tout;
834
  int hi;
835
  sock *s;
836
  node *n;
837

    
838
  /* FIXME: Use poll() if available */
839

    
840
  FD_ZERO(&rd);
841
  FD_ZERO(&wr);
842
  for(;;)
843
    {
844
      ev_run_list(&global_event_list);
845
      now = time(NULL);
846
      tout = tm_first_shot();
847
      if (tout <= now)
848
        {
849
          tm_shot();
850
          continue;
851
        }
852
      else
853
        {
854
          timo.tv_sec = tout - now;
855
          timo.tv_usec = 0;
856
        }
857

    
858
      hi = 0;
859
      WALK_LIST(n, sock_list)
860
        {
861
          s = SKIP_BACK(sock, n, n);
862
          if (s->rx_hook)
863
            {
864
              FD_SET(s->fd, &rd);
865
              if (s->fd > hi)
866
                hi = s->fd;
867
            }
868
          if (s->tx_hook && s->ttx != s->tpos)
869
            {
870
              FD_SET(s->fd, &wr);
871
              if (s->fd > hi)
872
                hi = s->fd;
873
            }
874
        }
875

    
876
      /*
877
       * Yes, this is racy. But even if the signal comes before this test
878
       * and entering select(), it gets caught on the next timer tick.
879
       */
880

    
881
      if (async_config_flag)
882
        {
883
          async_config();
884
          async_config_flag = 0;
885
          continue;
886
        }
887
      if (async_dump_flag)
888
        {
889
          async_dump();
890
          async_dump_flag = 0;
891
          continue;
892
        }
893
      if (async_shutdown_flag)
894
        {
895
          async_shutdown();
896
          async_shutdown_flag = 0;
897
          continue;
898
        }
899

    
900
      /* And finally enter select() to find active sockets */
901

    
902
      hi = select(hi+1, &rd, &wr, NULL, &timo);
903
      if (hi < 0)
904
        {
905
          if (errno == EINTR || errno == EAGAIN)
906
            continue;
907
          die("select: %m");
908
        }
909
      if (hi)
910
        {
911
          WALK_LIST(n, sock_list)
912
            {
913
              s = SKIP_BACK(sock, n, n);
914
              if (FD_ISSET(s->fd, &rd))
915
                {
916
                  FD_CLR(s->fd, &rd);
917
                  while (sk_read(s))
918
                    ;
919
                }
920
              if (FD_ISSET(s->fd, &wr))
921
                {
922
                  FD_CLR(s->fd, &wr);
923
                  sk_write(s);
924
                }
925
            }
926
        }
927
    }
928
}