AnyEvent-FastPing

 view release on metacpan or  search on metacpan

FastPing.xs  view on Meta::CPAN


            pkt = (PKT *)(buf + hdrlen);

            if (pkt->type != ICMP4_ECHO_REPLY
                || pkt->pinger >= pingercnt
                || !pingers [pkt->pinger])
              continue;

            pinger = pingers [pkt->pinger];

            if (!pkt_is_valid_for (pkt, pinger))
              continue;

            recv_feed (pinger, &sa.sin_addr, 4, NOW () - pkt_to_ts (pkt));
          }

        recv_flush ();
}

void
_recv_icmp6 (...)
	CODE:
{
        struct sockaddr_in6 sa;
        PKT pkt;
        int maxrecv;

        for (maxrecv = 256+1; --maxrecv; )
          {
            PINGER *pinger;
            socklen_t sl = sizeof (sa);
            int len = recvfrom (icmp6_fd, &pkt, sizeof (pkt), MSG_TRUNC, (struct sockaddr *)&sa, &sl);

            if (len != sizeof (PKT))
              break;

            if (pkt.type != ICMP6_ECHO_REPLY
                || pkt.pinger >= pingercnt
                || !pingers [pkt.pinger])
              continue;

            pinger = pingers [pkt.pinger];

            if (!pkt_is_valid_for (&pkt, pinger))
              continue;

            recv_feed (pinger, &sa.sin6_addr, 16, NOW () - pkt_to_ts (&pkt));
          }

        recv_flush ();
}

void
_new (SV *klass, UV magic1, UV magic2, UV magic3)
	PPCODE:
{
        SV *pv = NEWSV (0, sizeof (PINGER));
        PINGER *self = (PINGER *)SvPVX (pv);

        SvPOK_only (pv);
        XPUSHs (sv_2mortal (sv_bless (newRV_noinc (pv), gv_stashpv (SvPVutf8_nolen (klass), 1))));
        pinger_init (self);
        self->magic1 = magic1;
        self->magic2 = magic2;
        self->magic3 = magic3;
}

void
_free (PINGER *self)
	CODE:
        pinger_free (self);

IV
id (PINGER *self, ...)
	CODE:
        RETVAL = self->id;
	OUTPUT:
        RETVAL

void pinger_start (PINGER *self)

void pinger_stop (PINGER *self)

void
_stop_id (UV id)
	CODE:
        if (id < pingercnt && pingers [id])
          pinger_stop (pingers [id]);

void
interval (PINGER *self, NV interval)
	CODE:
        NOT_RUNNING;
        self->interval = interval > MIN_INTERVAL ? interval : MIN_INTERVAL;

void
max_rtt (PINGER *self, NV maxrtt)
	CODE:
        NOT_RUNNING;
        self->maxrtt = maxrtt;

void
on_recv (PINGER *self, SV *cb)
	CODE:
        SvREFCNT_dec (self->recvcb);
        self->recvcb = newSVsv (cb);

void
add_range (PINGER *self, SV *lo_, SV *hi_, NV interval = 0)
	CODE:
{
	STRLEN lo_len, hi_len;
  	char *lo = SvPVbyte (lo_, lo_len);
  	char *hi = SvPVbyte (hi_, hi_len);
        RANGE *range;
        NOT_RUNNING;

        if (lo_len != hi_len || (lo_len != 4 && lo_len != 16))
          croak ("AnyEvent::FastPing::add_range address range must be specified as two binary IPv4 or IPv6 addresses");

        if (lo_len ==  4 && icmp4_fd < 0) croak ("IPv4 support unavailable");
        if (lo_len == 16 && icmp6_fd < 0) croak ("IPv6 support unavailable");

        if (memcmp (lo, hi, lo_len) > 0)
          croak ("AnyEvent::FastPing::add_range called with lo > hi");

        range = calloc (1, sizeof (RANGE));

        range->next     = 0;
        range->interval = interval > MIN_INTERVAL ? interval : MIN_INTERVAL;
        range->addrlen  = lo_len;

        memcpy (sizeof (addr_tt) - lo_len + (char *)&range->lo, lo, lo_len);
        memcpy (sizeof (addr_tt) - lo_len + (char *)&range->hi, hi, lo_len);

        pinger_add_range (self, range);
}

void
add_hosts (PINGER *self, SV *addrs, NV interval = 0, UV interleave = 1)
	CODE:
{
  	AV *av;
        int i, j, k;
        int cnt;
        int addrlen = 0;
        RANGE *range;
        NOT_RUNNING;

        if (!SvROK (addrs) || SvTYPE (SvRV (addrs)) != SVt_PVAV)
          croak ("AnyEvent::FastPing::add_hosts expects an arrayref with binary IPv4 or IPv6 addresses");

        av = (AV *)SvRV (addrs);
        cnt = av_len (av) + 1;

        for (i = 0; i < cnt; ++i)
          {
            SV *sv = *av_fetch (av, i, 1);
            sv_utf8_downgrade (sv, 0);

            j = SvCUR (sv);

            if (j != 4 && j != 16)
              croak ("AnyEvent::FastPing::add_hosts addresses must be specified as binary IPv4 or IPv6 addresses");

            if (j > addrlen)
              addrlen = j;
          }

        if (!cnt)
          XSRETURN_EMPTY;

        range = calloc (1, sizeof (RANGE) + cnt * addrlen);

        range->next     = 0;
        range->interval = interval > MIN_INTERVAL ? interval : MIN_INTERVAL;
        range->addrlen  = addrlen;
        range->addrcnt  = cnt;

        if (interleave == 0)
          interleave = cnt <= 256 * 256 ? 256 : (int)sqrtf (cnt);

        k = cnt;
        for (j = 0; j < interleave; ++j)
          for (i = j; i < cnt; i += interleave)
            {
              uint8_t *dst = (uint8_t *)(range + 1) + --k * addrlen;
              char *pv;
              STRLEN pvlen;
              SV *sv = *av_fetch (av, i, 1);
              sv_utf8_downgrade (sv, 0);

              pv = SvPVbyte (sv, pvlen);

              if (pvlen != addrlen)
                {
                  dst [ 0] = 0x00; dst [ 1] = 0x00; dst [ 2] = 0x00; dst [ 3] = 0x00;
                  dst [ 4] = 0x00; dst [ 5] = 0x00; dst [ 6] = 0x00; dst [ 7] = 0x00;
                  dst [ 8] = 0x00; dst [ 9] = 0x00; dst [10] = 0xff; dst [11] = 0xff;
                  dst [12] = pv [0]; dst [13] = pv [1]; dst [14] = pv [2]; dst [15] = pv [3];
                }
              else
                memcpy (dst, pv, addrlen);
            }

        pinger_add_range (self, range);
}



( run in 1.035 second using v1.01-cache-2.11-cpan-e1769b4cff6 )