net-telnet-rfc2217 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/net-telnet-rfc2217.rb +1 -0
- data/lib/net/telnet/rfc2217.rb +181 -0
- data/lib/net/telnet/rfc2217/telnet.rb +78 -0
- data/lib/net/telnet/rfc2217/version.rb +7 -0
- metadata +88 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 80efcdecc1ad8f12d8546c6487de4ced9f2042beb7126046fd616cb4f507685c
|
4
|
+
data.tar.gz: 88afffcd92a3d0764047da96e01f1be3811614247230d4d58e563963d894ad06
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 984cfeac7c438e93816979be2ea410d398376e7d1bd0255c85e10e94bd18791c346a30357a3e36d650278ade772aff53b147e5f29485079d320995b3d606ec1d
|
7
|
+
data.tar.gz: 23c8a0d1ee8b9ac9179973f9ec8defde1402b21022febe9b26c29370eaff7def8f509c5c9848ec2cabc09c5013931eefb5224481a0eb9615f81eb9dcb96dee15
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'net/telnet/rfc2217'
|
@@ -0,0 +1,181 @@
|
|
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
|
+
attr_reader :telnet
|
12
|
+
|
13
|
+
COM_PORT_OPTION = 44.chr
|
14
|
+
|
15
|
+
SET_BAUDRATE = 1.chr
|
16
|
+
SET_DATASIZE = 2.chr
|
17
|
+
SET_PARITY = 3.chr
|
18
|
+
SET_STOPSIZE = 4.chr
|
19
|
+
SET_CONTROL = 5.chr
|
20
|
+
NOTIFY_LINESTATE = 6.chr
|
21
|
+
NOTIFY_MODEMSTATE = 7.chr
|
22
|
+
FLOWCONTROL_SUSPEND = 8.chr
|
23
|
+
SET_LINESTATE_MASK = 10.chr
|
24
|
+
SET_MODEMSTATE_MASK = 11.chr
|
25
|
+
PURGE_DATA = 12.chr
|
26
|
+
|
27
|
+
SET_BAUDRATE_RESPONSE = 101.chr
|
28
|
+
SET_DATASIZE_RESPONSE = 102.chr
|
29
|
+
SET_PARITY_RESPONSE = 103.chr
|
30
|
+
SET_STOPSIZE_RESPONSE = 104.chr
|
31
|
+
SET_CONTROL_RESPONSE = 105.chr
|
32
|
+
NOTIFY_LINESTATE_RESPONSE = 106.chr
|
33
|
+
NOTIFY_MODEMSTATE_RESPONSE = 107.chr
|
34
|
+
FLOWCONTROL_SUSPEND_RESPONSE = 108.chr
|
35
|
+
SET_LINESTATE_MASK_RESPONSE = 110.chr
|
36
|
+
SET_MODEMSTATE_MASK_RESPONSE = 111.chr
|
37
|
+
PURGE_DATA_RESPONSE = 112.chr
|
38
|
+
|
39
|
+
NONE = 1
|
40
|
+
ODD = 2
|
41
|
+
EVEN = 3
|
42
|
+
MARK = 4
|
43
|
+
SPACE = 5
|
44
|
+
|
45
|
+
SERIAL_PORT_PARAMS = %w{baud data_bits stop_bits parity}.freeze
|
46
|
+
|
47
|
+
class << self
|
48
|
+
def open(options)
|
49
|
+
sp = new(options)
|
50
|
+
if block_given?
|
51
|
+
begin
|
52
|
+
yield sp
|
53
|
+
ensure
|
54
|
+
sp.close
|
55
|
+
end
|
56
|
+
nil
|
57
|
+
else
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def initialize(options = {}, &block)
|
64
|
+
set_modem_params(options.slice(*SERIAL_PORT_PARAMS))
|
65
|
+
|
66
|
+
options['Binmode'] = true
|
67
|
+
options['Telnetmode'] = false
|
68
|
+
@telnet = Telnet.new(options, &block)
|
69
|
+
telnet.write(IAC + WILL + COM_PORT_OPTION)
|
70
|
+
sock.flush
|
71
|
+
@buffer = ''
|
72
|
+
readpartial(0)
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_modem_params
|
76
|
+
@modem_params
|
77
|
+
end
|
78
|
+
|
79
|
+
def set_modem_params(modem_params)
|
80
|
+
@modem_params = modem_params.dup
|
81
|
+
@modem_params['baud'] = 115200 unless @modem_params.key?('baud')
|
82
|
+
@modem_params['data_bits'] = 8 unless @modem_params.key?('data_bits')
|
83
|
+
@modem_params['stop_bits'] = 1 unless @modem_params.key?('stop_bits')
|
84
|
+
@modem_params['parity'] = (data_bits == 8 ? NONE : EVEN)
|
85
|
+
write_modem_params if telnet
|
86
|
+
end
|
87
|
+
|
88
|
+
def baud
|
89
|
+
get_modem_params['baud']
|
90
|
+
end
|
91
|
+
|
92
|
+
def data_bits
|
93
|
+
get_modem_params['data_bits']
|
94
|
+
end
|
95
|
+
|
96
|
+
def stop_bits
|
97
|
+
get_modem_params['stop_bits']
|
98
|
+
end
|
99
|
+
|
100
|
+
def parity
|
101
|
+
get_modem_params['parity']
|
102
|
+
end
|
103
|
+
|
104
|
+
def sock
|
105
|
+
@telnet.sock
|
106
|
+
end
|
107
|
+
|
108
|
+
def read(length, outbuf = '')
|
109
|
+
readpartial(length, outbuf)
|
110
|
+
while outbuf.length < length
|
111
|
+
outbuf.concat(length - outbuf.length)
|
112
|
+
end
|
113
|
+
outbuf
|
114
|
+
end
|
115
|
+
|
116
|
+
def readpartial(length, outbuf = '')
|
117
|
+
loop do
|
118
|
+
# 0 is special and means 'read at least one control sequence'
|
119
|
+
break if length != 0 && @buffer.length != 0
|
120
|
+
|
121
|
+
data = sock.sysread([length - @buffer.length, 64 * 1024].max)
|
122
|
+
|
123
|
+
# avoid getting caught in the middle of a control sequence
|
124
|
+
while (data[-1] == IAC && sock.wait_readable(0))
|
125
|
+
data.concat(sock.sysread(16))
|
126
|
+
end
|
127
|
+
|
128
|
+
saw_control = false
|
129
|
+
data = @telnet.preprocess(data) do |control|
|
130
|
+
saw_control = true
|
131
|
+
if DO[0] == control[0] && COM_PORT_OPTION == control[1]
|
132
|
+
# start negotiation
|
133
|
+
write_modem_params
|
134
|
+
true
|
135
|
+
elsif DONT[0] == control[0] && COM_PORT_OPTION == control[1]
|
136
|
+
raise "Serial port control not supported"
|
137
|
+
false
|
138
|
+
else
|
139
|
+
false
|
140
|
+
end
|
141
|
+
end
|
142
|
+
@buffer.concat(data)
|
143
|
+
break if length == 0 && saw_control
|
144
|
+
end
|
145
|
+
|
146
|
+
length = [length, @buffer.length].min
|
147
|
+
outbuf.replace(@buffer[0...length])
|
148
|
+
@buffer = @buffer[length..-1]
|
149
|
+
outbuf
|
150
|
+
end
|
151
|
+
|
152
|
+
def ungetbyte(b)
|
153
|
+
@buffer.insert(0, b.chr)
|
154
|
+
end
|
155
|
+
|
156
|
+
def ungetc(c)
|
157
|
+
@buffer.insert(0, c)
|
158
|
+
end
|
159
|
+
|
160
|
+
def write(string)
|
161
|
+
string = string.gsub(/#{IAC}/no, IAC + IAC)
|
162
|
+
telnet.write(string)
|
163
|
+
end
|
164
|
+
|
165
|
+
def close
|
166
|
+
telnet.close
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
def write_modem_params
|
172
|
+
telnet.write(
|
173
|
+
IAC + SB + COM_PORT_OPTION + SET_BAUDRATE + [baud].pack("N") + IAC + SE +
|
174
|
+
IAC + SB + COM_PORT_OPTION + SET_DATASIZE + data_bits.chr + IAC + SE +
|
175
|
+
IAC + SB + COM_PORT_OPTION + SET_STOPSIZE + stop_bits.chr + IAC + SE +
|
176
|
+
IAC + SB + COM_PORT_OPTION + SET_PARITY + parity.chr + IAC + SE)
|
177
|
+
sock.flush
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Net
|
2
|
+
class Telnet
|
3
|
+
module RFC2217::TelnetExtensions
|
4
|
+
def preprocess(string)
|
5
|
+
# combine CR+NULL into CR
|
6
|
+
string = string.gsub(/#{CR}#{NULL}/no, CR) if @options["Telnetmode"]
|
7
|
+
|
8
|
+
# combine EOL into "\n"
|
9
|
+
string = string.gsub(/#{EOL}/no, "\n") unless @options["Binmode"]
|
10
|
+
|
11
|
+
# remove NULL
|
12
|
+
string = string.gsub(/#{NULL}/no, '') unless @options["Binmode"]
|
13
|
+
|
14
|
+
string.gsub(/#{IAC}(
|
15
|
+
[#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]|
|
16
|
+
[#{DO}#{DONT}#{WILL}#{WONT}]
|
17
|
+
[#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{44.chr}#{OPT_EXOPL}]|
|
18
|
+
#{SB}[^#{IAC}]*#{IAC}#{SE}
|
19
|
+
)/xno) do
|
20
|
+
if block_given? && IAC != $1
|
21
|
+
# already handled; don't handle it ourselves
|
22
|
+
next '' if yield $1
|
23
|
+
end
|
24
|
+
|
25
|
+
if IAC == $1 # handle escaped IAC characters
|
26
|
+
IAC
|
27
|
+
elsif AYT == $1 # respond to "IAC AYT" (are you there)
|
28
|
+
self.write("nobody here but us pigeons" + EOL)
|
29
|
+
''
|
30
|
+
elsif DO[0] == $1[0] # respond to "IAC DO x"
|
31
|
+
if OPT_BINARY[0] == $1[1]
|
32
|
+
unless @telnet_option["BINARY"] == true
|
33
|
+
@telnet_option["BINARY"] = true
|
34
|
+
self.write(IAC + WILL + OPT_BINARY)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
self.write(IAC + WONT + $1[1..1])
|
38
|
+
end
|
39
|
+
''
|
40
|
+
elsif DONT[0] == $1[0] # respond to "IAC DON'T x" with "IAC WON'T x"
|
41
|
+
self.write(IAC + WONT + $1[1..1])
|
42
|
+
''
|
43
|
+
elsif WILL[0] == $1[0] # respond to "IAC WILL x"
|
44
|
+
if OPT_BINARY[0] == $1[1]
|
45
|
+
self.write(IAC + DO + OPT_BINARY)
|
46
|
+
elsif OPT_ECHO[0] == $1[1]
|
47
|
+
self.write(IAC + DO + OPT_ECHO)
|
48
|
+
elsif OPT_SGA[0] == $1[1]
|
49
|
+
unless @telnet_option["SGA"]
|
50
|
+
@telnet_option["SGA"] = true
|
51
|
+
self.write(IAC + DO + OPT_SGA)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
self.write(IAC + DONT + $1[1..1])
|
55
|
+
end
|
56
|
+
''
|
57
|
+
elsif WONT[0] == $1[0] # respond to "IAC WON'T x"
|
58
|
+
if OPT_ECHO[0] == $1[1]
|
59
|
+
self.write(IAC + DONT + OPT_ECHO)
|
60
|
+
elsif OPT_SGA[0] == $1[1]
|
61
|
+
unless @telnet_option["SGA"] == false
|
62
|
+
@telnet_option["SGA"] = false
|
63
|
+
self.write(IAC + DONT + OPT_SGA)
|
64
|
+
end
|
65
|
+
else
|
66
|
+
self.write(IAC + DONT + $1[1..1])
|
67
|
+
end
|
68
|
+
''
|
69
|
+
elsif SB[0] == $1[0] # yield sub option
|
70
|
+
''
|
71
|
+
else
|
72
|
+
''
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end # preprocess
|
76
|
+
end
|
77
|
+
end
|
78
|
+
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.1
|
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: []
|