libssh 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +1 -0
- data/example/exec.rb +7 -19
- data/example/local_forward.rb +65 -0
- data/example/sshkit.rb +2 -0
- data/ext/libssh_ruby/channel.c +163 -41
- data/ext/libssh_ruby/extconf.rb +15 -3
- data/ext/libssh_ruby/libssh_ruby.c +4 -0
- data/lib/libssh/version.rb +1 -1
- data/lib/sshkit/backends/libssh.rb +34 -44
- data/libssh.gemspec +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4aaa6647d6cc89439be59eeacbf35a3a21d72bf5
|
4
|
+
data.tar.gz: fe1ea02bf8d3405739187fddcfa2064486d5db98
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ded180b1cfe0766e45e2ddefd438db49c9ca8c2a4edf2dde1fe59453274010df4d7c3a9f038224d35345285d22a6c3b7a7836b1ffb6601119ce2aa3cb464c94a
|
7
|
+
data.tar.gz: 7b6fda7559baeeabe109e7ac30222335d52d930f752ae4542d51a81351d5e08e444fb48ad41826616d0b298dea8c67415e9d99f2c11b2a48d19c5e09d7a2e690
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -38,6 +38,7 @@ See [example](example) directory.
|
|
38
38
|
See [example/sshkit.rb](example/sshkit.rb) .
|
39
39
|
|
40
40
|
### With Capistrano
|
41
|
+
sshkit must be v1.9.0 or later due to [SSHKit::Backend::ConnectionPool API change](https://github.com/capistrano/sshkit/releases/tag/v1.9.0.rc1).
|
41
42
|
|
42
43
|
```ruby
|
43
44
|
require 'sshkit/backends/libssh'
|
data/example/exec.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'libssh'
|
3
|
-
require 'io/wait'
|
4
3
|
|
5
4
|
GC.stress = true
|
6
5
|
puts "libssh #{LibSSH::LIBSSH_VERSION}"
|
@@ -39,28 +38,17 @@ end
|
|
39
38
|
bufsiz = 16384
|
40
39
|
|
41
40
|
channel = LibSSH::Channel.new(session)
|
42
|
-
io = IO.for_fd(session.fd, autoclose: false)
|
43
41
|
channel.open_session do
|
44
42
|
channel.request_exec('ps auxf')
|
45
43
|
until channel.eof?
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
if out && !out.empty?
|
51
|
-
$stdout.write(out)
|
52
|
-
else
|
53
|
-
break
|
54
|
-
end
|
44
|
+
LibSSH::Channel.select([channel], [], [], nil)
|
45
|
+
out = channel.read_nonblocking(bufsiz)
|
46
|
+
if out && !out.empty?
|
47
|
+
$stdout.write(out)
|
55
48
|
end
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
if err && !err.empty?
|
60
|
-
$stderr.write(err)
|
61
|
-
else
|
62
|
-
break
|
63
|
-
end
|
49
|
+
err = channel.read_nonblocking(bufsiz, stderr: true)
|
50
|
+
if err && !err.empty?
|
51
|
+
$stderr.write(err)
|
64
52
|
end
|
65
53
|
end
|
66
54
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'libssh'
|
3
|
+
require 'socket'
|
4
|
+
require 'thread'
|
5
|
+
|
6
|
+
GC.stress = true
|
7
|
+
|
8
|
+
ssh_host = 'rossmann'
|
9
|
+
remote_host = 'localhost'
|
10
|
+
remote_port = 5432
|
11
|
+
local_port = 3000
|
12
|
+
|
13
|
+
session = LibSSH::Session.new
|
14
|
+
session.host = ssh_host
|
15
|
+
session.parse_config
|
16
|
+
session.add_identity('%d/id_ed25519')
|
17
|
+
|
18
|
+
session.connect
|
19
|
+
if session.server_known != LibSSH::SERVER_KNOWN_OK
|
20
|
+
raise 'server unknown'
|
21
|
+
end
|
22
|
+
if session.userauth_publickey_auto != LibSSH::AUTH_SUCCESS
|
23
|
+
raise 'authorization failed'
|
24
|
+
end
|
25
|
+
|
26
|
+
mutex = Mutex.new
|
27
|
+
cv = ConditionVariable.new
|
28
|
+
server_thread = Thread.start do
|
29
|
+
bufsiz = 16384
|
30
|
+
TCPServer.open(local_port) do |server|
|
31
|
+
mutex.synchronize { cv.signal }
|
32
|
+
socket = server.accept
|
33
|
+
channel = LibSSH::Channel.new(session)
|
34
|
+
channel.open_forward(remote_host, remote_port) do
|
35
|
+
reader = Thread.start do
|
36
|
+
begin
|
37
|
+
loop do
|
38
|
+
channel.write(socket.readpartial(bufsiz))
|
39
|
+
end
|
40
|
+
# rubocop:disable Lint/HandleExceptions
|
41
|
+
rescue EOFError
|
42
|
+
end
|
43
|
+
channel.send_eof
|
44
|
+
end
|
45
|
+
|
46
|
+
writer = Thread.start do
|
47
|
+
loop do
|
48
|
+
size = channel.poll
|
49
|
+
if size.nil?
|
50
|
+
break
|
51
|
+
end
|
52
|
+
data = channel.read(size)
|
53
|
+
socket.write(data)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
reader.join
|
58
|
+
writer.join
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
mutex.synchronize { cv.wait(mutex) }
|
64
|
+
system('psql', '-h', 'localhost', '-p', local_port.to_s, '-U', 'postgres', '-d', 'postgres', '-c', 'SELECT NOW()')
|
65
|
+
server_thread.join
|
data/example/sshkit.rb
CHANGED
data/ext/libssh_ruby/channel.c
CHANGED
@@ -105,34 +105,14 @@ static VALUE m_close(VALUE self) {
|
|
105
105
|
return Qnil;
|
106
106
|
}
|
107
107
|
|
108
|
-
static void select_session(ssh_session session) {
|
109
|
-
fd_set fds;
|
110
|
-
int fd;
|
111
|
-
|
112
|
-
FD_ZERO(&fds);
|
113
|
-
fd = ssh_get_fd(session);
|
114
|
-
FD_SET(fd, &fds);
|
115
|
-
select(fd + 1, &fds, NULL, NULL, NULL);
|
116
|
-
}
|
117
|
-
|
118
108
|
static void *nogvl_open_session(void *ptr) {
|
119
109
|
struct nogvl_channel_args *args = ptr;
|
120
|
-
|
121
|
-
int blocking = ssh_is_blocking(session);
|
122
|
-
|
123
|
-
ssh_set_blocking(session, 0);
|
124
|
-
while (1) {
|
125
|
-
args->rc = ssh_channel_open_session(args->channel);
|
126
|
-
if (args->rc != SSH_AGAIN) {
|
127
|
-
break;
|
128
|
-
}
|
129
|
-
rb_thread_check_ints();
|
130
|
-
select_session(session);
|
131
|
-
}
|
132
|
-
ssh_set_blocking(session, blocking);
|
110
|
+
args->rc = ssh_channel_open_session(args->channel);
|
133
111
|
return NULL;
|
134
112
|
}
|
135
113
|
|
114
|
+
/* FIXME: When Channel#open_session is called before authorization,
|
115
|
+
* #open_session will block infinitely and unable to stop it by C-c. */
|
136
116
|
/*
|
137
117
|
* @overload open_session
|
138
118
|
* Open a session channel, and close it after the block.
|
@@ -162,6 +142,51 @@ static VALUE m_open_session(VALUE self) {
|
|
162
142
|
}
|
163
143
|
}
|
164
144
|
|
145
|
+
struct nogvl_open_forward_args {
|
146
|
+
ssh_channel channel;
|
147
|
+
const char *remote_host;
|
148
|
+
int remote_port;
|
149
|
+
int rc;
|
150
|
+
};
|
151
|
+
|
152
|
+
static void *nogvl_open_forward(void *ptr) {
|
153
|
+
struct nogvl_open_forward_args *args = ptr;
|
154
|
+
args->rc = ssh_channel_open_forward(args->channel, args->remote_host,
|
155
|
+
args->remote_port, "localhost", 22);
|
156
|
+
return NULL;
|
157
|
+
}
|
158
|
+
|
159
|
+
/* FIXME: When Channel#open_forward is called before authorization,
|
160
|
+
* #open_session will block infinitely and unable to stop it by C-c. */
|
161
|
+
/*
|
162
|
+
* @overload open_forward(remote_host, remote_port)
|
163
|
+
* Open a TCP/IP forwarding channel.
|
164
|
+
* @param [String] remote_host The remote host to connected.
|
165
|
+
* @param [Fixnum] remote_port The remote port.
|
166
|
+
* @return [nil]
|
167
|
+
* @since 0.4.0
|
168
|
+
* @see http://api.libssh.org/stable/group__libssh__channel.html
|
169
|
+
* ssh_channel_open_forward
|
170
|
+
*/
|
171
|
+
static VALUE m_open_forward(VALUE self, VALUE remote_host, VALUE remote_port) {
|
172
|
+
ChannelHolder *holder;
|
173
|
+
struct nogvl_open_forward_args args;
|
174
|
+
|
175
|
+
TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder);
|
176
|
+
args.remote_host = StringValueCStr(remote_host);
|
177
|
+
Check_Type(remote_port, T_FIXNUM);
|
178
|
+
args.remote_port = FIX2INT(remote_port);
|
179
|
+
args.channel = holder->channel;
|
180
|
+
rb_thread_call_without_gvl(nogvl_open_forward, &args, RUBY_UBF_IO, NULL);
|
181
|
+
RAISE_IF_ERROR(args.rc);
|
182
|
+
|
183
|
+
if (rb_block_given_p()) {
|
184
|
+
return rb_ensure(rb_yield, Qnil, m_close, self);
|
185
|
+
} else {
|
186
|
+
return Qnil;
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
165
190
|
struct nogvl_request_exec_args {
|
166
191
|
ssh_channel channel;
|
167
192
|
char *cmd;
|
@@ -236,10 +261,10 @@ static void *nogvl_read(void *ptr) {
|
|
236
261
|
}
|
237
262
|
|
238
263
|
/*
|
239
|
-
* @overload read(count,
|
264
|
+
* @overload read(count, stderr: false, timeout: -1)
|
240
265
|
* Read data from a channel.
|
241
266
|
* @param [Fixnum] count The count of bytes to be read.
|
242
|
-
* @param [Boolean]
|
267
|
+
* @param [Boolean] stderr Read from the stderr flow or not.
|
243
268
|
* @param [Fixnum] timeout A timeout in seconds. +-1+ means infinite timeout.
|
244
269
|
* @return [String] Data read from the channel.
|
245
270
|
* @see http://api.libssh.org/stable/group__libssh__channel.html
|
@@ -333,7 +358,7 @@ static VALUE m_read_nonblocking(int argc, VALUE *argv, VALUE self) {
|
|
333
358
|
|
334
359
|
/*
|
335
360
|
* @overload eof?
|
336
|
-
* Check if remote
|
361
|
+
* Check if remote has sent an EOF.
|
337
362
|
* @return [Boolean]
|
338
363
|
* @see http://api.libssh.org/stable/group__libssh__channel.html
|
339
364
|
* ssh_channel_is_eof
|
@@ -345,6 +370,36 @@ static VALUE m_eof_p(VALUE self) {
|
|
345
370
|
return ssh_channel_is_eof(holder->channel) ? Qtrue : Qfalse;
|
346
371
|
}
|
347
372
|
|
373
|
+
/*
|
374
|
+
* @overload closed?
|
375
|
+
* Check if the channel is closed or not.
|
376
|
+
* @return [Boolean]
|
377
|
+
* @since 0.4.0
|
378
|
+
* @see http://api.libssh.org/stable/group__libssh__channel.html
|
379
|
+
* ssh_channel_is_closed
|
380
|
+
*/
|
381
|
+
static VALUE m_closed_p(VALUE self) {
|
382
|
+
ChannelHolder *holder;
|
383
|
+
|
384
|
+
TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder);
|
385
|
+
return ssh_channel_is_closed(holder->channel) ? Qtrue : Qfalse;
|
386
|
+
}
|
387
|
+
|
388
|
+
/*
|
389
|
+
* @overload open?
|
390
|
+
* Check if the channel is open or not.
|
391
|
+
* @return [Boolean]
|
392
|
+
* @since 0.4.0
|
393
|
+
* @see http://api.libssh.org/stable/group__libssh__channel.html
|
394
|
+
* ssh_channel_is_open
|
395
|
+
*/
|
396
|
+
static VALUE m_open_p(VALUE self) {
|
397
|
+
ChannelHolder *holder;
|
398
|
+
|
399
|
+
TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder);
|
400
|
+
return ssh_channel_is_open(holder->channel) ? Qtrue : Qfalse;
|
401
|
+
}
|
402
|
+
|
348
403
|
struct nogvl_poll_args {
|
349
404
|
ssh_channel channel;
|
350
405
|
int timeout;
|
@@ -360,9 +415,9 @@ static void *nogvl_poll(void *ptr) {
|
|
360
415
|
}
|
361
416
|
|
362
417
|
/*
|
363
|
-
* @overload poll(
|
418
|
+
* @overload poll(stderr: false, timeout: -1)
|
364
419
|
* Poll a channel for data to read.
|
365
|
-
* @param [Boolean]
|
420
|
+
* @param [Boolean] stderr A boolean to select the stderr stream.
|
366
421
|
* @param [Fixnum] timeout A timeout in milliseconds. A negative value means an
|
367
422
|
* infinite timeout.
|
368
423
|
* @return [Fixnum, nil] The number of bytes available for reading. +nil+ if
|
@@ -405,22 +460,12 @@ static VALUE m_poll(int argc, VALUE *argv, VALUE self) {
|
|
405
460
|
|
406
461
|
static void *nogvl_get_exit_status(void *ptr) {
|
407
462
|
struct nogvl_channel_args *args = ptr;
|
408
|
-
|
409
|
-
int blocking = ssh_is_blocking(session);
|
410
|
-
|
411
|
-
ssh_set_blocking(session, 0);
|
412
|
-
while (1) {
|
413
|
-
args->rc = ssh_channel_get_exit_status(args->channel);
|
414
|
-
if (args->rc != SSH_ERROR) {
|
415
|
-
break;
|
416
|
-
}
|
417
|
-
rb_thread_check_ints();
|
418
|
-
select_session(session);
|
419
|
-
}
|
420
|
-
ssh_set_blocking(session, blocking);
|
463
|
+
args->rc = ssh_channel_get_exit_status(args->channel);
|
421
464
|
return NULL;
|
422
465
|
}
|
423
466
|
|
467
|
+
/* FIXME: When Channel#get_exit_status is called before #request_exec,
|
468
|
+
* #get_exit_status will block infinitely and unable to stop it by C-c. */
|
424
469
|
/*
|
425
470
|
* @overload get_exit_status
|
426
471
|
* Get the exit status of the channel.
|
@@ -502,6 +547,76 @@ static VALUE m_send_eof(VALUE self) {
|
|
502
547
|
return Qnil;
|
503
548
|
}
|
504
549
|
|
550
|
+
struct nogvl_select_args {
|
551
|
+
ssh_channel *read_channels, *write_channels, *except_channels;
|
552
|
+
struct timeval *timeout;
|
553
|
+
int rc;
|
554
|
+
};
|
555
|
+
|
556
|
+
static void *nogvl_select(void *ptr) {
|
557
|
+
struct nogvl_select_args *args = ptr;
|
558
|
+
args->rc = ssh_channel_select(args->read_channels, args->write_channels,
|
559
|
+
args->except_channels, args->timeout);
|
560
|
+
return NULL;
|
561
|
+
}
|
562
|
+
|
563
|
+
static void set_select_channels(ssh_channel **c_channels, VALUE rb_channels) {
|
564
|
+
long i, len;
|
565
|
+
|
566
|
+
Check_Type(rb_channels, T_ARRAY);
|
567
|
+
len = RARRAY_LEN(rb_channels);
|
568
|
+
if (len == 0) {
|
569
|
+
*c_channels = NULL;
|
570
|
+
} else {
|
571
|
+
for (i = 0; i < len; i++) {
|
572
|
+
Check_TypedStruct(RARRAY_AREF(rb_channels, i), &channel_type);
|
573
|
+
}
|
574
|
+
*c_channels = ALLOC_N(ssh_channel, len+1);
|
575
|
+
for (i = 0; i < len; i++) {
|
576
|
+
ChannelHolder *holder;
|
577
|
+
TypedData_Get_Struct(RARRAY_AREF(rb_channels, i), ChannelHolder,
|
578
|
+
&channel_type, holder);
|
579
|
+
(*c_channels)[i] = holder->channel;
|
580
|
+
}
|
581
|
+
(*c_channels)[len] = NULL;
|
582
|
+
}
|
583
|
+
}
|
584
|
+
|
585
|
+
/*
|
586
|
+
* @overload select(read_channels, write_channels, except_channels, timeout)
|
587
|
+
* Act like the standard select(2) on channels.
|
588
|
+
* @param [Array<Channel>] read_channels
|
589
|
+
* @param [Array<Channel>] write_channels
|
590
|
+
* @param [Array<Channel>] except_channels
|
591
|
+
* @param [Fixnum, nil] timeout timeout in seconds.
|
592
|
+
* @return [nil]
|
593
|
+
* @see http://api.libssh.org/stable/group__libssh__channel.html
|
594
|
+
* ssh_channel_select
|
595
|
+
*/
|
596
|
+
static VALUE s_select(RB_UNUSED_VAR(VALUE self), VALUE read_channels,
|
597
|
+
VALUE write_channels, VALUE except_channels,
|
598
|
+
VALUE timeout) {
|
599
|
+
struct nogvl_select_args args;
|
600
|
+
struct timeval tv;
|
601
|
+
|
602
|
+
if (NIL_P(timeout)) {
|
603
|
+
args.timeout = NULL;
|
604
|
+
} else {
|
605
|
+
Check_Type(timeout, T_FIXNUM);
|
606
|
+
tv.tv_sec = FIX2INT(timeout);
|
607
|
+
tv.tv_usec = 0;
|
608
|
+
args.timeout = &tv;
|
609
|
+
}
|
610
|
+
set_select_channels(&args.read_channels, read_channels);
|
611
|
+
set_select_channels(&args.write_channels, write_channels);
|
612
|
+
set_select_channels(&args.except_channels, except_channels);
|
613
|
+
rb_thread_call_without_gvl(nogvl_select, &args, RUBY_UBF_IO, NULL);
|
614
|
+
ruby_xfree(args.read_channels);
|
615
|
+
ruby_xfree(args.write_channels);
|
616
|
+
ruby_xfree(args.except_channels);
|
617
|
+
return Qnil;
|
618
|
+
}
|
619
|
+
|
505
620
|
/*
|
506
621
|
* Document-class: LibSSH::Channel
|
507
622
|
* Wrapper for ssh_channel struct in libssh.
|
@@ -518,6 +633,8 @@ void Init_libssh_channel(void) {
|
|
518
633
|
RUBY_METHOD_FUNC(m_initialize), 1);
|
519
634
|
rb_define_method(rb_cLibSSHChannel, "open_session",
|
520
635
|
RUBY_METHOD_FUNC(m_open_session), 0);
|
636
|
+
rb_define_method(rb_cLibSSHChannel, "open_forward",
|
637
|
+
RUBY_METHOD_FUNC(m_open_forward), 2);
|
521
638
|
rb_define_method(rb_cLibSSHChannel, "close", RUBY_METHOD_FUNC(m_close), 0);
|
522
639
|
rb_define_method(rb_cLibSSHChannel, "request_exec",
|
523
640
|
RUBY_METHOD_FUNC(m_request_exec), 1);
|
@@ -528,12 +645,17 @@ void Init_libssh_channel(void) {
|
|
528
645
|
RUBY_METHOD_FUNC(m_read_nonblocking), -1);
|
529
646
|
rb_define_method(rb_cLibSSHChannel, "poll", RUBY_METHOD_FUNC(m_poll), -1);
|
530
647
|
rb_define_method(rb_cLibSSHChannel, "eof?", RUBY_METHOD_FUNC(m_eof_p), 0);
|
648
|
+
rb_define_method(rb_cLibSSHChannel, "closed?", RUBY_METHOD_FUNC(m_closed_p), 0);
|
649
|
+
rb_define_method(rb_cLibSSHChannel, "open?", RUBY_METHOD_FUNC(m_open_p), 0);
|
531
650
|
rb_define_method(rb_cLibSSHChannel, "get_exit_status",
|
532
651
|
RUBY_METHOD_FUNC(m_get_exit_status), 0);
|
533
652
|
rb_define_method(rb_cLibSSHChannel, "write", RUBY_METHOD_FUNC(m_write), 1);
|
534
653
|
rb_define_method(rb_cLibSSHChannel, "send_eof", RUBY_METHOD_FUNC(m_send_eof),
|
535
654
|
0);
|
536
655
|
|
656
|
+
rb_define_singleton_method(rb_cLibSSHChannel, "select",
|
657
|
+
RUBY_METHOD_FUNC(s_select), 4);
|
658
|
+
|
537
659
|
id_stderr = rb_intern("stderr");
|
538
660
|
id_timeout = rb_intern("timeout");
|
539
661
|
}
|
data/ext/libssh_ruby/extconf.rb
CHANGED
@@ -1,9 +1,21 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
|
3
|
-
|
3
|
+
if ENV['LIBSSH_CFLAGS']
|
4
|
+
$CFLAGS = ENV['LIBSSH_CFLAGS']
|
5
|
+
else
|
6
|
+
$CFLAGS << ' -Wall -W'
|
7
|
+
end
|
8
|
+
|
9
|
+
unless have_header('libssh/libssh.h')
|
10
|
+
abort 'Cannot find libssh/libssh.h'
|
11
|
+
end
|
12
|
+
unless have_library('ssh')
|
13
|
+
abort 'Cannot find libssh'
|
14
|
+
end
|
15
|
+
unless have_library('ssh_threads')
|
16
|
+
abort 'Cannot find libssh_threads'
|
17
|
+
end
|
4
18
|
|
5
|
-
have_header('libssh/libssh.h')
|
6
|
-
have_library('ssh')
|
7
19
|
have_const('SSH_KEYTYPE_ED25519', 'libssh/libssh.h')
|
8
20
|
|
9
21
|
create_makefile('libssh/libssh_ruby')
|
@@ -1,4 +1,5 @@
|
|
1
1
|
#include "libssh_ruby.h"
|
2
|
+
#include <libssh/callbacks.h>
|
2
3
|
|
3
4
|
VALUE rb_mLibSSH;
|
4
5
|
|
@@ -26,6 +27,9 @@ static VALUE m_version(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self)) {
|
|
26
27
|
}
|
27
28
|
|
28
29
|
void Init_libssh_ruby(void) {
|
30
|
+
ssh_threads_set_callbacks(ssh_threads_get_pthread());
|
31
|
+
ssh_init();
|
32
|
+
|
29
33
|
rb_mLibSSH = rb_define_module("LibSSH");
|
30
34
|
|
31
35
|
/* @see Session#server_known */
|
data/lib/libssh/version.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'libssh'
|
2
|
-
require 'io/wait'
|
3
2
|
require 'sshkit/backends/abstract'
|
4
3
|
require 'sshkit/backends/connection_pool'
|
5
4
|
|
@@ -53,8 +52,12 @@ module SSHKit
|
|
53
52
|
scp.init do
|
54
53
|
scp.push_file(File.basename(remote), io.size, mode)
|
55
54
|
info "Uploading #{remote}"
|
56
|
-
|
57
|
-
|
55
|
+
begin
|
56
|
+
loop do
|
57
|
+
scp.write(io.readpartial(BUFSIZ))
|
58
|
+
end
|
59
|
+
# rubocop:disable Lint/HandleExceptions
|
60
|
+
rescue EOFError
|
58
61
|
end
|
59
62
|
end
|
60
63
|
end
|
@@ -110,33 +113,24 @@ module SSHKit
|
|
110
113
|
|
111
114
|
with_session do |session|
|
112
115
|
channel = LibSSH::Channel.new(session)
|
113
|
-
io = IO.for_fd(session.fd, autoclose: false)
|
114
116
|
channel.open_session do
|
115
117
|
if Libssh.config.pty
|
116
118
|
channel.request_pty
|
117
119
|
end
|
118
120
|
channel.request_exec(cmd.to_command)
|
119
121
|
until channel.eof?
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
output.log_command_data(cmd, :stdout, buf)
|
127
|
-
else
|
128
|
-
break
|
129
|
-
end
|
122
|
+
LibSSH::Channel.select([channel], [], [], nil)
|
123
|
+
|
124
|
+
buf = channel.read_nonblocking(BUFSIZ)
|
125
|
+
if buf && !buf.empty?
|
126
|
+
cmd.on_stdout(channel, buf)
|
127
|
+
output.log_command_data(cmd, :stdout, buf)
|
130
128
|
end
|
131
129
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
output.log_command_data(cmd, :stderr, buf)
|
137
|
-
else
|
138
|
-
break
|
139
|
-
end
|
130
|
+
buf = channel.read_nonblocking(BUFSIZ, stderr: true)
|
131
|
+
if buf && !buf.empty?
|
132
|
+
cmd.on_stderr(channel, buf)
|
133
|
+
output.log_command_data(cmd, :stderr, buf)
|
140
134
|
end
|
141
135
|
end
|
142
136
|
|
@@ -182,30 +176,26 @@ module SSHKit
|
|
182
176
|
end
|
183
177
|
end
|
184
178
|
|
185
|
-
def with_session
|
179
|
+
def with_session(&block)
|
186
180
|
host.ssh_options = Libssh.config.ssh_options.merge(host.ssh_options || {})
|
187
|
-
|
188
|
-
|
189
|
-
session.host = hostname
|
190
|
-
username = ssh_options.fetch(:user, username)
|
191
|
-
if username
|
192
|
-
session.user = username
|
193
|
-
end
|
194
|
-
configure_session(session, ssh_options)
|
195
|
-
session.connect
|
196
|
-
if session.server_known != LibSSH::SERVER_KNOWN_OK
|
197
|
-
raise 'unknown host'
|
198
|
-
end
|
199
|
-
if session.userauth_publickey_auto != LibSSH::AUTH_SUCCESS
|
200
|
-
raise 'authorization failed'
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
181
|
+
self.class.pool.with(method(:create_session), String(host.hostname), host.username, host.netssh_options, &block)
|
182
|
+
end
|
204
183
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
184
|
+
def create_session(hostname, username, ssh_options)
|
185
|
+
LibSSH::Session.new.tap do |session|
|
186
|
+
session.host = hostname
|
187
|
+
username = ssh_options.fetch(:user, username)
|
188
|
+
if username
|
189
|
+
session.user = username
|
190
|
+
end
|
191
|
+
configure_session(session, ssh_options)
|
192
|
+
session.connect
|
193
|
+
if session.server_known != LibSSH::SERVER_KNOWN_OK
|
194
|
+
raise 'unknown host'
|
195
|
+
end
|
196
|
+
if session.userauth_publickey_auto != LibSSH::AUTH_SUCCESS
|
197
|
+
raise 'authorization failed'
|
198
|
+
end
|
209
199
|
end
|
210
200
|
end
|
211
201
|
|
data/libssh.gemspec
CHANGED
@@ -26,6 +26,6 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_development_dependency 'rake-compiler'
|
27
27
|
spec.add_development_dependency 'rspec', '>= 3.0.0'
|
28
28
|
spec.add_development_dependency 'rubocop', '>= 0.36.0'
|
29
|
-
spec.add_development_dependency 'sshkit'
|
29
|
+
spec.add_development_dependency 'sshkit', '>= 1.9.0'
|
30
30
|
spec.add_development_dependency 'yard'
|
31
31
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: libssh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kohei Suzuki
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-04-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -86,14 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
89
|
+
version: 1.9.0
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
96
|
+
version: 1.9.0
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: yard
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -130,6 +130,7 @@ files:
|
|
130
130
|
- bin/console
|
131
131
|
- bin/setup
|
132
132
|
- example/exec.rb
|
133
|
+
- example/local_forward.rb
|
133
134
|
- example/scp_download.rb
|
134
135
|
- example/scp_upload.rb
|
135
136
|
- example/sshkit.rb
|
@@ -167,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
167
168
|
version: '0'
|
168
169
|
requirements: []
|
169
170
|
rubyforge_project:
|
170
|
-
rubygems_version: 2.
|
171
|
+
rubygems_version: 2.6.1
|
171
172
|
signing_key:
|
172
173
|
specification_version: 4
|
173
174
|
summary: Ruby binding for libssh.
|