Class: HrrRbSsh::Connection::Channel

Inherits:
Object
  • Object
show all
Includes:
Loggable
Defined in:
lib/hrr_rb_ssh/connection/channel.rb,
lib/hrr_rb_ssh/connection/channel/channel_type.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/direct_tcpip.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/forwarded_tcpip.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/proc_chain.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/env.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/exec.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/shell.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/pty_req.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/subsystem.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/proc_chain/chain_context.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/env/context.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/exec/context.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/shell/context.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/window_change.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/pty_req/context.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/subsystem/context.rb,
lib/hrr_rb_ssh/connection/channel/channel_type/session/request_type/window_change/context.rb

Defined Under Namespace

Classes: ChannelType

Constant Summary collapse

INITIAL_WINDOW_SIZE =
100000
MAXIMUM_PACKET_SIZE =
100000

Instance Attribute Summary collapse

Attributes included from Loggable

#log_key, #logger

Instance Method Summary collapse

Methods included from Loggable

#log_debug, #log_error, #log_fatal, #log_info, #log_warn

Constructor Details

#initialize(connection, message, socket = nil, logger: nil) ⇒ Channel

Returns a new instance of Channel.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 29

def initialize connection, message, socket=nil, logger: nil
  self.logger = logger

  @connection = connection

  @channel_type = message[:'channel type']
  @local_channel  = connection.assign_channel
  @remote_channel = message[:'sender channel']
  @local_window_size          = INITIAL_WINDOW_SIZE
  @local_maximum_packet_size  = MAXIMUM_PACKET_SIZE
  @remote_window_size         = message[:'initial window size']
  @remote_maximum_packet_size = message[:'maximum packet size']

  @channel_type_instance = ChannelType[@channel_type].new connection, self, message, socket, logger: logger

  @receive_message_queue = Queue.new
  @receive_data_queue = Queue.new
  @receive_extended_data_queue = Queue.new

  @r_io_in,  @w_io_in  = IO.pipe
  @r_io_out, @w_io_out = IO.pipe
  @r_io_err, @w_io_err = IO.pipe

  @channel_closing_monitor = Monitor.new

  @closed = nil
  @exit_status = nil
end

Instance Attribute Details

#channel_typeObject (readonly)

Returns the value of attribute channel_type.



18
19
20
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 18

def channel_type
  @channel_type
end

#exit_statusObject (readonly)

Returns the value of attribute exit_status.



18
19
20
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 18

def exit_status
  @exit_status
end

#local_channelObject (readonly)

Returns the value of attribute local_channel.



18
19
20
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 18

def local_channel
  @local_channel
end

#local_maximum_packet_sizeObject (readonly)

Returns the value of attribute local_maximum_packet_size.



18
19
20
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 18

def local_maximum_packet_size
  @local_maximum_packet_size
end

#local_window_sizeObject (readonly)

Returns the value of attribute local_window_size.



18
19
20
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 18

def local_window_size
  @local_window_size
end

#receive_message_queueObject (readonly)

Returns the value of attribute receive_message_queue.



18
19
20
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 18

def receive_message_queue
  @receive_message_queue
end

#remote_channelObject (readonly)

Returns the value of attribute remote_channel.



18
19
20
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 18

def remote_channel
  @remote_channel
end

#remote_maximum_packet_sizeObject (readonly)

Returns the value of attribute remote_maximum_packet_size.



18
19
20
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 18

def remote_maximum_packet_size
  @remote_maximum_packet_size
end

#remote_window_sizeObject (readonly)

Returns the value of attribute remote_window_size.



18
19
20
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 18

def remote_window_size
  @remote_window_size
end

Instance Method Details

#channel_loop_threadObject



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 164

