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.3 by root, Fri May 4 13:50:02 2007 UTC vs.
Revision 1.7 by root, Fri May 4 16:17:25 2007 UTC

26#include <sys/socket.h> 26#include <sys/socket.h>
27 27
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
32# include <linux/icmp.h>
33#endif
34#if IPV6
35# include <netinet/icmp6.h>
36#endif
37
31#define ICMP4_ECHO 8 38#define ICMP4_ECHO 8
39#define ICMP4_ECHO_REPLY 0
32#define ICMP6_ECHO 128 40#define ICMP6_ECHO 128
41#define ICMP6_ECHO_REPLY 129
33 42
34#define DRAIN_INTERVAL .000001 // how long to wait when sendto returns ENOBUFS, in seconds 43#define DRAIN_INTERVAL .000001 // how long to wait when sendto returns ENOBUFS, in seconds
35#define MIN_INTERVAL .000001 // minimum packet send interval, in seconds 44#define MIN_INTERVAL .000001 // minimum packet send interval, in seconds
36 45
37#define HDR_SIZE_IP4 20 46#define HDR_SIZE_IP4 20
94 uint8_t dst[16]; 103 uint8_t dst[16];
95} IP6HDR; 104} IP6HDR;
96 105
97#define MAGIC 0xca4c 106#define MAGIC 0xca4c
98 107
108static uint16_t magic;
109
99typedef struct { 110typedef struct {
100 uint8_t type, code; 111 uint8_t type, code;
101 uint16_t cksum; 112 uint16_t cksum;
102 uint16_t id, seq; 113 uint16_t id, seq;
103 uint32_t payload; 114 uint32_t payload;
181 } 192 }
182 193
183 //TODO: bind to source address 194 //TODO: bind to source address
184 195
185 pkt.code = 0; 196 pkt.code = 0;
186 pkt.id = (uint16_t)MAGIC; 197 pkt.id = (uint16_t)magic;
187 pkt.seq = (uint16_t)~MAGIC; 198 pkt.seq = (uint16_t)~magic;
188 pkt.payload = req->payload; 199 pkt.payload = req->payload;
189 200
190 tstamp next = NOW (); 201 tstamp now = NOW ();
202 tstamp next = now;
203
204 {
205 int r;
206 for (r = req->nranges; r--; )
207 inc_addr (&req->ranges [r].hi);
208 }
191 209
192 while (req->nranges) 210 while (req->nranges)
193 { 211 {
194 RANGE *range = req->ranges; 212 RANGE *range = req->ranges;
195 213
196 if (!memcmp (&range->lo, &range->hi, sizeof (addr_t))) 214 if (!memcmp (&range->lo, &range->hi, sizeof (addr_t)))
197 req->ranges [0] = req->ranges [--req->nranges]; 215 req->ranges [0] = req->ranges [--req->nranges];
198 else 216 else
199 { 217 {
200 tstamp now = NOW ();
201
202 // ranges [0] is always the next range to ping 218 // ranges [0] is always the next range to ping
203 tstamp wait = range->next - now; 219 tstamp wait = range->next - now;
204 220
205 // compare with the global frequency limit 221 // compare with the global frequency limit
206 { 222 {
219 ts.tv_sec = wait; 235 ts.tv_sec = wait;
220 ts.tv_nsec = (wait - ts.tv_sec) * 1000000000.; 236 ts.tv_nsec = (wait - ts.tv_sec) * 1000000000.;
221 237
222 nanosleep (&ts, 0); 238 nanosleep (&ts, 0);
223 } 239 }
240
241 now = NOW ();
224 242
225 pkt.stamp = now; 243 pkt.stamp = now;
226 pkt.cksum = 0; 244 pkt.cksum = 0;
227 245
228 if (range->family == AF_INET) 246 if (range->family == AF_INET)
340 358
341 if (pipe (thr_recv) < 0) 359 if (pipe (thr_recv) < 0)
342 croak ("Net::FPing: unable to create receive pipe"); 360 croak ("Net::FPing: unable to create receive pipe");
343 361
344 icmp4_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); 362 icmp4_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
363#ifdef ICMP_FILTER
364 {
365 struct icmp_filter oval;
366 oval.data = 0xffffffff & ~(1 << ICMP4_ECHO_REPLY);
367 setsockopt (icmp4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval);
368 }
369#endif
370
345#if IPV6 371#if IPV6
346 icmp6_fd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 372 icmp6_fd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
347#endif
348
349#ifdef ICMP_FILTER 373# ifdef ICMP6_FILTER
350 { 374 {
351 icmp_filter oval; 375 struct icmp6_filter oval;
352 oval.data = 0xffffffff & ~(1 << ICMP4_ECHO); 376 ICMP6_FILTER_SETBLOCKALL (&oval);
377 ICMP6_FILTER_SETPASS (ICMP6_ECHO_REPLY, &oval);
353 setsockopt (icmpv4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval); 378 setsockopt (icmp6_fd, IPPROTO_ICMPV6, ICMP6_FILTER, &oval, sizeof oval);
354 } 379 }
380# endif
355#endif 381#endif
356 382
357 pthread_attr_init (&attr); 383 pthread_attr_init (&attr);
358 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); 384 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
359#ifdef PTHREAD_SCOPE_PROCESS 385#ifdef PTHREAD_SCOPE_PROCESS
381BOOT: 407BOOT:
382{ 408{
383 HV *stash = gv_stashpv ("Net::FPing", 1); 409 HV *stash = gv_stashpv ("Net::FPing", 1);
384 410
385 cbs = get_av ("Net::FPing::CB", 1); 411 cbs = get_av ("Net::FPing::CB", 1);
412 magic = getpid () ^ MAGIC;
386 413
387 boot (); 414 boot ();
388 415
389 newCONSTSUB (stash, "ipv4_supported", newSViv (icmp4_fd >= 0)); 416 newCONSTSUB (stash, "ipv4_supported", newSViv (icmp4_fd >= 0));
390 newCONSTSUB (stash, "ipv6_supported", newSViv (icmp6_fd >= 0)); 417 newCONSTSUB (stash, "ipv6_supported", newSViv (icmp6_fd >= 0));
391 418
392 newCONSTSUB (stash, "ipv4_pktsize", newSViv (HDR_SIZE_IP4 + sizeof (PKT))); 419 newCONSTSUB (stash, "icmp4_pktsize", newSViv (HDR_SIZE_IP4 + sizeof (PKT)));
393 newCONSTSUB (stash, "ipv6_pktsize", newSViv (HDR_SIZE_IP6 + sizeof (PKT))); 420 newCONSTSUB (stash, "icmp6_pktsize", newSViv (HDR_SIZE_IP6 + sizeof (PKT)));
394} 421}
395 422
396PROTOTYPES: DISABLE 423PROTOTYPES: DISABLE
397 424
398SV * 425SV *
516 CODE: 543 CODE:
517{ 544{
518 char buf [512]; 545 char buf [512];
519 struct sockaddr_in sa; 546 struct sockaddr_in sa;
520 socklen_t sl = sizeof (sa); 547 socklen_t sl = sizeof (sa);
521 AV *res_av = newAV (); 548 AV *res_av = av_len (cbs) < 0 ? 0 : (AV *)sv_2mortal ((SV *)newAV ());
522 SV *res_rv = sv_2mortal (newRV_noinc ((SV *)res_av));
523 tstamp now = NOW (); 549 tstamp now = NOW ();
524 550
525 for (;;) 551 for (;;)
526 { 552 {
527 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);
533 559
534 int hdrlen = (iphdr->version_ihl & 15) * 4; 560 int hdrlen = (iphdr->version_ihl & 15) * 4;
535 int totlen = ntohs (iphdr->tot_len); 561 int totlen = ntohs (iphdr->tot_len);
536 562
537 // packet corrupt? 563 // packet corrupt?
564 if (!res_av
538 if (totlen > len 565 || totlen > len
539 || iphdr->protocol != IPPROTO_ICMP 566 || iphdr->protocol != IPPROTO_ICMP
540 || hdrlen < HDR_SIZE_IP4 || hdrlen + sizeof (PKT) != totlen) 567 || hdrlen < HDR_SIZE_IP4 || hdrlen + sizeof (PKT) != totlen)
541 continue; 568 continue;
542 569
543 PKT *pkt = (PKT *)(buf + hdrlen); 570 PKT *pkt = (PKT *)(buf + hdrlen);
544 571
545 if (pkt->id != (uint16_t)MAGIC 572 if (pkt->type != ICMP4_ECHO_REPLY
573 || pkt->id != (uint16_t) magic
546 || pkt->seq != (uint16_t)~MAGIC 574 || pkt->seq != (uint16_t)~magic
547 || pkt->type != ICMP4_ECHO
548 || !isnormal (pkt->stamp)) 575 || !isnormal (pkt->stamp))
549 continue; 576 continue;
550 577
551 AV *av = newAV (); 578 AV *av = newAV ();
552 av_push (av, newSVpvn ((char *)&sa.sin_addr, 4)); 579 av_push (av, newSVpvn ((char *)&sa.sin_addr, 4));
554 av_push (av, newSVuv (pkt->payload)); 581 av_push (av, newSVuv (pkt->payload));
555 582
556 av_push (res_av, newRV_noinc ((SV *)av)); 583 av_push (res_av, newRV_noinc ((SV *)av));
557 } 584 }
558 585
586 if (res_av)
559 feed_reply (res_av); 587 feed_reply (res_av);
560} 588}
561 589
562void 590void
563_recv_icmp6 (...) 591_recv_icmp6 (...)
564 CODE: 592 CODE:
565{ 593{
566 struct sockaddr_in6 sa; 594 struct sockaddr_in6 sa;
567 socklen_t sl = sizeof (sa); 595 socklen_t sl = sizeof (sa);
568 AV *res_av = (AV *)sv_2mortal ((SV *)newAV ()); 596 AV *res_av = av_len (cbs) < 0 ? 0 : (AV *)sv_2mortal ((SV *)newAV ());
569 PKT pkt; 597 PKT pkt;
570 tstamp now = NOW (); 598 tstamp now = NOW ();
571 599
572 for (;;) 600 for (;;)
573 { 601 {
574 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);
575 603
576 if (len != sizeof (PKT)) 604 if (len != sizeof (PKT))
577 break; 605 break;
578 606
607 if (!res_av
579 if (pkt.type != ICMP6_ECHO 608 || pkt.type != ICMP6_ECHO_REPLY
580 || pkt.id != (uint16_t)MAGIC 609 || pkt.id != (uint16_t) magic
581 || pkt.seq != (uint16_t)~MAGIC 610 || pkt.seq != (uint16_t)~magic
582 || !isnormal (pkt.stamp)) 611 || !isnormal (pkt.stamp))
583 continue; 612 continue;
584 613
585 AV *av = newAV (); 614 AV *av = newAV ();
586 av_push (av, newSVpvn ((char *)&sa.sin6_addr, 16)); 615 av_push (av, newSVpvn ((char *)&sa.sin6_addr, 16));
588 av_push (av, newSVuv (pkt.payload)); 617 av_push (av, newSVuv (pkt.payload));
589 618
590 av_push (res_av, newRV_noinc ((SV *)av)); 619 av_push (res_av, newRV_noinc ((SV *)av));
591 } 620 }
592 621
622 if (res_av)
593 feed_reply (res_av); 623 feed_reply (res_av);
594} 624}
595 625

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines