AnyEvent-FastPing

 view release on metacpan or  search on metacpan

FastPing.pm  view on Meta::CPAN

=head1 SYNOPSIS

 use AnyEvent::FastPing;

=head1 DESCRIPTION

This module was written for a single purpose only: sending ICMP ECHO
REQUEST packets as quickly as possible to a large number of hosts
(thousands to millions).

It employs a separate thread and is fully event-driven (using AnyEvent),
so you have to run an event model supported by AnyEvent to use this
module.

=head1 FUNCTIONS

=over 4

=cut

package AnyEvent::FastPing;

FastPing.pm  view on Meta::CPAN


=item AnyEvent::FastPing::icmp6_pktsize

Like AnyEvent::FastPing::icmp4_pktsize, but for IPv6.

=back

=head1 THE AnyEvent::FastPing CLASS

The AnyEvent::FastPing class represents a single "pinger". A "pinger"
comes with its own thread to send packets in the background, a rate-limit
machinery and separate idle/receive callbacks.

The recommended workflow (there are others) is this: 1. create a new
AnyEvent::FastPing object 2. configure the address lists and ranges to
ping, also configure an idle callback and optionally a receive callback
3. C<start> the pinger.

When the pinger has finished pinging all the configured addresses it will
call the idle callback.

FastPing.pm  view on Meta::CPAN

- you should be stingy with your pinger objects.

=cut

sub new {
   _boot;

   our $ICMP4_W = $ICMP4_FD >= 0 && (open $ICMP4_FH, "<&=$ICMP4_FD") && AE::io $ICMP4_FH, 0, \&_recv_icmp4;
   our $ICMP6_W = $ICMP6_FD >= 0 && (open $ICMP6_FH, "<&=$ICMP6_FD") && AE::io $ICMP6_FH, 0, \&_recv_icmp6;

   open $THR_RES_FH, "<&=$THR_RES_FD" or die "AnyEvent::FastPing: FATAL: cannot fdopen thread result fd";

   our $THR_RES_W = AE::io $THR_RES_FH, 0, sub {
      sysread $THR_RES_FH, my $buf, 8;

      for my $id (unpack "S*", $buf) {
         _stop_id $id;
         ($IDLE_CB[$id] || sub { })->();
      }
   };

FastPing.pm  view on Meta::CPAN


If your idle callback were called instantly after all ranges were
exhausted and you destroyed the object inside (which is common), then
there would be no chance to receive some replies, as there would be no
time of the packet to travel over the network.

This can be fixed by starting a timer in the idle callback, or more simply
by selecting a suitable C<max_rtt> value, which should be the maximum time
you allow a ping packet to travel to its destination and back.

The pinger thread automatically waits for this amount of time before becoming idle.

The default is currently C<0.5> seconds, which is usually plenty.

=item $pinger->add_range ($lo, $hi[, $interval])

Ping the IPv4 (or IPv6, but see below) address range, starting at binary
address C<$lo> and ending at C<$hi> (both C<$lo> and C<$hi> will be
pinged), generating no more than one ping per C<$interval> seconds (or as
fast as possible if omitted).

FastPing.xs  view on Meta::CPAN

#if defined(__linux) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__CYGWIN__)
# define ENABLE_IPV6 1 // if you get compilation problems try to disable IPv6
#else
# define ENABLE_IPV6 0
#endif

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include <pthread.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <time.h>
#include <poll.h>
#include <unistd.h>
#include <inttypes.h>
#include <fcntl.h>

FastPing.xs  view on Meta::CPAN

#define ICMP4_ECHO_REPLY 0
#define ICMP6_ECHO       128
#define ICMP6_ECHO_REPLY 129

#define DRAIN_INTERVAL 1e-6 // how long to wait when sendto returns ENOBUFS, in seconds
#define MIN_INTERVAL   1e-6 // minimum packet send interval, in seconds

#define HDR_SIZE_IP4  20
#define HDR_SIZE_IP6  48

static int thr_res[2]; // worker thread finished status
static int icmp4_fd = -1;
static int icmp6_fd = -1;

/*****************************************************************************/

typedef double tstamp;

static tstamp
NOW (void)
{

FastPing.xs  view on Meta::CPAN

  uint16_t magic1;
  uint16_t magic2;
  uint16_t magic3;

  int id;

  AV *recvq; /* receive queue */
  int nextrecv;
  SV *recvcb;

  pthread_t thrid;
  int running;
} PINGER;

static PINGER **pingers;
static int *pingerfree; /* freelist next */
static int pingercnt;
static int pingermax;
static int firstfree = -1;
static int firstrecv = -1;

FastPing.xs  view on Meta::CPAN


/* NetBSD, Solaris... */
#ifndef PTHREAD_STACK_MIN
# define PTHREAD_STACK_MIN 0
#endif

static void
pinger_start (PINGER *self)
{
  sigset_t fullsigset, oldsigset;
  pthread_attr_t attr;

  if (self->running)
    return;

  sigfillset (&fullsigset);

  pthread_attr_init (&attr);
  pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN < sizeof (long) * 2048 ? sizeof (long) * 2048 : PTHREAD_STACK_MIN);

  pthread_sigmask (SIG_SETMASK, &fullsigset, &oldsigset);

  if (pthread_create (&self->thrid, &attr, ping_proc, (void *)self))
    croak ("AnyEvent::FastPing: unable to create pinger thread");

  pthread_sigmask (SIG_SETMASK, &oldsigset, 0);

  self->running = 1;
}

