Skip to content
This repository has been archived by the owner on Oct 31, 2023. It is now read-only.

mitchellh/libssh2-ruby

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

88 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

libssh2 Ruby Bindings

This library provides bindings to libssh2. LibSSH2 is a modern C-library implementing the SSH2 protocol and made by the same people who made cURL.

Project status: Alpha. Much of the library is still not yet done, and proper cross-platform testing has not been done. However, the library itself is functional, and everything in this README should work.

Motivation

The creation of libssh2-ruby was motivated primarily by edge-case issues experienced by Vagrant while using Net-SSH. Net-SSH has been around 7 years and is a stable library, but the Vagrant project found that around 1% of users were experiencing connectivity issues primarily revolving around slightly incompliant behavior by remote servers.

libssh2 is a heavily used library created by the same people as cURL, simply one of the best command line applications around. It has been around for a few years and handles the SSH2 protocol very well. It is under active development and the motivation for libssh2 to always work is high, since it is used by many high-profile open source projects.

For this reason, libssh2-ruby was made to interface with this high quality library and provide a stable and robust SSH2 interface for Ruby.

Usage

The API for interacting with SSH is idiomatic Ruby and you should find it friendly and intuitive:

require "libssh2"

# This API is not yet complete. More coming soon!

session = LibSSH2::Session.new("127.0.0.1", "2222")
session.auth_by_password("username", "password")
session.execute "echo foo" do |channel|
  channel.on_data do |data|
    puts "stdout: #{data}"
  end
end

However, if you require more fine-grained control, I don't want the API to limit you in any way. Therefore, it is my intention to expose all the native libssh2 functions on the LibSSH2::Native module as singleton methods, without the libssh2_ prefix. So if you want to call libssh2_init, you actually call LibSSH2::Native.init. Here is an example that executes a basic echo via SSH:

require "libssh2"
require "socket"
include LibSSH2::Native

# Remember, we're using the _native_ interface so below looks a lot
# like C and some nasty Ruby code, but it is the direct interface
# to libssh2. libssh2-ruby also provides a more idiomatic Ruby interface
# that you can see above in the README.
socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
socket.connect Socket.sockaddr_in("2222", "127.0.0.1")

session = session_init
session_set_blocking(session, true)
session_handshake(session, socket.fileno)
userauth_password(session, "username", "password")

channel = channel_open_session(session)
channel_exec(channel, "echo hello")
data, _ = channel_read(channel)

# Outputs "hello\n"
puts data

Are there any downsides? When should I use Net::SSH?

There are certainly some downsides. I've enumerated them below:

  • libssh2-ruby requires libssh2. This library requires libssh2 to be installed. On most platforms this is very easy but it is still another step, whereas Net::SSH is a pure Ruby implementation of the SSH protocol.
  • libssh2 can't do much for stdout/stderr ordering. Due to the way the libssh2 API is, the ordering of stdout/stderr is usually off. In practice this may or may not matter for you, and I'm working with the libssh2 team to try to address this issue in some way.
  • libssh2 doesn't have access to every stream/request. If you require advanced SSH usage, you can manually read from specific stream IDs, but the libssh2 evented interface won't work with custom stream IDs or request types. For the 99% case this is not an issue, but I did want to note that this problem exists.

That being said, libssh2 is wonderfully stable and fast, and if you're not negatively impacted by the above issues, then you should use it.

Contributing

Basic Steps

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Added some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

Using the Library from Source

Since this library is a C extension based library, it can be tricky to work on and test. It is annoying to have to build the project every time to test some new code. Luckily, you don't have to! Just follow the steps below:

  1. rake compile anytime you need to build the C extension. This should be done the first time you clone the project as well as any time you change any C code. On Linux, this will also build libssh2 for you!
  2. Make a test Ruby file that uses libssh2 as if it were actually installed. For example, just require "libssh2" like normal.
  3. Execute your test file using bundle exec ruby test.rb. This will use the source version instead of any gem installed version!

You can use the above steps to iterate on the code and verify things are working okay while you do. However, prior to committing any new functionality, you should run the acceptance tests and potentially add to it, which is covered below.

Running the Tests

This library has an acceptance test suite to verify everything is working. Since it is an acceptance test library, it will make actually SSH connections to verify things are working properly. Running the suite is easy. First, create a config.yml based on the config.yml.example file in the spec directory. This must be configured to point to a real server that can an SSH connection can be established to with both password and key based auth. Once the config.yml is in place, run the tests:

$ bundle exec rake