Agent-TCLI-Package-Net

 view release on metacpan or  search on metacpan

lib/Agent/TCLI/Package/Net/Traceroute.pm  view on Meta::CPAN

=over

=item new ( hash of attributes )

Usually the only attributes that are useful on creation are the
verbose and do_verbose attrbiutes that are inherited from Agent::TCLI::Base.

=cut

sub _start {
	my ($kernel,  $self,  $session) =
      @_[KERNEL, OBJECT,   SESSION];
	$self->Verbose("_start: tcli traceroute starting");

	# are we up before OIO has finished initializing object?
	if (!defined( $self->name ))
	{
		$kernel->yield('_start');
		return;
	}

	# There is only one command object per TCLI
    $kernel->alias_set($self->name);

	# Keep the pinger session so we can shut it down

	# Create a pinger component.
	POE::Component::Client::Traceroute->spawn(
    	Alias          => 'tracer',   # Defaults to tracer
    	FirstHop       => 1,          # Defaults to 1
    	MaxTTL         => 32,         # Defaults to 32 hops
    	Timeout        => 0,          # Defaults to never
    	QueryTimeout   => 3,          # Defaults to 3 seconds
    	Queries        => 3,          # Defaults to 3 queries per hop
    	BasePort       => 33434,      # Defaults to 33434
    	PacketLen      => 128,        # Defaults to 68
    	SourceAddress  => '0.0.0.0',  # Defaults to '0.0.0.0'
    	PerHopPostback => 0,          # Defaults to no PerHopPostback
    	Device         => undef,     # Defaults to undef
    	UseICMP        => 0,          # Defaults to 0
    	Debug          => 0,          # Defaults to 0
    	DebugSocket    => 0,          # Defaults to 0
	);

	return($self->name.":_start complete ");
} #end start

sub _shutdown {
    my ($kernel,  $self,) =
      @_[KERNEL, OBJECT,];
	$self->Verbose("_shutdown: ".$self->name." shutting down",2);
	$kernel->post('tracer' => 'shutdown');

	$kernel->alarm_remove_all();

	return($self->name.":_shutdown complete ");
}

=item trace

This POE event handler processes the trace command

=cut

sub trace {
    my ($kernel,  $self, $session, $request, ) =
      @_[KERNEL, OBJECT,  SESSION,     ARG0, ];

	my $txt = '';
	my $param;
	my $command = $request->command->[0];
	my $cmd = $self->commands->{'traceroute'};

	return unless ( $param = $cmd->Validate($kernel, $request, $self) );

	$self->Verbose("trace: param dump",4,$param);

	my $target;

	if ( defined( $param->{'target'} ) && ref( $param->{'target'} ) eq 'NetAddr::IP' )
	{
		$target = $param->{'target'}
	}
	else
	{
		$self->Verbose('trace: target not specified ');
		$request->Respond($kernel,  "Target must be defined in command line or in default settings.",412);
		return;
	}

	if ( $param->{'target'}->version() == 6 )
	{
		$request->Respond($kernel,  "IPv6 currently not supported.",400);
		return;
	}
	if ( $param->{'target'}->masklen() != 32 )
	{
		$request->Respond($kernel,  "Address blocks not supported.",400);
		return;
	}

	$self->Verbose("trace: target(".$param->{'target'}.") \n",2);

	# only one traceroute per host at a time
	if (defined($self->requests->{$param->{'target'}->addr}{'request'} ))
	{
		$self->Verbose('trace: trace in progress for target'.$param->{'target'}->addr);
		$request->Respond($kernel,"trace already in progress for ".$param->{'target'}->addr,409);
		return;
	}

	# $txt will be populated if there was an error.
	if ($txt)
	{
		$self->Verbose('trace: argument error '.$txt);
		$request->Respond($kernel, $txt,412);
		return;
	}

	my @trace_options;
	push(@trace_options,
		'MaxTTL'   		=> $param->{'max_ttl'},
		'FirstHop' 		=> $param->{'firsthop'},
    	'Timeout'  		=> $param->{'timeout'},
    	'QueryTimeout'  => $param->{'querytimeout'},
    	'Queries'		=> $param->{'queries'},
    	'BasePort'		=> $param->{'baseport'},
 		);
	push(@trace_options,'PerHopPostBack','TraceHopResponse')
		if $param->{'trace_verbose'};

	push(@trace_options,'UseICMP',1)
		if ($param->{'useicmp'} || ($^O eq "MSWin32"));

  	$self->requests->{$param->{'target'}->addr}{'request'} = $request;

	$self->Verbose(" target ".$param->{'target'}->addr." options ",
		1,\@trace_options );

	# execution
    $kernel->post(
        "tracer",           # Post request to 'tracer' component
        "traceroute",       # Ask it to traceroute to an address
        "TraceResponse",    # Post answers to 'trace_response'
        $param->{'target'}->addr, 	    # This is the host to traceroute to
        \@trace_options
#        [
#          PerHopPostback  => 'TraceHopResponse',
#          Queries   => 5,         # Override the global queries parameter
#          MaxTTL    => 30,        # Override the global MaxTTL parameter
#          Callback  => [ $args ], # Data to send back with postback event
#        ]
    );

	return($self->name.":trace done");
}

