Class: ESSH::Transport::PacketStream
- Inherits:
-
Libuv::TCP
- Object
- Libuv::TCP
- ESSH::Transport::PacketStream
- Includes:
- Net::SSH::Loggable, Net::SSH::Transport::Constants
- Defined in:
- lib/evented-ssh/transport/packet_stream.rb
Instance Attribute Summary collapse
-
#algorithms ⇒ Object
Returns the value of attribute algorithms.
-
#client ⇒ Object
readonly
The client state object, which encapsulates the algorithms used to build packets to send to the server.
-
#hints ⇒ Object
readonly
The map of “hints” that can be used to modify the behavior of the packet stream.
-
#server ⇒ Object
readonly
The server state object, which encapsulates the algorithms used to interpret packets coming from the server.
Instance Method Summary collapse
-
#available ⇒ Object
Returns the number of bytes available to be read from the input buffer.
-
#client_name ⇒ Object
The name of the client (local) end of the socket, as reported by the socket.
-
#enqueue_packet(payload) ⇒ Object
Enqueues a packet to be sent, but does not immediately send the packet.
- #get_packet(mode = :block) ⇒ Object
-
#if_needs_rekey? ⇒ Boolean
If the IO object requires a rekey operation (as indicated by either its client or server state objects, see State#needs_rekey?), this will yield.
-
#initialize(session, **options) ⇒ PacketStream
constructor
A new instance of PacketStream.
-
#peer_ip ⇒ Object
The IP address of the peer (remote) end of the socket, as reported by the socket.
- #prepare(buff) ⇒ Object
- #process_waiting ⇒ Object
- #queue_packet(packet) ⇒ Object
-
#read_available(length = nil) ⇒ Object
Read up to
length
bytes from the input buffer. -
#read_buffer ⇒ Object
:nodoc:.
Constructor Details
#initialize(session, **options) ⇒ PacketStream
Returns a new instance of PacketStream.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 15 def initialize(session, **) @hints = {} @server = ::Net::SSH::Transport::State.new(self, :server) @client = ::Net::SSH::Transport::State.new(self, :client) @packet = nil @packets = [] @packets = [] @pending_packets = [] @process_pending = nil @awaiting = [] @input = ::Net::SSH::Buffer.new @session = session @have_header = false self.logger = [:logger] super(session.reactor, **) progress { |data| check_packet(data) } end |
Instance Attribute Details
#algorithms ⇒ Object
Returns the value of attribute algorithms.
42 43 44 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 42 def algorithms @algorithms end |
#client ⇒ Object (readonly)
The client state object, which encapsulates the algorithms used to build packets to send to the server.
56 57 58 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 56 def client @client end |
#hints ⇒ Object (readonly)
The map of “hints” that can be used to modify the behavior of the packet stream. For instance, when authentication succeeds, an “authenticated” hint is set, which is used to determine whether or not to compress the data when using the “delayed” compression algorithm.
48 49 50 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 48 def hints @hints end |
#server ⇒ Object (readonly)
The server state object, which encapsulates the algorithms used to interpret packets coming from the server.
52 53 54 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 52 def server @server end |
Instance Method Details
#available ⇒ Object
Returns the number of bytes available to be read from the input buffer. (See #read_available.)
173 174 175 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 173 def available @input.available end |
#client_name ⇒ Object
The name of the client (local) end of the socket, as reported by the socket.
60 61 62 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 60 def client_name sockname[0] end |
#enqueue_packet(payload) ⇒ Object
Enqueues a packet to be sent, but does not immediately send the packet. The given payload is pre-processed according to the algorithms specified in the client state (compression, cipher, and hmac).
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 73 def enqueue_packet(payload) # try to compress the packet payload = client.compress(payload) # the length of the packet, minus the padding actual_length = 4 + payload.bytesize + 1 # compute the padding length padding_length = client.block_size - (actual_length % client.block_size) padding_length += client.block_size if padding_length < 4 # compute the packet length (sans the length field itself) packet_length = payload.bytesize + padding_length + 1 if packet_length < 16 padding_length += client.block_size packet_length = payload.bytesize + padding_length + 1 end padding = Array.new(padding_length) { rand(256) }.pack("C*") unencrypted_data = [packet_length, padding_length, payload, padding].pack("NCA*A*") mac = client.hmac.digest([client.sequence_number, unencrypted_data].pack("NA*")) encrypted_data = client.update_cipher(unencrypted_data) << client.final_cipher = "#{encrypted_data}#{mac}" debug { "queueing packet nr #{client.sequence_number} type #{payload.getbyte(0)} len #{packet_length}" } client.increment(packet_length) direct_write() self end |
#get_packet(mode = :block) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 108 def get_packet(mode = :block) case mode when :nonblock return @packets.shift when :block packet = @packets.shift return packet unless packet.nil? defer = @reactor.defer @awaiting << defer return defer.promise.value else raise ArgumentError, "expected :block or :nonblock, got #{mode.inspect}" end rescue nil end |
#if_needs_rekey? ⇒ Boolean
If the IO object requires a rekey operation (as indicated by either its client or server state objects, see State#needs_rekey?), this will yield. Otherwise, this does nothing.
157 158 159 160 161 162 163 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 157 def if_needs_rekey? if client.needs_rekey? || server.needs_rekey? yield client.reset! if client.needs_rekey? server.reset! if server.needs_rekey? end end |
#peer_ip ⇒ Object
The IP address of the peer (remote) end of the socket, as reported by the socket.
66 67 68 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 66 def peer_ip peername[0] end |
#prepare(buff) ⇒ Object
36 37 38 39 40 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 36 def prepare(buff) progress { |data| check_packet(data) } check_packet(buff) unless buff.empty? #start_read end |
#process_waiting ⇒ Object
145 146 147 148 149 150 151 152 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 145 def process_waiting loop do break if @packets.empty? waiting = @awaiting.shift break unless waiting waiting.resolve(@packets.shift) end end |
#queue_packet(packet) ⇒ Object
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 125 def queue_packet(packet) pending = @algorithms.pending? if not pending @packets << packet elsif Algorithms.allowed_packet?(packet) @packets << packet else @pending_packets << packet if @process_pending.nil? @process_pending = pending @process_pending.promise.finally do @process_pending = nil @packets.concat(@pending_packets) @pending_packets.clear process_waiting end end end end |
#read_available(length = nil) ⇒ Object
Read up to length
bytes from the input buffer. If length
is nil, all available data is read from the buffer. (See #available.)
167 168 169 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 167 def read_available(length = nil) @input.read(length || available) end |
#read_buffer ⇒ Object
:nodoc:
177 178 179 |
# File 'lib/evented-ssh/transport/packet_stream.rb', line 177 def read_buffer #:nodoc: @input.to_s end |