Class: EventMachine::Protocols::SimpleTelnet
- Inherits:
-
Connection
- Object
- Connection
- EventMachine::Protocols::SimpleTelnet
- Defined in:
- lib/em-simple_telnet.rb
Overview
Provides the facility to connect to telnet servers using EventMachine. The asynchronity is hidden so you can use this library just like Net::Telnet in a seemingly synchronous manner. See README for an example.
EventMachine.run do
opts = {
host: "localhost",
username: "user",
password: "secret",
}
EM::P::SimpleTelnet.new(opts) do |host|
# already logged in
puts host.cmd("ls -la")
end
end
Because of being event-driven, it performs quite well and can handle a lot of connections concurrently.
Defined Under Namespace
Classes: ConnectionFailed, LoginFailed, TimeoutError
Constant Summary
- IAC =
:stopdoc:
255.chr
- DONT =
254.chr
- DO =
253.chr
- WONT =
252.chr
- WILL =
251.chr
- SB =
250.chr
- GA =
249.chr
- EL =
248.chr
- EC =
247.chr
- AYT =
246.chr
- AO =
245.chr
- IP =
244.chr
- BREAK =
243.chr
- DM =
242.chr
- NOP =
241.chr
- SE =
240.chr
- EOR =
239.chr
- ABORT =
238.chr
- SUSP =
237.chr
- EOF =
236.chr
- SYNCH =
"377" # "xff" # interpret as command "376" # "xfe" # you are not to use option "375" # "xfd" # please, you use option "374" # "xfc" # I won't use option "373" # "xfb" # I will use option "372" # "xfa" # interpret as subnegotiation "371" # "xf9" # you may reverse the line "370" # "xf8" # erase the current line "367" # "xf7" # erase the current character "366" # "xf6" # are you there "365" # "xf5" # abort output--but let prog finish "364" # "xf4" # interrupt process--permanently "363" # "xf3" # break "362" # "xf2" # data mark--for connect. cleaning "361" # "xf1" # nop "360" # "xf0" # end sub negotiation "357" # "xef" # end of record (transparent mode) "356" # "xee" # Abort process "355" # "xed" # Suspend process "354" # "xec" # End of file "362" # "xf2" # for telfunc calls
242.chr
- OPT_BINARY =
0.chr
- OPT_ECHO =
1.chr
- OPT_RCP =
2.chr
- OPT_SGA =
3.chr
- OPT_NAMS =
4.chr
- OPT_STATUS =
5.chr
- OPT_TM =
6.chr
- OPT_RCTE =
7.chr
- OPT_NAOL =
8.chr
- OPT_NAOP =
9.chr
- OPT_NAOCRD =
10.chr
- OPT_NAOHTS =
11.chr
- OPT_NAOHTD =
12.chr
- OPT_NAOFFD =
13.chr
- OPT_NAOVTS =
14.chr
- OPT_NAOVTD =
15.chr
- OPT_NAOLFD =
16.chr
- OPT_XASCII =
17.chr
- OPT_LOGOUT =
18.chr
- OPT_BM =
19.chr
- OPT_DET =
20.chr
- OPT_SUPDUP =
21.chr
- OPT_SUPDUPOUTPUT =
22.chr
- OPT_SNDLOC =
23.chr
- OPT_TTYPE =
24.chr
- OPT_EOR =
25.chr
- OPT_TUID =
26.chr
- OPT_OUTMRK =
27.chr
- OPT_TTYLOC =
28.chr
- OPT_3270REGIME =
29.chr
- OPT_X3PAD =
30.chr
- OPT_NAWS =
31.chr
- OPT_TSPEED =
32.chr
- OPT_LFLOW =
33.chr
- OPT_LINEMODE =
34.chr
- OPT_XDISPLOC =
35.chr
- OPT_OLD_ENVIRON =
36.chr
- OPT_AUTHENTICATION =
37.chr
- OPT_ENCRYPT =
38.chr
- OPT_NEW_ENVIRON =
39.chr
- OPT_EXOPL =
"000" # "x00" # Binary Transmission "001" # "x01" # Echo "002" # "x02" # Reconnection "003" # "x03" # Suppress Go Ahead "004" # "x04" # Approx Message Size Negotiation "005" # "x05" # Status "006" # "x06" # Timing Mark "a" # "x07" # Remote Controlled Trans and Echo "010" # "x08" # Output Line Width "t" # "x09" # Output Page Size "n" # "x0a" # Output Carriage-Return Disposition "v" # "x0b" # Output Horizontal Tab Stops "f" # "x0c" # Output Horizontal Tab Disposition "r" # "x0d" # Output Formfeed Disposition "016" # "x0e" # Output Vertical Tabstops "017" # "x0f" # Output Vertical Tab Disposition "020" # "x10" # Output Linefeed Disposition "021" # "x11" # Extended ASCII "022" # "x12" # Logout "023" # "x13" # Byte Macro "024" # "x14" # Data Entry Terminal "025" # "x15" # SUPDUP "026" # "x16" # SUPDUP Output "027" # "x17" # Send Location "030" # "x18" # Terminal Type "031" # "x19" # End of Record "032" # "x1a" # TACACS User Identification "e" # "x1b" # Output Marking "034" # "x1c" # Terminal Location Number "035" # "x1d" # Telnet 3270 Regime "036" # "x1e" # X.3 PAD "037" # "x1f" # Negotiate About Window Size " " # "x20" # Terminal Speed "!" # "x21" # Remote Flow Control """ # "x22" # Linemode "#" # "x23" # X Display Location "$" # "x24" # Environment Option "%" # "x25" # Authentication Option "&" # "x26" # Encryption Option "'" # "x27" # New Environment Option "377" # "xff" # Extended-Options-List
255.chr
- NULL =
"\000"- CR =
"\015"- LF =
"\012"- EOL =
CR + LF
- DefaultOptions =
default options for new connections (used for merging)
{ host: "localhost", port: 23, prompt: %r{[$%#>] \z}n, connect_timeout: 3, timeout: 10, wait_time: 0, bin_mode: false, telnet_mode: true, output_log: nil, command_log: nil, login_prompt: %r{[Ll]ogin[: ]*\z}n, password_prompt: %r{[Pp]ass(?:word|phrase)[: ]*\z}n, username: nil, password: nil, # telnet protocol stuff SGA: false, BINARY: false, }.freeze
- StopWhenEMDone =
lambda do stop_ticks += 1 if stop_ticks >= 100 stop_ticks = 0 # stop when everything is done if self.connection_count.zero? and EventMachine.defers_finished? EventMachine.stop else EventMachine.next_tick(&StopWhenEMDone) end else EventMachine.next_tick(&StopWhenEMDone) end end
- @@_telnet_connection_count =
number of active connections
0
Instance Attribute Summary (collapse)
-
- (Object) command_logger
readonly
Logger used to log commands.
-
- (Object) connection_state_callback
the callback executed after connection established or failed.
-
- (Object) last_command
readonly
Last command that was executed in this telnet session.
-
- (Object) last_prompt
readonly
last prompt matched.
-
- (Object) logged_in
readonly
When the login succeeded for this connection.
-
- (Object) output_logger
readonly
Logger used to log output.
-
- (Object) telnet_options
readonly
used telnet options Hash.
Class Method Summary (collapse)
-
+ (Object) connect(opts)
Merges DefaultOptions with opts.
-
+ (Object) connection_count
Returns the number of active connections (@@_telnet_connection_count).
-
+ (Object) new(*args, &blk)
Recognizes whether this call was issued by the user program or by EventMachine.
Instance Method Summary (collapse)
-
- (Object) bin_mode=(bool)
Turn newline conversion on or off for this connection.
-
- (Boolean) bin_mode?
Return current bin mode option of this connection.
-
- (Object) check_input_buffer
Checks the input buffer (@input_buffer) for the prompt we're waiting for.
-
- (Object) close
Tells EventMachine to close the connection after sending what's in the output buffer.
-
- (Object) close_logs
Close output and command logs if they're set.
-
- (Boolean) closed?
Returns true if the connection is closed.
-
- (Object) cmd(command, opts = {})
Sends a command to the host.
-
- (Object) connection_completed
Called by EventMachine after the connection is successfully established.
-
- (SimpleTelnet) initialize(opts)
constructor
Initializes the current instance.
-
- (Boolean) logged_in?
Returns true if the login already succeeded for this connection.
-
- (Object) login(opts = {})
Login to the host with a given username and password.
-
- (Object) post_init
Called by EventMachine when the connection is being established (not after the connection is established! see #connection_completed).
-
- (Object) print(string)
Sends a string to the host.
-
- (Object) puts(string)
Sends a string to the host.
-
- (Object) receive_data(data)
Called by EventMachine when data is received.
-
- (Object) telnet_mode=(bool)
Turn telnet command interpretation on or off for this connection.
-
- (Boolean) telnet_mode?
Return current telnet mode option of this connection.
-
- (Object) timeout(seconds = nil)
If a block is given, sets the timeout to seconds (see #timeout=), executes the block and restores the previous timeout.
-
- (Object) timeout=(seconds)
Set the activity timeout to seconds for this connection.
-
- (Object) unbind
Called by EventMachine after this connection is closed.
-
- (Object) waitfor(prompt = nil, opts = {})
Read data from the host until a certain sequence is matched.
Constructor Details
- (SimpleTelnet) initialize(opts)
Initializes the current instance. opts is a Hash of options. The default values are in the constant DefaultOptions. The following keys are recognized:
:host |
the hostname or IP address of the host to connect to, as a String. Defaults to "localhost". |
:port |
the port to connect to. Defaults to 23. |
:bin_mode |
if false (the default), newline substitution is performed. Outgoing LF is converted to CRLF, and incoming CRLF is converted to LF. If true, this substitution is not performed. This value can also be set with the #bin_mode= method. The outgoing conversion only applies to the #puts and #print methods, not the #write method. The precise nature of the newline conversion is also affected by the telnet options SGA and BIN. |
:output_log |
the name of the file to write connection status messages and all received traffic to. In the case of a proper Telnet session, this will include the client input as echoed by the host; otherwise, it only includes server responses. Output is appended verbatim to this file. By default, no output log is kept. |
:command_log |
the name of the file to write the commands executed in this Telnet session. Commands are appended to this file. By default, no command log is kept. |
:prompt |
a regular expression matching the host's command-line prompt sequence. This is needed by the Telnet class to determine when the output from a command has finished and the host is ready to receive a new command. By default, this regular expression is %r{[$%#>] \z}n. |
:login_prompt |
a regular expression (or String, see #waitfor) used to wait for the login prompt. |
:password_prompt |
a regular expression (or String, see #waitfor) used to wait for the password prompt. |
:username |
the String that is sent to the telnet server after seeing the login prompt. Just leave this value as nil which is the default value if you don't have to log in. |
:password |
the String that is sent to the telnet server after seeing the password prompt. Just leave this value as nil which is the default value if you don't have to print a password after printing the username. |
:telnet_mode |
a boolean value, true by default. In telnet mode, traffic received from the host is parsed for special command sequences, and these sequences are escaped in outgoing traffic sent using #puts or #print (but not #write). If you are connecting to a non-telnet service (such as SMTP or POP), this should be set to "false" to prevent undesired data corruption. This value can also be set by the #telnetmode method. |
:timeout |
the number of seconds (default: 10) to wait before timing out while waiting for the prompt (in #waitfor). Exceeding this timeout causes a TimeoutError to be raised. You can disable the timeout by setting this value to nil. |
:connect_timeout |
the number of seconds (default: 3) to wait before timing out the initial attempt to connect. You can disable the timeout by setting this value to nil. |
:wait_time |
the amount of time to wait after seeing what looks like a prompt (that is, received data that matches the Prompt option regular expression) to see if more data arrives. If more data does arrive in this time, it assumes that what it saw was not really a prompt. This is to try to avoid false matches, but it can also lead to missing real prompts (if, for instance, a background process writes to the terminal soon after the prompt is displayed). By default, set to 0, meaning not to wait for more data. |
The options are actually merged in connect().
391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
# File 'lib/em-simple_telnet.rb', line 391 def initialize opts @telnet_options = opts @last_command = nil @logged_in = nil @connection_state = :connecting @connection_state_callback = nil @input_buffer = "" @input_rest = "" @wait_time_timer = nil @check_input_buffer_timer = nil setup_logging end |
Instance Attribute Details
- (Object) command_logger (readonly)
Logger used to log commands
413 414 415 |
# File 'lib/em-simple_telnet.rb', line 413 def command_logger @command_logger end |
- (Object) connection_state_callback
the callback executed after connection established or failed
419 420 421 |
# File 'lib/em-simple_telnet.rb', line 419 def connection_state_callback @connection_state_callback end |
- (Object) last_command (readonly)
Last command that was executed in this telnet session
407 408 409 |
# File 'lib/em-simple_telnet.rb', line 407 def last_command @last_command end |
- (Object) last_prompt (readonly)
last prompt matched
422 423 424 |
# File 'lib/em-simple_telnet.rb', line 422 def last_prompt @last_prompt end |
- (Object) logged_in (readonly)
When the login succeeded for this connection.
500 501 502 |
# File 'lib/em-simple_telnet.rb', line 500 def logged_in @logged_in end |
- (Object) output_logger (readonly)
Logger used to log output
410 411 412 |
# File 'lib/em-simple_telnet.rb', line 410 def output_logger @output_logger end |
- (Object) telnet_options (readonly)
used telnet options Hash
416 417 418 |
# File 'lib/em-simple_telnet.rb', line 416 def @telnet_options end |
Class Method Details
+ (Object) connect(opts)
Merges DefaultOptions with opts. Establishes the connection to the :host key using EventMachine.connect, logs in using #login and passes the connection to the block provided. Closes the connection using #close after the block terminates. The connection is then returned.
251 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 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/em-simple_telnet.rb', line 251 def connect opts opts = DefaultOptions.merge opts params = [ # for EventMachine.connect opts[:host], opts[:port], self, # pass the *merged* options to SimpleTelnet#initialize opts ] # start establishing the connection connection = EventMachine.connect(*params) # set callback to be executed when connection establishing # fails/succeeds f = Fiber.current connection.connection_state_callback = lambda do |obj=nil| @connection_state_callback = nil f.resume obj end # block here and get result from establishing connection state = Fiber.yield # raise if exception (e.g. Telnet::ConnectionFailed) raise state if state.is_a? Exception # login connection.instance_eval { login } begin yield connection ensure # Use #close so a subclass can execute some kind of logout command # before the connection is closed. connection.close end return connection end |
+ (Object) connection_count
Returns the number of active connections (@@_telnet_connection_count).
299 300 301 |
# File 'lib/em-simple_telnet.rb', line 299 def connection_count @@_telnet_connection_count end |
+ (Object) new(*args, &blk)
Recognizes whether this call was issued by the user program or by EventMachine. If the call was not issued by EventMachine, merges the options provided with the DefaultOptions and creates a Fiber (not started yet). Inside the Fiber SimpleTelnet.connect would be called.
If EventMachine's reactor is already running, just starts the Fiber.
If it's not running yet, starts a new EventMachine reactor and starts the Fiber. The EventMachine block is stopped using the StopWhenEMDone proc (lambda).
The (closed) connection is returned.
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/em-simple_telnet.rb', line 213 def new *args, &blk # call super if first argument is a connection signature of # EventMachine return super(*args, &blk) if args.first.is_a? Integer # This method was probably called with a Hash of connection options. # create new fiber to connect and execute block opts = args[0] || {} connection = nil fiber = Fiber.new do | callback | connection = connect(opts, &blk) callback.call if callback end if EventMachine.reactor_running? # Transfer control to the "inner" Fiber and stop the current one. # The block will be called after connect() returned to transfer control # back to the "outer" Fiber. outer_fiber = Fiber.current fiber.transfer ->{ outer_fiber.transfer } else # start EventMachine and stop it when connection is done EventMachine.run do fiber.resume EventMachine.next_tick(&StopWhenEMDone) end end return connection end |
Instance Method Details
- (Object) bin_mode=(bool)
Turn newline conversion on or off for this connection.
450 451 452 |
# File 'lib/em-simple_telnet.rb', line 450 def bin_mode=(bool) @telnet_options[:bin_mode] = bool end |
- (Boolean) bin_mode?
Return current bin mode option of this connection.
443 444 445 |
# File 'lib/em-simple_telnet.rb', line 443 def bin_mode? @telnet_options[:bin_mode] end |
- (Object) check_input_buffer
Checks the input buffer (@input_buffer) for the prompt we're waiting for. Calls the proc in @connection_state_callback if the prompt has been found. Thus, call this method only if @connection_state_callback is set!
If @telnet_options[:wait_time] is set, this amount of seconds is waited (call to @connection_state_callback is scheduled) after seeing what looks like the prompt before firing the @connection_state_callback is fired, so more data can come until the real prompt is reached. This is useful for commands which will cause multiple prompts to be sent.
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 |
# File 'lib/em-simple_telnet.rb', line 621 def check_input_buffer if md = @input_buffer.match(@telnet_options[:prompt]) blk = lambda do @last_prompt = md.to_s # remember last prompt output = md.pre_match + @last_prompt @input_buffer = md.post_match @connection_state_callback.call(output) end if s = @telnet_options[:wait_time] # fire @connection_state_callback after s seconds @wait_time_timer = EventMachine::Timer.new(s, &blk) else # fire @connection_state_callback now blk.call end end end |
- (Object) close
Tells EventMachine to close the connection after sending what's in the output buffer. Redefine this method to execute some logout command like exit or logout before the connection is closed. Don't forget: The command will probably not return a prompt, so use #puts, which doesn't wait for a prompt.
906 907 908 |
# File 'lib/em-simple_telnet.rb', line 906 def close close_connection_after_writing end |
- (Object) close_logs
Close output and command logs if they're set. IOError is rescued because they could already be closed. #closed? can't be used, because the method is not implemented by Logger, for example.
915 916 917 918 919 920 921 922 |
# File 'lib/em-simple_telnet.rb', line 915 def close_logs begin @output_logger.close rescue IOError end if @telnet_options[:output_log] begin @command_logger.close rescue IOError end if @telnet_options[:command_log] end |
- (Boolean) closed?
Returns true if the connection is closed.
513 514 515 |
# File 'lib/em-simple_telnet.rb', line 513 def closed? @connection_state == :closed end |
- (Object) cmd(command, opts = {})
Sends a command to the host.
More exactly, the following things are done:
-
stores the command in @last_command
-
logs it using #log_command
-
sends a string to the host (#print or #puts)
-
reads in all received data (using #waitfor)
-
returns the received data as String
opts can be a Hash of options. It is passed to #waitfor as the second parameter. The element in opts with the key :prompt is used as the first parameter in the call to #waitfor. Example usage:
host.cmd "delete user john", prompt: /Are you sure?/
host.cmd "yes"
Note that the received data includes the prompt and in most cases the host's echo of our command.
If opts has the key :hide which evaluates to true, calls #log_command with "<hidden command>" instead of the command itself. This is useful for passwords, so they don't get logged to the command log.
If opts has the key :raw_command which evaluates to true, #print is used to send the command to the host instead of #puts.
764 765 766 767 768 769 770 771 772 773 774 775 776 777 |
# File 'lib/em-simple_telnet.rb', line 764 def cmd command, opts={} command = command.to_s @last_command = command # log the command log_command(opts[:hide] ? "<hidden command>" : command) # send the command sendcmd = opts[:raw_command] ? :print : :puts self.__send__(sendcmd, command) # wait for the output waitfor(opts[:prompt], opts) end |
- (Object) connection_completed
Called by EventMachine after the connection is successfully established.
894 895 896 897 |
# File 'lib/em-simple_telnet.rb', line 894 def connection_completed @connection_state = :connected @connection_state_callback.call if @connection_state_callback end |
- (Boolean) logged_in?
Returns true if the login already succeeded for this connection. Returns false otherwise.
506 507 508 |
# File 'lib/em-simple_telnet.rb', line 506 def logged_in? @logged_in ? true : false end |
- (Object) login(opts = {})
Login to the host with a given username and password.
host.login username: "myuser", password: "mypass"
This method looks for the login and password prompt (see implementation) from the host to determine when to send the username and password. If the login sequence does not follow this pattern (for instance, you are connecting to a service other than telnet), you will need to handle login yourself.
If the key :password is omitted (and not set on connection level), the method will not look for a prompt.
The method returns all data received during the login process from the host, including the echoed username but not the password (which the host should not echo anyway).
Don't forget to set @logged_in after the login succeeds when you redefine this method!
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 |
# File 'lib/em-simple_telnet.rb', line 800 def login opts={} opts = @telnet_options.merge opts # don't log in if username is not set if opts[:username].nil? @logged_in = Time.now return end begin output = waitfor opts[:login_prompt] if opts[:password] # login with username and password output << cmd(opts[:username], prompt: opts[:password_prompt]) output << cmd(opts[:password], hide: true) else # login with username only output << cmd(opts[:username]) end rescue Timeout::Error e = LoginFailed.new("Timed out while expecting some kind of prompt.") e.set_backtrace $!.backtrace raise e end @logged_in = Time.now output end |
- (Object) post_init
Called by EventMachine when the connection is being established (not after the connection is established! see #connection_completed). This occurs directly after the call to #initialize.
Sets the pending_connect_timeout to @telnet_options[:connect_timeout] seconds. This is the duration after which a TCP connection in the connecting state will fail (abort and run #unbind). Increases @@_telnet_connection_count by one after that.
Sets also the comm_inactivity_timeout to @telnet_options[:timeout] seconds. This is the duration after which a TCP connection is automatically closed if no data was sent or received.
846 847 848 849 850 |
# File 'lib/em-simple_telnet.rb', line 846 def post_init self.pending_connect_timeout = @telnet_options[:connect_timeout] self.comm_inactivity_timeout = @telnet_options[:timeout] @@_telnet_connection_count += 1 end |
- (Object) print(string)
Sends a string to the host.
This does not automatically append a newline to the string. Embedded newlines may be converted and telnet command sequences escaped depending upon the values of #telnet_mode, #bin_mode, and telnet options set by the host.
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 |
# File 'lib/em-simple_telnet.rb', line 703 def print(string) string = string.gsub(/#{IAC}/no, IAC + IAC) if telnet_mode? unless bin_mode? string = if @telnet_options[:BINARY] and @telnet_options[:SGA] # IAC WILL SGA IAC DO BIN send EOL --> CR string.gsub(/\n/n, CR) elsif @telnet_options[:SGA] # IAC WILL SGA send EOL --> CR+NULL string.gsub(/\n/n, CR + NULL) else # NONE send EOL --> CR+LF string.gsub(/\n/n, EOL) end end send_data string end |
- (Object) puts(string)
Sends a string to the host.
Same as #print, but appends a newline to the string unless there's already one.
730 731 732 733 |
# File 'lib/em-simple_telnet.rb', line 730 def puts(string) string += "\n" unless string.end_with? "\n" print string end |
- (Object) receive_data(data)
Called by EventMachine when data is received.
The data is processed using #preprocess_telnet and appended to the @input_buffer. The appended data is also logged using #log_output. Then #check_input_buffer is called which checks the input buffer for the prompt.
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 |
# File 'lib/em-simple_telnet.rb', line 525 def receive_data data if @telnet_options[:telnet_mode] c = @input_rest + data se_pos = c.rindex(/#{IAC}#{SE}/no) || 0 sb_pos = c.rindex(/#{IAC}#{SB}/no) || 0 if se_pos < sb_pos buf = preprocess_telnet(c[0 ... sb_pos]) @input_rest = c[sb_pos .. -1] elsif pt_pos = c.rindex( /#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no) || c.rindex(/\r\z/no) buf = preprocess_telnet(c[0 ... pt_pos]) @input_rest = c[pt_pos .. -1] else buf = preprocess_telnet(c) @input_rest.clear end else # Not Telnetmode. # # We cannot use #preprocess_telnet on this data, because that # method makes some Telnetmode-specific assumptions. buf = @input_rest + data @input_rest.clear unless @telnet_options[:bin_mode] if pt_pos = buf.rindex(/\r\z/no) buf = buf[0 ... pt_pos] @input_rest = buf[pt_pos .. -1] end buf.gsub!(/#{EOL}/no, "\n") end end # in case only telnet sequences were received return if buf.empty? # append output from server to input buffer and log it @input_buffer << buf log_output buf, true # cancel the timer for wait_time value because we received more data if @wait_time_timer @wait_time_timer.cancel @wait_time_timer = nil end # we only need to do something if there's a connection state callback return unless @connection_state_callback # we ensure there's no timer running to check the input buffer if @check_input_buffer_timer @check_input_buffer_timer.cancel @check_input_buffer_timer = nil end if @input_buffer.size >= 100_000 ## # if the input buffer is really big # # We postpone checking the input buffer by one second because the regular # expression matches can get quite slow. # # So as long as data is received (continuously), the input buffer is not # checked. It's only checked one second after the whole output has been # received. @check_input_buffer_timer = EventMachine::Timer.new(1) do @check_input_buffer_timer = nil check_input_buffer end else ## # as long as the input buffer is small # # check the input buffer now check_input_buffer end end |
- (Object) telnet_mode=(bool)
Turn telnet command interpretation on or off for this connection. It should be on for true telnet sessions, off if used to connect to a non-telnet service such as SMTP.
436 437 438 |
# File 'lib/em-simple_telnet.rb', line 436 def telnet_mode=(bool) @telnet_options[:telnet_mode] = bool end |
- (Boolean) telnet_mode?
Return current telnet mode option of this connection.
427 428 429 |
# File 'lib/em-simple_telnet.rb', line 427 def telnet_mode? @telnet_options[:telnet_mode] end |
- (Object) timeout(seconds = nil)
If a block is given, sets the timeout to seconds (see #timeout=), executes the block and restores the previous timeout. The block value is returned. This is useful if you want to execute one or more commands with a special timeout.
If no block is given, the current timeout is returned.
Example:
current_timeout = host.timeout
host.timeout 200 do
host.cmd "command 1"
host.cmd "command 2"
end
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 |
# File 'lib/em-simple_telnet.rb', line 480 def timeout seconds=nil if block_given? before = @telnet_options[:timeout] self.timeout = seconds begin yield ensure self.timeout = before end else if seconds warn "Warning: Use EM::P::SimpleTelnet#timeout= to set the timeout." end @telnet_options[:timeout] end end |
- (Object) timeout=(seconds)
Set the activity timeout to seconds for this connection. To disable it, set it to 0 or nil.
458 459 460 461 |
# File 'lib/em-simple_telnet.rb', line 458 def timeout= seconds @telnet_options[:timeout] = seconds set_comm_inactivity_timeout( seconds ) end |
- (Object) unbind
Called by EventMachine after this connection is closed.
Decreases @@_telnet_connection_count by one and calls #close_logs.
After that and if @connection_state_callback is set, it takes a look on @connection_state. If it was :connecting, calls @connection_state_callback with a new instance of ConnectionFailed. If it was :waiting_for_prompt, calls the callback with a new instance of TimeoutError.
Finally, the @connection_state is set to closed.
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 |
# File 'lib/em-simple_telnet.rb', line 865 def unbind @@_telnet_connection_count -= 1 close_logs if @connection_state_callback # if we were connecting or waiting for a prompt, return an exception to # #waitfor case @connection_state when :connecting @connection_state_callback.call(ConnectionFailed.new) when :waiting_for_prompt error = TimeoutError.new # set hostname and command if hostname = @telnet_options[:host] error.hostname = hostname end error.command = @last_command if @last_command @connection_state_callback.call(error) end end @connection_state = :closed end |
- (Object) waitfor(prompt = nil, opts = {})
Read data from the host until a certain sequence is matched.
All data read will be returned in a single string. Note that the received data includes the matched sequence we were looking for.
prompt can be a Regexp or String. If it's not a Regexp, it's converted to a Regexp (all special characters escaped) assuming it's a String.
opts can be a hash of options. The following options are used and thus can be overridden:
-
:timeout
-
:wait_time (actually used by #check_input_buffer)
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 |
# File 'lib/em-simple_telnet.rb', line 655 def waitfor prompt=nil, opts={} = @telnet_options timeout_was = self.timeout if opts.key?(:timeout) opts[:prompt] = prompt if prompt @telnet_options = @telnet_options.merge opts # convert String prompt into a Regexp unless @telnet_options[:prompt].is_a? Regexp regex = Regexp.new(Regexp.quote(@telnet_options[:prompt])) @telnet_options[:prompt] = regex end # set custom inactivity timeout, if wanted self.timeout = @telnet_options[:timeout] if opts.key?(:timeout) # so #unbind knows we were waiting for a prompt (in case that inactivity # timeout fires) @connection_state = :waiting_for_prompt # for the block in @connection_state_callback f = Fiber.current # will be called by #receive_data to resume at "Fiber.yield" below @connection_state_callback = lambda do |output| @connection_state_callback = nil f.resume(output) end result = Fiber.yield raise result if result.is_a? Exception return result ensure @telnet_options = self.timeout = timeout_was if opts.key?(:timeout) @connection_state = :connected end |