net-telnet-rfc2217 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f0b5b2b5e014b1fc9906ae0be1e7d33fb5d3971cce0b4eda74332e6a1ee24a9e
4
+ data.tar.gz: b56a17ffee69e60c4c8f805fd5fb16a0195a95719ed3b93a4fc5417c1dbb0e2f
5
+ SHA512:
6
+ metadata.gz: 1b4b82e214841d59828c733e9c15a65d2e623ee807f42df97353054564cb6bd7991f6900182ecd35cedebf83876c9388ecdce8574639a86b0e4d237e3e8f0a96
7
+ data.tar.gz: 35da8ce422ca87cfc75ad2c4461582d9ec54f8335f74bb381fe178d12890bae4f5034e7338488187c07cdfb6a900e2eb89f95909c7cdd536a33581062b0c5861
@@ -0,0 +1 @@
1
+ require 'net/telnet/rfc2217'
@@ -0,0 +1,219 @@
1
+ require 'net/telnet'
2
+ require 'byebug'
3
+
4
+ # have to patch Telnet to allow us to read control sequences
5
+ require 'net/telnet/rfc2217/telnet'
6
+ Net::Telnet.prepend(Net::Telnet::RFC2217::TelnetExtensions)
7
+
8
+ module Net
9
+ class Telnet
10
+ class RFC2217
11
+ class WaitReadable < RuntimeError
12
+ include ::IO::WaitReadable
13
+ end
14
+
15
+ attr_reader :telnet
16
+
17
+ COM_PORT_OPTION = 44.chr
18
+
19
+ SET_BAUDRATE = 1.chr
20
+ SET_DATASIZE = 2.chr
21
+ SET_PARITY = 3.chr
22
+ SET_STOPSIZE = 4.chr
23
+ SET_CONTROL = 5.chr
24
+ NOTIFY_LINESTATE = 6.chr
25
+ NOTIFY_MODEMSTATE = 7.chr
26
+ FLOWCONTROL_SUSPEND = 8.chr
27
+ SET_LINESTATE_MASK = 10.chr
28
+ SET_MODEMSTATE_MASK = 11.chr
29
+ PURGE_DATA = 12.chr
30
+
31
+ SET_BAUDRATE_RESPONSE = 101.chr
32
+ SET_DATASIZE_RESPONSE = 102.chr
33
+ SET_PARITY_RESPONSE = 103.chr
34
+ SET_STOPSIZE_RESPONSE = 104.chr
35
+ SET_CONTROL_RESPONSE = 105.chr
36
+ NOTIFY_LINESTATE_RESPONSE = 106.chr
37
+ NOTIFY_MODEMSTATE_RESPONSE = 107.chr
38
+ FLOWCONTROL_SUSPEND_RESPONSE = 108.chr
39
+ SET_LINESTATE_MASK_RESPONSE = 110.chr
40
+ SET_MODEMSTATE_MASK_RESPONSE = 111.chr
41
+ PURGE_DATA_RESPONSE = 112.chr
42
+
43
+ NONE = 1
44
+ ODD = 2
45
+ EVEN = 3
46
+ MARK = 4
47
+ SPACE = 5
48
+
49
+ SERIAL_PORT_PARAMS = %w{baud data_bits stop_bits parity}.freeze
50
+
51
+ class << self
52
+ def open(options)
53
+ sp = new(options)
54
+ if block_given?
55
+ begin
56
+ yield sp
57
+ ensure
58
+ sp.close
59
+ end
60
+ nil
61
+ else
62
+ nil
63
+ end
64
+ end
65
+ end
66
+
67
+ def initialize(options = {}, &block)
68
+ set_modem_params(options.slice(*SERIAL_PORT_PARAMS))
69
+
70
+ options['Binmode'] = true
71
+ options['Telnetmode'] = false
72
+ @telnet = Telnet.new(options, &block)
73
+ telnet.write(IAC + WILL + COM_PORT_OPTION)
74
+ sock.flush
75
+ @buffer = ''
76
+ readpartial(0)
77
+ end
78
+
79
+ def get_modem_params
80
+ @modem_params
81
+ end
82
+
83
+ def set_modem_params(modem_params)
84
+ @modem_params = modem_params.dup
85
+ @modem_params['baud'] = 115200 unless @modem_params.key?('baud')
86
+ @modem_params['data_bits'] = 8 unless @modem_params.key?('data_bits')
87
+ @modem_params['stop_bits'] = 1 unless @modem_params.key?('stop_bits')
88
+ unless @modem_params.key?('parity')
89
+ @modem_params['parity'] = (data_bits == 8 ? NONE : EVEN)
90
+ end
91
+ write_modem_params if telnet
92
+ end
93
+
94
+ def baud
95
+ get_modem_params['baud']
96
+ end
97
+
98
+ def data_bits
99
+ get_modem_params['data_bits']
100
+ end
101
+
102
+ def stop_bits
103
+ get_modem_params['stop_bits']
104
+ end
105
+
106
+ def parity
107
+ get_modem_params['parity']
108
+ end
109
+
110
+ def sock
111
+ @telnet.sock
112
+ end
113
+
114
+ def read(length, outbuf = '')
115
+ readpartial(length, outbuf)
116
+ while outbuf.length < length
117
+ outbuf.concat(length - outbuf.length)
118
+ end
119
+ outbuf
120
+ end
121
+
122
+ def readpartial(length, outbuf = '')
123
+ loop do
124
+ # 0 is special and means 'read at least one control sequence'
125
+ break if length != 0 || @buffer.length != 0
126
+
127
+ data = sock.sysread([length - @buffer.length, 64 * 1024].max)
128
+
129
+ # avoid getting caught in the middle of a control sequence
130
+ while (data[-1] == IAC && sock.wait_readable(0))
131
+ data.concat(sock.sysread(16))
132
+ end
133
+
134
+ saw_control = false
135
+ data = @telnet.preprocess(data) do |control|
136
+ saw_control = true
137
+ if DO[0] == control[0] && COM_PORT_OPTION == control[1]
138
+ # start negotiation
139
+ write_modem_params
140
+ true
141
+ elsif DONT[0] == control[0] && COM_PORT_OPTION == control[1]
142
+ raise "Serial port control not supported"
143
+ elsif (WILL[0] == control[0] || DONT[0] == control[0]) && OPT_ECHO == control[1]
144
+ # just ignore echo requests
145
+ true
146
+ else
147
+ false
148
+ end
149
+ end
150
+ @buffer.concat(data)
151
+ break if length == 0 && saw_control
152
+ end
153
+
154
+ length = [length, @buffer.length].min
155
+ outbuf.replace(@buffer[0...length])
156
+ @buffer = @buffer[length..-1]
157
+ outbuf
158
+ end
159
+
160
+ def read_nonblock(length, outbuf = '', options = {})
161
+ if outbuf == ({ exception: false })
162
+ options = outbuf
163
+ outbuf = ''
164
+ end
165
+ loop do
166
+ result = wait_readable(0)
167
+ if result == nil
168
+ raise WaitReadable unless options[:exception] == false
169
+ return :wait_readable
170
+ end
171
+ # we have to try to consume control characters first
172
+ readpartial(0)
173
+ # and then only do a real read if we have something
174
+ return readpartial(length, outbuf) unless @buffer.empty?
175
+ # otherwise loop and see if there's more there
176
+ end
177
+ end
178
+
179
+ def wait_readable(timeout = nil)
180
+ return true unless @buffer.empty?
181
+ result = sock.wait_readable(timeout)
182
+ result = self if result == sock
183
+ result
184
+ end
185
+
186
+ def ungetbyte(b)
187
+ @buffer.insert(0, b.chr)
188
+ end
189
+
190
+ def ungetc(c)
191
+ @buffer.insert(0, c)
192
+ end
193
+
194
+ def write(string)
195
+ string = string.gsub(/#{IAC}/no, IAC + IAC)
196
+ telnet.write(string)
197
+ end
198
+
199
+ def flush
200
+ sock.flush
201
+ end
202
+
203
+ def close
204
+ telnet.close
205
+ end
206
+
207
+ private
208
+
209
+ def write_modem_params
210
+ telnet.write(
211
+ IAC + SB + COM_PORT_OPTION + SET_BAUDRATE + [baud].pack("N") + IAC + SE +
212
+ IAC + SB + COM_PORT_OPTION + SET_DATASIZE + data_bits.chr + IAC + SE +
213
+ IAC + SB + COM_PORT_OPTION + SET_STOPSIZE + stop_bits.chr + IAC + SE +
214
+ IAC + SB + COM_PORT_OPTION + SET_PARITY + parity.chr + IAC + SE)
215
+ sock.flush
216
+ end
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,80 @@
1
+ module Net
2
+ class Telnet
3
+ class RFC2217
4
+ module TelnetExtensions
5
+ def preprocess(string)
6
+ # combine CR+NULL into CR
7
+ string = string.gsub(/#{CR}#{NULL}/no, CR) if @options["Telnetmode"]
8
+
9
+ # combine EOL into "\n"
10
+ string = string.gsub(/#{EOL}/no, "\n") unless @options["Binmode"]
11
+
12
+ # remove NULL
13
+ string = string.gsub(/#{NULL}/no, '') unless @options["Binmode"]
14
+
15
+ string.gsub(/#{IAC}(
16
+ [#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]|
17
+ [#{DO}#{DONT}#{WILL}#{WONT}]
18
+ [#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{44.chr}#{OPT_EXOPL}]|
19
+ #{SB}[^#{IAC}]*#{IAC}#{SE}
20
+ )/xno) do
21
+ if block_given? && IAC != $1
22
+ # already handled; don't handle it ourselves
23
+ next '' if yield $1
24
+ end
25
+
26
+ if IAC == $1 # handle escaped IAC characters
27
+ IAC
28
+ elsif AYT == $1 # respond to "IAC AYT" (are you there)
29
+ self.write("nobody here but us pigeons" + EOL)
30
+ ''
31
+ elsif DO[0] == $1[0] # respond to "IAC DO x"
32
+ if OPT_BINARY[0] == $1[1]
33
+ unless @telnet_option["BINARY"] == true
34
+ @telnet_option["BINARY"] = true
35
+ self.write(IAC + WILL + OPT_BINARY)
36
+ end
37
+ else
38
+ self.write(IAC + WONT + $1[1..1])
39
+ end
40
+ ''
41
+ elsif DONT[0] == $1[0] # respond to "IAC DON'T x" with "IAC WON'T x"
42
+ self.write(IAC + WONT + $1[1..1])
43
+ ''
44
+ elsif WILL[0] == $1[0] # respond to "IAC WILL x"
45
+ if OPT_BINARY[0] == $1[1]
46
+ self.write(IAC + DO + OPT_BINARY)
47
+ elsif OPT_ECHO[0] == $1[1]
48
+ self.write(IAC + DO + OPT_ECHO)
49
+ elsif OPT_SGA[0] == $1[1]
50
+ unless @telnet_option["SGA"]
51
+ @telnet_option["SGA"] = true
52
+ self.write(IAC + DO + OPT_SGA)
53
+ end
54
+ else
55
+ self.write(IAC + DONT + $1[1..1])
56
+ end
57
+ ''
58
+ elsif WONT[0] == $1[0] # respond to "IAC WON'T x"
59
+ if OPT_ECHO[0] == $1[1]
60
+ self.write(IAC + DONT + OPT_ECHO)
61
+ elsif OPT_SGA[0] == $1[1]
62
+ unless @telnet_option["SGA"] == false
63
+ @telnet_option["SGA"] = false
64
+ self.write(IAC + DONT + OPT_SGA)
65
+ end
66
+ else
67
+ self.write(IAC + DONT + $1[1..1])
68
+ end
69
+ ''
70
+ elsif SB[0] == $1[0] # yield sub option
71
+ ''
72
+ else
73
+ ''
74
+ end
75
+ end
76
+ end # preprocess
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,7 @@
1
+ module Net
2
+ class Telnet
3
+ class RFC2217
4
+ VERSION = '0.0.2'
5
+ end
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: net-telnet-rfc2217
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Cody Cutrer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-05-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: net-telnet
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: byebug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '9.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '9.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ description:
56
+ email: cody@cutrer.com'
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - lib/net-telnet-rfc2217.rb
62
+ - lib/net/telnet/rfc2217.rb
63
+ - lib/net/telnet/rfc2217/telnet.rb
64
+ - lib/net/telnet/rfc2217/version.rb
65
+ homepage: https://github.com/ccutrer/net-telnet-2217
66
+ licenses:
67
+ - MIT
68
+ metadata: {}
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ requirements: []
84
+ rubygems_version: 3.0.3
85
+ signing_key:
86
+ specification_version: 4
87
+ summary: Library for getting an IO-like object for a remote serial port
88
+ test_files: []