libssh 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7be9ae9a286b0ce4ae93064adb441780d087d3b8
4
+ data.tar.gz: 16f67e922fe6a5079b4f1548b815496b5151664b
5
+ SHA512:
6
+ metadata.gz: fb7c02285aba9f22d8c5c60ed386d2b8e1e167032ebd044d804bbc747ceeb6f740d76643312cf3910c6a04c18385e160cda2f9efdfc48db32a0385edadcafcd6
7
+ data.tar.gz: af5ed17903b463d777f6b7eee70a2fc8347a66d16eab1cad402bb8ffd272c509d4b741547505226ff40324193726dd1a90764e51a60c0f4ba3ee841bc420b3c3
@@ -0,0 +1,3 @@
1
+ Language: Cpp
2
+ BasedOnStyle: Google
3
+ Standard: C++11
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
@@ -0,0 +1,30 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ AllCops:
4
+ DisplayCopNames: true
5
+
6
+ Metrics/AbcSize:
7
+ Enabled: false
8
+ Metrics/CyclomaticComplexity:
9
+ Enabled: false
10
+ Metrics/LineLength:
11
+ Enabled: false
12
+ Metrics/MethodLength:
13
+ Enabled: false
14
+
15
+ Style/GlobalVars:
16
+ Exclude:
17
+ - 'ext/libssh_ruby/extconf.rb'
18
+ Style/HashSyntax:
19
+ Exclude:
20
+ - 'Rakefile'
21
+ Style/IfUnlessModifier:
22
+ Enabled: false
23
+ Style/Next:
24
+ Enabled: false
25
+ Style/NumericLiterals:
26
+ Enabled: false
27
+ Style/PercentLiteralDelimiters:
28
+ Enabled: false
29
+ Style/SignalException:
30
+ EnforcedStyle: only_raise
@@ -0,0 +1,7 @@
1
+ Style/Documentation:
2
+ Exclude:
3
+ - 'spec/**/*'
4
+ - 'test/**/*'
5
+ - 'lib/libssh.rb'
6
+ - 'lib/libssh/key.rb'
7
+ - 'lib/sshkit/backends/libssh.rb'
@@ -0,0 +1,16 @@
1
+ language: ruby
2
+ sudo: required
3
+ dist: trusty # Require libssh >= 0.6.0
4
+ addons:
5
+ apt:
6
+ packages:
7
+ - libssh-dev
8
+ rvm:
9
+ - 2.2
10
+ - 2.3.0
11
+ - ruby-head
12
+ before_install:
13
+ - gem install --no-rdoc --no-ri bundler
14
+ matrix:
15
+ allow_failures:
16
+ - rvm: ruby-head
@@ -0,0 +1,2 @@
1
+ ## 0.1.0 (2016-01-24)
2
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in libssh.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Kohei Suzuki
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,60 @@
1
+ # LibSSH
2
+ [![Build Status](https://travis-ci.org/eagletmt/libssh-ruby.svg?branch=master)](https://travis-ci.org/eagletmt/libssh-ruby)
3
+
4
+ Ruby binding for [libssh](https://www.libssh.org/) .
5
+
6
+ ## Stability
7
+
8
+ Under development
9
+
10
+ ## Requirement
11
+
12
+ - libssh >= 0.6.0
13
+ - ed25519 keys support is available from [libssh 0.7.0](https://www.libssh.org/2015/05/11/libssh-0-7-0/).
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'libssh'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install libssh
30
+
31
+ ## Usage
32
+
33
+ See [example/exec.rb](example/exec.rb) and [example/write.rb](example/write.rb).
34
+
35
+ ### With SSHKit
36
+
37
+ See [example/sshkit.rb](example/sshkit.rb) .
38
+
39
+ ### With Capistrano
40
+
41
+ ```ruby
42
+ require 'sshkit/backends/libssh'
43
+ set :sshkit_backend, SSHKit::Backend::Libssh
44
+ ```
45
+
46
+ ## Development
47
+
48
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
49
+
50
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
51
+
52
+ ## Contributing
53
+
54
+ Bug reports and pull requests are welcome on GitHub at https://github.com/eagletmt/libssh-ruby.
55
+
56
+
57
+ ## License
58
+
59
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
60
+
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/extensiontask'
3
+
4
+ task :build => :compile
5
+
6
+ Rake::ExtensionTask.new('libssh_ruby') do |ext|
7
+ ext.lib_dir = 'lib/libssh'
8
+ end
9
+
10
+ task :default => [:clobber, :compile]
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'libssh'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+ require 'libssh'
3
+
4
+ GC.stress = true
5
+ session = LibSSH::Session.new
6
+ # session.log_verbosity = :debug
7
+ session.host = 'barkhorn'
8
+ session.parse_config
9
+ session.add_identity('%d/id_ed25519')
10
+
11
+ session.connect
12
+ if session.server_known == LibSSH::SERVER_NOT_KNOWN
13
+ pubkey = session.get_publickey
14
+ print "Connect to #{pubkey.type_str} #{pubkey.sha1_hex} ? (y/N) "
15
+ $stdout.flush
16
+ yesno = $stdin.gets.chomp
17
+ if yesno != 'y'
18
+ raise
19
+ end
20
+ session.write_knownhost
21
+ puts 'Wrote known_hosts'
22
+ elsif session.server_known != LibSSH::SERVER_KNOWN_OK
23
+ raise
24
+ end
25
+
26
+ session.userauth_none
27
+ list = session.userauth_list
28
+ unless list.include?(:publickey)
29
+ raise "publickey is unsupported: #{list}"
30
+ end
31
+
32
+ if session.userauth_publickey_auto != LibSSH::AUTH_SUCCESS
33
+ raise 'authorization failed'
34
+ end
35
+
36
+ bufsiz = 16384
37
+
38
+ channel = LibSSH::Channel.new(session)
39
+ channel.open_session do
40
+ channel.request_exec('ps auxf')
41
+ until channel.eof?
42
+ stdout_avail = channel.poll(timeout: 1)
43
+ if stdout_avail && stdout_avail > 0
44
+ $stdout.write(channel.read(bufsiz))
45
+ end
46
+
47
+ stderr_avail = channel.poll(stderr: true, timeout: 1)
48
+ if stderr_avail && stderr_avail > 0
49
+ $stderr.write(channel.read(bufsiz, stderr: true))
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ require 'shellwords'
3
+ require 'sshkit'
4
+ require 'sshkit/backends/libssh'
5
+ require 'sshkit/dsl'
6
+
7
+ SSHKit.config.backend = SSHKit::Backend::Libssh
8
+ SSHKit.config.backend.configure do |backend|
9
+ backend.pty = ENV.key?('REQUEST_PTY')
10
+ end
11
+ SSHKit.config.output = SSHKit::Formatter::Pretty.new($stdout)
12
+ SSHKit.config.output_verbosity = :debug
13
+
14
+ on %w[barkhorn rossmann], in: :parallel do |host|
15
+ date = capture(:date)
16
+ puts "#{host}: #{date}"
17
+ end
18
+
19
+ on %w[barkhorn rossmann], in: :parallel do
20
+ execute :ruby, '-e', Shellwords.escape('puts "stdout"; $stderr.puts "stderr"')
21
+ execute :false, raise_on_non_zero_exit: false
22
+ end
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+ require 'libssh'
3
+
4
+ GC.stress = true
5
+ session = LibSSH::Session.new
6
+ # session.log_verbosity = :debug
7
+ session.host = 'barkhorn'
8
+ session.parse_config
9
+ session.add_identity('%d/id_ed25519')
10
+
11
+ session.connect
12
+ if session.server_known == LibSSH::SERVER_NOT_KNOWN
13
+ pubkey = session.get_publickey
14
+ print "Connect to #{pubkey.type_str} #{pubkey.sha1_hex} ? (y/N) "
15
+ $stdout.flush
16
+ yesno = $stdin.gets.chomp
17
+ if yesno != 'y'
18
+ raise
19
+ end
20
+ session.write_knownhost
21
+ puts 'Wrote known_hosts'
22
+ elsif session.server_known != LibSSH::SERVER_KNOWN_OK
23
+ raise
24
+ end
25
+
26
+ session.userauth_none
27
+ list = session.userauth_list
28
+ unless list.include?(:publickey)
29
+ raise "publickey is unsupported: #{list}"
30
+ end
31
+
32
+ if session.userauth_publickey_auto != LibSSH::AUTH_SUCCESS
33
+ raise 'authorization failed'
34
+ end
35
+
36
+ bufsiz = 16384
37
+
38
+ channel = LibSSH::Channel.new(session)
39
+ channel.open_session do
40
+ channel.request_exec('sed -e s/foo/bar/')
41
+ channel.write("foobarbaz\n")
42
+ channel.send_eof
43
+ until channel.eof?
44
+ stdout_avail = channel.poll(timeout: 1)
45
+ if stdout_avail && stdout_avail > 0
46
+ $stdout.write(channel.read(bufsiz))
47
+ end
48
+
49
+ stderr_avail = channel.poll(stderr: true, timeout: 1)
50
+ if stderr_avail && stderr_avail > 0
51
+ $stderr.write(channel.read(bufsiz, stderr: true))
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,350 @@
1
+ #include "libssh_ruby.h"
2
+ #include <ruby/thread.h>
3
+
4
+ #define RAISE_IF_ERROR(rc) \
5
+ if ((rc) == SSH_ERROR) \
6
+ libssh_ruby_raise(ssh_channel_get_session(holder->channel))
7
+
8
+ VALUE rb_cLibSSHChannel;
9
+
10
+ static ID id_stderr, id_timeout;
11
+
12
+ static void channel_mark(void *);
13
+ static void channel_free(void *);
14
+ static size_t channel_memsize(const void *);
15
+
16
+ struct ChannelHolderStruct {
17
+ ssh_channel channel;
18
+ VALUE session;
19
+ };
20
+ typedef struct ChannelHolderStruct ChannelHolder;
21
+
22
+ static const rb_data_type_t channel_type = {
23
+ "ssh_channel",
24
+ {channel_mark, channel_free, channel_memsize, {NULL, NULL}},
25
+ NULL,
26
+ NULL,
27
+ RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY,
28
+ };
29
+
30
+ static VALUE channel_alloc(VALUE klass) {
31
+ ChannelHolder *holder = ALLOC(ChannelHolder);
32
+ holder->channel = NULL;
33
+ holder->session = Qundef;
34
+ return TypedData_Wrap_Struct(klass, &channel_type, holder);
35
+ }
36
+
37
+ static void channel_mark(void *arg) {
38
+ ChannelHolder *holder = arg;
39
+ if (holder->channel != NULL) {
40
+ rb_gc_mark(holder->session);
41
+ }
42
+ }
43
+
44
+ static void channel_free(void *arg) {
45
+ ChannelHolder *holder = arg;
46
+
47
+ if (holder->channel != NULL) {
48
+ /* XXX: ssh_channel is freed by ssh_session */
49
+ /* ssh_channel_free(holder->channel); */
50
+ holder->channel = NULL;
51
+ }
52
+
53
+ ruby_xfree(holder);
54
+ }
55
+
56
+ static size_t channel_memsize(RB_UNUSED_VAR(const void *arg)) {
57
+ return sizeof(ChannelHolder);
58
+ }
59
+
60
+ static VALUE m_initialize(VALUE self, VALUE session) {
61
+ ChannelHolder *holder;
62
+ SessionHolder *session_holder;
63
+
64
+ TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder);
65
+ session_holder = libssh_ruby_session_holder(session);
66
+ holder->channel = ssh_channel_new(session_holder->session);
67
+ holder->session = session;
68
+
69
+ return self;
70
+ }
71
+
72
+ struct nogvl_channel_args {
73
+ ssh_channel channel;
74
+ int rc;
75
+ };
76
+
77
+ static void *nogvl_close(void *ptr) {
78
+ struct nogvl_channel_args *args = ptr;
79
+ args->rc = ssh_channel_close(args->channel);
80
+ return NULL;
81
+ }
82
+
83
+ static VALUE m_close(VALUE self) {
84
+ ChannelHolder *holder;
85
+ struct nogvl_channel_args args;
86
+
87
+ TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder);
88
+ args.channel = holder->channel;
89
+ rb_thread_call_without_gvl(nogvl_close, &args, RUBY_UBF_IO, NULL);
90
+ RAISE_IF_ERROR(args.rc);
91
+
92
+ return Qnil;
93
+ }
94
+
95
+ static void *nogvl_open_session(void *ptr) {
96
+ struct nogvl_channel_args *args = ptr;
97
+ args->rc = ssh_channel_open_session(args->channel);
98
+ return NULL;
99
+ }
100
+
101
+ static VALUE m_open_session(VALUE self) {
102
+ ChannelHolder *holder;
103
+ struct nogvl_channel_args args;
104
+
105
+ TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder);
106
+ args.channel = holder->channel;
107
+ rb_thread_call_without_gvl(nogvl_open_session, &args, RUBY_UBF_IO, NULL);
108
+ RAISE_IF_ERROR(args.rc);
109
+
110
+ if (rb_block_given_p()) {
111
+ return rb_ensure(rb_yield, Qnil, m_close, self);
112
+ } else {
113
+ return Qnil;
114
+ }
115
+ }
116
+
117
+ struct nogvl_request_exec_args {
118
+ ssh_channel channel;
119
+ char *cmd;
120
+ int rc;
121
+ };
122
+
123
+ static void *nogvl_request_exec(void *ptr) {
124
+ struct nogvl_request_exec_args *args = ptr;
125
+ args->rc = ssh_channel_request_exec(args->channel, args->cmd);
126
+
127
+ return NULL;
128
+ }
129
+
130
+ static VALUE m_request_exec(VALUE self, VALUE cmd) {
131
+ ChannelHolder *holder;
132
+ struct nogvl_request_exec_args args;
133
+
134
+ TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder);
135
+ args.channel = holder->channel;
136
+ args.cmd = StringValueCStr(cmd);
137
+ rb_thread_call_without_gvl(nogvl_request_exec, &args, RUBY_UBF_IO, NULL);
138
+ RAISE_IF_ERROR(args.rc);
139
+ return Qnil;
140
+ }
141
+
142
+ static void *nogvl_request_pty(void *ptr) {
143
+ struct nogvl_channel_args *args = ptr;
144
+ args->rc = ssh_channel_request_pty(args->channel);
145
+ return NULL;
146
+ }
147
+
148
+ static VALUE m_request_pty(VALUE self) {
149
+ ChannelHolder *holder;
150
+ struct nogvl_channel_args args;
151
+
152
+ TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder);
153
+ args.channel = holder->channel;
154
+ rb_thread_call_without_gvl(nogvl_request_pty, &args, RUBY_UBF_IO, NULL);
155
+ RAISE_IF_ERROR(args.rc);
156
+ return Qnil;
157
+ }
158
+
159
+ struct nogvl_read_args {
160
+ ssh_channel channel;
161
+ char *buf;
162
+ uint32_t count;
163
+ int is_stderr;
164
+ int timeout;
165
+ int rc;
166
+ };
167
+
168
+ static void *nogvl_read(void *ptr) {
169
+ struct nogvl_read_args *args = ptr;
170
+ args->rc = ssh_channel_read_timeout(args->channel, args->buf, args->count,
171
+ args->is_stderr, args->timeout);
172
+ return NULL;
173
+ }
174
+
175
+ static VALUE m_read(int argc, VALUE *argv, VALUE self) {
176
+ ChannelHolder *holder;
177
+ VALUE count, opts;
178
+ const ID table[] = {id_stderr, id_timeout};
179
+ VALUE kwvals[sizeof(table) / sizeof(*table)];
180
+ struct nogvl_read_args args;
181
+ VALUE ret;
182
+
183
+ TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder);
184
+ rb_scan_args(argc, argv, "10:", &count, &opts);
185
+ Check_Type(count, T_FIXNUM);
186
+ rb_get_kwargs(opts, table, 0, 2, kwvals);
187
+ if (kwvals[0] == Qundef) {
188
+ args.is_stderr = 0;
189
+ } else {
190
+ args.is_stderr = RTEST(kwvals[0]) ? 1 : 0;
191
+ }
192
+ if (kwvals[1] == Qundef) {
193
+ args.timeout = -1;
194
+ } else {
195
+ Check_Type(kwvals[1], T_FIXNUM);
196
+ args.timeout = FIX2INT(kwvals[1]);
197
+ }
198
+ args.channel = holder->channel;
199
+ args.count = FIX2UINT(count);
200
+ args.buf = ALLOC_N(char, args.count);
201
+ rb_thread_call_without_gvl(nogvl_read, &args, RUBY_UBF_IO, NULL);
202
+
203
+ ret = rb_utf8_str_new(args.buf, args.rc);
204
+ ruby_xfree(args.buf);
205
+ return ret;
206
+ }
207
+
208
+ static VALUE m_eof_p(VALUE self) {
209
+ ChannelHolder *holder;
210
+
211
+ TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder);
212
+ return ssh_channel_is_eof(holder->channel) ? Qtrue : Qfalse;
213
+ }
214
+
215
+ struct nogvl_poll_args {
216
+ ssh_channel channel;
217
+ int timeout;
218
+ int is_stderr;
219
+ int rc;
220
+ };
221
+
222
+ static void *nogvl_poll(void *ptr) {
223
+ struct nogvl_poll_args *args = ptr;
224
+ args->rc =
225
+ ssh_channel_poll_timeout(args->channel, args->timeout, args->is_stderr);
226
+ return NULL;
227
+ }
228
+
229
+ static VALUE m_poll(int argc, VALUE *argv, VALUE self) {
230
+ ChannelHolder *holder;
231
+ VALUE opts;
232
+ const ID table[] = {id_stderr, id_timeout};
233
+ VALUE kwvals[sizeof(table) / sizeof(*table)];
234
+ struct nogvl_poll_args args;
235
+
236
+ TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder);
237
+ rb_scan_args(argc, argv, "00:", &opts);
238
+ rb_get_kwargs(opts, table, 0, 2, kwvals);
239
+ if (kwvals[0] == Qundef) {
240
+ args.is_stderr = 0;
241
+ } else {
242
+ args.is_stderr = RTEST(kwvals[0]) ? 1 : 0;
243
+ }
244
+ if (kwvals[1] == Qundef) {
245
+ args.timeout = -1;
246
+ } else {
247
+ Check_Type(kwvals[1], T_FIXNUM);
248
+ args.timeout = FIX2INT(kwvals[1]);
249
+ }
250
+
251
+ args.channel = holder->channel;
252
+ rb_thread_call_without_gvl(nogvl_poll, &args, RUBY_UBF_IO, NULL);
253
+ RAISE_IF_ERROR(args.rc);
254
+
255
+ if (args.rc == SSH_EOF) {
256
+ return Qnil;
257
+ } else {
258
+ return INT2FIX(args.rc);
259
+ }
260
+ }
261
+
262
+ static void *nogvl_get_exit_status(void *ptr) {
263
+ struct nogvl_channel_args *args = ptr;
264
+ args->rc = ssh_channel_get_exit_status(args->channel);
265
+ return NULL;
266
+ }
267
+
268
+ static VALUE m_get_exit_status(VALUE self) {
269
+ ChannelHolder *holder;
270
+ struct nogvl_channel_args args;
271
+
272
+ TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder);
273
+ args.channel = holder->channel;
274
+ rb_thread_call_without_gvl(nogvl_get_exit_status, &args, RUBY_UBF_IO, NULL);
275
+ if (args.rc == -1) {
276
+ return Qnil;
277
+ } else {
278
+ return INT2FIX(args.rc);
279
+ }
280
+ }
281
+
282
+ struct nogvl_write_args {
283
+ ssh_channel channel;
284
+ const void *data;
285
+ uint32_t len;
286
+ int rc;
287
+ };
288
+
289
+ static void *nogvl_write(void *ptr) {
290
+ struct nogvl_write_args *args = ptr;
291
+ args->rc = ssh_channel_write(args->channel, args->data, args->len);
292
+ return NULL;
293
+ }
294
+
295
+ static VALUE m_write(VALUE self, VALUE data) {
296
+ ChannelHolder *holder;
297
+ struct nogvl_write_args args;
298
+
299
+ Check_Type(data, T_STRING);
300
+ TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder);
301
+ args.channel = holder->channel;
302
+ args.data = RSTRING_PTR(data);
303
+ args.len = RSTRING_LEN(data);
304
+ rb_thread_call_without_gvl(nogvl_write, &args, RUBY_UBF_IO, NULL);
305
+ RAISE_IF_ERROR(args.rc);
306
+ return INT2FIX(args.rc);
307
+ }
308
+
309
+ static void *nogvl_send_eof(void *ptr) {
310
+ struct nogvl_channel_args *args = ptr;
311
+ args->rc = ssh_channel_send_eof(args->channel);
312
+ return NULL;
313
+ }
314
+
315
+ static VALUE m_send_eof(VALUE self) {
316
+ ChannelHolder *holder;
317
+ struct nogvl_channel_args args;
318
+
319
+ TypedData_Get_Struct(self, ChannelHolder, &channel_type, holder);
320
+ args.channel = holder->channel;
321
+ rb_thread_call_without_gvl(nogvl_send_eof, &args, RUBY_UBF_IO, NULL);
322
+ RAISE_IF_ERROR(args.rc);
323
+ return Qnil;
324
+ }
325
+
326
+ void Init_libssh_channel(void) {
327
+ rb_cLibSSHChannel = rb_define_class_under(rb_mLibSSH, "Channel", rb_cObject);
328
+ rb_define_alloc_func(rb_cLibSSHChannel, channel_alloc);
329
+
330
+ rb_define_method(rb_cLibSSHChannel, "initialize",
331
+ RUBY_METHOD_FUNC(m_initialize), 1);
332
+ rb_define_method(rb_cLibSSHChannel, "open_session",
333
+ RUBY_METHOD_FUNC(m_open_session), 0);
334
+ rb_define_method(rb_cLibSSHChannel, "close", RUBY_METHOD_FUNC(m_close), 0);
335
+ rb_define_method(rb_cLibSSHChannel, "request_exec",
336
+ RUBY_METHOD_FUNC(m_request_exec), 1);
337
+ rb_define_method(rb_cLibSSHChannel, "request_pty",
338
+ RUBY_METHOD_FUNC(m_request_pty), 0);
339
+ rb_define_method(rb_cLibSSHChannel, "read", RUBY_METHOD_FUNC(m_read), -1);
340
+ rb_define_method(rb_cLibSSHChannel, "poll", RUBY_METHOD_FUNC(m_poll), -1);
341
+ rb_define_method(rb_cLibSSHChannel, "eof?", RUBY_METHOD_FUNC(m_eof_p), 0);
342
+ rb_define_method(rb_cLibSSHChannel, "get_exit_status",
343
+ RUBY_METHOD_FUNC(m_get_exit_status), 0);
344
+ rb_define_method(rb_cLibSSHChannel, "write", RUBY_METHOD_FUNC(m_write), 1);
345
+ rb_define_method(rb_cLibSSHChannel, "send_eof", RUBY_METHOD_FUNC(m_send_eof),
346
+ 0);
347
+
348
+ id_stderr = rb_intern("stderr");
349
+ id_timeout = rb_intern("timeout");
350
+ }