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.1 by root, Fri May 4 07:02:19 2007 UTC vs.
Revision 1.3 by root, Fri May 4 13:50:02 2007 UTC

1#define _POSIX_C_SOURCE 199309 1#define _POSIX_C_SOURCE 199309
2#define _GNU_SOURCE 1 2#define _GNU_SOURCE 1
3 3
4#define IPV6 1 4#define IPV6 1 // if you get compilation problems try to disable IPv6
5 5
6#include "EXTERN.h" 6#include "EXTERN.h"
7#include "perl.h" 7#include "perl.h"
8#include "XSUB.h" 8#include "XSUB.h"
9 9
57 double interval; 57 double interval;
58 tstamp next; 58 tstamp next;
59} RANGE; 59} RANGE;
60 60
61typedef struct { 61typedef struct {
62 int send_fd;
63 SV *id; 62 SV *id;
64 double interval; 63 double interval;
65 int nranges; 64 int nranges;
66 RANGE *ranges; 65 RANGE *ranges;
67 uint32_t payload; 66 uint32_t payload;
99 98
100typedef struct { 99typedef struct {
101 uint8_t type, code; 100 uint8_t type, code;
102 uint16_t cksum; 101 uint16_t cksum;
103 uint16_t id, seq; 102 uint16_t id, seq;
103 uint32_t payload;
104 tstamp stamp; // be careful when accessing this 104 tstamp stamp; // be careful when accessing this
105 uint32_t payload;
106} PKT; 105} PKT;
107 106
108pthread_t pthrid; 107static pthread_t pthrid;
109int thr_send[2]; // send to worker 108static int thr_send[2]; // send to worker
110int thr_recv[2]; // receive from worker 109static int thr_recv[2]; // receive from worker
111 110
112int icmp4_fd, icmp6_fd; 111static int icmp4_fd, icmp6_fd;
113 112
114uint16_t 113static AV *cbs;
114
115static uint16_t
115icmp_cksum (void *data, unsigned int len) 116icmp_cksum (void *data, unsigned int len)
116{ 117{
117 register int sum = 0; 118 register int sum = 0;
118 uint16_t *wp; 119 uint16_t *wp;
119 120
157 158
158 memset (&pkt, 0, sizeof (pkt)); 159 memset (&pkt, 0, sizeof (pkt));
159 160
160 memset (&sa4, 0, sizeof (sa4)); 161 memset (&sa4, 0, sizeof (sa4));
161 sa4.sin_family = AF_INET; 162 sa4.sin_family = AF_INET;
162 sa4.sin_port = 0; // unused 163 sa4.sin_port = 0;
163#if IPV6 164#if IPV6
164 memset (&sa6, 0, sizeof (sa6)); 165 memset (&sa6, 0, sizeof (sa6));
165 sa6.sin6_family = AF_INET6; 166 sa6.sin6_family = AF_INET6;
166 sa6.sin6_port = 0; // unused 167 sa6.sin6_port = 0;
167#endif 168#endif
168 169
169 for (;;) 170 for (;;)
170 { 171 {
171 REQ *req; 172 REQ *req;
231 232
232 memcpy (&sa4.sin_addr, 233 memcpy (&sa4.sin_addr,
233 sizeof (addr_t) - sizeof (sa4.sin_addr) + (char *)&range->lo, 234 sizeof (addr_t) - sizeof (sa4.sin_addr) + (char *)&range->lo,
234 sizeof (sa4.sin_addr)); 235 sizeof (sa4.sin_addr));
235 236
236 if (sendto (req->send_fd, &pkt, sizeof (pkt), 0, (struct sockaddr *)&sa4, sizeof (sa4)) > 0) 237 if (sendto (icmp4_fd, &pkt, sizeof (pkt), 0, (struct sockaddr *)&sa4, sizeof (sa4)) > 0)
237 errno = 0; 238 errno = 0;
238 } 239 }
239 else 240 else
240 { 241 {
241#if IPV6 242#if IPV6
243 244
244 memcpy (&sa6.sin6_addr, 245 memcpy (&sa6.sin6_addr,
245 sizeof (addr_t) - sizeof (sa6.sin6_addr) + (char *)&range->lo, 246 sizeof (addr_t) - sizeof (sa6.sin6_addr) + (char *)&range->lo,
246 sizeof (sa6.sin6_addr)); 247 sizeof (sa6.sin6_addr));
247 248
248 if (sendto (req->send_fd, &pkt, sizeof (pkt), 0, (struct sockaddr *)&sa6, sizeof (sa6)) > 0) 249 if (sendto (icmp6_fd, &pkt, sizeof (pkt), 0, (struct sockaddr *)&sa6, sizeof (sa6)) > 0)
249 errno = 0; 250 errno = 0;
250#endif 251#endif
251 } 252 }
252 253
253 if (errno == ENOBUFS) 254 if (errno == ENOBUFS)
300 301
301 return 0; 302 return 0;
302} 303}
303 304
304static void 305static void
306feed_reply (AV *res_av)
307{
308 if (av_len (res_av) < 0)
309 return;
310
311 dSP;
312 SV *res = sv_2mortal (newRV_inc ((SV *)res_av));
313 int i;
314
315 ENTER;
316 SAVETMPS;
317
318 for (i = av_len (cbs) + 1; i--; )
319 {
320 SV *cb = *av_fetch (cbs, i, 1);
321
322 PUSHMARK (SP);
323 XPUSHs (res);
324 PUTBACK;
325 call_sv (cb, G_DISCARD | G_VOID);
326 }
327
328 FREETMPS;
329 LEAVE;
330}
331
332static void
305boot () 333boot ()
306{ 334{
307 sigset_t fullsigset, oldsigset; 335 sigset_t fullsigset, oldsigset;
308 pthread_attr_t attr; 336 pthread_attr_t attr;
309 337
314 croak ("Net::FPing: unable to create receive pipe"); 342 croak ("Net::FPing: unable to create receive pipe");
315 343
316 icmp4_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); 344 icmp4_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
317#if IPV6 345#if IPV6
318 icmp6_fd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 346 icmp6_fd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
347#endif
348
349#ifdef ICMP_FILTER
350 {
351 icmp_filter oval;
352 oval.data = 0xffffffff & ~(1 << ICMP4_ECHO);
353 setsockopt (icmpv4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval);
354 }
319#endif 355#endif
320 356
321 pthread_attr_init (&attr); 357 pthread_attr_init (&attr);
322 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); 358 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
323#ifdef PTHREAD_SCOPE_PROCESS 359#ifdef PTHREAD_SCOPE_PROCESS
341} 377}
342 378
343MODULE = Net::FPing PACKAGE = Net::FPing 379MODULE = Net::FPing PACKAGE = Net::FPing
344 380
345BOOT: 381BOOT:
382{
383 HV *stash = gv_stashpv ("Net::FPing", 1);
384
385 cbs = get_av ("Net::FPing::CB", 1);
386
346 boot (); 387 boot ();
347 388
389 newCONSTSUB (stash, "ipv4_supported", newSViv (icmp4_fd >= 0));
390 newCONSTSUB (stash, "ipv6_supported", newSViv (icmp6_fd >= 0));
391
392 newCONSTSUB (stash, "ipv4_pktsize", newSViv (HDR_SIZE_IP4 + sizeof (PKT)));
393 newCONSTSUB (stash, "ipv6_pktsize", newSViv (HDR_SIZE_IP6 + sizeof (PKT)));
394}
395
348PROTOTYPES: DISABLE 396PROTOTYPES: DISABLE
349 397
350SV * 398SV *
351_req_ranges4 (SV *ranges, NV interval, U32 payload, SV *id) 399_req_icmp_ping (SV *ranges, NV interval, U32 payload, SV *id)
352 CODE: 400 CODE:
353{ 401{
354 if (!SvROK (ranges) || SvTYPE (SvRV (ranges)) != SVt_PVAV) 402 if (!SvROK (ranges) || SvTYPE (SvRV (ranges)) != SVt_PVAV)
355 croak ("address ranges must be given as arrayref with lo, hi pairs"); 403 croak ("address ranges must be given as arrayref with lo, hi pairs");
356 404
361 int i; 409 int i;
362 410
363 if (interval < MIN_INTERVAL) 411 if (interval < MIN_INTERVAL)
364 interval = MIN_INTERVAL; 412 interval = MIN_INTERVAL;
365 413
366 req->send_fd = icmp4_fd;
367 req->id = newSVsv (id); 414 req->id = newSVsv (id);
368 req->interval = interval; 415 req->interval = interval;
369 req->payload = payload; 416 req->payload = payload;
370 req->nranges = nranges; 417 req->nranges = nranges;
371 req->ranges = (RANGE *)malloc (nranges * sizeof (RANGE)); 418 req->ranges = (RANGE *)malloc (nranges * sizeof (RANGE));
422 addr = htonl (SvUV (hi)); memcpy (sizeof (addr_t) - 4 + (char *)&r->hi, &addr, 4); 469 addr = htonl (SvUV (hi)); memcpy (sizeof (addr_t) - 4 + (char *)&r->hi, &addr, 4);
423 } 470 }
424 else 471 else
425 croak ("addresses in range must be strings with either 4 (IPv4) or 16 (IPv6) octets"); 472 croak ("addresses in range must be strings with either 4 (IPv4) or 16 (IPv6) octets");
426 473
427 if (r->family = AF_INET) 474 if (r->family == AF_INET)
428 { 475 {
429 if (icmp4_fd < 0) 476 if (icmp4_fd < 0)
430 croak ("Net::FPing: IPv4 ping support not available on this system"); 477 croak ("Net::FPing: IPv4 ping support not available on this system");
431 } 478 }
432 else 479 else
471 char buf [512]; 518 char buf [512];
472 struct sockaddr_in sa; 519 struct sockaddr_in sa;
473 socklen_t sl = sizeof (sa); 520 socklen_t sl = sizeof (sa);
474 AV *res_av = newAV (); 521 AV *res_av = newAV ();
475 SV *res_rv = sv_2mortal (newRV_noinc ((SV *)res_av)); 522 SV *res_rv = sv_2mortal (newRV_noinc ((SV *)res_av));
523 tstamp now = NOW ();
476 524
477 for (;;) 525 for (;;)
478 { 526 {
479 int len = recvfrom (icmp4_fd, buf, sizeof (buf), MSG_DONTWAIT | MSG_TRUNC, &sa, &sl); 527 int len = recvfrom (icmp4_fd, buf, sizeof (buf), MSG_DONTWAIT | MSG_TRUNC, &sa, &sl);
480 528
498 || pkt->seq != (uint16_t)~MAGIC 546 || pkt->seq != (uint16_t)~MAGIC
499 || pkt->type != ICMP4_ECHO 547 || pkt->type != ICMP4_ECHO
500 || !isnormal (pkt->stamp)) 548 || !isnormal (pkt->stamp))
501 continue; 549 continue;
502 550
503 // just drain for now 551 AV *av = newAV ();
504 //av_push 552 av_push (av, newSVpvn ((char *)&sa.sin_addr, 4));
553 av_push (av, newSVnv (now - pkt->stamp));
554 av_push (av, newSVuv (pkt->payload));
555
556 av_push (res_av, newRV_noinc ((SV *)av));
505 } 557 }
506 558
507 // feed (res_av); 559 feed_reply (res_av);
508} 560}
509 561
510void 562void
511_recv_icmp6 (...) 563_recv_icmp6 (...)
512 CODE: 564 CODE:
513{ 565{
514 char buf [512];
515 struct sockaddr_in sa; 566 struct sockaddr_in6 sa;
516 socklen_t sl = sizeof (sa); 567 socklen_t sl = sizeof (sa);
517 AV *res_av = (AV *)sv_2mortal ((SV *)newAV ()); 568 AV *res_av = (AV *)sv_2mortal ((SV *)newAV ());
569 PKT pkt;
570 tstamp now = NOW ();
518 571
519 for (;;) 572 for (;;)
520 { 573 {
521 int len = recvfrom (icmp6_fd, buf, sizeof (buf), MSG_DONTWAIT | MSG_TRUNC, &sa, &sl); 574 int len = recvfrom (icmp6_fd, &pkt, sizeof (pkt), MSG_DONTWAIT | MSG_TRUNC, &sa, &sl);
522 575
523 if (len <= HDR_SIZE_IP6) 576 if (len != sizeof (PKT))
524 break; 577 break;
525 578
526 IP6HDR *iphdr = (IP6HDR *)buf; 579 if (pkt.type != ICMP6_ECHO
527 580 || pkt.id != (uint16_t)MAGIC
528 int datalen = ntohs (iphdr->payload_len); 581 || pkt.seq != (uint16_t)~MAGIC
529 582 || !isnormal (pkt.stamp))
530 // packet corrupt?
531 if (HDR_SIZE_IP6 + datalen > len
532 || iphdr->nxt_hdr != IPPROTO_ICMPV6
533 || HDR_SIZE_IP6 + sizeof (PKT) != datalen)
534 continue; 583 continue;
535 584
536 PKT *pkt = (PKT *)(buf + HDR_SIZE_IP6); 585 AV *av = newAV ();
586 av_push (av, newSVpvn ((char *)&sa.sin6_addr, 16));
587 av_push (av, newSVnv (now - pkt.stamp));
588 av_push (av, newSVuv (pkt.payload));
537 589
538 if (pkt->id != (uint16_t)MAGIC 590 av_push (res_av, newRV_noinc ((SV *)av));
539 || pkt->seq != (uint16_t)~MAGIC
540 || pkt->type != ICMP6_ECHO
541 || !isnormal (pkt->stamp))
542 continue;
543
544 //fprintf (stderr, "ip6 echo received\n");
545 // just drain for now
546 //av_push
547 } 591 }
548 592
549 // feed (res_av); 593 feed_reply (res_av);
550} 594}
551 595

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines