… | |
… | |
197 | } |
197 | } |
198 | |
198 | |
199 | static void |
199 | static void |
200 | pkt_cksum (PKT *pkt) |
200 | pkt_cksum (PKT *pkt) |
201 | { |
201 | { |
202 | uint_fast32_t sum = -pkt->cksum; |
202 | uint_fast32_t sum = 0; |
203 | uint32_t *wp = (uint32_t *)pkt; |
203 | uint32_t *wp = (uint32_t *)pkt; |
204 | int len = sizeof (*pkt) / 4; |
204 | int len = sizeof (*pkt) / 4; |
205 | |
205 | |
206 | do |
206 | do |
207 | { |
207 | { |
208 | uint_fast32_t w = *(volatile uint32_t *)wp++; |
208 | uint_fast32_t w = *(volatile uint32_t *)wp++; |
209 | sum += (w & 0xffff) + (w >> 16); |
209 | sum += (w & 0xffff) + (w >> 16); |
210 | } |
210 | } |
211 | while (len--); |
211 | while (--len); |
212 | |
212 | |
213 | sum = (sum >> 16) + (sum & 0xffff); /* add high 16 to low 16 */ |
213 | sum = (sum >> 16) + (sum & 0xffff); /* add high 16 to low 16 */ |
214 | sum += sum >> 16; /* add carry */ |
214 | sum += sum >> 16; /* add carry */ |
215 | |
215 | |
216 | pkt->cksum = ~sum; |
216 | pkt->cksum = ~sum; |
… | |
… | |
268 | |
268 | |
269 | if (addrlen == 4) |
269 | if (addrlen == 4) |
270 | { |
270 | { |
271 | struct sockaddr_in sa; |
271 | struct sockaddr_in sa; |
272 | |
272 | |
273 | pkt->type = ICMP4_ECHO; |
273 | pkt->type = ICMP4_ECHO; |
274 | pkt_cksum (pkt); |
274 | pkt_cksum (pkt); |
275 | |
275 | |
276 | sa.sin_family = AF_INET; |
276 | sa.sin_family = AF_INET; |
277 | sa.sin_port = 0; |
277 | sa.sin_port = 0; |
278 | |
278 | |
… | |
… | |
636 | LEAVE; |
636 | LEAVE; |
637 | } |
637 | } |
638 | #endif |
638 | #endif |
639 | |
639 | |
640 | static void |
640 | static void |
641 | boot () |
641 | boot_protocols (void) |
642 | { |
642 | { |
643 | if (pipe (thr_res) < 0) |
|
|
644 | croak ("AnyEvent::FastPing: unable to create receive pipe"); |
|
|
645 | |
|
|
646 | sv_setiv (get_sv ("AnyEvent::FastPing::THR_RES_FD", 1), thr_res [0]); |
|
|
647 | |
|
|
648 | icmp4_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); |
643 | icmp4_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); |
649 | fcntl (icmp4_fd, F_SETFL, O_NONBLOCK); |
644 | fcntl (icmp4_fd, F_SETFL, O_NONBLOCK); |
650 | #ifdef ICMP_FILTER |
645 | #ifdef ICMP_FILTER |
651 | { |
646 | { |
652 | struct icmp_filter oval; |
647 | struct icmp_filter oval; |
… | |
… | |
665 | ICMP6_FILTER_SETPASS (ICMP6_ECHO_REPLY, &oval); |
660 | ICMP6_FILTER_SETPASS (ICMP6_ECHO_REPLY, &oval); |
666 | setsockopt (icmp6_fd, IPPROTO_ICMPV6, ICMP6_FILTER, &oval, sizeof oval); |
661 | setsockopt (icmp6_fd, IPPROTO_ICMPV6, ICMP6_FILTER, &oval, sizeof oval); |
667 | } |
662 | } |
668 | # endif |
663 | # endif |
669 | #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 (); |
670 | |
676 | |
671 | sv_setiv (get_sv ("AnyEvent::FastPing::ICMP4_FD", 1), icmp4_fd); |
677 | sv_setiv (get_sv ("AnyEvent::FastPing::ICMP4_FD", 1), icmp4_fd); |
672 | sv_setiv (get_sv ("AnyEvent::FastPing::ICMP6_FD", 1), icmp6_fd); |
678 | sv_setiv (get_sv ("AnyEvent::FastPing::ICMP6_FD", 1), icmp6_fd); |
673 | } |
679 | } |
674 | |
680 | |
675 | #define NOT_RUNNING \ |
681 | #define NOT_RUNNING \ |
676 | if (self->running) \ |
682 | if (self->running) \ |
677 | 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"); |
678 | |
684 | |
679 | MODULE = AnyEvent::FastPing PACKAGE = AnyEvent::FastPing PREFIX = pinger_ |
685 | MODULE = AnyEvent::FastPing PACKAGE = AnyEvent::FastPing PREFIX = pinger_ |
680 | |
686 | |
|
|
687 | PROTOTYPES: DISABLE |
|
|
688 | |
681 | BOOT: |
689 | BOOT: |
682 | { |
690 | { |
683 | HV *stash = gv_stashpv ("AnyEvent::FastPing", 1); |
691 | HV *stash = gv_stashpv ("AnyEvent::FastPing", 1); |
684 | |
692 | |
685 | if (sizeof (PKT) & 3) |
693 | if (sizeof (PKT) & 3) |
686 | croak ("size of PKT structure is not a multiple of 4"); |
694 | croak ("size of PKT structure is not a multiple of 4"); |
687 | |
695 | |
688 | boot (); |
|
|
689 | |
|
|
690 | newCONSTSUB (stash, "ipv4_supported", newSViv (icmp4_fd >= 0)); |
|
|
691 | newCONSTSUB (stash, "ipv6_supported", newSViv (icmp6_fd >= 0)); |
|
|
692 | |
|
|
693 | newCONSTSUB (stash, "icmp4_pktsize", newSViv (HDR_SIZE_IP4 + sizeof (PKT))); |
696 | newCONSTSUB (stash, "icmp4_pktsize", newSViv (HDR_SIZE_IP4 + sizeof (PKT))); |
694 | newCONSTSUB (stash, "icmp6_pktsize", newSViv (HDR_SIZE_IP6 + sizeof (PKT))); |
697 | newCONSTSUB (stash, "icmp6_pktsize", newSViv (HDR_SIZE_IP6 + sizeof (PKT))); |
695 | } |
|
|
696 | |
698 | |
697 | 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 (); |
698 | |
712 | |
699 | void |
713 | void |
700 | _recv_icmp4 (...) |
714 | _recv_icmp4 (...) |
701 | CODE: |
715 | CODE: |
702 | { |
716 | { |