static void
pinger_stop (PINGER *self)
{
  if (!self->running)
    return;

  self->running = 0;
  pthread_cancel (self->thrid);
  pthread_join (self->thrid, 0);
}

static void
pinger_init (PINGER *self)
{
  memset (self, 0, sizeof (PINGER));

  if (firstfree >= 0)
    {
      self->id = firstfree;

Makefile.PL  view on Meta::CPAN

	            PREOP	=> 'pod2text FastPing.pm | tee README >$(DISTVNAME)/README; chmod -R u=rwX,go=rX . ;',
	            COMPRESS	=> 'gzip -9v',
	            SUFFIX	=> '.gz',
	           },
    PREREQ_PM      => {
       AnyEvent      => 0,
       common::sense => 3.4,
    },
    NAME           => "AnyEvent::FastPing",
    VERSION_FROM   => "FastPing.pm",
    LIBS           => ["-lpthread -lm"],
    EXE_FILES      => ["bin/fastping"],
);

README  view on Meta::CPAN

    AnyEvent::FastPing - quickly ping a large number of hosts

SYNOPSIS
     use AnyEvent::FastPing;

DESCRIPTION
    This module was written for a single purpose only: sending ICMP ECHO
    REQUEST packets as quickly as possible to a large number of hosts
    (thousands to millions).

    It employs a separate thread and is fully event-driven (using AnyEvent),
    so you have to run an event model supported by AnyEvent to use this
    module.

FUNCTIONS
    AnyEvent::FastPing::ipv4_supported
        Returns true iff IPv4 is supported in this module and on this
        system.

    AnyEvent::FastPing::ipv6_supported
        Returns true iff IPv6 is supported in this module and on this

README  view on Meta::CPAN

           my $packets_per_second = $kilobit_per_second
                                    * (1000 / 8 / AnyEvent::FastPing::icmp4_pktsize);

        etc.

    AnyEvent::FastPing::icmp6_pktsize
        Like AnyEvent::FastPing::icmp4_pktsize, but for IPv6.

THE AnyEvent::FastPing CLASS
    The AnyEvent::FastPing class represents a single "pinger". A "pinger"
    comes with its own thread to send packets in the background, a
    rate-limit machinery and separate idle/receive callbacks.

    The recommended workflow (there are others) is this: 1. create a new
    AnyEvent::FastPing object 2. configure the address lists and ranges to
    ping, also configure an idle callback and optionally a receive callback
    3. "start" the pinger.

    When the pinger has finished pinging all the configured addresses it
    will call the idle callback.

README  view on Meta::CPAN

        If your idle callback were called instantly after all ranges were
        exhausted and you destroyed the object inside (which is common),
        then there would be no chance to receive some replies, as there
        would be no time of the packet to travel over the network.

        This can be fixed by starting a timer in the idle callback, or more
        simply by selecting a suitable "max_rtt" value, which should be the
        maximum time you allow a ping packet to travel to its destination
        and back.

        The pinger thread automatically waits for this amount of time before
        becoming idle.

        The default is currently 0.5 seconds, which is usually plenty.

    $pinger->add_range ($lo, $hi[, $interval])
        Ping the IPv4 (or IPv6, but see below) address range, starting at
        binary address $lo and ending at $hi (both $lo and $hi will be
        pinged), generating no more than one ping per $interval seconds (or
        as fast as possible if omitted).



( run in 0.280 second using v1.01-cache-2.11-cpan-3cd7ad12f66 )