def channel_loop_thread
  Thread.start do
    log_info { "start channel loop thread" }
    begin
      loop do
        begin
          message = @receive_message_queue.deq
          if message.nil? && @receive_message_queue.closed?
            break
          end
          case message[:'message number']
          when Message::SSH_MSG_CHANNEL_EOF::VALUE
            @receive_data_queue.close
            @receive_extended_data_queue.close
          when Message::SSH_MSG_CHANNEL_REQUEST::VALUE
            log_info { "received channel request: #{message[:'request type']}" }
            case @connection.mode
            when Mode::SERVER
              begin
                @channel_type_instance.request message
              rescue => e
                log_warn { "request failed: #{e.message}" }
                send_channel_failure if message[:'want reply']
              else
                send_channel_success if message[:'want reply']
              end
            when Mode::CLIENT
              case message[:'request type']
              when "exit-status"
                log_info { "exit status: #{message[:'exit status']}" }
                @exit_status = message[:'exit status'].to_i
              end
            end
          when Message::SSH_MSG_CHANNEL_DATA::VALUE
            log_info { "received channel data" }
            local_channel = message[:'recipient channel']
            @receive_data_queue.enq message[:'data']
          when Message::SSH_MSG_CHANNEL_EXTENDED_DATA::VALUE
            log_info { "received channel extended data" }
            local_channel = message[:'recipient channel']
            @receive_extended_data_queue.enq message[:'data']
          when Message::SSH_MSG_CHANNEL_WINDOW_ADJUST::VALUE
            log_debug { "received channel window adjust" }
            @remote_window_size = [@remote_window_size + message[:'bytes to add'], 0xffff_ffff].min
          else
            log_warn { "received unsupported message: #{message.inspect}" }
          end
        rescue => e
          log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
          close from=:channel_loop_thread
          break
        end
      end
    ensure
      log_info { "closing channel loop thread" }
      @receive_data_queue.close
      @receive_extended_data_queue.close
    end
    log_info { "channel loop thread closed" }
  end
end

#close(from = :outside, exitstatus = 0) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 111

def close from=:outside, exitstatus=0
  @channel_closing_monitor.synchronize {
    return if @closed
    log_info { "close channel" }
    @closed = true
  }
  unless from == :channel_type_instance
    @channel_type_instance.close
  end
  @receive_message_queue.close
  begin
    if from == :channel_type_instance
      send_channel_eof
      case exitstatus
      when Integer
        send_channel_request_exit_status exitstatus
      else
        log_warn { "skip sending exit-status because exitstatus is not an instance of Integer" }
      end
    elsif from == :sender_thread
      send_channel_eof
    end
    send_channel_close
  rescue Error::ClosedConnection => e
    Thread.pass
  rescue => e
    log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
  end
  log_info { "channel closed" }
end

#closed?Boolean

Returns:

  • (Boolean)


160
161
162
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 160

def closed?
  @closed
end

#err_receiver_threadObject



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 344

def err_receiver_thread
  Thread.start {
    log_info { "start err receiver thread" }
    loop do
      begin
        data = @receive_extended_data_queue.deq
        if data.nil? && @receive_extended_data_queue.closed?
          log_info { "closing err receiver thread" }
          log_info { "closing w_io_err" }
          @w_io_err.close
          log_info { "w_io_err closed" }
          break
        end
        @w_io_err.write data
        @local_window_size -= data.size
        if @local_window_size < INITIAL_WINDOW_SIZE/2
          log_info { "send channel window adjust" }
          send_channel_window_adjust
          @local_window_size += INITIAL_WINDOW_SIZE
        end
      rescue Error::EPIPE, IOError => e
        close
        break
      rescue => e
        log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
        close
        break
      end
    end
    log_info { "err receiver thread closed" }
  }
end

#err_sender_threadObject



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 252

def err_sender_thread
  Thread.start {
    log_info { "start err sender thread" }
    loop do
      if @r_io_err.closed?
        log_info { "closing err sender thread" }
        break
      end
      begin
        data = @r_io_err.readpartial(10240)
        sendable_size = [data.size, @remote_window_size].min
        sending_data = data[0, sendable_size]
        send_channel_extended_data sending_data if sendable_size > 0
        @remote_window_size -= sendable_size
      rescue EOFError, IOError => e
        @r_io_err.close rescue nil
      rescue => e
        log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
        @r_io_err.close rescue nil
        close
      end
    end
    log_info { "err sender thread closed" }
  }
end

#ioObject



64
65
66
67
68
69
70
71
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 64

def io
  case @connection.mode
  when Mode::SERVER
    [@r_io_in, @w_io_out, @w_io_err]
  when Mode::CLIENT
    [@w_io_in, @r_io_out, @r_io_err]
  end
end

#out_receiver_threadObject



311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 311

def out_receiver_thread
  Thread.start {
    log_info { "start out receiver thread" }
    loop do
      begin
        data = @receive_data_queue.deq
        if data.nil? && @receive_data_queue.closed?
          log_info { "closing out receiver thread" }
          log_info { "closing w_io_out" }
          @w_io_out.close
          log_info { "w_io_out closed" }
          break
        end
        @w_io_out.write data
        @local_window_size -= data.size
        if @local_window_size < INITIAL_WINDOW_SIZE/2
          log_info { "send channel window adjust" }
          send_channel_window_adjust
          @local_window_size += INITIAL_WINDOW_SIZE
        end
      rescue Errno::EPIPE, IOError => e
        close
        break
      rescue => e
        log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
        close
        break
      end
    end
    log_info { "out receiver thread closed" }
  }
end

#out_sender_threadObject



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 226

def out_sender_thread
  Thread.start {
    log_info { "start out sender thread" }
    loop do
      if @r_io_out.closed?
        log_info { "closing out sender thread" }
        break
      end
      begin
        data = @r_io_out.readpartial(10240)
        sendable_size = [data.size, @remote_window_size].min
        sending_data = data[0, sendable_size]
        send_channel_data sending_data if sendable_size > 0
        @remote_window_size -= sendable_size
      rescue EOFError, IOError => e
        @r_io_out.close rescue nil
      rescue => e
        log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
        @r_io_out.close rescue nil
        close
      end
    end
    log_info { "out sender thread closed" }
  }
end

#receiver_threadObject



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 278

def receiver_thread
  Thread.start {
    log_info { "start receiver thread" }
    loop do
      begin
        data = @receive_data_queue.deq
        if data.nil? && @receive_data_queue.closed?
          log_info { "closing receiver thread" }
          log_info { "closing w_io_in" }
          @w_io_in.close
          log_info { "w_io_in closed" }
          break
        end
        @w_io_in.write data
        @local_window_size -= data.size
        if @local_window_size < INITIAL_WINDOW_SIZE/2
          log_info { "send channel window adjust" }
          send_channel_window_adjust
          @local_window_size += INITIAL_WINDOW_SIZE
        end
      rescue Errno::EPIPE, IOError => e
        close
        break
      rescue => e
        log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
        close
        break
      end
    end
    log_info { "receiver thread closed" }
  }
end

#send_channel_closeObject



565
566
567
568
569
570
571
572
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 565

def send_channel_close
  message = {
    :'message number'    => Message::SSH_MSG_CHANNEL_CLOSE::VALUE,
    :'recipient channel' => @remote_channel,
  }
  payload = Message::SSH_MSG_CHANNEL_CLOSE.new(logger: logger).encode message
  @connection.send payload
end

#send_channel_data(data) ⇒ Object



431
432
433
434
435
436
437
438
439
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 431

def send_channel_data data
  message = {
    :'message number'    => Message::SSH_MSG_CHANNEL_DATA::VALUE,
    :'recipient channel' => @remote_channel,
    :'data'              => data,
  }
  payload = Message::SSH_MSG_CHANNEL_DATA.new(logger: logger).encode message
  @connection.send payload
end

#send_channel_eofObject



556
557
558
559
560
561
562
563
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 556

def send_channel_eof
  message = {
    :'message number'    => Message::SSH_MSG_CHANNEL_EOF::VALUE,
    :'recipient channel' => @remote_channel,
  }
  payload = Message::SSH_MSG_CHANNEL_EOF.new(logger: logger).encode message
  @connection.send payload
end

#send_channel_extended_data(data, code = Message::SSH_MSG_CHANNEL_EXTENDED_DATA::DataTypeCode::SSH_EXTENDED_DATA_STDERR) ⇒ Object



441
442
443
444
445
446
447
448
449
450
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 441

