Net-Netconf

 view release on metacpan or  search on metacpan

lib/Net/Netconf/Access/ssh.pm  view on Meta::CPAN


    my $ssh2 = Net::SSH2->new();
    croak "Failed to create a new Net::SSH2 object" unless(ref $ssh2);

    $self->trace("Making SSH connection to '$self->{'hostname'}:$port'...");
    $ssh2->connect($self->{'hostname'}, $port);
    croak "SSH connection failed: " . $ssh2->error() if($ssh2->error());
    $self->trace("SSH connection succeeded!");

    $self->trace("Performing SSH authentication");
    $ssh2->auth(username => $self->{'login'},
                password => $self->{'password'});
    croak "SSH authentication failed" if(!$ssh2->auth_ok() or $ssh2->error());
    $self->trace("Authentication succeeded!");

    $self->trace("Requesting SSH channel...");
    my $chan = $ssh2->channel();
    croak "Failed to create SSH channel" if(!ref $chan or $ssh2->error());
    $self->trace("Successfully created SSH channel!");

    $self->trace("Starting subsystem '$self->{'server'}'...");
    my $subsystem = $chan->subsystem($self->{'server'});
    if(!$subsystem) {
        $self->trace("Failed to start '$self->{'server'}' subsystem, trying to exec");
        $chan->exec($self->{'server'})
            or croak "Failed to exec ". $self->{'server'};
	$chan->flush();
	$self->trace("Started server '$self->{'server'}' in exec");
    } else {
        $self->trace("Successfully started subsystem!");
    }

    $self->{'ssh2'} = $ssh2;
    $self->{'chan'} = $chan;
    return $self;
}

# Gracefully disconnect from Netconf server
sub disconnect {
    my $self = shift;

    my $ssh2 = $self->{'ssh2'};
    $ssh2->disconnect("Bye bye from $0 [" . __PACKAGE__ . " v$VERSION]");
    $self->trace("Disconnected from SSH server");

    undef $self;
}

# Writes an XML request to the Netconf server.
sub send {
    my ($self, $xml) = @_;

    $xml .= ']]>]]>';

    my $len = length($xml);

    $self->trace("Will write $len bytes to the SSH channel:");
    $self->trace("$xml");

    # Make the channel blocking, so the write() call below waits until there
    # is available buffer space. Otherwise we'll end up busy-looping.
    $self->{'chan'}->blocking(1);

    my $written = 0;
    while($written != $len) {
        my $nbytes = $self->{'chan'}->write($xml)
            or croak "Failed to write XML data to SSH channel!";
        $written += $nbytes;
        $self->trace("Wrote $nbytes bytes (total written: $written).");
        substr($xml, 0, $nbytes) = '';
    }
    $self->trace("Successfully wrote $written bytes to SSH channel!");
    return 1;
}

# Reads an XML reply from the Netconf server.
sub recv {
    my $self = shift;
    my $ssh2 = $self->{'ssh2'};
    my $chan = $self->{'chan'};

    # Make the channel non-blocking, so that read() below allows for partial
    # reads (as we can't possibly know if the data we're about to receive is an
    # exact multiple of the buffer size argument, and doing it one character at
    # a time instead would be terribly inefficient).
    $chan->blocking(0);

    $self->trace("Reading XML response from Netconf server...");
    my ($resp, $buf);
    my $end_time = time() + 15;
    do {
        # Wait up to 10 seconds for data to become available before attempting
        # to read anything (in order to avoid busy-looping on $chan->read())
        my @poll = ({ handle => $chan, events => 'in' });
        $ssh2->poll(40000, \@poll);

        $nbytes = $chan->read($buf, 65536);

        if (!defined $nbytes || time() > $end_time) {
            croak "Failed to read XML data from SSH channel!";
        }
	if($nbytes > 0){
	    $end_time = time() + 15;
	}
        $self->trace("Read $nbytes bytes from SSH channel: '$buf'");
        $resp .= $buf;
    } until($resp =~ s/]]>]]>$//);
    $self->trace("Received XML response '$resp'");

    return $resp;
}

# Checks if the server sent us an EOF
sub eof {
    my $self = shift;
    return $self->{'chan'}->eof();
}

1;

__END__

=head1 NAME

Net::Netconf::Access::ssh

=head1 SYNOPSIS

The Net::Netconf::Access::ssh module is used internally to provide SSH access to
a Net::Netconf::Access instance, using Net::SSH2.

=head1 DESCRIPTION

This is a subclass of Net::Netconf::Access class that manages an SSH connection
with the destination host. The underlying mechanics for managing the SSH
connection is based on Net::SSH2.

=head1 CONSTRUCTOR

new($ARGS)

Please refer to the constructor of Net::Netconf::Access class.

=head1 SEE ALSO

=over 4

=item *

Net::SSH2

=item *



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