=item TraceResponse

This POE event handler processes the return data from the PoCo::Client::Traceroute.

=cut

sub TraceResponse {
	my ($kernel,  $self, $trace, $reply) =
	  @_[KERNEL, OBJECT,   ARG0,  ARG1];

    my ($destination, $options, $callback) = @$trace;
    my ($hops, $data, $error)              = @$reply;

	$self->Verbose("TraceResponse: destination(".$destination.")");
	my ($txt,$code);
	my $request = delete($self->requests->{$destination}{'request'});

	# define code first, so that error can include hops that might
	# have been successful.
	$code = 200;

	if ($error)
	{
		$txt = "trace failed for ".$destination.": ".$error;
		$code = 400;  # request_timeout
	}

	# Hops are returned whether success of failure.
	if ($hops)
	{
		$txt .= "Traceroute results for $destination\n";

		foreach my $hop (@$data)
		{
			my $hopnumber = $hop->{hop};
        	my $routerip  = $hop->{routerip};
        	my @rtts      = @{$hop->{results}};

        	$txt .= "$hopnumber\t$routerip";
        	foreach (@rtts)
        	{
          		if ($_ eq "*") { $txt .= "\t   *     "; }
          		else { $txt .= "\t".sprintf "%0.3fms ", $_*1000; }
        	}
        	$txt .= "\n";
		}
	}

	$request->Respond($kernel, $txt, $code );

	return($self->name.":TraceResponse done");
}

=item TraceHopResponse

This POE event handler processes the per hop return data from the
PoCo::Client::Traceroute.

=cut

sub TraceHopResponse {
	my ($kernel,  $self, $trace, $reply) =
	  @_[KERNEL, OBJECT,   ARG0,  ARG1];

    my ($destination, $options, $callback) = @$trace;
    my ($hops, $data, $error)              = @$reply;

	$self->Verbose("TraceResponse: destination(".$destination.")");
	my ($txt,$code);
	my $request = delete($self->requests->{$destination}{'request'});

	# define code first, so that error can include hops that might
	# have been successful.
	$code = 206;  # partial content

	if ($error)
	{
		$txt = "trace failed for ".$destination.": ".$error;
		$code = 400;  # request_timeout
	}

	# Hops are returned whether success of failure.
	if ($hops)
	{
		$txt .= "Traceroute results for $destination\n";

		foreach my $hop (@$data)
		{
			my $hopnumber = $hop->{hop};
        	my $routerip  = $hop->{routerip};
        	my @rtts      = @{$hop->{results}};

        	$txt .= "$hopnumber\t$routerip\t";
        	foreach (@rtts)
        	{
          		if ($_ eq "*") { $txt .= "* "; }
          		else { $txt .= sprintf "%0.3fms ", $_*1000; }
        	}
        	$txt .= "\n";
		}
	}

	$request->Respond($kernel, $txt, $code );

	return($self->name.":TraceResponse done");
}

sub _preinit :PreInit {
	my ($self,$args) = @_;

	$args->{'name'} = 'tcli_trace';

	$args->{'session'} = POE::Session->create(
      object_states => [
          $self => [qw(
          	_start



( run in 1.457 second using v1.01-cache-2.11-cpan-39bf76dae61 )