ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-FastPing/FastPing.xs
(Generate patch)

Comparing AnyEvent-FastPing/FastPing.xs (file contents):
Revision 1.12 by root, Wed Feb 2 19:26:45 2011 UTC vs.
Revision 1.15 by root, Sat Nov 12 01:20:46 2016 UTC

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
198static void 199static void
199pkt_cksum (PKT *pkt) 200pkt_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;
237static int 238static int
238range_send_ping (RANGE *self, PKT *pkt) 239range_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
427static void 451static void
428pinger_start (PINGER *self) 452pinger_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
616static void 640static void
617boot () 641boot_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
667static void
668boot (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
655MODULE = AnyEvent::FastPing PACKAGE = AnyEvent::FastPing PREFIX = pinger_ 685MODULE = AnyEvent::FastPing PACKAGE = AnyEvent::FastPing PREFIX = pinger_
656 686
687PROTOTYPES: DISABLE
688
657BOOT: 689BOOT:
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
673PROTOTYPES: 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
708void
709_boot ()
710 CODE:
711 boot ();
674 712
675void 713void
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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines