--- AnyEvent-FastPing/FPing.xs 2007/05/04 07:36:45 1.2 +++ AnyEvent-FastPing/FPing.xs 2007/05/04 13:50:02 1.3 @@ -59,7 +59,6 @@ } RANGE; typedef struct { - int send_fd; SV *id; double interval; int nranges; @@ -105,11 +104,13 @@ tstamp stamp; // be careful when accessing this } PKT; -pthread_t pthrid; -int thr_send[2]; // send to worker -int thr_recv[2]; // receive from worker +static pthread_t pthrid; +static int thr_send[2]; // send to worker +static int thr_recv[2]; // receive from worker -int icmp4_fd, icmp6_fd; +static int icmp4_fd, icmp6_fd; + +static AV *cbs; static uint16_t icmp_cksum (void *data, unsigned int len) @@ -159,11 +160,11 @@ memset (&sa4, 0, sizeof (sa4)); sa4.sin_family = AF_INET; - sa4.sin_port = IPPROTO_ICMP; + sa4.sin_port = 0; #if IPV6 memset (&sa6, 0, sizeof (sa6)); sa6.sin6_family = AF_INET6; - sa6.sin6_port = IPPROTO_ICMPV6; + sa6.sin6_port = 0; #endif for (;;) @@ -227,13 +228,13 @@ if (range->family == AF_INET) { pkt.type = ICMP4_ECHO; - pkt.cksum = icmp_cksum (&pkt, sizeof (pkt));//D + pkt.cksum = icmp_cksum (&pkt, sizeof (pkt)); memcpy (&sa4.sin_addr, sizeof (addr_t) - sizeof (sa4.sin_addr) + (char *)&range->lo, sizeof (sa4.sin_addr)); - if (sendto (req->send_fd, &pkt, sizeof (pkt), 0, (struct sockaddr *)&sa4, sizeof (sa4)) > 0) + if (sendto (icmp4_fd, &pkt, sizeof (pkt), 0, (struct sockaddr *)&sa4, sizeof (sa4)) > 0) errno = 0; } else @@ -245,7 +246,7 @@ sizeof (addr_t) - sizeof (sa6.sin6_addr) + (char *)&range->lo, sizeof (sa6.sin6_addr)); - if (sendto (req->send_fd, &pkt, sizeof (pkt), 0, (struct sockaddr *)&sa6, sizeof (sa6)) > 0) + if (sendto (icmp6_fd, &pkt, sizeof (pkt), 0, (struct sockaddr *)&sa6, sizeof (sa6)) > 0) errno = 0; #endif } @@ -302,6 +303,33 @@ } static void +feed_reply (AV *res_av) +{ + if (av_len (res_av) < 0) + return; + + dSP; + SV *res = sv_2mortal (newRV_inc ((SV *)res_av)); + int i; + + ENTER; + SAVETMPS; + + for (i = av_len (cbs) + 1; i--; ) + { + SV *cb = *av_fetch (cbs, i, 1); + + PUSHMARK (SP); + XPUSHs (res); + PUTBACK; + call_sv (cb, G_DISCARD | G_VOID); + } + + FREETMPS; + LEAVE; +} + +static void boot () { sigset_t fullsigset, oldsigset; @@ -314,6 +342,9 @@ croak ("Net::FPing: unable to create receive pipe"); icmp4_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); +#if IPV6 + icmp6_fd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); +#endif #ifdef ICMP_FILTER { @@ -323,10 +354,6 @@ } #endif -#if IPV6 - icmp6_fd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); -#endif - pthread_attr_init (&attr); pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); #ifdef PTHREAD_SCOPE_PROCESS @@ -355,6 +382,8 @@ { HV *stash = gv_stashpv ("Net::FPing", 1); + cbs = get_av ("Net::FPing::CB", 1); + boot (); newCONSTSUB (stash, "ipv4_supported", newSViv (icmp4_fd >= 0)); @@ -382,7 +411,6 @@ if (interval < MIN_INTERVAL) interval = MIN_INTERVAL; - req->send_fd = icmp4_fd; req->id = newSVsv (id); req->interval = interval; req->payload = payload; @@ -443,7 +471,7 @@ else croak ("addresses in range must be strings with either 4 (IPv4) or 16 (IPv6) octets"); - if (r->family = AF_INET) + if (r->family == AF_INET) { if (icmp4_fd < 0) croak ("Net::FPing: IPv4 ping support not available on this system"); @@ -492,6 +520,7 @@ socklen_t sl = sizeof (sa); AV *res_av = newAV (); SV *res_rv = sv_2mortal (newRV_noinc ((SV *)res_av)); + tstamp now = NOW (); for (;;) { @@ -519,52 +548,48 @@ || !isnormal (pkt->stamp)) continue; - // just drain for now - //av_push + AV *av = newAV (); + av_push (av, newSVpvn ((char *)&sa.sin_addr, 4)); + av_push (av, newSVnv (now - pkt->stamp)); + av_push (av, newSVuv (pkt->payload)); + + av_push (res_av, newRV_noinc ((SV *)av)); } - // feed (res_av); + feed_reply (res_av); } void _recv_icmp6 (...) CODE: { - char buf [512]; - struct sockaddr_in sa; + struct sockaddr_in6 sa; socklen_t sl = sizeof (sa); AV *res_av = (AV *)sv_2mortal ((SV *)newAV ()); + PKT pkt; + tstamp now = NOW (); for (;;) { - int len = recvfrom (icmp6_fd, buf, sizeof (buf), MSG_DONTWAIT | MSG_TRUNC, &sa, &sl); + int len = recvfrom (icmp6_fd, &pkt, sizeof (pkt), MSG_DONTWAIT | MSG_TRUNC, &sa, &sl); - if (len <= HDR_SIZE_IP6) + if (len != sizeof (PKT)) break; - IP6HDR *iphdr = (IP6HDR *)buf; - - int datalen = ntohs (iphdr->payload_len); - - // packet corrupt? - if (HDR_SIZE_IP6 + datalen > len - || iphdr->nxt_hdr != IPPROTO_ICMPV6 - || HDR_SIZE_IP6 + sizeof (PKT) != datalen) + if (pkt.type != ICMP6_ECHO + || pkt.id != (uint16_t)MAGIC + || pkt.seq != (uint16_t)~MAGIC + || !isnormal (pkt.stamp)) continue; - PKT *pkt = (PKT *)(buf + HDR_SIZE_IP6); - - if (pkt->id != (uint16_t)MAGIC - || pkt->seq != (uint16_t)~MAGIC - || pkt->type != ICMP6_ECHO - || !isnormal (pkt->stamp)) - continue; + AV *av = newAV (); + av_push (av, newSVpvn ((char *)&sa.sin6_addr, 16)); + av_push (av, newSVnv (now - pkt.stamp)); + av_push (av, newSVuv (pkt.payload)); - //fprintf (stderr, "ip6 echo received\n"); - // just drain for now - //av_push + av_push (res_av, newRV_noinc ((SV *)av)); } - // feed (res_av); + feed_reply (res_av); }