def send_channel_extended_data data, code=Message::SSH_MSG_CHANNEL_EXTENDED_DATA::DataTypeCode::SSH_EXTENDED_DATA_STDERR
  message = {
    :'message number'    => Message::SSH_MSG_CHANNEL_EXTENDED_DATA::VALUE,
    :'recipient channel' => @remote_channel,
    :'data type code'    => code,
    :'data'              => data,
  }
  payload = Message::SSH_MSG_CHANNEL_EXTENDED_DATA.new(logger: logger).encode message
  @connection.send payload
end

#send_channel_failureObject



412
413
414
415
416
417
418
419
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 412

def send_channel_failure
  message = {
    :'message number'    => Message::SSH_MSG_CHANNEL_FAILURE::VALUE,
    :'recipient channel' => @remote_channel,
  }
  payload = Message::SSH_MSG_CHANNEL_FAILURE.new(logger: logger).encode message
  @connection.send payload
end

#send_channel_request_env(variable_name, variable_value) ⇒ Object



469
470
471
472
473
474
475
476
477
478
479
480
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 469

def send_channel_request_env variable_name, variable_value
  message = {
    :'message number'    => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
    :'recipient channel' => @remote_channel,
    :'request type'      => "env",
    :'want reply'        => false,
    :'variable name'     => variable_name,
    :'variable value'    => variable_value,
  }
  payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
  @connection.send payload
end

#send_channel_request_exec(command) ⇒ Object



493
494
495
496
497
498
499
500
501
502
503
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 493

def send_channel_request_exec command
  message = {
    :'message number'    => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
    :'recipient channel' => @remote_channel,
    :'request type'      => "exec",
    :'want reply'        => false,
    :'command'           => command,
  }
  payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
  @connection.send payload
end

#send_channel_request_exit_status(exitstatus) ⇒ Object



544
545
546
547
548
549
550
551
552
553
554
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 544

def send_channel_request_exit_status exitstatus
  message = {
    :'message number'    => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
    :'recipient channel' => @remote_channel,
    :'request type'      => "exit-status",
    :'want reply'        => false,
    :'exit status'       => exitstatus,
  }
  payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
  @connection.send payload
end

#send_channel_request_pty_req(term_env_var_val, term_width_chars, term_height_rows, term_width_pixel, term_height_pixel, encoded_term_modes) ⇒ Object



452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 452

def send_channel_request_pty_req term_env_var_val, term_width_chars, term_height_rows, term_width_pixel, term_height_pixel, encoded_term_modes
  message = {
    :'message number'                  => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
    :'recipient channel'               => @remote_channel,
    :'request type'                    => "pty-req",
    :'want reply'                      => false,
    :'TERM environment variable value' => term_env_var_val,
    :'terminal width, characters'      => term_width_chars,
    :'terminal height, rows'           => term_height_rows,
    :'terminal width, pixels'          => term_width_pixel,
    :'terminal height, pixels'         => term_height_pixel,
    :'encoded terminal modes'          => encoded_term_modes,
  }
  payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
  @connection.send payload
end

#send_channel_request_shellObject



482
483
484
485
486
487
488
489
490
491
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 482

def send_channel_request_shell
  message = {
    :'message number'    => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
    :'recipient channel' => @remote_channel,
    :'request type'      => "shell",
    :'want reply'        => false,
  }
  payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
  @connection.send payload
end

#send_channel_request_signal(signal_name) ⇒ Object



532
533
534
535
536
537
538
539
540
541
542
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 532

def send_channel_request_signal signal_name
  message = {
    :'message number'    => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
    :'recipient channel' => @remote_channel,
    :'request type'      => "signal",
    :'want reply'        => false,
    :'signal name'       => signal_name,
  }
  payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
  @connection.send payload
end

#send_channel_request_subsystem(subsystem_name) ⇒ Object



505
506
507
508
509
510
511
512
513
514
515
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 505

def send_channel_request_subsystem subsystem_name
  message = {
    :'message number'    => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
    :'recipient channel' => @remote_channel,
    :'request type'      => "subsystem",
    :'want reply'        => false,
    :'subsystem name'    => subsystem_name,
  }
  payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
  @connection.send payload
end

#send_channel_request_window_change(term_width_cols, term_height_rows, term_width_pixel, term_height_pixel) ⇒ Object



517
518
519
520
521
522
523
524
525
526
527
528
529
530
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 517

