2 * BIRD Internet Routing Daemon -- Unix I/O
4 * (c) 1998--2004 Martin Mares <mj@ucw.cz>
5 * (c) 2004 Ondrej Filip <feela@network.cz>
7 * Can be freely distributed and used under the terms of the GNU GPL.
10 /* Unfortunately, some glibc versions hide parts of RFC 3542 API
11 if _GNU_SOURCE is not defined. */
18 #include <sys/types.h>
19 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <netinet/tcp.h>
28 #include <netinet/udp.h>
29 #include <netinet/icmp6.h>
31 #include "nest/bird.h"
32 #include "lib/lists.h"
33 #include "lib/resource.h"
34 #include "lib/timer.h"
35 #include "lib/socket.h"
36 #include "lib/event.h"
37 #include "lib/string.h"
38 #include "nest/iface.h"
41 #include "lib/sysio.h"
43 /* Maximum number of calls of tx handler for one socket in one
44 * select iteration. Should be small enough to not monopolize CPU by
45 * one protocol instance.
49 /* Maximum number of calls of rx handler for all sockets in one select
50 iteration. RX callbacks are often much more costly so we limit
51 this to gen small latencies */
52 #define MAX_RX_STEPS 4
66 struct rfile
*a
= (struct rfile
*) r
;
74 struct rfile
*a
= (struct rfile
*) r
;
76 debug("(FILE *%p)\n", a
->f
);
79 static struct resclass rf_class
= {
89 tracked_fopen(pool
*p
, char *name
, char *mode
)
91 FILE *f
= fopen(name
, mode
);
95 struct rfile
*r
= ralloc(p
, &rf_class
);
104 * Timers are resources which represent a wish of a module to call
105 * a function at the specified time. The platform dependent code
106 * doesn't guarantee exact timing, only that a timer function
107 * won't be called before the requested time.
109 * In BIRD, time is represented by values of the &bird_clock_t type
110 * which are integral numbers interpreted as a relative number of seconds since
111 * some fixed time point in past. The current time can be read
112 * from variable @now with reasonable accuracy and is monotonic. There is also
113 * a current 'absolute' time in variable @now_real reported by OS.
115 * Each timer is described by a &timer structure containing a pointer
116 * to the handler function (@hook), data private to this function (@data),
117 * time the function should be called at (@expires, 0 for inactive timers),
118 * for the other fields see |timer.h|.
121 #define NEAR_TIMER_LIMIT 4
123 static list near_timers
, far_timers
;
124 static bird_clock_t first_far_timer
= TIME_INFINITY
;
126 /* now must be different from 0, because 0 is a special value in timer->expires */
127 bird_clock_t now
= 1, now_real
, boot_time
;
130 update_times_plain(void)
132 bird_clock_t new_time
= time(NULL
);
133 int delta
= new_time
- now_real
;
135 if ((delta
>= 0) && (delta
< 60))
137 else if (now_real
!= 0)
138 log(L_WARN
"Time jump, delta %d s", delta
);
144 update_times_gettime(void)
149 rv
= clock_gettime(CLOCK_MONOTONIC
, &ts
);
151 die("clock_gettime: %m");
153 if (ts
.tv_sec
!= now
) {
155 log(L_ERR
"Monotonic timer is broken");
158 now_real
= time(NULL
);
162 static int clock_monotonic_available
;
167 if (clock_monotonic_available
)
168 update_times_gettime();
170 update_times_plain();
177 clock_monotonic_available
= (clock_gettime(CLOCK_MONOTONIC
, &ts
) == 0);
178 if (!clock_monotonic_available
)
179 log(L_WARN
"Monotonic timer is missing");
186 timer
*t
= (timer
*) r
;
194 timer
*t
= (timer
*) r
;
196 debug("(code %p, data %p, ", t
->hook
, t
->data
);
198 debug("rand %d, ", t
->randomize
);
200 debug("recur %d, ", t
->recurrent
);
202 debug("expires in %d sec)\n", t
->expires
- now
);
204 debug("inactive)\n");
207 static struct resclass tm_class
= {
217 * tm_new - create a timer
220 * This function creates a new timer resource and returns
221 * a pointer to it. To use the timer, you need to fill in
222 * the structure fields and call tm_start() to start timing.
227 timer
*t
= ralloc(p
, &tm_class
);
232 tm_insert_near(timer
*t
)
234 node
*n
= HEAD(near_timers
);
236 while (n
->next
&& (SKIP_BACK(timer
, n
, n
)->expires
< t
->expires
))
238 insert_node(&t
->n
, n
->prev
);
242 * tm_start - start a timer
244 * @after: number of seconds the timer should be run after
246 * This function schedules the hook function of the timer to
247 * be called after @after seconds. If the timer has been already
248 * started, it's @expire time is replaced by the new value.
250 * You can have set the @randomize field of @t, the timeout
251 * will be increased by a random number of seconds chosen
252 * uniformly from range 0 .. @randomize.
254 * You can call tm_start() from the handler function of the timer
255 * to request another run of the timer. Also, you can set the @recurrent
256 * field to have the timer re-added automatically with the same timeout.
259 tm_start(timer
*t
, unsigned after
)
264 after
+= random() % (t
->randomize
+ 1);
266 if (t
->expires
== when
)
271 if (after
<= NEAR_TIMER_LIMIT
)
275 if (!first_far_timer
|| first_far_timer
> when
)
276 first_far_timer
= when
;
277 add_tail(&far_timers
, &t
->n
);
282 * tm_stop - stop a timer
285 * This function stops a timer. If the timer is already stopped,
299 tm_dump_them(char *name
, list
*l
)
304 debug("%s timers:\n", name
);
307 t
= SKIP_BACK(timer
, n
, n
);
317 tm_dump_them("Near", &near_timers
);
318 tm_dump_them("Far", &far_timers
);
324 time_t x
= first_far_timer
;
326 if (!EMPTY_LIST(near_timers
))
328 timer
*t
= SKIP_BACK(timer
, n
, HEAD(near_timers
));
335 void io_log_event(void *hook
, void *data
);
343 if (first_far_timer
<= now
)
345 bird_clock_t limit
= now
+ NEAR_TIMER_LIMIT
;
346 first_far_timer
= TIME_INFINITY
;
347 n
= HEAD(far_timers
);
350 t
= SKIP_BACK(timer
, n
, n
);
351 if (t
->expires
<= limit
)
356 else if (t
->expires
< first_far_timer
)
357 first_far_timer
= t
->expires
;
361 while ((n
= HEAD(near_timers
)) -> next
)
364 t
= SKIP_BACK(timer
, n
, n
);
365 if (t
->expires
> now
)
368 delay
= t
->expires
- now
;
372 int i
= t
->recurrent
- delay
;
377 io_log_event(t
->hook
, t
->data
);
383 * tm_parse_datetime - parse a date and time
384 * @x: datetime string
386 * tm_parse_datetime() takes a textual representation of
387 * a date and time (dd-mm-yyyy hh:mm:ss)
388 * and converts it to the corresponding value of type &bird_clock_t.
391 tm_parse_datetime(char *x
)
397 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
])
398 return tm_parse_date(x
);
402 if (t
== (time_t) -1)
407 * tm_parse_date - parse a date
410 * tm_parse_date() takes a textual representation of a date (dd-mm-yyyy)
411 * and converts it to the corresponding value of type &bird_clock_t.
414 tm_parse_date(char *x
)
420 if (sscanf(x
, "%d-%d-%d%n", &tm
.tm_mday
, &tm
.tm_mon
, &tm
.tm_year
, &n
) != 3 || x
[n
])
424 tm
.tm_hour
= tm
.tm_min
= tm
.tm_sec
= 0;
426 if (t
== (time_t) -1)
432 tm_format_reltime(char *x
, struct tm
*tm
, bird_clock_t delta
)
434 static char *month_names
[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
435 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
438 bsprintf(x
, "%02d:%02d", tm
->tm_hour
, tm
->tm_min
);
439 else if (delta
< 360*86400)
440 bsprintf(x
, "%s%02d", month_names
[tm
->tm_mon
], tm
->tm_mday
);
442 bsprintf(x
, "%d", tm
->tm_year
+1900);
445 #include "conf/conf.h"
448 * tm_format_datetime - convert date and time to textual representation
449 * @x: destination buffer of size %TM_DATETIME_BUFFER_SIZE
452 * This function formats the given relative time value @t to a textual
453 * date/time representation (dd-mm-yyyy hh:mm:ss) in real time.
456 tm_format_datetime(char *x
, struct timeformat
*fmt_spec
, bird_clock_t t
)
458 const char *fmt_used
;
460 bird_clock_t delta
= now
- t
;
461 t
= now_real
- delta
;
464 if (fmt_spec
->fmt1
== NULL
)
465 return tm_format_reltime(x
, tm
, delta
);
467 if ((fmt_spec
->limit
== 0) || (delta
< fmt_spec
->limit
))
468 fmt_used
= fmt_spec
->fmt1
;
470 fmt_used
= fmt_spec
->fmt2
;
472 int rv
= strftime(x
, TM_DATETIME_BUFFER_SIZE
, fmt_used
, tm
);
473 if (((rv
== 0) && fmt_used
[0]) || (rv
== TM_DATETIME_BUFFER_SIZE
))
474 strcpy(x
, "<too-long>");
481 * Socket resources represent network connections. Their data structure (&socket)
482 * contains a lot of fields defining the exact type of the socket, the local and
483 * remote addresses and ports, pointers to socket buffers and finally pointers to
484 * hook functions to be called when new data have arrived to the receive buffer
485 * (@rx_hook), when the contents of the transmit buffer have been transmitted
486 * (@tx_hook) and when an error or connection close occurs (@err_hook).
488 * Freeing of sockets from inside socket hooks is perfectly safe.
492 #define SOL_IP IPPROTO_IP
496 #define SOL_IPV6 IPPROTO_IPV6
500 #define SOL_ICMPV6 IPPROTO_ICMPV6
505 * Sockaddr helper functions
508 static inline int sockaddr_length(int af
)
509 { return (af
== AF_INET
) ? sizeof(struct sockaddr_in
) : sizeof(struct sockaddr_in6
); }
512 sockaddr_fill4(struct sockaddr_in
*sa
, ip_addr a
, struct iface
*ifa
, uint port
)
514 memset(sa
, 0, sizeof(struct sockaddr_in
));
516 sa
->sin_len
= sizeof(struct sockaddr_in
);
518 sa
->sin_family
= AF_INET
;
519 sa
->sin_port
= htons(port
);
520 sa
->sin_addr
= ipa_to_in4(a
);
524 sockaddr_fill6(struct sockaddr_in6
*sa
, ip_addr a
, struct iface
*ifa
, uint port
)
526 memset(sa
, 0, sizeof(struct sockaddr_in6
));
528 sa
->sin6_len
= sizeof(struct sockaddr_in6
);
530 sa
->sin6_family
= AF_INET6
;
531 sa
->sin6_port
= htons(port
);
532 sa
->sin6_flowinfo
= 0;
533 sa
->sin6_addr
= ipa_to_in6(a
);
535 if (ifa
&& ipa_is_link_local(a
))
536 sa
->sin6_scope_id
= ifa
->index
;
540 sockaddr_fill(sockaddr
*sa
, int af
, ip_addr a
, struct iface
*ifa
, uint port
)
543 sockaddr_fill4((struct sockaddr_in
*) sa
, a
, ifa
, port
);
544 else if (af
== AF_INET6
)
545 sockaddr_fill6((struct sockaddr_in6
*) sa
, a
, ifa
, port
);
551 sockaddr_read4(struct sockaddr_in
*sa
, ip_addr
*a
, struct iface
**ifa
, uint
*port
)
553 *port
= ntohs(sa
->sin_port
);
554 *a
= ipa_from_in4(sa
->sin_addr
);
558 sockaddr_read6(struct sockaddr_in6
*sa
, ip_addr
*a
, struct iface
**ifa
, uint
*port
)
560 *port
= ntohs(sa
->sin6_port
);
561 *a
= ipa_from_in6(sa
->sin6_addr
);
563 if (ifa
&& ipa_is_link_local(*a
))
564 *ifa
= if_find_by_index(sa
->sin6_scope_id
);
568 sockaddr_read(sockaddr
*sa
, int af
, ip_addr
*a
, struct iface
**ifa
, uint
*port
)
570 if (sa
->sa
.sa_family
!= af
)
574 sockaddr_read4((struct sockaddr_in
*) sa
, a
, ifa
, port
);
575 else if (af
== AF_INET6
)
576 sockaddr_read6((struct sockaddr_in6
*) sa
, a
, ifa
, port
);
590 * IPv6 multicast syscalls
593 /* Fortunately standardized in RFC 3493 */
595 #define INIT_MREQ6(maddr,ifa) \
596 { .ipv6mr_multiaddr = ipa_to_in6(maddr), .ipv6mr_interface = ifa->index }
599 sk_setup_multicast6(sock
*s
)
601 int index
= s
->iface
->index
;
605 if (setsockopt(s
->fd
, SOL_IPV6
, IPV6_MULTICAST_IF
, &index
, sizeof(index
)) < 0)
606 ERR("IPV6_MULTICAST_IF");
608 if (setsockopt(s
->fd
, SOL_IPV6
, IPV6_MULTICAST_HOPS
, &ttl
, sizeof(ttl
)) < 0)
609 ERR("IPV6_MULTICAST_HOPS");
611 if (setsockopt(s
->fd
, SOL_IPV6
, IPV6_MULTICAST_LOOP
, &n
, sizeof(n
)) < 0)
612 ERR("IPV6_MULTICAST_LOOP");
618 sk_join_group6(sock
*s
, ip_addr maddr
)
620 struct ipv6_mreq mr
= INIT_MREQ6(maddr
, s
->iface
);
622 if (setsockopt(s
->fd
, SOL_IPV6
, IPV6_JOIN_GROUP
, &mr
, sizeof(mr
)) < 0)
623 ERR("IPV6_JOIN_GROUP");
629 sk_leave_group6(sock
*s
, ip_addr maddr
)
631 struct ipv6_mreq mr
= INIT_MREQ6(maddr
, s
->iface
);
633 if (setsockopt(s
->fd
, SOL_IPV6
, IPV6_LEAVE_GROUP
, &mr
, sizeof(mr
)) < 0)
634 ERR("IPV6_LEAVE_GROUP");
641 * IPv6 packet control messages
644 /* Also standardized, in RFC 3542 */
647 * RFC 2292 uses IPV6_PKTINFO for both the socket option and the cmsg
648 * type, RFC 3542 changed the socket option to IPV6_RECVPKTINFO. If we
649 * don't have IPV6_RECVPKTINFO we suppose the OS implements the older
650 * RFC and we use IPV6_PKTINFO.
652 #ifndef IPV6_RECVPKTINFO
653 #define IPV6_RECVPKTINFO IPV6_PKTINFO
656 * Same goes for IPV6_HOPLIMIT -> IPV6_RECVHOPLIMIT.
658 #ifndef IPV6_RECVHOPLIMIT
659 #define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
663 #define CMSG6_SPACE_PKTINFO CMSG_SPACE(sizeof(struct in6_pktinfo))
664 #define CMSG6_SPACE_TTL CMSG_SPACE(sizeof(int))
667 sk_request_cmsg6_pktinfo(sock
*s
)
671 if (setsockopt(s
->fd
, SOL_IPV6
, IPV6_RECVPKTINFO
, &y
, sizeof(y
)) < 0)
672 ERR("IPV6_RECVPKTINFO");
678 sk_request_cmsg6_ttl(sock
*s
)
682 if (setsockopt(s
->fd
, SOL_IPV6
, IPV6_RECVHOPLIMIT
, &y
, sizeof(y
)) < 0)
683 ERR("IPV6_RECVHOPLIMIT");
689 sk_process_cmsg6_pktinfo(sock
*s
, struct cmsghdr
*cm
)
691 if (cm
->cmsg_type
== IPV6_PKTINFO
)
693 struct in6_pktinfo
*pi
= (struct in6_pktinfo
*) CMSG_DATA(cm
);
694 s
->laddr
= ipa_from_in6(pi
->ipi6_addr
);
695 s
->lifindex
= pi
->ipi6_ifindex
;
700 sk_process_cmsg6_ttl(sock
*s
, struct cmsghdr
*cm
)
702 if (cm
->cmsg_type
== IPV6_HOPLIMIT
)
703 s
->rcv_ttl
= * (int *) CMSG_DATA(cm
);
707 sk_prepare_cmsgs6(sock
*s
, struct msghdr
*msg
, void *cbuf
, size_t cbuflen
)
710 struct in6_pktinfo
*pi
;
713 msg
->msg_control
= cbuf
;
714 msg
->msg_controllen
= cbuflen
;
716 cm
= CMSG_FIRSTHDR(msg
);
717 cm
->cmsg_level
= SOL_IPV6
;
718 cm
->cmsg_type
= IPV6_PKTINFO
;
719 cm
->cmsg_len
= CMSG_LEN(sizeof(*pi
));
720 controllen
+= CMSG_SPACE(sizeof(*pi
));
722 pi
= (struct in6_pktinfo
*) CMSG_DATA(cm
);
723 pi
->ipi6_ifindex
= s
->iface
? s
->iface
->index
: 0;
724 pi
->ipi6_addr
= ipa_to_in6(s
->saddr
);
726 msg
->msg_controllen
= controllen
;
731 * Miscellaneous socket syscalls
735 sk_set_ttl4(sock
*s
, int ttl
)
737 if (setsockopt(s
->fd
, SOL_IP
, IP_TTL
, &ttl
, sizeof(ttl
)) < 0)
744 sk_set_ttl6(sock
*s
, int ttl
)
746 if (setsockopt(s
->fd
, SOL_IPV6
, IPV6_UNICAST_HOPS
, &ttl
, sizeof(ttl
)) < 0)
747 ERR("IPV6_UNICAST_HOPS");
753 sk_set_tos4(sock
*s
, int tos
)
755 if (setsockopt(s
->fd
, SOL_IP
, IP_TOS
, &tos
, sizeof(tos
)) < 0)
762 sk_set_tos6(sock
*s
, int tos
)
764 if (setsockopt(s
->fd
, SOL_IPV6
, IPV6_TCLASS
, &tos
, sizeof(tos
)) < 0)
771 sk_set_high_port(sock
*s
)
773 /* Port range setting is optional, ignore it if not supported */
778 int range
= IP_PORTRANGE_HIGH
;
779 if (setsockopt(s
->fd
, SOL_IP
, IP_PORTRANGE
, &range
, sizeof(range
)) < 0)
784 #ifdef IPV6_PORTRANGE
787 int range
= IPV6_PORTRANGE_HIGH
;
788 if (setsockopt(s
->fd
, SOL_IPV6
, IPV6_PORTRANGE
, &range
, sizeof(range
)) < 0)
789 ERR("IPV6_PORTRANGE");
797 sk_skip_ip_header(byte
*pkt
, int *len
)
799 if ((*len
< 20) || ((*pkt
& 0xf0) != 0x40))
802 int hlen
= (*pkt
& 0x0f) * 4;
803 if ((hlen
< 20) || (hlen
> *len
))
811 sk_rx_buffer(sock
*s
, int *len
)
813 if (sk_is_ipv4(s
) && (s
->type
== SK_IP
))
814 return sk_skip_ip_header(s
->rbuf
, len
);
821 * Public socket functions
825 * sk_setup_multicast - enable multicast for given socket
828 * Prepare transmission of multicast packets for given datagram socket.
829 * The socket must have defined @iface.
831 * Result: 0 for success, -1 for an error.
835 sk_setup_multicast(sock
*s
)
840 return sk_setup_multicast4(s
);
842 return sk_setup_multicast6(s
);
846 * sk_join_group - join multicast group for given socket
848 * @maddr: multicast address
850 * Join multicast group for given datagram socket and associated interface.
851 * The socket must have defined @iface.
853 * Result: 0 for success, -1 for an error.
857 sk_join_group(sock
*s
, ip_addr maddr
)
860 return sk_join_group4(s
, maddr
);
862 return sk_join_group6(s
, maddr
);
866 * sk_leave_group - leave multicast group for given socket
868 * @maddr: multicast address
870 * Leave multicast group for given datagram socket and associated interface.
871 * The socket must have defined @iface.
873 * Result: 0 for success, -1 for an error.
877 sk_leave_group(sock
*s
, ip_addr maddr
)
880 return sk_leave_group4(s
, maddr
);
882 return sk_leave_group6(s
, maddr
);
886 * sk_setup_broadcast - enable broadcast for given socket
889 * Allow reception and transmission of broadcast packets for given datagram
890 * socket. The socket must have defined @iface. For transmission, packets should
891 * be send to @brd address of @iface.
893 * Result: 0 for success, -1 for an error.
897 sk_setup_broadcast(sock
*s
)
901 if (setsockopt(s
->fd
, SOL_SOCKET
, SO_BROADCAST
, &y
, sizeof(y
)) < 0)
908 * sk_set_ttl - set transmit TTL for given socket
912 * Set TTL for already opened connections when TTL was not set before. Useful
913 * for accepted connections when different ones should have different TTL.
915 * Result: 0 for success, -1 for an error.
919 sk_set_ttl(sock
*s
, int ttl
)
924 return sk_set_ttl4(s
, ttl
);
926 return sk_set_ttl6(s
, ttl
);
930 * sk_set_min_ttl - set minimal accepted TTL for given socket
934 * Set minimal accepted TTL for given socket. Can be used for TTL security.
937 * Result: 0 for success, -1 for an error.
941 sk_set_min_ttl(sock
*s
, int ttl
)
944 return sk_set_min_ttl4(s
, ttl
);
946 return sk_set_min_ttl6(s
, ttl
);
951 * sk_set_md5_auth - add / remove MD5 security association for given socket
953 * @a: IP address of the other side
954 * @ifa: Interface for link-local IP address
955 * @passwd: password used for MD5 authentication
957 * In TCP MD5 handling code in kernel, there is a set of pairs (address,
958 * password) used to choose password according to address of the other side.
959 * This function is useful for listening socket, for active sockets it is enough
960 * to set s->password field.
962 * When called with passwd != NULL, the new pair is added,
963 * When called with passwd == NULL, the existing pair is removed.
965 * Result: 0 for success, -1 for an error.
969 sk_set_md5_auth(sock
*s
, ip_addr a
, struct iface
*ifa
, char *passwd
)
974 * sk_set_ipv6_checksum - specify IPv6 checksum offset for given socket
978 * Specify IPv6 checksum field offset for given raw IPv6 socket. After that, the
979 * kernel will automatically fill it for outgoing packets and check it for
980 * incoming packets. Should not be used on ICMPv6 sockets, where the position is
981 * known to the kernel.
983 * Result: 0 for success, -1 for an error.
987 sk_set_ipv6_checksum(sock
*s
, int offset
)
989 if (setsockopt(s
->fd
, SOL_IPV6
, IPV6_CHECKSUM
, &offset
, sizeof(offset
)) < 0)
990 ERR("IPV6_CHECKSUM");
996 sk_set_icmp6_filter(sock
*s
, int p1
, int p2
)
998 /* a bit of lame interface, but it is here only for Radv */
999 struct icmp6_filter f
;
1001 ICMP6_FILTER_SETBLOCKALL(&f
);
1002 ICMP6_FILTER_SETPASS(p1
, &f
);
1003 ICMP6_FILTER_SETPASS(p2
, &f
);
1005 if (setsockopt(s
->fd
, SOL_ICMPV6
, ICMP6_FILTER
, &f
, sizeof(f
)) < 0)
1006 ERR("ICMP6_FILTER");
1012 sk_log_error(sock
*s
, const char *p
)
1014 log(L_ERR
"%s: Socket error: %s%#m", p
, s
->err
);
1019 * Actual struct birdsock code
1022 static list sock_list
;
1023 static struct birdsock
*current_sock
;
1024 static struct birdsock
*stored_sock
;
1025 static int sock_recalc_fdsets_p
;
1027 static inline sock
*
1030 if (!s
->n
.next
->next
)
1033 return SKIP_BACK(sock
, n
, s
->n
.next
);
1037 sk_alloc_bufs(sock
*s
)
1039 if (!s
->rbuf
&& s
->rbsize
)
1040 s
->rbuf
= s
->rbuf_alloc
= xmalloc(s
->rbsize
);
1042 if (!s
->tbuf
&& s
->tbsize
)
1043 s
->tbuf
= s
->tbuf_alloc
= xmalloc(s
->tbsize
);
1044 s
->tpos
= s
->ttx
= s
->tbuf
;
1048 sk_free_bufs(sock
*s
)
1052 xfree(s
->rbuf_alloc
);
1053 s
->rbuf
= s
->rbuf_alloc
= NULL
;
1057 xfree(s
->tbuf_alloc
);
1058 s
->tbuf
= s
->tbuf_alloc
= NULL
;
1063 sk_free(resource
*r
)
1065 sock
*s
= (sock
*) r
;
1072 /* FIXME: we should call sk_stop() for SKF_THREAD sockets */
1073 if (s
->flags
& SKF_THREAD
)
1076 if (s
== current_sock
)
1077 current_sock
= sk_next(s
);
1078 if (s
== stored_sock
)
1079 stored_sock
= sk_next(s
);
1081 sock_recalc_fdsets_p
= 1;
1086 sk_set_rbsize(sock
*s
, uint val
)
1088 ASSERT(s
->rbuf_alloc
== s
->rbuf
);
1090 if (s
->rbsize
== val
)
1094 xfree(s
->rbuf_alloc
);
1095 s
->rbuf_alloc
= xmalloc(val
);
1096 s
->rpos
= s
->rbuf
= s
->rbuf_alloc
;
1100 sk_set_tbsize(sock
*s
, uint val
)
1102 ASSERT(s
->tbuf_alloc
== s
->tbuf
);
1104 if (s
->tbsize
== val
)
1107 byte
*old_tbuf
= s
->tbuf
;
1110 s
->tbuf
= s
->tbuf_alloc
= xrealloc(s
->tbuf_alloc
, val
);
1111 s
->tpos
= s
->tbuf
+ (s
->tpos
- old_tbuf
);
1112 s
->ttx
= s
->tbuf
+ (s
->ttx
- old_tbuf
);
1116 sk_set_tbuf(sock
*s
, void *tbuf
)
1118 s
->tbuf
= tbuf
?: s
->tbuf_alloc
;
1119 s
->ttx
= s
->tpos
= s
->tbuf
;
1123 sk_reallocate(sock
*s
)
1130 sk_dump(resource
*r
)
1132 sock
*s
= (sock
*) r
;
1133 static char *sk_type_names
[] = { "TCP<", "TCP>", "TCP", "UDP", NULL
, "IP", NULL
, "MAGIC", "UNIX<", "UNIX", "DEL!" };
1135 debug("(%s, ud=%p, sa=%I, sp=%d, da=%I, dp=%d, tos=%d, ttl=%d, if=%s)\n",
1136 sk_type_names
[s
->type
],
1144 s
->iface
? s
->iface
->name
: "none");
1147 static struct resclass sk_class
= {
1157 * sk_new - create a socket
1160 * This function creates a new socket resource. If you want to use it,
1161 * you need to fill in all the required fields of the structure and
1162 * call sk_open() to do the actual opening of the socket.
1164 * The real function name is sock_new(), sk_new() is a macro wrapper
1165 * to avoid collision with OpenSSL.
1170 sock
*s
= ralloc(p
, &sk_class
);
1172 // s->saddr = s->daddr = IPA_NONE;
1173 s
->tos
= s
->priority
= s
->ttl
= -1;
1184 if (fcntl(fd
, F_SETFL
, O_NONBLOCK
) < 0)
1190 if (ipa_nonzero(s
->saddr
) && !(s
->flags
& SKF_BIND
))
1191 s
->flags
|= SKF_PKTINFO
;
1193 #ifdef CONFIG_USE_HDRINCL
1194 if (sk_is_ipv4(s
) && (s
->type
== SK_IP
) && (s
->flags
& SKF_PKTINFO
))
1196 s
->flags
&= ~SKF_PKTINFO
;
1197 s
->flags
|= SKF_HDRINCL
;
1198 if (setsockopt(fd
, SOL_IP
, IP_HDRINCL
, &y
, sizeof(y
)) < 0)
1205 #ifdef SO_BINDTODEVICE
1207 strcpy(ifr
.ifr_name
, s
->iface
->name
);
1208 if (setsockopt(s
->fd
, SOL_SOCKET
, SO_BINDTODEVICE
, &ifr
, sizeof(ifr
)) < 0)
1209 ERR("SO_BINDTODEVICE");
1212 #ifdef CONFIG_UNIX_DONTROUTE
1213 if (setsockopt(s
->fd
, SOL_SOCKET
, SO_DONTROUTE
, &y
, sizeof(y
)) < 0)
1214 ERR("SO_DONTROUTE");
1218 if (s
->priority
>= 0)
1219 if (sk_set_priority(s
, s
->priority
) < 0)
1224 if (s
->flags
& SKF_LADDR_RX
)
1225 if (sk_request_cmsg4_pktinfo(s
) < 0)
1228 if (s
->flags
& SKF_TTL_RX
)
1229 if (sk_request_cmsg4_ttl(s
) < 0)
1232 if ((s
->type
== SK_UDP
) || (s
->type
== SK_IP
))
1233 if (sk_disable_mtu_disc4(s
) < 0)
1237 if (sk_set_ttl4(s
, s
->ttl
) < 0)
1241 if (sk_set_tos4(s
, s
->tos
) < 0)
1247 if (s
->flags
& SKF_V6ONLY
)
1248 if (setsockopt(fd
, SOL_IPV6
, IPV6_V6ONLY
, &y
, sizeof(y
)) < 0)
1251 if (s
->flags
& SKF_LADDR_RX
)
1252 if (sk_request_cmsg6_pktinfo(s
) < 0)
1255 if (s
->flags
& SKF_TTL_RX
)
1256 if (sk_request_cmsg6_ttl(s
) < 0)
1259 if ((s
->type
== SK_UDP
) || (s
->type
== SK_IP
))
1260 if (sk_disable_mtu_disc6(s
) < 0)
1264 if (sk_set_ttl6(s
, s
->ttl
) < 0)
1268 if (sk_set_tos6(s
, s
->tos
) < 0)
1278 add_tail(&sock_list
, &s
->n
);
1279 sock_recalc_fdsets_p
= 1;
1283 sk_tcp_connected(sock
*s
)
1286 int sa_len
= sizeof(sa
);
1288 if ((getsockname(s
->fd
, &sa
.sa
, &sa_len
) < 0) ||
1289 (sockaddr_read(&sa
, s
->af
, &s
->saddr
, &s
->iface
, &s
->sport
) < 0))
1290 log(L_WARN
"SOCK: Cannot get local IP address for TCP>");
1298 sk_passive_connected(sock
*s
, int type
)
1300 sockaddr loc_sa
, rem_sa
;
1301 int loc_sa_len
= sizeof(loc_sa
);
1302 int rem_sa_len
= sizeof(rem_sa
);
1304 int fd
= accept(s
->fd
, ((type
== SK_TCP
) ? &rem_sa
.sa
: NULL
), &rem_sa_len
);
1307 if ((errno
!= EINTR
) && (errno
!= EAGAIN
))
1308 s
->err_hook(s
, errno
);
1312 sock
*t
= sk_new(s
->pool
);
1318 t
->rbsize
= s
->rbsize
;
1319 t
->tbsize
= s
->tbsize
;
1323 if ((getsockname(fd
, &loc_sa
.sa
, &loc_sa_len
) < 0) ||
1324 (sockaddr_read(&loc_sa
, s
->af
, &t
->saddr
, &t
->iface
, &t
->sport
) < 0))
1325 log(L_WARN
"SOCK: Cannot get local IP address for TCP<");
1327 if (sockaddr_read(&rem_sa
, s
->af
, &t
->daddr
, &t
->iface
, &t
->dport
) < 0)
1328 log(L_WARN
"SOCK: Cannot get remote IP address for TCP<");
1331 if (fd
>= FD_SETSIZE
)
1333 /* FIXME: Call err_hook instead ? */
1334 log(L_ERR
"SOCK: Incoming connection from %I%J (port %d) %s",
1335 t
->daddr
, ipa_is_link_local(t
->daddr
) ? t
->iface
: NULL
,
1336 t
->dport
, "rejected due to FD_SETSIZE limit");
1343 if (sk_setup(t
) < 0)
1345 /* FIXME: Call err_hook instead ? */
1346 log(L_ERR
"SOCK: Incoming connection: %s%#m", t
->err
);
1348 /* FIXME: handle it better in rfree() */
1362 * sk_open - open a socket
1365 * This function takes a socket resource created by sk_new() and
1366 * initialized by the user and binds a corresponding network connection
1369 * Result: 0 for success, -1 for an error.
1378 ip_addr bind_addr
= IPA_NONE
;
1384 s
->ttx
= ""; /* Force s->ttx != s->tpos */
1386 case SK_TCP_PASSIVE
:
1387 fd
= socket(af
, SOCK_STREAM
, IPPROTO_TCP
);
1388 bind_port
= s
->sport
;
1389 bind_addr
= s
->saddr
;
1390 do_bind
= bind_port
|| ipa_nonzero(bind_addr
);
1394 fd
= socket(af
, SOCK_DGRAM
, IPPROTO_UDP
);
1395 bind_port
= s
->sport
;
1396 bind_addr
= (s
->flags
& SKF_BIND
) ? s
->saddr
: IPA_NONE
;
1401 fd
= socket(af
, SOCK_RAW
, s
->dport
);
1403 bind_addr
= (s
->flags
& SKF_BIND
) ? s
->saddr
: IPA_NONE
;
1404 do_bind
= ipa_nonzero(bind_addr
);
1413 bug("sk_open() called for invalid sock type %d", s
->type
);
1419 if (fd
>= FD_SETSIZE
)
1420 ERR2("FD_SETSIZE limit reached");
1425 if (sk_setup(s
) < 0)
1434 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &y
, sizeof(y
)) < 0)
1435 ERR2("SO_REUSEADDR");
1437 #ifdef CONFIG_NO_IFACE_BIND
1438 /* Workaround missing ability to bind to an iface */
1439 if ((s
->type
== SK_UDP
) && s
->iface
&& ipa_zero(bind_addr
))
1441 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &y
, sizeof(y
)) < 0)
1442 ERR2("SO_REUSEPORT");
1447 if (s
->flags
& SKF_HIGH_PORT
)
1448 if (sk_set_high_port(s
) < 0)
1449 log(L_WARN
"Socket error: %s%#m", s
->err
);
1451 sockaddr_fill(&sa
, af
, bind_addr
, s
->iface
, bind_port
);
1452 if (bind(fd
, &sa
.sa
, SA_LEN(sa
)) < 0)
1457 if (sk_set_md5_auth(s
, s
->daddr
, s
->iface
, s
->password
) < 0)
1463 sockaddr_fill(&sa
, af
, s
->daddr
, s
->iface
, s
->dport
);
1464 if (connect(fd
, &sa
.sa
, SA_LEN(sa
)) >= 0)
1465 sk_tcp_connected(s
);
1466 else if (errno
!= EINTR
&& errno
!= EAGAIN
&& errno
!= EINPROGRESS
&&
1467 errno
!= ECONNREFUSED
&& errno
!= EHOSTUNREACH
&& errno
!= ENETUNREACH
)
1471 case SK_TCP_PASSIVE
:
1472 if (listen(fd
, 8) < 0)
1483 if (!(s
->flags
& SKF_THREAD
))
1494 sk_open_unix(sock
*s
, char *name
)
1496 struct sockaddr_un sa
;
1499 /* We are sloppy during error (leak fd and not set s->err), but we die anyway */
1501 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
1505 if (fcntl(fd
, F_SETFL
, O_NONBLOCK
) < 0)
1508 /* Path length checked in test_old_bird() */
1509 sa
.sun_family
= AF_UNIX
;
1510 strcpy(sa
.sun_path
, name
);
1512 if (bind(fd
, (struct sockaddr
*) &sa
, SUN_LEN(&sa
)) < 0)
1515 if (listen(fd
, 8) < 0)
1524 #define CMSG_RX_SPACE MAX(CMSG4_SPACE_PKTINFO+CMSG4_SPACE_TTL, \
1525 CMSG6_SPACE_PKTINFO+CMSG6_SPACE_TTL)
1526 #define CMSG_TX_SPACE MAX(CMSG4_SPACE_PKTINFO,CMSG6_SPACE_PKTINFO)
1529 sk_prepare_cmsgs(sock
*s
, struct msghdr
*msg
, void *cbuf
, size_t cbuflen
)
1532 sk_prepare_cmsgs4(s
, msg
, cbuf
, cbuflen
);
1534 sk_prepare_cmsgs6(s
, msg
, cbuf
, cbuflen
);
1538 sk_process_cmsgs(sock
*s
, struct msghdr
*msg
)
1542 s
->laddr
= IPA_NONE
;
1546 for (cm
= CMSG_FIRSTHDR(msg
); cm
!= NULL
; cm
= CMSG_NXTHDR(msg
, cm
))
1548 if ((cm
->cmsg_level
== SOL_IP
) && sk_is_ipv4(s
))
1550 sk_process_cmsg4_pktinfo(s
, cm
);
1551 sk_process_cmsg4_ttl(s
, cm
);
1554 if ((cm
->cmsg_level
== SOL_IPV6
) && sk_is_ipv6(s
))
1556 sk_process_cmsg6_pktinfo(s
, cm
);
1557 sk_process_cmsg6_ttl(s
, cm
);
1566 struct iovec iov
= {s
->tbuf
, s
->tpos
- s
->tbuf
};
1567 byte cmsg_buf
[CMSG_TX_SPACE
];
1570 sockaddr_fill(&dst
, s
->af
, s
->daddr
, s
->iface
, s
->dport
);
1572 struct msghdr msg
= {
1573 .msg_name
= &dst
.sa
,
1574 .msg_namelen
= SA_LEN(dst
),
1579 #ifdef CONFIG_USE_HDRINCL
1581 struct iovec iov2
[2] = { {hdr
, 20}, iov
};
1583 if (s
->flags
& SKF_HDRINCL
)
1585 sk_prepare_ip_header(s
, hdr
, iov
.iov_len
);
1591 if (s
->flags
& SKF_PKTINFO
)
1592 sk_prepare_cmsgs(s
, &msg
, cmsg_buf
, sizeof(cmsg_buf
));
1594 return sendmsg(s
->fd
, &msg
, 0);
1600 struct iovec iov
= {s
->rbuf
, s
->rbsize
};
1601 byte cmsg_buf
[CMSG_RX_SPACE
];
1604 struct msghdr msg
= {
1605 .msg_name
= &src
.sa
,
1606 .msg_namelen
= sizeof(src
), // XXXX ??
1609 .msg_control
= cmsg_buf
,
1610 .msg_controllen
= sizeof(cmsg_buf
),
1614 int rv
= recvmsg(s
->fd
, &msg
, 0);
1619 // if (cf_type == SK_IP)
1620 // rv = ipv4_skip_header(pbuf, rv);
1623 sockaddr_read(&src
, s
->af
, &s
->faddr
, NULL
, &s
->fport
);
1624 sk_process_cmsgs(s
, &msg
);
1626 if (msg
.msg_flags
& MSG_TRUNC
)
1627 s
->flags
|= SKF_TRUNCATED
;
1629 s
->flags
&= ~SKF_TRUNCATED
;
1635 static inline void reset_tx_buffer(sock
*s
) { s
->ttx
= s
->tpos
= s
->tbuf
; }
1638 sk_maybe_write(sock
*s
)
1647 while (s
->ttx
!= s
->tpos
)
1649 e
= write(s
->fd
, s
->ttx
, s
->tpos
- s
->ttx
);
1653 if (errno
!= EINTR
&& errno
!= EAGAIN
)
1656 /* EPIPE is just a connection close notification during TX */
1657 s
->err_hook(s
, (errno
!= EPIPE
) ? errno
: 0);
1670 if (s
->tbuf
== s
->tpos
)
1677 if (errno
!= EINTR
&& errno
!= EAGAIN
)
1680 s
->err_hook(s
, errno
);
1692 bug("sk_maybe_write: unknown socket type %d", s
->type
);
1697 sk_rx_ready(sock
*s
)
1700 struct timeval timo
;
1711 rv
= select(s
->fd
+1, &rd
, &wr
, NULL
, &timo
);
1713 if ((rv
< 0) && (errno
== EINTR
|| errno
== EAGAIN
))
1720 * sk_send - send data to a socket
1722 * @len: number of bytes to send
1724 * This function sends @len bytes of data prepared in the
1725 * transmit buffer of the socket @s to the network connection.
1726 * If the packet can be sent immediately, it does so and returns
1727 * 1, else it queues the packet for later processing, returns 0
1728 * and calls the @tx_hook of the socket when the tranmission
1732 sk_send(sock
*s
, unsigned len
)
1735 s
->tpos
= s
->tbuf
+ len
;
1736 return sk_maybe_write(s
);
1740 * sk_send_to - send data to a specific destination
1742 * @len: number of bytes to send
1743 * @addr: IP address to send the packet to
1744 * @port: port to send the packet to
1746 * This is a sk_send() replacement for connection-less packet sockets
1747 * which allows destination of the packet to be chosen dynamically.
1748 * Raw IP sockets should use 0 for @port.
1751 sk_send_to(sock
*s
, unsigned len
, ip_addr addr
, unsigned port
)
1758 s
->tpos
= s
->tbuf
+ len
;
1759 return sk_maybe_write(s
);
1764 sk_send_full(sock *s, unsigned len, struct iface *ifa,
1765 ip_addr saddr, ip_addr daddr, unsigned dport)
1772 s->tpos = s->tbuf + len;
1773 return sk_maybe_write(s);
1777 /* sk_read() and sk_write() are called from BFD's event loop */
1784 case SK_TCP_PASSIVE
:
1785 return sk_passive_connected(s
, SK_TCP
);
1787 case SK_UNIX_PASSIVE
:
1788 return sk_passive_connected(s
, SK_UNIX
);
1793 int c
= read(s
->fd
, s
->rpos
, s
->rbuf
+ s
->rbsize
- s
->rpos
);
1797 if (errno
!= EINTR
&& errno
!= EAGAIN
)
1798 s
->err_hook(s
, errno
);
1805 if (s
->rx_hook(s
, s
->rpos
- s
->rbuf
))
1807 /* We need to be careful since the socket could have been deleted by the hook */
1808 if (current_sock
== s
)
1817 return s
->rx_hook(s
, 0);
1821 int e
= sk_recvmsg(s
);
1825 if (errno
!= EINTR
&& errno
!= EAGAIN
)
1826 s
->err_hook(s
, errno
);
1830 s
->rpos
= s
->rbuf
+ e
;
1845 sockaddr_fill(&sa
, s
->af
, s
->daddr
, s
->iface
, s
->dport
);
1847 if (connect(s
->fd
, &sa
.sa
, SA_LEN(sa
)) >= 0 || errno
== EISCONN
)
1848 sk_tcp_connected(s
);
1849 else if (errno
!= EINTR
&& errno
!= EAGAIN
&& errno
!= EINPROGRESS
)
1850 s
->err_hook(s
, errno
);
1855 if (s
->ttx
!= s
->tpos
&& sk_maybe_write(s
) > 0)
1871 debug("Open sockets:\n");
1872 WALK_LIST(n
, sock_list
)
1874 s
= SKIP_BACK(sock
, n
, n
);
1883 * Internal event log and watchdog
1886 #define EVENT_LOG_LENGTH 32
1888 struct event_log_entry
1896 static struct event_log_entry event_log
[EVENT_LOG_LENGTH
];
1897 static struct event_log_entry
*event_open
;
1898 static int event_log_pos
, event_log_num
, watchdog_active
;
1899 static btime last_time
;
1900 static btime loop_time
;
1903 io_update_time(void)
1908 if (!clock_monotonic_available
)
1912 * This is third time-tracking procedure (after update_times() above and
1913 * times_update() in BFD), dedicated to internal event log and latency
1914 * tracking. Hopefully, we consolidate these sometimes.
1917 rv
= clock_gettime(CLOCK_MONOTONIC
, &ts
);
1919 die("clock_gettime: %m");
1921 last_time
= ((s64
) ts
.tv_sec S
) + (ts
.tv_nsec
/ 1000);
1925 event_open
->duration
= last_time
- event_open
->timestamp
;
1927 if (event_open
->duration
> config
->latency_limit
)
1928 log(L_WARN
"Event 0x%p 0x%p took %d ms",
1929 event_open
->hook
, event_open
->data
, (int) (event_open
->duration TO_MS
));
1936 * io_log_event - mark approaching event into event log
1937 * @hook: event hook address
1938 * @data: event data address
1940 * Store info (hook, data, timestamp) about the following internal event into
1941 * a circular event log (@event_log). When latency tracking is enabled, the log
1942 * entry is kept open (in @event_open) so the duration can be filled later.
1945 io_log_event(void *hook
, void *data
)
1947 if (config
->latency_debug
)
1950 struct event_log_entry
*en
= event_log
+ event_log_pos
;
1954 en
->timestamp
= last_time
;
1959 event_log_pos
%= EVENT_LOG_LENGTH
;
1961 event_open
= config
->latency_debug
? en
: NULL
;
1965 io_close_event(void)
1976 log(L_DEBUG
"Event log:");
1977 for (i
= 0; i
< EVENT_LOG_LENGTH
; i
++)
1979 struct event_log_entry
*en
= event_log
+ (event_log_pos
+ i
) % EVENT_LOG_LENGTH
;
1981 log(L_DEBUG
" Event 0x%p 0x%p at %8d for %d ms", en
->hook
, en
->data
,
1982 (int) ((last_time
- en
->timestamp
) TO_MS
), (int) (en
->duration TO_MS
));
1987 watchdog_sigalrm(int sig UNUSED
)
1989 /* Update last_time and duration, but skip latency check */
1990 config
->latency_limit
= 0xffffffff;
1993 /* We want core dump */
1998 watchdog_start1(void)
2002 loop_time
= last_time
;
2006 watchdog_start(void)
2010 loop_time
= last_time
;
2013 if (config
->watchdog_timeout
)
2015 alarm(config
->watchdog_timeout
);
2016 watchdog_active
= 1;
2025 if (watchdog_active
)
2028 watchdog_active
= 0;
2031 btime duration
= last_time
- loop_time
;
2032 if (duration
> config
->watchdog_warning
)
2033 log(L_WARN
"I/O loop cycle took %d ms for %d events",
2034 (int) (duration TO_MS
), event_log_num
);
2042 volatile int async_config_flag
; /* Asynchronous reconfiguration/dump scheduled */
2043 volatile int async_dump_flag
;
2048 init_list(&near_timers
);
2049 init_list(&far_timers
);
2050 init_list(&sock_list
);
2051 init_list(&global_event_list
);
2056 srandom((int) now_real
);
2059 static int short_loops
= 0;
2060 #define SHORT_LOOP_MAX 10
2066 struct timeval timo
;
2073 sock_recalc_fdsets_p
= 1;
2076 events
= ev_run_list(&global_event_list
);
2078 tout
= tm_first_shot();
2084 timo
.tv_sec
= events
? 0 : MIN(tout
- now
, 3);
2089 if (sock_recalc_fdsets_p
)
2091 sock_recalc_fdsets_p
= 0;
2097 WALK_LIST(n
, sock_list
)
2099 s
= SKIP_BACK(sock
, n
, n
);
2108 if (s
->tx_hook
&& s
->ttx
!= s
->tpos
)
2119 * Yes, this is racy. But even if the signal comes before this test
2120 * and entering select(), it gets caught on the next timer tick.
2123 if (async_config_flag
)
2125 io_log_event(async_config
, NULL
);
2127 async_config_flag
= 0;
2130 if (async_dump_flag
)
2132 io_log_event(async_dump
, NULL
);
2134 async_dump_flag
= 0;
2137 if (async_shutdown_flag
)
2139 io_log_event(async_shutdown
, NULL
);
2141 async_shutdown_flag
= 0;
2145 /* And finally enter select() to find active sockets */
2147 hi
= select(hi
+1, &rd
, &wr
, NULL
, &timo
);
2152 if (errno
== EINTR
|| errno
== EAGAIN
)
2158 /* guaranteed to be non-empty */
2159 current_sock
= SKIP_BACK(sock
, n
, HEAD(sock_list
));
2161 while (current_sock
)
2163 sock
*s
= current_sock
;
2168 if ((s
->type
>= SK_MAGIC
) && FD_ISSET(s
->fd
, &rd
) && s
->rx_hook
)
2172 io_log_event(s
->rx_hook
, s
->data
);
2174 if (s
!= current_sock
)
2177 while (e
&& s
->rx_hook
&& steps
);
2180 if (FD_ISSET(s
->fd
, &wr
))
2184 io_log_event(s
->tx_hook
, s
->data
);
2186 if (s
!= current_sock
)
2190 current_sock
= sk_next(s
);
2195 if (events
&& (short_loops
< SHORT_LOOP_MAX
))
2200 current_sock
= stored_sock
;
2201 if (current_sock
== NULL
)
2202 current_sock
= SKIP_BACK(sock
, n
, HEAD(sock_list
));
2204 while (current_sock
&& count
< MAX_RX_STEPS
)
2206 sock
*s
= current_sock
;
2209 if ((s
->type
< SK_MAGIC
) && FD_ISSET(s
->fd
, &rd
) && s
->rx_hook
)
2212 io_log_event(s
->rx_hook
, s
->data
);
2214 if (s
!= current_sock
)
2217 current_sock
= sk_next(s
);
2221 stored_sock
= current_sock
;
2227 test_old_bird(char *path
)
2230 struct sockaddr_un sa
;
2232 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
2234 die("Cannot create socket: %m");
2235 if (strlen(path
) >= sizeof(sa
.sun_path
))
2236 die("Socket path too long");
2237 bzero(&sa
, sizeof(sa
));
2238 sa
.sun_family
= AF_UNIX
;
2239 strcpy(sa
.sun_path
, path
);
2240 if (connect(fd
, (struct sockaddr
*) &sa
, SUN_LEN(&sa
)) == 0)
2241 die("I found another BIRD running.");