Class: SimpleTelnet::Connection
- Inherits:
-
EventMachine::Connection
- Object
- EventMachine::Connection
- SimpleTelnet::Connection
- 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.
Defined Under Namespace
Classes: ConnectionFailed, LoginFailed, TimeoutError
Constant Summary collapse
- IAC =
:stopdoc:
255.chr
- DONT =
“377” # “xff” # interpret as command
254.chr
- DO =
“376” # “xfe” # you are not to use option
253.chr
- WONT =
“375” # “xfd” # please, you use option
252.chr
- WILL =
“374” # “xfc” # I won’t use option
251.chr
- SB =
“373” # “xfb” # I will use option
250.chr
- GA =
“372” # “xfa” # interpret as subnegotiation
249.chr
- EL =
“371” # “xf9” # you may reverse the line
248.chr
- EC =
“370” # “xf8” # erase the current line
247.chr
- AYT =
“367” # “xf7” # erase the current character
246.chr
- AO =
“366” # “xf6” # are you there
245.chr
- IP =
“365” # “xf5” # abort output–but let prog finish
244.chr
- BREAK =
“364” # “xf4” # interrupt process–permanently
243.chr
- DM =
“363” # “xf3” # break
242.chr
- NOP =
“362” # “xf2” # data mark–for connect. cleaning
241.chr
- SE =
“361” # “xf1” # nop
240.chr
- EOR =
“360” # “xf0” # end sub negotiation
239.chr
- ABORT =
“357” # “xef” # end of record (transparent mode)
238.chr
- SUSP =
“356” # “xee” # Abort process
237.chr
- EOF =
“355” # “xed” # Suspend process
236.chr
- SYNCH =
“354” # “xec” # End of file
242.chr
- OPT_BINARY =
“362” # “xf2” # for telfunc calls
0.chr
- OPT_ECHO =
“000” # “x00” # Binary Transmission
1.chr
- OPT_RCP =
“001” # “x01” # Echo
2.chr
- OPT_SGA =
“002” # “x02” # Reconnection
3.chr
- OPT_NAMS =
“003” # “x03” # Suppress Go Ahead
4.chr
- OPT_STATUS =
“004” # “x04” # Approx Message Size Negotiation
5.chr
- OPT_TM =
“005” # “x05” # Status
6.chr
- OPT_RCTE =
“006” # “x06” # Timing Mark
7.chr
- OPT_NAOL =
“a” # “x07” # Remote Controlled Trans and Echo
8.chr
- OPT_NAOP =
“010” # “x08” # Output Line Width
9.chr
- OPT_NAOCRD =
“t” # “x09” # Output Page Size
10.chr
- OPT_NAOHTS =
“n” # “x0a” # Output Carriage-Return Disposition
11.chr
- OPT_NAOHTD =
“v” # “x0b” # Output Horizontal Tab Stops
12.chr
- OPT_NAOFFD =
“f” # “x0c” # Output Horizontal Tab Disposition
13.chr
- OPT_NAOVTS =
“r” # “x0d” # Output Formfeed Disposition
14.chr
- OPT_NAOVTD =
“016” # “x0e” # Output Vertical Tabstops
15.chr
- OPT_NAOLFD =
“017” # “x0f” # Output Vertical Tab Disposition
16.chr
- OPT_XASCII =
“020” # “x10” # Output Linefeed Disposition
17.chr
- OPT_LOGOUT =
“021” # “x11” # Extended ASCII
18.chr
- OPT_BM =
“022” # “x12” # Logout
19.chr
- OPT_DET =
“023” # “x13” # Byte Macro
20.chr
- OPT_SUPDUP =
“024” # “x14” # Data Entry Terminal
21.chr
- OPT_SUPDUPOUTPUT =
“025” # “x15” # SUPDUP
22.chr
- OPT_SNDLOC =
“026” # “x16” # SUPDUP Output
23.chr
- OPT_TTYPE =
“027” # “x17” # Send Location
24.chr
- OPT_EOR =
“030” # “x18” # Terminal Type
25.chr
- OPT_TUID =
“031” # “x19” # End of Record
26.chr
- OPT_OUTMRK =
“032” # “x1a” # TACACS User Identification
27.chr
- OPT_TTYLOC =
“e” # “x1b” # Output Marking
28.chr
- OPT_3270REGIME =
“034” # “x1c” # Terminal Location Number
29.chr
- OPT_X3PAD =
“035” # “x1d” # Telnet 3270 Regime
30.chr
- OPT_NAWS =
“036” # “x1e” # X.3 PAD
31.chr
- OPT_TSPEED =
“037” # “x1f” # Negotiate About Window Size
32.chr
- OPT_LFLOW =
“ ” # “x20” # Terminal Speed
33.chr
- OPT_LINEMODE =
“!” # “x21” # Remote Flow Control
34.chr
- OPT_XDISPLOC =
“"” # “x22” # Linemode
35.chr
- OPT_OLD_ENVIRON =
“#” # “x23” # X Display Location
36.chr
- OPT_AUTHENTICATION =
“$” # “x24” # Environment Option
37.chr
- OPT_ENCRYPT =
“%” # “x25” # Authentication Option
38.chr
- OPT_NEW_ENVIRON =
“&” # “x26” # Encryption Option
39.chr
- OPT_EXOPL =
“‘” # “x27” # New Environment Option
255.chr
- NULL =
“377” # “xff” # Extended-Options-List
"\000"
- CR =
"\015"
- LF =
"\012"
- EOL =
CR + LF
- DEFAULT_OPTIONS =
Returns 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, logger_class: Logger, 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
- DefaultOptions =
Deprecated.
DEFAULT_OPTIONS
- STOP_WHEN_DONE =
Returns used to stop EventMachine when everything has completed.
lambda do # stop when everything is done if self.connection_count.zero? and EventMachine.defers_finished? EventMachine.stop else EventMachine.next_tick(&STOP_WHEN_DONE) end end
- StopWhenEMDone =
Deprecated.
STOP_WHEN_DONE
- RootFiber =
Returns the root fiber.
Fiber.current
- @@_telnet_connection_count =
Returns number of active connections.
0
Instance Attribute Summary collapse
-
#command_logger ⇒ Logger
readonly
Connection specific logger used to log commands.
-
#fiber_resumer ⇒ Proc
The callback executed again and again to resume this connection’s Fiber.
-
#last_command ⇒ String
readonly
Last command that was executed in this telnet session.
-
#last_data_sent_at ⇒ Time
readonly
When the last data was sent.
-
#last_prompt ⇒ String
readonly
Last prompt matched.
-
#logged_in ⇒ Time
readonly
When the login succeeded for this connection.
-
#logger ⇒ Logger, ...
Logger for connection activity (messages from SimpleTelnet).
-
#options ⇒ Hash
readonly
Used telnet options Hash.
-
#output_logger ⇒ Logger
readonly
Connection specific logger used to log output.
Class Method Summary collapse
-
.connect(opts) {|connection| ... } ⇒ SimpleTelnet::Connection
Establishes connection to the host.
-
.connection_count ⇒ Integer
Number of active connections.
-
.logger ⇒ Logger, ...
The logger instance for SimpleTelnet.
-
.new(*args, &blk) ⇒ SimpleTelnet::Connection
Recognizes whether this call was issued by the user program or by EventMachine.
Instance Method Summary collapse
-
#bin_mode=(bool) ⇒ Object
Turn newline conversion on or off for this connection.
-
#bin_mode? ⇒ Boolean
Current bin mode option of this connection.
-
#check_input_buffer ⇒ void
Checks the input buffer (
@input_buffer
) for the prompt we’re waiting for. -
#close ⇒ Object
Redefine this method to execute some logout command like
exit
orlogout
before the connection is closed. - #close_logs ⇒ Object
-
#closed? ⇒ Boolean
Whether the connection is closed.
-
#cmd(command, opts = {}) ⇒ String
Sends a command to the host and returns its output.
-
#connection_completed ⇒ void
Called by EventMachine after the connection is successfully established.
-
#connection_state_callback ⇒ Object
deprecated
Deprecated.
use #fiber_resumer instead
-
#host ⇒ String
Hostname/address for this connection.
-
#initialize(opts) ⇒ Connection
constructor
Initializes the current instance.
-
#listen(opts = {}) {|output| ... } ⇒ void
Listen for anything that’s received from the host.
-
#logged_in? ⇒ Boolean
Whether the login already succeeded for this connection.
-
#login(opts = {}) ⇒ String
Login to the host with a given username and password.
-
#pause_and_wait_for_result ⇒ String
Pauses the current Fiber.
-
#post_init ⇒ void
Called by EventMachine when the connection is being established (not after the connection is established! see #connection_completed).
-
#print(string) ⇒ void
Sends a string to the host.
-
#process_match_data(md) ⇒ void
Remembers md as the
@last_prompt
and resumes the fiber, passing it the whole output received up to and including the match data. -
#process_payload(buf) ⇒ void
Appends buf to the
@input_buffer
. -
#puts(string) ⇒ void
Sends a string to the host, along with an appended newline if there isn’t one already.
-
#receive_data(data) ⇒ void
Called by EventMachine when data is received.
-
#send_data(s) ⇒ Object
Tells EventMachine to send raw data to the telnet server.
-
#telnet_mode=(bool) ⇒ Object
Turn telnet command interpretation on or off for this connection.
-
#telnet_mode? ⇒ Boolean
Whether telnet mode is enabled or not.
- #telnet_options ⇒ Hash deprecated Deprecated.
-
#timeout(seconds = nil) ⇒ Integer, Object
If a block is given, sets the timeout to seconds and executes the block and restores the previous timeout.
-
#timeout=(seconds) ⇒ Object
Set the activity timeout to seconds for this connection.
-
#unbind(reason) ⇒ void
Finally, the connection state is set to
:closed
. -
#waitfor(prompt = nil, opts = {}) ⇒ String
Read data from the host until a certain sequence is matched.
-
#write(s) ⇒ Object
Passes argument to #send_data.
Constructor Details
#initialize(opts) ⇒ Connection
Initializes the current instance. opts is a Hash of options. The default values are in the constant DEFAULT_OPTIONS.
The options are actually merged in connect.
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 |
# File 'lib/em-simple_telnet.rb', line 403 def initialize(opts) @options = opts @last_command = nil @logged_in = nil @connection_state = :connecting f = Fiber.current @fiber_resumer = ->(result = nil){ f.resume(result) } @input_buffer = "" @input_rest = "" @wait_time_timer = nil @check_input_buffer_timer = nil @recently_received_data = "" @logger = opts[:logger] || EventMachine::Protocols::SimpleTelnet.logger setup_logging end |
Instance Attribute Details
#command_logger ⇒ Logger (readonly)
Returns connection specific logger used to log commands.
428 429 430 |
# File 'lib/em-simple_telnet.rb', line 428 def command_logger @command_logger end |
#fiber_resumer ⇒ Proc
Returns the callback executed again and again to resume this connection’s Fiber.
442 443 444 |
# File 'lib/em-simple_telnet.rb', line 442 def fiber_resumer @fiber_resumer end |
#last_command ⇒ String (readonly)
Returns Last command that was executed in this telnet session.
422 423 424 |
# File 'lib/em-simple_telnet.rb', line 422 def last_command @last_command end |
#last_data_sent_at ⇒ Time (readonly)
Returns when the last data was sent.
457 458 459 |
# File 'lib/em-simple_telnet.rb', line 457 def last_data_sent_at @last_data_sent_at end |
#last_prompt ⇒ String (readonly)
Returns last prompt matched.
454 455 456 |
# File 'lib/em-simple_telnet.rb', line 454 def last_prompt @last_prompt end |
#logged_in ⇒ Time (readonly)
Returns when the login succeeded for this connection.
522 523 524 |
# File 'lib/em-simple_telnet.rb', line 522 def logged_in @logged_in end |
#logger ⇒ Logger, ...
Returns logger for connection activity (messages from SimpleTelnet).
446 447 448 |
# File 'lib/em-simple_telnet.rb', line 446 def logger @logger end |
#options ⇒ Hash (readonly)
Returns used telnet options Hash.
431 432 433 |
# File 'lib/em-simple_telnet.rb', line 431 def @options end |
#output_logger ⇒ Logger (readonly)
Returns connection specific logger used to log output.
425 426 427 |
# File 'lib/em-simple_telnet.rb', line 425 def output_logger @output_logger end |
Class Method Details
.connect(opts) {|connection| ... } ⇒ SimpleTelnet::Connection
Establishes connection to the host.
Merges DEFAULT_OPTIONS with opts. Tells EventMachine to establish the connection to the desired host and port using SimpleTelnet::Connection, and logs into the host using #login.
Passes the connection to the block provided. It also ensures that the connection is closed using #close after the block returns, unless it’s already #closed?. The connection is then returned.
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 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
# File 'lib/em-simple_telnet.rb', line 269 def connect(opts) opts = DEFAULT_OPTIONS.merge opts params = [ # for EventMachine.connect opts[:host], opts[:port], self, # pass the *merged* options to SimpleTelnet#initialize opts ] begin # start establishing the connection connection = EventMachine.connect(*params) # will be resumed by #connection_completed or #unbind connection.pause_and_wait_for_result # login connection.__send__(:login) begin yield connection ensure # Use #close so a subclass can execute some kind of logout command # before the connection is closed. connection.close unless connection.closed? end ensure # close the connection in any case if connection connection.close_connection_after_writing # give some time to send the remaining data, which should be nothing EventMachine.add_timer(2) { connection.close_connection } end end return connection end |
.connection_count ⇒ Integer
Returns number of active connections.
313 314 315 |
# File 'lib/em-simple_telnet.rb', line 313 def connection_count @@_telnet_connection_count end |
.logger ⇒ Logger, ...
Returns the logger instance for SimpleTelnet.
198 |
# File 'lib/em-simple_telnet.rb', line 198 def logger() @logger end |
.new(*args, &blk) ⇒ SimpleTelnet::Connection
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 DEFAULT_OPTIONS 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. It’ll stop automatically when everything has completed (connections and deferred tasks).
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 244 245 246 247 248 249 250 251 252 |
# 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? and Fiber.current == RootFiber logger.debug "EventMachine reactor had been started " + "independently. Won't stop it automatically." fiber.resume elsif EventMachine.reactor_running? # NOTE: Seems like the EventMachine reactor is already running, but we're # not in the root Fiber. That means we're probably in the process of # establishing a nested connection (from inside a Fiber created by SimpleTelnet). # 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(&STOP_WHEN_DONE) end end return connection end |
Instance Method Details
#bin_mode=(bool) ⇒ Object
Turn newline conversion on or off for this connection.
481 482 483 |
# File 'lib/em-simple_telnet.rb', line 481 def bin_mode=(bool) @options[:bin_mode] = bool end |
#bin_mode? ⇒ Boolean
Returns current bin mode option of this connection.
474 475 476 |
# File 'lib/em-simple_telnet.rb', line 474 def bin_mode? @options[:bin_mode] end |
#check_input_buffer ⇒ void
This method returns an undefined value.
Checks the input buffer (@input_buffer
) for the prompt we’re waiting for. Calls @fiber_resumer
with the output if the prompt has been found.
If @options[:wait_time]
is set, it will wait this amount of seconds after seeing what looks like the prompt before calling until the real prompt is received. This is useful for commands that result in multiple prompts.
657 658 659 660 661 662 663 664 665 666 667 |
# File 'lib/em-simple_telnet.rb', line 657 def check_input_buffer return unless md = @input_buffer.match(@options[:prompt]) if s = @options[:wait_time] and s > 0 # resume Fiber after s seconds @wait_time_timer = EventMachine::Timer.new(s) { process_match_data(md) } else # resume Fiber now process_match_data(md) end end |
#close ⇒ Object
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.
1000 1001 |
# File 'lib/em-simple_telnet.rb', line 1000 def close end |
#close_logs ⇒ Object
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 |
# File 'lib/em-simple_telnet.rb', line 1007 def close_logs # NOTE: IOError is rescued because they could already be closed. # {#closed?} can't be used, because the method is not implemented by # Logger, for example. begin @output_logger.close rescue IOError # already closed end if @options[:output_log] begin @command_logger.close rescue IOError # already closed end if @options[:command_log] end |
#closed? ⇒ Boolean
Returns whether the connection is closed.
530 531 532 |
# File 'lib/em-simple_telnet.rb', line 530 def closed? @connection_state == :closed end |
#cmd(command, opts = {}) ⇒ String
The returned output includes the prompt and in most cases the
Sends a command to the host and returns its output.
More exactly, the following things are done:
-
stores the command (see #last_command)
-
logs it (see #command_logger)
-
reads in all received data (using #waitfor)
host’s echo of the command sent.
848 849 850 851 852 853 854 855 856 857 858 859 860 861 |
# File 'lib/em-simple_telnet.rb', line 848 def cmd(command, opts = {}) @last_command = command = command.to_s # log the command if @command_logger @command_logger.info(opts[:hide] ? "<hidden command>" : command) end # send the command opts[:raw_command] ? print(command) : puts(command) # wait for the output waitfor(opts[:prompt], opts) end |
#connection_completed ⇒ void
This method returns an undefined value.
Called by EventMachine after the connection is successfully established.
If the debug level in #logger is active, this will cause received data to be logged periodically.
984 985 986 987 988 989 990 991 992 |
# File 'lib/em-simple_telnet.rb', line 984 def connection_completed self.connection_state = :connected @fiber_resumer.(:connection_completed) # log received data in a more readable way if logger.debug? EventMachine.add_periodic_timer(0.5) { log_recently_received_data } end end |
#connection_state_callback ⇒ Object
use #fiber_resumer instead
449 450 451 |
# File 'lib/em-simple_telnet.rb', line 449 def connection_state_callback fiber_resumer end |
#host ⇒ String
Hostname/address for this connection.
738 739 740 |
# File 'lib/em-simple_telnet.rb', line 738 def host @options[:host] end |
#listen(opts = {}) {|output| ... } ⇒ void
This method returns an undefined value.
Listen for anything that’s received from the host. Each received chunk will be yielded to the block passed. To make it stop listening, the block should return or raise something.
749 750 751 752 753 754 755 756 |
# File 'lib/em-simple_telnet.rb', line 749 def listen(opts = {}, &blk) self.connection_state = :listening timeout(opts.fetch(:timeout, 90)) do yield pause_and_wait_for_result while true end ensure self.connection_state = :connected if !closed? end |
#logged_in? ⇒ Boolean
Returns whether the login already succeeded for this connection.
525 526 527 |
# File 'lib/em-simple_telnet.rb', line 525 def logged_in? @logged_in ? true : false end |
#login(opts = {}) ⇒ String
Don’t forget to set @logged_in
after the login succeeds if you override this method!
Login to the host with a given username and password.
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.
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 |
# File 'lib/em-simple_telnet.rb', line 882 def login opts={} opts = @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 raise LoginFailed, "Timed out while expecting some kind of prompt." end @logged_in = Time.now output end |
#pause_and_wait_for_result ⇒ String
Pauses the current Fiber. When resumed, returns the value passed. If the value passed is an Exeption, it’s raised.
726 727 728 729 730 731 732 733 734 |
# File 'lib/em-simple_telnet.rb', line 726 def pause_and_wait_for_result result = nil while result.nil? result = Fiber.yield end raise result if result.is_a? Exception return result end |
#post_init ⇒ void
This method returns an undefined value.
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 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 options[:timeout]
seconds. This is the duration after which a TCP connection is automatically closed if no data was sent or received.
927 928 929 930 931 |
# File 'lib/em-simple_telnet.rb', line 927 def post_init self.pending_connect_timeout = @options[:connect_timeout] self.comm_inactivity_timeout = @options[:timeout] @@_telnet_connection_count += 1 end |
#print(string) ⇒ void
This method returns an undefined value.
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.
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 |
# File 'lib/em-simple_telnet.rb', line 787 def print(string) string = string.gsub(/#{IAC}/no, IAC + IAC) if telnet_mode? unless bin_mode? string = if @options[:BINARY] and @options[:SGA] # IAC WILL SGA IAC DO BIN send EOL --> CR string.gsub(/\n/n, CR) elsif @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 |
#process_match_data(md) ⇒ void
This method returns an undefined value.
Remembers md as the @last_prompt
and resumes the fiber, passing it the whole output received up to and including the match data.
673 674 675 676 677 678 |
# File 'lib/em-simple_telnet.rb', line 673 def process_match_data(md) @last_prompt = md.to_s # remember the prompt matched output = md.pre_match + @last_prompt @input_buffer = md.post_match @fiber_resumer.(output) end |
#process_payload(buf) ⇒ void
This method returns an undefined value.
Appends buf to the @input_buffer
. Then cancels the @wait_time_timer
and @check_input_buffer_timer
if they’re set.
Does some performance optimizations in case the input buffer is becoming huge and finally calls #check_input_buffer.
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 |
# File 'lib/em-simple_telnet.rb', line 592 def process_payload(buf) # append output from server to input buffer and log it @input_buffer << buf case @connection_state when :waiting_for_prompt # 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 ensure there's no timer running for checking 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 being 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 when :listening @fiber_resumer.(buf) when :connected, :sleeping logger.debug "#{host}: Discarding data that was received " + "while not waiting " + "for data (state = #{@connection_state.inspect}): #{buf.inspect}" else raise "Don't know what to do with received data while being in " + "connection state #{@connection_state.inspect}" end end |
#puts(string) ⇒ void
This method returns an undefined value.
Sends a string to the host, along with an appended newline if there isn’t one already.
814 815 816 817 |
# File 'lib/em-simple_telnet.rb', line 814 def puts(string) string += "\n" unless string.end_with? "\n" print string end |
#receive_data(data) ⇒ void
This method returns an undefined value.
Called by EventMachine when data is received.
The data is processed using #preprocess, which processes telnet sequences and strips them away. The resulting “payload” is logged and handed over to #process_payload.
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 |
# File 'lib/em-simple_telnet.rb', line 542 def receive_data(data) @recently_received_data << data if log_recently_received_data? if @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(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(c[0 ... pt_pos]) @input_rest = c[pt_pos .. -1] else buf = preprocess(c) @input_rest.clear end else # Not Telnetmode. # # We cannot use #preprocess on this data, because that # method makes some Telnetmode-specific assumptions. buf = @input_rest + data @input_rest.clear unless @options[:bin_mode] buf.chop! if buf =~ /\r\z/no buf.gsub!(/#{EOL}/no, "\n") end end # in case only telnet sequences were received return if buf.empty? @output_logger << buf if @output_logger process_payload(buf) end |
#send_data(s) ⇒ Object
Tells EventMachine to send raw data to the telnet server. This also updates #last_data_sent_at and logs recently received data, if wanted.
768 769 770 771 772 773 774 775 |
# File 'lib/em-simple_telnet.rb', line 768 def send_data(s) raise Errno::ENOTCONN, "Can't send data: Connection is already closed." if closed? @last_data_sent_at = Time.now log_recently_received_data logger.debug "#{host}: Sending #{s.inspect}" super end |
#telnet_mode=(bool) ⇒ Object
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.
469 470 471 |
# File 'lib/em-simple_telnet.rb', line 469 def telnet_mode=(bool) @options[:telnet_mode] = bool end |
#telnet_mode? ⇒ Boolean
Returns whether telnet mode is enabled or not.
460 461 462 |
# File 'lib/em-simple_telnet.rb', line 460 def telnet_mode? @options[:telnet_mode] end |
#telnet_options ⇒ Hash
Same as #options.
436 437 438 |
# File 'lib/em-simple_telnet.rb', line 436 def @options end |
#timeout(seconds = nil) ⇒ Integer, Object
If a block is given, sets the timeout to seconds and executes the block and restores the previous timeout. This is useful when you want to temporarily change the timeout for some commands.
If no block is given, the current timeout is returned.
511 512 513 514 515 516 517 518 519 |
# File 'lib/em-simple_telnet.rb', line 511 def timeout(seconds = nil) return @options[:timeout] unless block_given? before = @options[:timeout] self.timeout = seconds yield ensure self.timeout = before end |
#timeout=(seconds) ⇒ Object
Set the activity timeout to seconds for this connection. To disable it, set it to 0
or nil
. If no data is received (or sent) for that amount of time, the connection will be closed.
489 490 491 492 |
# File 'lib/em-simple_telnet.rb', line 489 def timeout=(seconds) @options[:timeout] = seconds set_comm_inactivity_timeout( seconds ) end |
#unbind(reason) ⇒ void
This method returns an undefined value.
Finally, the connection state is set to :closed
.
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 |
# File 'lib/em-simple_telnet.rb', line 947 def unbind(reason) prev_conn_state = @connection_state self.connection_state = :closed logger.debug "#{host}: Unbind reason: " + reason.inspect @@_telnet_connection_count -= 1 close_logs # if we were connecting or waiting for a prompt, return an exception to # #waitfor case prev_conn_state when :waiting_for_prompt, :listening # NOTE: reason should be Errno::ETIMEDOUT in these cases. error = TimeoutError.new # set hostname and command if hostname = @options[:host] error.hostname = hostname end error.command = @last_command if @last_command @fiber_resumer.(error) when :sleeping, :connected when :connecting @fiber_resumer.(ConnectionFailed.new) else logger.error "#{host}: bad connection state #{prev_conn_state.inspect} " + "while unbinding" end end |
#waitfor(prompt = nil, opts = {}) ⇒ String
Read data from the host until a certain sequence is matched.
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 |
# File 'lib/em-simple_telnet.rb', line 690 def waitfor(prompt = nil, opts = {}) if closed? raise Errno::ENOTCONN, "Can't wait for anything when connection is already closed!" end = @options timeout_was = self.timeout if opts.key?(:timeout) opts[:prompt] = prompt if prompt @options = @options.merge opts # convert String prompt into a Regexp unless @options[:prompt].is_a? Regexp regex = Regexp.new(Regexp.quote(@options[:prompt])) @options[:prompt] = regex end # set custom inactivity timeout, if wanted self.timeout = @options[:timeout] if opts.key?(:timeout) # so #unbind knows we were waiting for a prompt (in case that inactivity # timeout fires) self.connection_state = :waiting_for_prompt pause_and_wait_for_result ensure @options = self.timeout = timeout_was if opts.key?(:timeout) # NOTE: #unbind could have been called in the meantime self.connection_state = :connected if !closed? end |
#write(s) ⇒ Object
Passes argument to #send_data.
760 761 762 |
# File 'lib/em-simple_telnet.rb', line 760 def write(s) send_data(s) end |