def send_channel_request_window_change term_width_cols, term_height_rows, term_width_pixel, term_height_pixel
  message = {
    :'message number'          => Message::SSH_MSG_CHANNEL_REQUEST::VALUE,
    :'recipient channel'       => @remote_channel,
    :'request type'            => "window-change",
    :'want reply'              => false,
    :'terminal width, columns' => term_width_cols,
    :'terminal height, rows'   => term_height_rows,
    :'terminal width, pixels'  => term_width_pixel,
    :'terminal height, pixels' => term_height_pixel,
  }
  payload = Message::SSH_MSG_CHANNEL_REQUEST.new(logger: logger).encode message
  @connection.send payload
end

#send_channel_successObject



403
404
405
406
407
408
409
410
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 403

def send_channel_success
  message = {
    :'message number'    => Message::SSH_MSG_CHANNEL_SUCCESS::VALUE,
    :'recipient channel' => @remote_channel,
  }
  payload = Message::SSH_MSG_CHANNEL_SUCCESS.new(logger: logger).encode message
  @connection.send payload
end

#send_channel_window_adjustObject



421
422
423
424
425
426
427
428
429
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 421

def send_channel_window_adjust
  message = {
    :'message number'    => Message::SSH_MSG_CHANNEL_WINDOW_ADJUST::VALUE,
    :'recipient channel' => @remote_channel,
    :'bytes to add'      => INITIAL_WINDOW_SIZE,
  }
  payload = Message::SSH_MSG_CHANNEL_WINDOW_ADJUST.new(logger: logger).encode message
  @connection.send payload
end

#sender_threadObject



377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 377

def sender_thread
  Thread.start {
    log_info { "start sender thread" }
    loop do
      if @r_io_in.closed?
        log_info { "closing sender thread" }
        break
      end
      begin
        data = @r_io_in.readpartial(10240)
        sendable_size = [data.size, @remote_window_size].min
        sending_data = data[0, sendable_size]
        send_channel_data sending_data if sendable_size > 0
        @remote_window_size -= sendable_size
      rescue EOFError, IOError => e
        @r_io_in.close rescue nil
      rescue => e
        log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
        @r_io_in.close rescue nil
      end
    end
    close from=:sender_thread
    log_info { "sender thread closed" }
  }
end

#set_remote_parameters(message) ⇒ Object



58
59
60
61
62
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 58

def set_remote_parameters message
  @remote_channel = message[:'sender channel']
  @remote_window_size = message[:'initial window size']
  @remote_maximum_packet_size = message[:'maximum packet size']
end

#startObject



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 73

def start
  @channel_loop_thread = channel_loop_thread
  case @connection.mode
  when Mode::SERVER
    @out_sender_thread   = out_sender_thread
    @err_sender_thread   = err_sender_thread
    @receiver_thread     = receiver_thread
    @channel_type_instance.start
  when Mode::CLIENT
    @out_receiver_thread = out_receiver_thread
    @err_receiver_thread = err_receiver_thread
    @sender_thread       = sender_thread
    @channel_type_instance.start
  end
  @closed = false
  log_debug { "in start: #{@waiting_thread}" }
  @waiting_thread.wakeup if @waiting_thread
end

#wait_until_closedObject



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 142

def wait_until_closed
  [
    @out_sender_thread,
    @err_sender_thread,
    @receiver_thread,
    @out_receiver_thread,
    @err_receiver_thread,
    @sender_thread,
    @channel_loop_thread
  ].each{ |t|
    begin
      t.join if t.instance_of? Thread
    rescue => e
      log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
    end
  }
end

#wait_until_senders_closedObject



98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 98

def wait_until_senders_closed
  [
    @out_sender_thread,
    @err_sender_thread,
  ].each{ |t|
    begin
      t.join if t.instance_of? Thread
    rescue => e
      log_error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
    end
  }
end

#wait_until_startedObject



92
93
94
95
96
# File 'lib/hrr_rb_ssh/connection/channel.rb', line 92

def wait_until_started
  @waiting_thread = Thread.current
  log_debug { "in wait_until_started: #{@waiting_thread}" }
  Thread.stop
end