… | |
… | |
18 | #include <poll.h> |
18 | #include <poll.h> |
19 | #include <unistd.h> |
19 | #include <unistd.h> |
20 | #include <inttypes.h> |
20 | #include <inttypes.h> |
21 | #include <fcntl.h> |
21 | #include <fcntl.h> |
22 | #include <errno.h> |
22 | #include <errno.h> |
|
|
23 | #include <limits.h> |
23 | |
24 | |
24 | #include <sys/types.h> |
25 | #include <sys/types.h> |
25 | #include <sys/time.h> |
26 | #include <sys/time.h> |
26 | #include <sys/socket.h> |
27 | #include <sys/socket.h> |
27 | |
28 | |
… | |
… | |
196 | } |
197 | } |
197 | |
198 | |
198 | static void |
199 | static void |
199 | pkt_cksum (PKT *pkt) |
200 | pkt_cksum (PKT *pkt) |
200 | { |
201 | { |
201 | uint_fast32_t sum = -pkt->cksum; |
202 | uint_fast32_t sum = 0; |
202 | uint32_t *wp = (uint32_t *)pkt; |
203 | uint32_t *wp = (uint32_t *)pkt; |
203 | int len = sizeof (*pkt) / 4; |
204 | int len = sizeof (*pkt) / 4; |
204 | |
205 | |
205 | do |
206 | do |
206 | { |
207 | { |
207 | uint_fast32_t w = *(volatile uint32_t *)wp++; |
208 | uint_fast32_t w = *(volatile uint32_t *)wp++; |
208 | sum += (w & 0xffff) + (w >> 16); |
209 | sum += (w & 0xffff) + (w >> 16); |
209 | } |
210 | } |
210 | while (len--); |
211 | while (--len); |
211 | |
212 | |
212 | sum = (sum >> 16) + (sum & 0xffff); /* add high 16 to low 16 */ |
213 | sum = (sum >> 16) + (sum & 0xffff); /* add high 16 to low 16 */ |
213 | sum += sum >> 16; /* add carry */ |
214 | sum += sum >> 16; /* add carry */ |
214 | |
215 | |
215 | pkt->cksum = ~sum; |
216 | pkt->cksum = ~sum; |
… | |
… | |
237 | static int |
238 | static int |
238 | range_send_ping (RANGE *self, PKT *pkt) |
239 | range_send_ping (RANGE *self, PKT *pkt) |
239 | { |
240 | { |
240 | // send ping |
241 | // send ping |
241 | uint8_t *addr; |
242 | uint8_t *addr; |
|
|
243 | int addrlen; |
242 | |
244 | |
243 | if (self->addrcnt) |
245 | if (self->addrcnt) |
244 | addr = (self->addrcnt - 1) * self->addrlen + (uint8_t *)(self + 1); |
246 | addr = (self->addrcnt - 1) * self->addrlen + (uint8_t *)(self + 1); |
245 | else |
247 | else |
246 | addr = sizeof (addr_tt) - self->addrlen + self->lo; |
248 | addr = sizeof (addr_tt) - self->addrlen + self->lo; |
247 | |
249 | |
|
|
250 | addrlen = self->addrlen; |
|
|
251 | |
|
|
252 | /* convert ipv4 mapped addresses - this only works for host lists */ |
|
|
253 | /* this tries to match 0000:0000:0000:0000:0000:ffff:a.b.c.d */ |
|
|
254 | /* efficiently but also with few insns */ |
|
|
255 | if (addrlen == 16 && !addr [0] && icmp4_fd >= 0 |
|
|
256 | && !( addr [ 1] |
|
|
257 | | addr [ 2] | addr [ 3] |
|
|
258 | | addr [ 4] | addr [ 5] |
|
|
259 | | addr [ 6] | addr [ 7] |
|
|
260 | | addr [ 8] | addr [ 9] |
|
|
261 | | (255-addr [10]) | (255-addr [11]))) |
|
|
262 | { |
|
|
263 | addr += 12; |
|
|
264 | addrlen -= 12; |
|
|
265 | } |
|
|
266 | |
248 | pkt->cksum = 0; |
267 | pkt->cksum = 0; |
249 | |
268 | |
250 | if (self->addrlen == 4) |
269 | if (addrlen == 4) |
251 | { |
270 | { |
252 | struct sockaddr_in sa; |
271 | struct sockaddr_in sa; |
253 | |
272 | |
254 | pkt->type = ICMP4_ECHO; |
273 | pkt->type = ICMP4_ECHO; |
255 | pkt_cksum (pkt); |
274 | pkt_cksum (pkt); |
256 | |
275 | |
257 | sa.sin_family = AF_INET; |
276 | sa.sin_family = AF_INET; |
258 | sa.sin_port = 0; |
277 | sa.sin_port = 0; |
259 | |
278 | |
… | |
… | |
422 | return 0; |
441 | return 0; |
423 | } |
442 | } |
424 | |
443 | |
425 | /*****************************************************************************/ |
444 | /*****************************************************************************/ |
426 | |
445 | |
|
|
446 | /* NetBSD, Solaris... */ |
|
|
447 | #ifndef PTHREAD_STACK_MIN |
|
|
448 | # define PTHREAD_STACK_MIN 0 |
|
|
449 | #endif |
|
|
450 | |
427 | static void |
451 | static void |
428 | pinger_start (PINGER *self) |
452 | pinger_start (PINGER *self) |
429 | { |
453 | { |
430 | sigset_t fullsigset, oldsigset; |
454 | sigset_t fullsigset, oldsigset; |
431 | pthread_attr_t attr; |
455 | pthread_attr_t attr; |
… | |
… | |
612 | LEAVE; |
636 | LEAVE; |
613 | } |
637 | } |
614 | #endif |
638 | #endif |
615 | |
639 | |
616 | static void |
640 | static void |
617 | boot () |
641 | boot_protocols (void) |
618 | { |
642 | { |
619 | if (pipe (thr_res) < 0) |
|
|
620 | croak ("AnyEvent::FastPing: unable to create receive pipe"); |
|
|
621 | |
|
|
622 | sv_setiv (get_sv ("AnyEvent::FastPing::THR_RES_FD", 1), thr_res [0]); |
|
|
623 | |
|
|
624 | icmp4_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); |
643 | icmp4_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); |
625 | fcntl (icmp4_fd, F_SETFL, O_NONBLOCK); |
644 | fcntl (icmp4_fd, F_SETFL, O_NONBLOCK); |
626 | #ifdef ICMP_FILTER |
645 | #ifdef ICMP_FILTER |
627 | { |
646 | { |
628 | struct icmp_filter oval; |
647 | struct icmp_filter oval; |
… | |
… | |
641 | ICMP6_FILTER_SETPASS (ICMP6_ECHO_REPLY, &oval); |
660 | ICMP6_FILTER_SETPASS (ICMP6_ECHO_REPLY, &oval); |
642 | setsockopt (icmp6_fd, IPPROTO_ICMPV6, ICMP6_FILTER, &oval, sizeof oval); |
661 | setsockopt (icmp6_fd, IPPROTO_ICMPV6, ICMP6_FILTER, &oval, sizeof oval); |
643 | } |
662 | } |
644 | # endif |
663 | # endif |
645 | #endif |
664 | #endif |
|
|
665 | } |
|
|
666 | |
|
|
667 | static void |
|
|
668 | boot (void) |
|
|
669 | { |
|
|
670 | if (pipe (thr_res) < 0) |
|
|
671 | croak ("AnyEvent::FastPing: unable to create receive pipe"); |
|
|
672 | |
|
|
673 | sv_setiv (get_sv ("AnyEvent::FastPing::THR_RES_FD", 1), thr_res [0]); |
|
|
674 | |
|
|
675 | boot_protocols (); |
646 | |
676 | |
647 | sv_setiv (get_sv ("AnyEvent::FastPing::ICMP4_FD", 1), icmp4_fd); |
677 | sv_setiv (get_sv ("AnyEvent::FastPing::ICMP4_FD", 1), icmp4_fd); |
648 | sv_setiv (get_sv ("AnyEvent::FastPing::ICMP6_FD", 1), icmp6_fd); |
678 | sv_setiv (get_sv ("AnyEvent::FastPing::ICMP6_FD", 1), icmp6_fd); |
649 | } |
679 | } |
650 | |
680 | |
651 | #define NOT_RUNNING \ |
681 | #define NOT_RUNNING \ |
652 | if (self->running) \ |
682 | if (self->running) \ |
653 | croak ("AnyEvent::FastPing object has been started - you have to sotp t first before calling this method, caught"); |
683 | croak ("AnyEvent::FastPing object has been started - you have to stop it first before calling this method, caught"); |
654 | |
684 | |
655 | MODULE = AnyEvent::FastPing PACKAGE = AnyEvent::FastPing PREFIX = pinger_ |
685 | MODULE = AnyEvent::FastPing PACKAGE = AnyEvent::FastPing PREFIX = pinger_ |
656 | |
686 | |
|
|
687 | PROTOTYPES: DISABLE |
|
|
688 | |
657 | BOOT: |
689 | BOOT: |
658 | { |
690 | { |
659 | HV *stash = gv_stashpv ("AnyEvent::FastPing", 1); |
691 | HV *stash = gv_stashpv ("AnyEvent::FastPing", 1); |
660 | |
692 | |
661 | if (sizeof (PKT) & 3) |
693 | if (sizeof (PKT) & 3) |
662 | croak ("size of PKT structure is not a multiple of 4"); |
694 | croak ("size of PKT structure is not a multiple of 4"); |
663 | |
695 | |
664 | boot (); |
|
|
665 | |
|
|
666 | newCONSTSUB (stash, "ipv4_supported", newSViv (icmp4_fd >= 0)); |
|
|
667 | newCONSTSUB (stash, "ipv6_supported", newSViv (icmp6_fd >= 0)); |
|
|
668 | |
|
|
669 | newCONSTSUB (stash, "icmp4_pktsize", newSViv (HDR_SIZE_IP4 + sizeof (PKT))); |
696 | newCONSTSUB (stash, "icmp4_pktsize", newSViv (HDR_SIZE_IP4 + sizeof (PKT))); |
670 | newCONSTSUB (stash, "icmp6_pktsize", newSViv (HDR_SIZE_IP6 + sizeof (PKT))); |
697 | newCONSTSUB (stash, "icmp6_pktsize", newSViv (HDR_SIZE_IP6 + sizeof (PKT))); |
671 | } |
|
|
672 | |
698 | |
673 | PROTOTYPES: DISABLE |
699 | boot_protocols (); |
|
|
700 | |
|
|
701 | newCONSTSUB (stash, "ipv4_supported", newSViv (icmp4_fd >= 0)); |
|
|
702 | newCONSTSUB (stash, "ipv6_supported", newSViv (icmp6_fd >= 0)); |
|
|
703 | |
|
|
704 | close (icmp4_fd); |
|
|
705 | close (icmp6_fd); |
|
|
706 | } |
|
|
707 | |
|
|
708 | void |
|
|
709 | _boot () |
|
|
710 | CODE: |
|
|
711 | boot (); |
674 | |
712 | |
675 | void |
713 | void |
676 | _recv_icmp4 (...) |
714 | _recv_icmp4 (...) |
677 | CODE: |
715 | CODE: |
678 | { |
716 | { |
… | |
… | |
842 | CODE: |
880 | CODE: |
843 | { |
881 | { |
844 | AV *av; |
882 | AV *av; |
845 | int i, j, k; |
883 | int i, j, k; |
846 | int cnt; |
884 | int cnt; |
847 | int addrlen; |
885 | int addrlen = 0; |
848 | RANGE *range; |
886 | RANGE *range; |
849 | NOT_RUNNING; |
887 | NOT_RUNNING; |
850 | |
888 | |
851 | if (!SvROK (addrs) || SvTYPE (SvRV (addrs)) != SVt_PVAV) |
889 | if (!SvROK (addrs) || SvTYPE (SvRV (addrs)) != SVt_PVAV) |
852 | croak ("AnyEvent::FastPing::add_hosts expects an arrayref with binary IPv4 or IPv6 addresses"); |
890 | croak ("AnyEvent::FastPing::add_hosts expects an arrayref with binary IPv4 or IPv6 addresses"); |
853 | |
891 | |
854 | av = (AV *)SvRV (addrs); |
892 | av = (AV *)SvRV (addrs); |
855 | cnt = av_len (av) + 1; |
893 | cnt = av_len (av) + 1; |
856 | |
894 | |
|
|
895 | for (i = 0; i < cnt; ++i) |
|
|
896 | { |
|
|
897 | SV *sv = *av_fetch (av, i, 1); |
|
|
898 | sv_utf8_downgrade (sv, 0); |
|
|
899 | |
|
|
900 | j = SvCUR (sv); |
|
|
901 | |
|
|
902 | if (j != 4 && j != 16) |
|
|
903 | croak ("AnyEvent::FastPing::add_hosts addresses must be specified as binary IPv4 or IPv6 addresses"); |
|
|
904 | |
|
|
905 | if (j > addrlen) |
|
|
906 | addrlen = j; |
|
|
907 | } |
|
|
908 | |
857 | if (!cnt) |
909 | if (!cnt) |
858 | XSRETURN_EMPTY; |
910 | XSRETURN_EMPTY; |
859 | |
|
|
860 | addrlen = SvCUR (*av_fetch (av, 0, 1)); |
|
|
861 | |
|
|
862 | if (addrlen != 4 && addrlen != 16) |
|
|
863 | croak ("AnyEvent::FastPing::add_hosts addresses must be specified as binary IPv4 or IPv6 addresses"); |
|
|
864 | |
|
|
865 | for (i = cnt; --i; ) |
|
|
866 | { |
|
|
867 | SV *sv = *av_fetch (av, i, 1); |
|
|
868 | |
|
|
869 | if (!sv_utf8_downgrade (sv, 1) || addrlen != SvCUR (sv)) |
|
|
870 | croak ("AnyEvent::FastPing::add_hosts addresses must all have the same size"); |
|
|
871 | } |
|
|
872 | |
911 | |
873 | range = calloc (1, sizeof (RANGE) + cnt * addrlen); |
912 | range = calloc (1, sizeof (RANGE) + cnt * addrlen); |
874 | |
913 | |
875 | range->next = 0; |
914 | range->next = 0; |
876 | range->interval = interval > MIN_INTERVAL ? interval : MIN_INTERVAL; |
915 | range->interval = interval > MIN_INTERVAL ? interval : MIN_INTERVAL; |
… | |
… | |
881 | interleave = cnt <= 256 * 256 ? 256 : (int)sqrtf (cnt); |
920 | interleave = cnt <= 256 * 256 ? 256 : (int)sqrtf (cnt); |
882 | |
921 | |
883 | k = cnt; |
922 | k = cnt; |
884 | for (j = 0; j < interleave; ++j) |
923 | for (j = 0; j < interleave; ++j) |
885 | for (i = j; i < cnt; i += interleave) |
924 | for (i = j; i < cnt; i += interleave) |
|
|
925 | { |
886 | memcpy ((uint8_t *)(range + 1) + --k * addrlen, |
926 | uint8_t *dst = (uint8_t *)(range + 1) + --k * addrlen; |
887 | SvPVbyte_nolen (*av_fetch (av, i, 1)), |
927 | char *pv; |
888 | addrlen); |
928 | STRLEN pvlen; |
|
|
929 | SV *sv = *av_fetch (av, i, 1); |
|
|
930 | sv_utf8_downgrade (sv, 0); |
|
|
931 | |
|
|
932 | pv = SvPVbyte (sv, pvlen); |
|
|
933 | |
|
|
934 | if (pvlen != addrlen) |
|
|
935 | { |
|
|
936 | dst [ 0] = 0x00; dst [ 1] = 0x00; dst [ 2] = 0x00; dst [ 3] = 0x00; |
|
|
937 | dst [ 4] = 0x00; dst [ 5] = 0x00; dst [ 6] = 0x00; dst [ 7] = 0x00; |
|
|
938 | dst [ 8] = 0x00; dst [ 9] = 0x00; dst [10] = 0xff; dst [11] = 0xff; |
|
|
939 | dst [12] = pv [0]; dst [13] = pv [1]; dst [14] = pv [2]; dst [15] = pv [3]; |
|
|
940 | } |
|
|
941 | else |
|
|
942 | memcpy (dst, pv, addrlen); |
|
|
943 | } |
889 | |
944 | |
890 | pinger_add_range (self, range); |
945 | pinger_add_range (self, range); |
891 | } |
946 | } |
892 | |
947 | |