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

Comparing AnyEvent-FastPing/FPing.xs (file contents):
Revision 1.4 by root, Fri May 4 15:16:14 2007 UTC vs.
Revision 1.7 by root, Fri May 4 16:17:25 2007 UTC

28#include <netinet/in.h> 28#include <netinet/in.h>
29#include <arpa/inet.h> 29#include <arpa/inet.h>
30 30
31#ifdef __linux 31#ifdef __linux
32# include <linux/icmp.h> 32# include <linux/icmp.h>
33#endif
34#if IPV6
35# include <netinet/icmp6.h>
33#endif 36#endif
34 37
35#define ICMP4_ECHO 8 38#define ICMP4_ECHO 8
36#define ICMP4_ECHO_REPLY 0 39#define ICMP4_ECHO_REPLY 0
37#define ICMP6_ECHO 128 40#define ICMP6_ECHO 128
100 uint8_t dst[16]; 103 uint8_t dst[16];
101} IP6HDR; 104} IP6HDR;
102 105
103#define MAGIC 0xca4c 106#define MAGIC 0xca4c
104 107
108static uint16_t magic;
109
105typedef struct { 110typedef struct {
106 uint8_t type, code; 111 uint8_t type, code;
107 uint16_t cksum; 112 uint16_t cksum;
108 uint16_t id, seq; 113 uint16_t id, seq;
109 uint32_t payload; 114 uint32_t payload;
187 } 192 }
188 193
189 //TODO: bind to source address 194 //TODO: bind to source address
190 195
191 pkt.code = 0; 196 pkt.code = 0;
192 pkt.id = (uint16_t)MAGIC; 197 pkt.id = (uint16_t)magic;
193 pkt.seq = (uint16_t)~MAGIC; 198 pkt.seq = (uint16_t)~magic;
194 pkt.payload = req->payload; 199 pkt.payload = req->payload;
195 200
196 tstamp now = NOW (); 201 tstamp now = NOW ();
197 tstamp next = now; 202 tstamp next = now;
203
204 {
205 int r;
206 for (r = req->nranges; r--; )
207 inc_addr (&req->ranges [r].hi);
208 }
198 209
199 while (req->nranges) 210 while (req->nranges)
200 { 211 {
201 RANGE *range = req->ranges; 212 RANGE *range = req->ranges;
202 213
347 358
348 if (pipe (thr_recv) < 0) 359 if (pipe (thr_recv) < 0)
349 croak ("Net::FPing: unable to create receive pipe"); 360 croak ("Net::FPing: unable to create receive pipe");
350 361
351 icmp4_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); 362 icmp4_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
352#if IPV6
353 icmp6_fd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
354#endif
355
356#ifdef ICMP_FILTER 363#ifdef ICMP_FILTER
357 { 364 {
358 struct icmp_filter oval; 365 struct icmp_filter oval;
359 oval.data = 0xffffffff & ~(1 << ICMP4_ECHO_REPLY); 366 oval.data = 0xffffffff & ~(1 << ICMP4_ECHO_REPLY);
360 setsockopt (icmp4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval); 367 setsockopt (icmp4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval);
361 } 368 }
362#endif 369#endif
363 370
371#if IPV6
372 icmp6_fd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
373# ifdef ICMP6_FILTER
374 {
375 struct icmp6_filter oval;
376 ICMP6_FILTER_SETBLOCKALL (&oval);
377 ICMP6_FILTER_SETPASS (ICMP6_ECHO_REPLY, &oval);
378 setsockopt (icmp6_fd, IPPROTO_ICMPV6, ICMP6_FILTER, &oval, sizeof oval);
379 }
380# endif
381#endif
382
364 pthread_attr_init (&attr); 383 pthread_attr_init (&attr);
365 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); 384 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
366#ifdef PTHREAD_SCOPE_PROCESS 385#ifdef PTHREAD_SCOPE_PROCESS
367 pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS); 386 pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS);
368#endif 387#endif
388BOOT: 407BOOT:
389{ 408{
390 HV *stash = gv_stashpv ("Net::FPing", 1); 409 HV *stash = gv_stashpv ("Net::FPing", 1);
391 410
392 cbs = get_av ("Net::FPing::CB", 1); 411 cbs = get_av ("Net::FPing::CB", 1);
412 magic = getpid () ^ MAGIC;
393 413
394 boot (); 414 boot ();
395 415
396 newCONSTSUB (stash, "ipv4_supported", newSViv (icmp4_fd >= 0)); 416 newCONSTSUB (stash, "ipv4_supported", newSViv (icmp4_fd >= 0));
397 newCONSTSUB (stash, "ipv6_supported", newSViv (icmp6_fd >= 0)); 417 newCONSTSUB (stash, "ipv6_supported", newSViv (icmp6_fd >= 0));
523 CODE: 543 CODE:
524{ 544{
525 char buf [512]; 545 char buf [512];
526 struct sockaddr_in sa; 546 struct sockaddr_in sa;
527 socklen_t sl = sizeof (sa); 547 socklen_t sl = sizeof (sa);
528 AV *res_av = newAV (); 548 AV *res_av = av_len (cbs) < 0 ? 0 : (AV *)sv_2mortal ((SV *)newAV ());
529 SV *res_rv = sv_2mortal (newRV_noinc ((SV *)res_av));
530 tstamp now = NOW (); 549 tstamp now = NOW ();
531 550
532 for (;;) 551 for (;;)
533 { 552 {
534 int len = recvfrom (icmp4_fd, buf, sizeof (buf), MSG_DONTWAIT | MSG_TRUNC, &sa, &sl); 553 int len = recvfrom (icmp4_fd, buf, sizeof (buf), MSG_DONTWAIT | MSG_TRUNC, &sa, &sl);
540 559
541 int hdrlen = (iphdr->version_ihl & 15) * 4; 560 int hdrlen = (iphdr->version_ihl & 15) * 4;
542 int totlen = ntohs (iphdr->tot_len); 561 int totlen = ntohs (iphdr->tot_len);
543 562
544 // packet corrupt? 563 // packet corrupt?
564 if (!res_av
545 if (totlen > len 565 || totlen > len
546 || iphdr->protocol != IPPROTO_ICMP 566 || iphdr->protocol != IPPROTO_ICMP
547 || hdrlen < HDR_SIZE_IP4 || hdrlen + sizeof (PKT) != totlen) 567 || hdrlen < HDR_SIZE_IP4 || hdrlen + sizeof (PKT) != totlen)
548 continue; 568 continue;
549 569
550 PKT *pkt = (PKT *)(buf + hdrlen); 570 PKT *pkt = (PKT *)(buf + hdrlen);
551 571
552 if (pkt->type != ICMP4_ECHO_REPLY 572 if (pkt->type != ICMP4_ECHO_REPLY
553 || pkt->id != (uint16_t) MAGIC 573 || pkt->id != (uint16_t) magic
554 || pkt->seq != (uint16_t)~MAGIC 574 || pkt->seq != (uint16_t)~magic
555 || !isnormal (pkt->stamp)) 575 || !isnormal (pkt->stamp))
556 continue; 576 continue;
557 577
558 AV *av = newAV (); 578 AV *av = newAV ();
559 av_push (av, newSVpvn ((char *)&sa.sin_addr, 4)); 579 av_push (av, newSVpvn ((char *)&sa.sin_addr, 4));
561 av_push (av, newSVuv (pkt->payload)); 581 av_push (av, newSVuv (pkt->payload));
562 582
563 av_push (res_av, newRV_noinc ((SV *)av)); 583 av_push (res_av, newRV_noinc ((SV *)av));
564 } 584 }
565 585
586 if (res_av)
566 feed_reply (res_av); 587 feed_reply (res_av);
567} 588}
568 589
569void 590void
570_recv_icmp6 (...) 591_recv_icmp6 (...)
571 CODE: 592 CODE:
572{ 593{
573 struct sockaddr_in6 sa; 594 struct sockaddr_in6 sa;
574 socklen_t sl = sizeof (sa); 595 socklen_t sl = sizeof (sa);
575 AV *res_av = (AV *)sv_2mortal ((SV *)newAV ()); 596 AV *res_av = av_len (cbs) < 0 ? 0 : (AV *)sv_2mortal ((SV *)newAV ());
576 PKT pkt; 597 PKT pkt;
577 tstamp now = NOW (); 598 tstamp now = NOW ();
578 599
579 for (;;) 600 for (;;)
580 { 601 {
581 int len = recvfrom (icmp6_fd, &pkt, sizeof (pkt), MSG_DONTWAIT | MSG_TRUNC, &sa, &sl); 602 int len = recvfrom (icmp6_fd, &pkt, sizeof (pkt), MSG_DONTWAIT | MSG_TRUNC, &sa, &sl);
582 603
583 if (len != sizeof (PKT)) 604 if (len != sizeof (PKT))
584 break; 605 break;
585 606
607 if (!res_av
586 if (pkt.type != ICMP6_ECHO_REPLY 608 || pkt.type != ICMP6_ECHO_REPLY
587 || pkt.id != (uint16_t) MAGIC 609 || pkt.id != (uint16_t) magic
588 || pkt.seq != (uint16_t)~MAGIC 610 || pkt.seq != (uint16_t)~magic
589 || !isnormal (pkt.stamp)) 611 || !isnormal (pkt.stamp))
590 continue; 612 continue;
591 613
592 AV *av = newAV (); 614 AV *av = newAV ();
593 av_push (av, newSVpvn ((char *)&sa.sin6_addr, 16)); 615 av_push (av, newSVpvn ((char *)&sa.sin6_addr, 16));
595 av_push (av, newSVuv (pkt.payload)); 617 av_push (av, newSVuv (pkt.payload));
596 618
597 av_push (res_av, newRV_noinc ((SV *)av)); 619 av_push (res_av, newRV_noinc ((SV *)av));
598 } 620 }
599 621
622 if (res_av)
600 feed_reply (res_av); 623 feed_reply (res_av);
601} 624}
602 625

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines