AnyEvent-FastPing
view release on metacpan or search on metacpan
FastPing.xs view on Meta::CPAN
pinger_add_range (PINGER *self, RANGE *range)
{
if (self->rangecnt == self->rangemax)
self->ranges = realloc (self->ranges, sizeof (self->ranges [0]) * (self->rangemax <<= 1));
self->ranges [self->rangecnt] = range;
upheap (self, self->rangecnt);
++self->rangecnt;
}
/*****************************************************************************/
static void
recv_feed (PINGER *self, void *addr, int addrlen, tstamp rtt)
{
if (!self->recvq)
{
/* first seen this round */
if (!SvOK (self->recvcb))
return;
self->recvq = newAV ();
self->nextrecv = firstrecv;
firstrecv = self->id;
}
{
AV *pkt = newAV ();
av_extend (pkt, 2-1);
AvARRAY (pkt)[0] = newSVpvn (addr, addrlen);
AvARRAY (pkt)[1] = newSVnv (rtt);
AvFILLp (pkt) = 2-1;
av_push (self->recvq, newRV_noinc ((SV *)pkt));
}
}
static void
recv_flush (void)
{
if (firstrecv < 0)
return;
ENTER;
SAVETMPS;
do
{
dSP;
PINGER *self = pingers [firstrecv];
firstrecv = self->nextrecv;
self->nextrecv = -1;
PUSHMARK (SP);
XPUSHs (sv_2mortal (newRV_noinc ((SV *)self->recvq)));
self->recvq = 0;
PUTBACK;
call_sv (self->recvcb, G_DISCARD | G_VOID);
}
while (firstrecv >= 0);
FREETMPS;
LEAVE;
}
/*****************************************************************************/
#if 0
static void
feed_reply (AV *res_av)
{
dSP;
SV *res = sv_2mortal (newRV_inc ((SV *)res_av));
int i;
if (av_len (res_av) < 0)
return;
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;
}
#endif
static void
boot_protocols (void)
{
icmp4_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
fcntl (icmp4_fd, F_SETFL, O_NONBLOCK);
#ifdef ICMP_FILTER
{
struct icmp_filter oval;
oval.data = 0xffffffff & ~(1 << ICMP4_ECHO_REPLY);
setsockopt (icmp4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval);
}
#endif
#if ENABLE_IPV6
icmp6_fd = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
fcntl (icmp6_fd, F_SETFL, O_NONBLOCK);
# ifdef ICMP6_FILTER
{
struct icmp6_filter oval;
ICMP6_FILTER_SETBLOCKALL (&oval);
ICMP6_FILTER_SETPASS (ICMP6_ECHO_REPLY, &oval);
setsockopt (icmp6_fd, IPPROTO_ICMPV6, ICMP6_FILTER, &oval, sizeof oval);
}
# endif
#endif
}
static void
boot (void)
{
if (pipe (thr_res) < 0)
croak ("AnyEvent::FastPing: unable to create receive pipe");
sv_setiv (get_sv ("AnyEvent::FastPing::THR_RES_FD", 1), thr_res [0]);
boot_protocols ();
sv_setiv (get_sv ("AnyEvent::FastPing::ICMP4_FD", 1), icmp4_fd);
sv_setiv (get_sv ("AnyEvent::FastPing::ICMP6_FD", 1), icmp6_fd);
}
#define NOT_RUNNING \
if (self->running) \
croak ("AnyEvent::FastPing object has been started - you have to stop it first before calling this method, caught");
MODULE = AnyEvent::FastPing PACKAGE = AnyEvent::FastPing PREFIX = pinger_
PROTOTYPES: DISABLE
BOOT:
{
HV *stash = gv_stashpv ("AnyEvent::FastPing", 1);
FastPing.xs view on Meta::CPAN
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);
}
( run in 2.121 seconds using v1.01-cache-2.11-cpan-13bb782fe5a )