iof-bird-daemon / sysdep / unix / io.c @ 9a158361
History | View | Annotate | Download (15.1 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 |
#include "lib/unix.h" |
32 |
|
33 |
/*
|
34 |
* Timers
|
35 |
*/
|
36 |
|
37 |
#define NEAR_TIMER_LIMIT 4 |
38 |
|
39 |
#ifdef TIME_T_IS_64BIT
|
40 |
#define TIME_INFINITY 0x7fffffffffffffff |
41 |
#else
|
42 |
#ifdef TIME_T_IS_SIGNED
|
43 |
#define TIME_INFINITY 0x7fffffff |
44 |
#else
|
45 |
#define TIME_INFINITY 0xffffffff |
46 |
#endif
|
47 |
#endif
|
48 |
|
49 |
static list near_timers, far_timers;
|
50 |
static bird_clock_t first_far_timer = TIME_INFINITY;
|
51 |
|
52 |
bird_clock_t now; |
53 |
|
54 |
static void |
55 |
tm_free(resource *r) |
56 |
{ |
57 |
timer *t = (timer *) r; |
58 |
|
59 |
tm_stop(t); |
60 |
} |
61 |
|
62 |
static void |
63 |
tm_dump(resource *r) |
64 |
{ |
65 |
timer *t = (timer *) r; |
66 |
|
67 |
debug("(code %p, data %p, ", t->hook, t->data);
|
68 |
if (t->randomize)
|
69 |
debug("rand %d, ", t->randomize);
|
70 |
if (t->recurrent)
|
71 |
debug("recur %d, ", t->recurrent);
|
72 |
if (t->expires)
|
73 |
debug("expires in %d sec)\n", t->expires - now);
|
74 |
else
|
75 |
debug("inactive)\n");
|
76 |
} |
77 |
|
78 |
static struct resclass tm_class = { |
79 |
"Timer",
|
80 |
sizeof(timer),
|
81 |
tm_free, |
82 |
tm_dump |
83 |
}; |
84 |
|
85 |
timer * |
86 |
tm_new(pool *p) |
87 |
{ |
88 |
timer *t = ralloc(p, &tm_class); |
89 |
t->hook = NULL;
|
90 |
t->data = NULL;
|
91 |
t->randomize = 0;
|
92 |
t->expires = 0;
|
93 |
return t;
|
94 |
} |
95 |
|
96 |
static inline void |
97 |
tm_insert_near(timer *t) |
98 |
{ |
99 |
node *n = HEAD(near_timers); |
100 |
|
101 |
while (n->next && (SKIP_BACK(timer, n, n)->expires < t->expires))
|
102 |
n = n->next; |
103 |
insert_node(&t->n, n->prev); |
104 |
} |
105 |
|
106 |
void
|
107 |
tm_start(timer *t, unsigned after)
|
108 |
{ |
109 |
bird_clock_t when; |
110 |
|
111 |
if (t->randomize)
|
112 |
after += random() % (t->randomize + 1);
|
113 |
when = now + after; |
114 |
if (t->expires == when)
|
115 |
return;
|
116 |
if (t->expires)
|
117 |
rem_node(&t->n); |
118 |
t->expires = when; |
119 |
if (after <= NEAR_TIMER_LIMIT)
|
120 |
tm_insert_near(t); |
121 |
else
|
122 |
{ |
123 |
if (!first_far_timer || first_far_timer > when)
|
124 |
first_far_timer = when; |
125 |
add_tail(&far_timers, &t->n); |
126 |
} |
127 |
} |
128 |
|
129 |
void
|
130 |
tm_stop(timer *t) |
131 |
{ |
132 |
if (t->expires)
|
133 |
{ |
134 |
rem_node(&t->n); |
135 |
t->expires = 0;
|
136 |
} |
137 |
} |
138 |
|
139 |
static void |
140 |
tm_dump_them(char *name, list *l)
|
141 |
{ |
142 |
node *n; |
143 |
timer *t; |
144 |
|
145 |
debug("%s timers:\n", name);
|
146 |
WALK_LIST(n, *l) |
147 |
{ |
148 |
t = SKIP_BACK(timer, n, n); |
149 |
debug("%p ", t);
|
150 |
tm_dump(&t->r); |
151 |
} |
152 |
debug("\n");
|
153 |
} |
154 |
|
155 |
void
|
156 |
tm_dump_all(void)
|
157 |
{ |
158 |
tm_dump_them("Near", &near_timers);
|
159 |
tm_dump_them("Far", &far_timers);
|
160 |
} |
161 |
|
162 |
static inline time_t |
163 |
tm_first_shot(void)
|
164 |
{ |
165 |
time_t x = first_far_timer; |
166 |
|
167 |
if (!EMPTY_LIST(near_timers))
|
168 |
{ |
169 |
timer *t = SKIP_BACK(timer, n, HEAD(near_timers)); |
170 |
if (t->expires < x)
|
171 |
x = t->expires; |
172 |
} |
173 |
return x;
|
174 |
} |
175 |
|
176 |
static void |
177 |
tm_shot(void)
|
178 |
{ |
179 |
timer *t; |
180 |
node *n, *m; |
181 |
|
182 |
if (first_far_timer <= now)
|
183 |
{ |
184 |
bird_clock_t limit = now + NEAR_TIMER_LIMIT; |
185 |
first_far_timer = TIME_INFINITY; |
186 |
n = HEAD(far_timers); |
187 |
while (m = n->next)
|
188 |
{ |
189 |
t = SKIP_BACK(timer, n, n); |
190 |
if (t->expires <= limit)
|
191 |
{ |
192 |
rem_node(n); |
193 |
tm_insert_near(t); |
194 |
} |
195 |
else if (t->expires < first_far_timer) |
196 |
first_far_timer = t->expires; |
197 |
n = m; |
198 |
} |
199 |
} |
200 |
while ((n = HEAD(near_timers)) -> next)
|
201 |
{ |
202 |
int delay;
|
203 |
t = SKIP_BACK(timer, n, n); |
204 |
if (t->expires > now)
|
205 |
break;
|
206 |
rem_node(n); |
207 |
delay = t->expires - now; |
208 |
t->expires = 0;
|
209 |
if (t->recurrent)
|
210 |
{ |
211 |
int i = t->recurrent - delay;
|
212 |
if (i < 0) |
213 |
i = 0;
|
214 |
tm_start(t, i); |
215 |
} |
216 |
t->hook(t); |
217 |
} |
218 |
} |
219 |
|
220 |
/*
|
221 |
* Sockets
|
222 |
*/
|
223 |
|
224 |
#ifndef SOL_IP
|
225 |
#define SOL_IP IPPROTO_IP
|
226 |
#endif
|
227 |
|
228 |
static list sock_list;
|
229 |
|
230 |
static void |
231 |
sk_free(resource *r) |
232 |
{ |
233 |
sock *s = (sock *) r; |
234 |
|
235 |
if (s->fd >= 0) |
236 |
rem_node(&s->n); |
237 |
} |
238 |
|
239 |
static void |
240 |
sk_dump(resource *r) |
241 |
{ |
242 |
sock *s = (sock *) r; |
243 |
static char *sk_type_names[] = { "TCP<", "TCP>", "TCP", "UDP", "UDP/MC", "IP", "IP/MC", "MAGIC" }; |
244 |
|
245 |
debug("(%s, ud=%p, sa=%08x, sp=%d, da=%08x, dp=%d, tos=%d, ttl=%d, if=%s)\n",
|
246 |
sk_type_names[s->type], |
247 |
s->data, |
248 |
s->saddr, |
249 |
s->sport, |
250 |
s->daddr, |
251 |
s->dport, |
252 |
s->tos, |
253 |
s->ttl, |
254 |
s->iface ? s->iface->name : "none");
|
255 |
} |
256 |
|
257 |
static struct resclass sk_class = { |
258 |
"Socket",
|
259 |
sizeof(sock),
|
260 |
sk_free, |
261 |
sk_dump |
262 |
}; |
263 |
|
264 |
sock * |
265 |
sk_new(pool *p) |
266 |
{ |
267 |
sock *s = ralloc(p, &sk_class); |
268 |
s->pool = p; |
269 |
s->data = NULL;
|
270 |
s->saddr = s->daddr = IPA_NONE; |
271 |
s->sport = s->dport = 0;
|
272 |
s->tos = s->ttl = -1;
|
273 |
s->iface = NULL;
|
274 |
s->rbuf = NULL;
|
275 |
s->rx_hook = NULL;
|
276 |
s->rbsize = 0;
|
277 |
s->tbuf = NULL;
|
278 |
s->tx_hook = NULL;
|
279 |
s->tbsize = 0;
|
280 |
s->err_hook = NULL;
|
281 |
s->fd = -1;
|
282 |
return s;
|
283 |
} |
284 |
|
285 |
#define ERR(x) do { err = x; goto bad; } while(0) |
286 |
|
287 |
static inline void |
288 |
set_inaddr(struct in_addr *ia, ip_addr a)
|
289 |
{ |
290 |
a = ipa_hton(a); |
291 |
memcpy(&ia->s_addr, &a, sizeof(a));
|
292 |
} |
293 |
|
294 |
void
|
295 |
fill_in_sockaddr(struct sockaddr_in *sa, ip_addr a, unsigned port) |
296 |
{ |
297 |
sa->sin_family = AF_INET; |
298 |
sa->sin_port = htons(port); |
299 |
set_inaddr(&sa->sin_addr, a); |
300 |
} |
301 |
|
302 |
void
|
303 |
get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port) |
304 |
{ |
305 |
if (sa->sin_family != AF_INET)
|
306 |
bug("get_sockaddr called for wrong address family");
|
307 |
if (port)
|
308 |
*port = ntohs(sa->sin_port); |
309 |
memcpy(a, &sa->sin_addr.s_addr, sizeof(*a));
|
310 |
*a = ipa_ntoh(*a); |
311 |
} |
312 |
|
313 |
static char * |
314 |
sk_setup(sock *s) |
315 |
{ |
316 |
int fd = s->fd;
|
317 |
int one = 1; |
318 |
char *err;
|
319 |
|
320 |
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) |
321 |
ERR("fcntl(O_NONBLOCK)");
|
322 |
if ((s->tos >= 0) && setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0) |
323 |
ERR("IP_TOS");
|
324 |
if (s->ttl >= 0) |
325 |
{ |
326 |
if (setsockopt(fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0) |
327 |
ERR("IP_TTL");
|
328 |
if (setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) |
329 |
ERR("SO_DONTROUTE");
|
330 |
} |
331 |
#ifdef IP_PMTUDISC
|
332 |
if (s->type != SK_TCP_PASSIVE && s->type != SK_TCP_ACTIVE && s->type != SK_MAGIC)
|
333 |
{ |
334 |
int dont = IP_PMTUDISC_DONT;
|
335 |
if (setsockopt(fd, SOL_IP, IP_PMTUDISC, &dont, sizeof(dont)) < 0) |
336 |
ERR("IP_PMTUDISC");
|
337 |
} |
338 |
#endif
|
339 |
/* FIXME: Set send/receive buffers? */
|
340 |
/* FIXME: Set keepalive for TCP connections? */
|
341 |
err = NULL;
|
342 |
bad:
|
343 |
return err;
|
344 |
} |
345 |
|
346 |
static void |
347 |
sk_alloc_bufs(sock *s) |
348 |
{ |
349 |
if (!s->rbuf && s->rbsize)
|
350 |
s->rbuf = mb_alloc(s->pool, s->rbsize); |
351 |
s->rpos = s->rbuf; |
352 |
if (!s->tbuf && s->tbsize)
|
353 |
s->tbuf = mb_alloc(s->pool, s->tbsize); |
354 |
s->tpos = s->ttx = s->tbuf; |
355 |
} |
356 |
|
357 |
void
|
358 |
sk_tcp_connected(sock *s) |
359 |
{ |
360 |
s->rx_hook(s, 0);
|
361 |
s->type = SK_TCP; |
362 |
sk_alloc_bufs(s); |
363 |
} |
364 |
|
365 |
int
|
366 |
sk_open(sock *s) |
367 |
{ |
368 |
int fd, e;
|
369 |
struct sockaddr_in sa;
|
370 |
int zero = 0; |
371 |
int one = 1; |
372 |
int type = s->type;
|
373 |
int has_src = ipa_nonzero(s->saddr) || s->sport;
|
374 |
int has_dest = ipa_nonzero(s->daddr);
|
375 |
char *err;
|
376 |
|
377 |
switch (type)
|
378 |
{ |
379 |
case SK_TCP_ACTIVE:
|
380 |
case SK_TCP_PASSIVE:
|
381 |
fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); |
382 |
break;
|
383 |
case SK_UDP:
|
384 |
case SK_UDP_MC:
|
385 |
fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); |
386 |
break;
|
387 |
case SK_IP:
|
388 |
case SK_IP_MC:
|
389 |
fd = socket(PF_INET, SOCK_RAW, s->dport); |
390 |
break;
|
391 |
case SK_MAGIC:
|
392 |
fd = s->fd; |
393 |
break;
|
394 |
default:
|
395 |
bug("sk_open() called for invalid sock type %d", type);
|
396 |
} |
397 |
if (fd < 0) |
398 |
die("sk_open: socket: %m");
|
399 |
s->fd = fd; |
400 |
|
401 |
if (err = sk_setup(s))
|
402 |
goto bad;
|
403 |
switch (type)
|
404 |
{ |
405 |
case SK_UDP:
|
406 |
case SK_IP:
|
407 |
if (s->iface) /* It's a broadcast socket */ |
408 |
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0) |
409 |
ERR("SO_BROADCAST");
|
410 |
break;
|
411 |
case SK_UDP_MC:
|
412 |
case SK_IP_MC:
|
413 |
{ |
414 |
#ifdef HAVE_STRUCT_IP_MREQN
|
415 |
struct ip_mreqn mreq;
|
416 |
#define mreq_add mreq
|
417 |
ASSERT(s->iface && s->iface->addr); |
418 |
mreq.imr_ifindex = s->iface->index; |
419 |
set_inaddr(&mreq.imr_address, s->iface->addr->ip); |
420 |
#else
|
421 |
struct in_addr mreq;
|
422 |
struct ip_mreq mreq_add;
|
423 |
ASSERT(s->iface && s->iface->addr); |
424 |
set_inaddr(&mreq, s->iface->addr->ip); |
425 |
#ifdef SO_BINDTODEVICE
|
426 |
{ |
427 |
struct ifreq ifr;
|
428 |
strcpy(ifr.ifr_name, s->iface->name); |
429 |
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) |
430 |
ERR("SO_BINDTODEVICE");
|
431 |
mreq_add.imr_interface.s_addr = INADDR_ANY; |
432 |
} |
433 |
#else
|
434 |
#error Multicasts not supported on PtP devices /* FIXME: Solve it somehow? */ |
435 |
mreq_add.imr_interface = mreq; |
436 |
#endif
|
437 |
#endif
|
438 |
set_inaddr(&mreq_add.imr_multiaddr, s->daddr); |
439 |
if (has_dest)
|
440 |
{ |
441 |
if (
|
442 |
#ifdef IP_DEFAULT_MULTICAST_TTL
|
443 |
s->ttl != IP_DEFAULT_MULTICAST_TTL && |
444 |
#endif
|
445 |
setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &s->ttl, sizeof(s->ttl)) < 0) |
446 |
ERR("IP_MULTICAST_TTL");
|
447 |
if (
|
448 |
#ifdef IP_DEFAULT_MULTICAST_LOOP
|
449 |
IP_DEFAULT_MULTICAST_LOOP && |
450 |
#endif
|
451 |
setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0) |
452 |
ERR("IP_MULTICAST_LOOP");
|
453 |
/* This defines where should we send _outgoing_ multicasts */
|
454 |
if (setsockopt(fd, SOL_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)) < 0) |
455 |
ERR("IP_MULTICAST_IF");
|
456 |
} |
457 |
/* And this one sets interface for _receiving_ multicasts from */
|
458 |
if (has_src && setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq_add, sizeof(mreq_add)) < 0) |
459 |
ERR("IP_ADD_MEMBERSHIP");
|
460 |
break;
|
461 |
} |
462 |
} |
463 |
if (has_src)
|
464 |
{ |
465 |
int port;
|
466 |
|
467 |
if (type == SK_IP || type == SK_IP_MC)
|
468 |
port = 0;
|
469 |
else
|
470 |
{ |
471 |
port = s->sport; |
472 |
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) |
473 |
ERR("SO_REUSEADDR");
|
474 |
} |
475 |
fill_in_sockaddr(&sa, s->saddr, port); |
476 |
if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) |
477 |
ERR("bind");
|
478 |
} |
479 |
fill_in_sockaddr(&sa, s->daddr, s->dport); |
480 |
switch (type)
|
481 |
{ |
482 |
case SK_TCP_ACTIVE:
|
483 |
if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0) |
484 |
sk_tcp_connected(s); |
485 |
else if (errno != EINTR && errno != EAGAIN) |
486 |
ERR("connect");
|
487 |
break;
|
488 |
case SK_TCP_PASSIVE:
|
489 |
if (listen(fd, 8)) |
490 |
ERR("listen");
|
491 |
break;
|
492 |
} |
493 |
|
494 |
sk_alloc_bufs(s); |
495 |
add_tail(&sock_list, &s->n); |
496 |
return 0; |
497 |
|
498 |
bad:
|
499 |
log(L_ERR "sk_open: %s: %m", err);
|
500 |
close(fd); |
501 |
s->fd = -1;
|
502 |
return -1; |
503 |
} |
504 |
|
505 |
static int |
506 |
sk_maybe_write(sock *s) |
507 |
{ |
508 |
int e;
|
509 |
|
510 |
switch (s->type)
|
511 |
{ |
512 |
case SK_TCP:
|
513 |
case SK_MAGIC:
|
514 |
while (s->ttx != s->tpos)
|
515 |
{ |
516 |
e = write(s->fd, s->ttx, s->tpos - s->ttx); |
517 |
if (e < 0) |
518 |
{ |
519 |
if (errno != EINTR && errno != EAGAIN)
|
520 |
{ |
521 |
log(L_ERR "write: %m");
|
522 |
s->err_hook(s, errno); |
523 |
return -1; |
524 |
} |
525 |
return 0; |
526 |
} |
527 |
s->ttx += e; |
528 |
} |
529 |
s->ttx = s->tpos = s->tbuf; |
530 |
return 1; |
531 |
case SK_UDP:
|
532 |
case SK_UDP_MC:
|
533 |
case SK_IP:
|
534 |
case SK_IP_MC:
|
535 |
{ |
536 |
struct sockaddr_in sa;
|
537 |
|
538 |
if (s->tbuf == s->tpos)
|
539 |
return 1; |
540 |
fill_in_sockaddr(&sa, s->faddr, s->fport); |
541 |
e = sendto(s->fd, s->tbuf, s->tpos - s->tbuf, 0, (struct sockaddr *) &sa, sizeof(sa)); |
542 |
if (e < 0) |
543 |
{ |
544 |
if (errno != EINTR && errno != EAGAIN)
|
545 |
{ |
546 |
log(L_ERR "sendto: %m");
|
547 |
s->err_hook(s, errno); |
548 |
return -1; |
549 |
} |
550 |
return 0; |
551 |
} |
552 |
s->tpos = s->tbuf; |
553 |
return 1; |
554 |
} |
555 |
default:
|
556 |
bug("sk_maybe_write: unknown socket type %d", s->type);
|
557 |
} |
558 |
} |
559 |
|
560 |
int
|
561 |
sk_send(sock *s, unsigned len)
|
562 |
{ |
563 |
s->faddr = s->daddr; |
564 |
s->fport = s->dport; |
565 |
s->ttx = s->tbuf; |
566 |
s->tpos = s->tbuf + len; |
567 |
return sk_maybe_write(s);
|
568 |
} |
569 |
|
570 |
int
|
571 |
sk_send_to(sock *s, unsigned len, ip_addr addr, unsigned port) |
572 |
{ |
573 |
s->faddr = addr; |
574 |
s->fport = port; |
575 |
s->ttx = s->tbuf; |
576 |
s->tpos = s->tbuf + len; |
577 |
return sk_maybe_write(s);
|
578 |
} |
579 |
|
580 |
static int |
581 |
sk_read(sock *s) |
582 |
{ |
583 |
switch (s->type)
|
584 |
{ |
585 |
case SK_TCP_ACTIVE:
|
586 |
{ |
587 |
struct sockaddr_in sa;
|
588 |
fill_in_sockaddr(&sa, s->daddr, s->dport); |
589 |
if (connect(s->fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0) |
590 |
sk_tcp_connected(s); |
591 |
else if (errno != EINTR && errno != EAGAIN) |
592 |
{ |
593 |
log(L_ERR "connect: %m");
|
594 |
s->err_hook(s, errno); |
595 |
} |
596 |
return 0; |
597 |
} |
598 |
case SK_TCP_PASSIVE:
|
599 |
{ |
600 |
struct sockaddr_in sa;
|
601 |
int al = sizeof(sa); |
602 |
int fd = accept(s->fd, (struct sockaddr *) &sa, &al); |
603 |
if (fd >= 0) |
604 |
{ |
605 |
sock *t = sk_new(s->pool); |
606 |
char *err;
|
607 |
t->type = SK_TCP; |
608 |
t->fd = fd; |
609 |
add_tail(&sock_list, &t->n); |
610 |
s->rx_hook(t, 0);
|
611 |
if (err = sk_setup(t))
|
612 |
{ |
613 |
log(L_ERR "Incoming connection: %s: %m", err);
|
614 |
s->err_hook(s, errno); |
615 |
return 0; |
616 |
} |
617 |
sk_alloc_bufs(t); |
618 |
return 1; |
619 |
} |
620 |
else if (errno != EINTR && errno != EAGAIN) |
621 |
{ |
622 |
log(L_ERR "accept: %m");
|
623 |
s->err_hook(s, errno); |
624 |
} |
625 |
return 0; |
626 |
} |
627 |
case SK_TCP:
|
628 |
{ |
629 |
int c = read(s->fd, s->rpos, s->rbuf + s->rbsize - s->rpos);
|
630 |
|
631 |
if (c < 0) |
632 |
{ |
633 |
if (errno != EINTR && errno != EAGAIN)
|
634 |
{ |
635 |
log(L_ERR "read: %m");
|
636 |
s->err_hook(s, errno); |
637 |
} |
638 |
} |
639 |
else if (!c) |
640 |
s->err_hook(s, 0);
|
641 |
else
|
642 |
{ |
643 |
s->rpos += c; |
644 |
if (s->rx_hook(s, s->rpos - s->rbuf))
|
645 |
s->rpos = s->rbuf; |
646 |
return 1; |
647 |
} |
648 |
return 0; |
649 |
} |
650 |
case SK_MAGIC:
|
651 |
return s->rx_hook(s, 0); |
652 |
default:
|
653 |
{ |
654 |
struct sockaddr_in sa;
|
655 |
int al = sizeof(sa); |
656 |
int e = recvfrom(s->fd, s->rbuf, s->rbsize, 0, (struct sockaddr *) &sa, &al); |
657 |
|
658 |
if (e < 0) |
659 |
{ |
660 |
if (errno != EINTR && errno != EAGAIN)
|
661 |
{ |
662 |
log(L_ERR "recvfrom: %m");
|
663 |
s->err_hook(s, errno); |
664 |
} |
665 |
return 0; |
666 |
} |
667 |
s->rpos = s->rbuf + e; |
668 |
get_sockaddr(&sa, &s->faddr, &s->fport); |
669 |
s->rx_hook(s, e); |
670 |
return 1; |
671 |
} |
672 |
} |
673 |
} |
674 |
|
675 |
static void |
676 |
sk_write(sock *s) |
677 |
{ |
678 |
while (s->ttx != s->tbuf && sk_maybe_write(s) > 0) |
679 |
s->tx_hook(s); |
680 |
} |
681 |
|
682 |
void
|
683 |
sk_dump_all(void)
|
684 |
{ |
685 |
node *n; |
686 |
sock *s; |
687 |
|
688 |
debug("Open sockets:\n");
|
689 |
WALK_LIST(n, sock_list) |
690 |
{ |
691 |
s = SKIP_BACK(sock, n, n); |
692 |
debug("%p ", s);
|
693 |
sk_dump(&s->r); |
694 |
} |
695 |
debug("\n");
|
696 |
} |
697 |
|
698 |
#undef ERR
|
699 |
|
700 |
/*
|
701 |
* Main I/O Loop
|
702 |
*/
|
703 |
|
704 |
volatile int async_config_flag; /* Asynchronous reconfiguration/dump scheduled */ |
705 |
volatile int async_dump_flag; |
706 |
|
707 |
void
|
708 |
io_init(void)
|
709 |
{ |
710 |
init_list(&near_timers); |
711 |
init_list(&far_timers); |
712 |
init_list(&sock_list); |
713 |
init_list(&global_event_list); |
714 |
krt_io_init(); |
715 |
now = time(NULL);
|
716 |
} |
717 |
|
718 |
void
|
719 |
io_loop(void)
|
720 |
{ |
721 |
fd_set rd, wr; |
722 |
struct timeval timo;
|
723 |
time_t tout; |
724 |
int hi;
|
725 |
sock *s; |
726 |
node *n; |
727 |
|
728 |
/* FIXME: Use poll() if available */
|
729 |
|
730 |
FD_ZERO(&rd); |
731 |
FD_ZERO(&wr); |
732 |
for(;;)
|
733 |
{ |
734 |
ev_run_list(&global_event_list); |
735 |
now = time(NULL);
|
736 |
tout = tm_first_shot(); |
737 |
if (tout <= now)
|
738 |
{ |
739 |
tm_shot(); |
740 |
continue;
|
741 |
} |
742 |
else
|
743 |
{ |
744 |
timo.tv_sec = tout - now; |
745 |
timo.tv_usec = 0;
|
746 |
} |
747 |
|
748 |
hi = 0;
|
749 |
WALK_LIST(n, sock_list) |
750 |
{ |
751 |
s = SKIP_BACK(sock, n, n); |
752 |
if (s->rx_hook)
|
753 |
{ |
754 |
FD_SET(s->fd, &rd); |
755 |
if (s->fd > hi)
|
756 |
hi = s->fd; |
757 |
} |
758 |
if (s->tx_hook && s->ttx != s->tpos)
|
759 |
{ |
760 |
FD_SET(s->fd, &wr); |
761 |
if (s->fd > hi)
|
762 |
hi = s->fd; |
763 |
} |
764 |
} |
765 |
|
766 |
/*
|
767 |
* Yes, this is racy. But even if the signal comes before this test
|
768 |
* and entering select(), it gets caught on the next timer tick.
|
769 |
*/
|
770 |
|
771 |
if (async_config_flag)
|
772 |
{ |
773 |
async_config(); |
774 |
async_config_flag = 0;
|
775 |
continue;
|
776 |
} |
777 |
if (async_dump_flag)
|
778 |
{ |
779 |
async_dump(); |
780 |
async_dump_flag = 0;
|
781 |
continue;
|
782 |
} |
783 |
if (async_shutdown_flag)
|
784 |
{ |
785 |
async_shutdown(); |
786 |
async_shutdown_flag = 0;
|
787 |
continue;
|
788 |
} |
789 |
|
790 |
/* And finally enter select() to find active sockets */
|
791 |
|
792 |
hi = select(hi+1, &rd, &wr, NULL, &timo); |
793 |
if (hi < 0) |
794 |
{ |
795 |
if (errno == EINTR || errno == EAGAIN)
|
796 |
continue;
|
797 |
die("select: %m");
|
798 |
} |
799 |
if (hi)
|
800 |
{ |
801 |
WALK_LIST(n, sock_list) |
802 |
{ |
803 |
s = SKIP_BACK(sock, n, n); |
804 |
if (FD_ISSET(s->fd, &rd))
|
805 |
{ |
806 |
FD_CLR(s->fd, &rd); |
807 |
while (sk_read(s))
|
808 |
; |
809 |
} |
810 |
if (FD_ISSET(s->fd, &wr))
|
811 |
{ |
812 |
FD_CLR(s->fd, &wr); |
813 |
sk_write(s); |
814 |
} |
815 |
} |
816 |
} |
817 |
} |
818 |
} |