From c1241cd2ed230573bb81b52173d6cd2bd91176f2 Mon Sep 17 00:00:00 2001 From: matz Date: Wed, 9 Jun 1999 09:21:37 +0000 Subject: thread bugs git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_3@482 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/telnet.rb | 363 ++++++++++++++++++++++++++++++++------------------------ lib/tempfile.rb | 6 +- 2 files changed, 208 insertions(+), 161 deletions(-) (limited to 'lib') diff --git a/lib/telnet.rb b/lib/telnet.rb index 855a9f5334..4251de1ee9 100644 --- a/lib/telnet.rb +++ b/lib/telnet.rb @@ -1,21 +1,23 @@ =begin +$Date: 1999/06/04 06:24:58 $ -= simple telnet cliant library +== SIMPLE TELNET CLIANT LIBRARY -telnet.rb ver0.17 1999/04/30 -Wakou Aoyama +telnet.rb + +Version 0.20 +Wakou Aoyama -= methods -== new (make new Telnet object) +=== MAKE NEW TELNET OBJECT host = Telnet.new({"Binmode" => FALSE, # default: FALSE "Host" => "localhost", # default: "localhost" "Output_log" => "output_log", # default: not output "Dump_log" => "dump_log", # default: not output "Port" => 23, # default: 23 - "Prompt" => /[$%#>] \Z/, # default: /[$%#>] \Z/ + "Prompt" => /[$%#>] \z/n, # default: /[$%#>] \z/n "Telnetmode" => TRUE, # default: TRUE "Timeout" => 10, # default: 10 "Waittime" => 0, # default: 0 @@ -29,7 +31,7 @@ if set "Telnetmode" option FALSE. not TELNET command interpretation. the same character as "Prompt" is included in the data, and, when the network or the host is very heavy, the value is enlarged. -=== status output +=== STATUS OUTPUT host = Telnet.new({"Hosh" => "localhost"){|c| print c } @@ -37,11 +39,11 @@ connection status output. example -Trying localhost... -Connected to localhost. + Trying localhost... + Connected to localhost. -== waitfor (wait for match) +=== WAIT FOR MATCH line = host.waitfor(/match/) line = host.waitfor({"Match" => /match/, @@ -51,7 +53,7 @@ Connected to localhost. if set "String" option. Match = Regexp.new(quote(string)) -=== realtime output +==== REALTIME OUTPUT host.waitfor(/match/){|c| print c } host.waitfor({"Match" => /match/, @@ -61,138 +63,157 @@ if set "String" option. Match = Regexp.new(quote(string)) of cource, set sync=TRUE or flush is necessary. -== cmd (send string and wait prompt) +=== SEND STRING AND WAIT PROMPT line = host.cmd("string") line = host.cmd({"String" => "string", - "Prompt" => /[$%#>] \Z/, + "Prompt" => /[$%#>] \z/n, "Timeout" => 10}) -=== realtime output +==== REALTIME OUTPUT host.cmd("string"){|c| print c } host.cmd({"String" => "string", - "Prompt" => /[$%#>] \Z/, + "Prompt" => /[$%#>] \z/n, "Timeout" => 10}){|c| print c } of cource, set sync=TRUE or flush is necessary. -== print (send string) +=== SEND STRING host.print("string") -== telnetmode (turn telnet command interpretation) +=== TURN TELNET COMMAND INTERPRETATION host.telnetmode # turn on/off host.telnetmode(TRUE) # on host.telnetmode(FALSE) # off -== binmode (toggle newline translation) +=== TOGGLE NEWLINE TRANSLATION host.binmode # turn TRUE/FALSE host.binmode(TRUE) # no translate newline host.binmode(FALSE) # translate newline -== login +=== LOGIN host.login("username", "password") host.login({"Name" => "username", "Password" => "password", - "Prompt" => /[$%#>] \Z/, + "Prompt" => /[$%#>] \z/n, "Timeout" => 10}) -=== realtime output +==== REALTIME OUTPUT host.login("username", "password"){|c| print c } host.login({"Name" => "username", "Password" => "password", - "Prompt" => /[$%#>] \Z/, + "Prompt" => /[$%#>] \z/n, "Timeout" => 10}){|c| print c } of cource, set sync=TRUE or flush is necessary. -= sample +== EXAMPLE -== login and send command +=== LOGIN AND SEND COMMAND localhost = Telnet.new({"Host" => "localhost", "Timeout" => 10, - "Prompt" => /[$%#>] \Z/}) + "Prompt" => /[$%#>] \z/n}) localhost.login("username", "password"){|c| print c } localhost.cmd("command"){|c| print c } localhost.close -== checks a POP server to see if you have mail +=== CHECKS A POP SERVER TO SEE IF YOU HAVE MAIL pop = Telnet.new({"Host" => "your_destination_host_here", "Port" => 110, "Telnetmode" => FALSE, - "Prompt" => /^\+OK/}) + "Prompt" => /^\+OK/n}) pop.cmd("user " + "your_username_here"){|c| print c} pop.cmd("pass " + "your_password_here"){|c| print c} pop.cmd("list"){|c| print c} -= history +== HISTORY + +=== Version 0.20 +waitfor: support for divided telnet command + +=== Version 0.181 1999/05/22 +bug fix: print method + +=== Version 0.18 1999/05/14 +respond to "IAC WON'T SGA" with "IAC DON'T SGA" + +DON'T SGA : end of line --> CR + LF + +bug fix: preprocess method -ver0.17 1999/04/30 -bug fix -$! + "\n" --> $!.to_s + "\n" +=== Version 0.17 1999/04/30 +bug fix: $! + "\n" --> $!.to_s + "\n" -ver0.163 1999/04/11 +=== Version 0.163 1999/04/11 STDOUT.write(message) --> yield(message) if iterator? -ver0.162 1999/03/17 +=== Version 0.162 1999/03/17 add "Proxy" option + required timeout.rb -ver0.161 1999/02/03 +=== Version 0.161 1999/02/03 select --> IO::select -ver0.16 1998/10/09 +=== Version 0.16 1998/10/09 preprocess method change for the better + add binmode method. -change default Binmode + +change default Binmode TRUE --> FALSE -ver0.15 1998/10/04 +=== Version 0.15 1998/10/04 add telnetmode method. -ver0.141 1998/09/22 +=== Version 0.141 1998/09/22 change default prompt -/[$%#>] $/ --> /[$%#>] \Z/ + /[$%#>] $/ --> /[$%#>] \Z/ -ver0.14 1998/09/01 +=== Version 0.14 1998/09/01 IAC WILL SGA send EOL --> CR+NULL + IAC WILL SGA IAC DO BIN send EOL --> CR + NONE send EOL --> LF + add Dump_log option. -ver0.13 1998/08/25 +=== Version 0.13 1998/08/25 add print method. -ver0.122 1998/08/05 +=== Version 0.122 1998/08/05 support for HP-UX 10.20 thanks to WATANABE Tetsuya + socket.<< --> socket.write -ver0.121 1998/07/15 +=== Version 0.121 1998/07/15 string.+= --> string.concat -ver0.12 1998/06/01 +=== Version 0.12 1998/06/01 add timeout, waittime. -ver0.11 1998/04/21 +=== Version 0.11 1998/04/21 add realtime output. -ver0.10 1998/04/13 +=== Version 0.10 1998/04/13 first release. =end @@ -205,84 +226,89 @@ TimeOut = TimeoutError class Telnet < SimpleDelegator - IAC = 255.chr # interpret as command: - DONT = 254.chr # you are not to use option - DO = 253.chr # please, you use option - WONT = 252.chr # I won't use option - WILL = 251.chr # I will use option - SB = 250.chr # interpret as subnegotiation - GA = 249.chr # you may reverse the line - EL = 248.chr # erase the current line - EC = 247.chr # erase the current character - AYT = 246.chr # are you there - AO = 245.chr # abort output--but let prog finish - IP = 244.chr # interrupt process--permanently - BREAK = 243.chr # break - DM = 242.chr # data mark--for connect. cleaning - NOP = 241.chr # nop - SE = 240.chr # end sub negotiation - EOR = 239.chr # end of record (transparent mode) - ABORT = 238.chr # Abort process - SUSP = 237.chr # Suspend process - EOF = 236.chr # End of file - SYNCH = 242.chr # for telfunc calls - - OPT_BINARY = 0.chr # Binary Transmission - OPT_ECHO = 1.chr # Echo - OPT_RCP = 2.chr # Reconnection - OPT_SGA = 3.chr # Suppress Go Ahead - OPT_NAMS = 4.chr # Approx Message Size Negotiation - OPT_STATUS = 5.chr # Status - OPT_TM = 6.chr # Timing Mark - OPT_RCTE = 7.chr # Remote Controlled Trans and Echo - OPT_NAOL = 8.chr # Output Line Width - OPT_NAOP = 9.chr # Output Page Size - OPT_NAOCRD = 10.chr # Output Carriage-Return Disposition - OPT_NAOHTS = 11.chr # Output Horizontal Tab Stops - OPT_NAOHTD = 12.chr # Output Horizontal Tab Disposition - OPT_NAOFFD = 13.chr # Output Formfeed Disposition - OPT_NAOVTS = 14.chr # Output Vertical Tabstops - OPT_NAOVTD = 15.chr # Output Vertical Tab Disposition - OPT_NAOLFD = 16.chr # Output Linefeed Disposition - OPT_XASCII = 17.chr # Extended ASCII - OPT_LOGOUT = 18.chr # Logout - OPT_BM = 19.chr # Byte Macro - OPT_DET = 20.chr # Data Entry Terminal - OPT_SUPDUP = 21.chr # SUPDUP - OPT_SUPDUPOUTPUT = 22.chr # SUPDUP Output - OPT_SNDLOC = 23.chr # Send Location - OPT_TTYPE = 24.chr # Terminal Type - OPT_EOR = 25.chr # End of Record - OPT_TUID = 26.chr # TACACS User Identification - OPT_OUTMRK = 27.chr # Output Marking - OPT_TTYLOC = 28.chr # Terminal Location Number - OPT_3270REGIME = 29.chr # Telnet 3270 Regime - OPT_X3PAD = 30.chr # X.3 PAD - OPT_NAWS = 31.chr # Negotiate About Window Size - OPT_TSPEED = 32.chr # Terminal Speed - OPT_LFLOW = 33.chr # Remote Flow Control - OPT_LINEMODE = 34.chr # Linemode - OPT_XDISPLOC = 35.chr # X Display Location - OPT_OLD_ENVIRON = 36.chr # Environment Option - OPT_AUTHENTICATION = 37.chr # Authentication Option - OPT_ENCRYPT = 38.chr # Encryption Option - OPT_NEW_ENVIRON = 39.chr # New Environment Option - OPT_EXOPL = 255.chr # Extended-Options-List + IAC = 255.chr # "\377" # interpret as command: + DONT = 254.chr # "\376" # you are not to use option + DO = 253.chr # "\375" # please, you use option + WONT = 252.chr # "\374" # I won't use option + WILL = 251.chr # "\373" # I will use option + SB = 250.chr # "\372" # interpret as subnegotiation + GA = 249.chr # "\371" # you may reverse the line + EL = 248.chr # "\370" # erase the current line + EC = 247.chr # "\367" # erase the current character + AYT = 246.chr # "\366" # are you there + AO = 245.chr # "\365" # abort output--but let prog finish + IP = 244.chr # "\364" # interrupt process--permanently + BREAK = 243.chr # "\363" # break + DM = 242.chr # "\362" # data mark--for connect. cleaning + NOP = 241.chr # "\361" # nop + SE = 240.chr # "\360" # end sub negotiation + EOR = 239.chr # "\357" # end of record (transparent mode) + ABORT = 238.chr # "\356" # Abort process + SUSP = 237.chr # "\355" # Suspend process + EOF = 236.chr # "\354" # End of file + SYNCH = 242.chr # "\362" # for telfunc calls + + OPT_BINARY = 0.chr # "\000" # Binary Transmission + OPT_ECHO = 1.chr # "\001" # Echo + OPT_RCP = 2.chr # "\002" # Reconnection + OPT_SGA = 3.chr # "\003" # Suppress Go Ahead + OPT_NAMS = 4.chr # "\004" # Approx Message Size Negotiation + OPT_STATUS = 5.chr # "\005" # Status + OPT_TM = 6.chr # "\006" # Timing Mark + OPT_RCTE = 7.chr # "\a" # Remote Controlled Trans and Echo + OPT_NAOL = 8.chr # "\010" # Output Line Width + OPT_NAOP = 9.chr # "\t" # Output Page Size + OPT_NAOCRD = 10.chr # "\n" # Output Carriage-Return Disposition + OPT_NAOHTS = 11.chr # "\v" # Output Horizontal Tab Stops + OPT_NAOHTD = 12.chr # "\f" # Output Horizontal Tab Disposition + OPT_NAOFFD = 13.chr # "\r" # Output Formfeed Disposition + OPT_NAOVTS = 14.chr # "\016" # Output Vertical Tabstops + OPT_NAOVTD = 15.chr # "\017" # Output Vertical Tab Disposition + OPT_NAOLFD = 16.chr # "\020" # Output Linefeed Disposition + OPT_XASCII = 17.chr # "\021" # Extended ASCII + OPT_LOGOUT = 18.chr # "\022" # Logout + OPT_BM = 19.chr # "\023" # Byte Macro + OPT_DET = 20.chr # "\024" # Data Entry Terminal + OPT_SUPDUP = 21.chr # "\025" # SUPDUP + OPT_SUPDUPOUTPUT = 22.chr # "\026" # SUPDUP Output + OPT_SNDLOC = 23.chr # "\027" # Send Location + OPT_TTYPE = 24.chr # "\030" # Terminal Type + OPT_EOR = 25.chr # "\031" # End of Record + OPT_TUID = 26.chr # "\032" # TACACS User Identification + OPT_OUTMRK = 27.chr # "\e" # Output Marking + OPT_TTYLOC = 28.chr # "\034" # Terminal Location Number + OPT_3270REGIME = 29.chr # "\035" # Telnet 3270 Regime + OPT_X3PAD = 30.chr # "\036" # X.3 PAD + OPT_NAWS = 31.chr # "\037" # Negotiate About Window Size + OPT_TSPEED = 32.chr # " " # Terminal Speed + OPT_LFLOW = 33.chr # "!" # Remote Flow Control + OPT_LINEMODE = 34.chr # "\"" # Linemode + OPT_XDISPLOC = 35.chr # "#" # X Display Location + OPT_OLD_ENVIRON = 36.chr # "$" # Environment Option + OPT_AUTHENTICATION = 37.chr # "%" # Authentication Option + OPT_ENCRYPT = 38.chr # "&" # Encryption Option + OPT_NEW_ENVIRON = 39.chr # "'" # New Environment Option + OPT_EXOPL = 255.chr # "\377" # Extended-Options-List NULL = "\000" CR = "\015" LF = "\012" EOL = CR + LF +v = $-v +$-v = false + VERSION = "0.20" + RELEASE_DATE = "$Date: 1999/06/04 06:24:58 $" +$-v = v def initialize(options) @options = options - @options["Binmode"] = FALSE if not @options.include?("Binmode") - @options["Host"] = "localhost" if not @options.include?("Host") - @options["Port"] = 23 if not @options.include?("Port") - @options["Prompt"] = /[$%#>] \Z/ if not @options.include?("Prompt") - @options["Telnetmode"] = TRUE if not @options.include?("Telnetmode") - @options["Timeout"] = 10 if not @options.include?("Timeout") - @options["Waittime"] = 0 if not @options.include?("Waittime") + @options["Binmode"] = FALSE if not @options.include?("Binmode") + @options["Host"] = "localhost" if not @options.include?("Host") + @options["Port"] = 23 if not @options.include?("Port") + @options["Prompt"] = /[$%#>] \z/n if not @options.include?("Prompt") + @options["Telnetmode"] = TRUE if not @options.include?("Telnetmode") + @options["Timeout"] = 10 if not @options.include?("Timeout") + @options["Waittime"] = 0 if not @options.include?("Waittime") @telnet_option = { "SGA" => FALSE, "BINARY" => FALSE } @@ -333,7 +359,7 @@ class Telnet < SimpleDelegator end super(@sock) - end + end # initialize attr :sock @@ -353,50 +379,64 @@ class Telnet < SimpleDelegator end end - def preprocess(str) + def preprocess(string) + str = string.dup - if not @options["Binmode"] - str.gsub!(/#{CR}#{NULL}/no, CR) # combine CR+NULL into CR - str.gsub!(/#{EOL}/no, "\n") # combine EOL into "\n" - end + # combine CR+NULL into CR + str.gsub!(/#{CR}#{NULL}/no, CR) if @options["Telnetmode"] + + # combine EOL into "\n" + str.gsub!(/#{EOL}/no, "\n") if not @options["Binmode"] # respond to "IAC DO x" - str.gsub!(/(?:(?!#{IAC}))?#{IAC}#{DO}([#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}])/no){ - if OPT_BINARY == $1 + str.gsub!(/([^#{IAC}]?)#{IAC}#{DO}([#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}])/no){ + if OPT_BINARY == $2 @telnet_option["BINARY"] = TRUE @sock.write(IAC + WILL + OPT_BINARY) else - @sock.write(IAC + WONT + $1) + @sock.write(IAC + WONT + $2) end - '' + $1 } # respond to "IAC DON'T x" with "IAC WON'T x" - str.gsub!(/(?:(?!#{IAC}))?#{IAC}#{DONT}([#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}])/no){ - @sock.write(IAC + WONT + $1) - '' + str.gsub!(/([^#{IAC}]?)#{IAC}#{DONT}([#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}])/no){ + @sock.write(IAC + WONT + $2) + $1 } # respond to "IAC WILL x" - str.gsub!(/(?:(?!#{IAC}))?#{IAC}#{WILL}([#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}])/no){ - if OPT_SGA == $1 + str.gsub!(/([^#{IAC}]?)#{IAC}#{WILL}([#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}])/no){ + if OPT_ECHO == $2 + @sock.write(IAC + DO + OPT_ECHO) + elsif OPT_SGA == $2 @telnet_option["SGA"] = TRUE @sock.write(IAC + DO + OPT_SGA) end - '' + $1 } - # ignore "IAC WON'T x" - str.gsub!(/(?:(?!#{IAC}))?#{IAC}#{WONT}[#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}]/no, '') + # respond to "IAC WON'T x" + str.gsub!(/([^#{IAC}]?)#{IAC}#{WONT}([#{OPT_BINARY}-#{OPT_NEW_ENVIRON}#{OPT_EXOPL}])/no){ + if OPT_ECHO == $2 + @sock.write(IAC + DONT + OPT_ECHO) + elsif OPT_SGA == $2 + @telnet_option["SGA"] = FALSE + @sock.write(IAC + DONT + OPT_SGA) + end + $1 + } # respond to "IAC AYT" (are you there) - str.gsub!(/(?:(?!#{IAC}))?#{IAC}#{AYT}/no){ + str.gsub!(/([^#{IAC}]?)#{IAC}#{AYT}/no){ @sock.write("nobody here but us pigeons" + EOL) - '' + $1 } - str.gsub(/#{IAC}#{IAC}/no, IAC) # handle escaped IAC characters - end + str.gsub!(/#{IAC}#{IAC}/no, IAC) # handle escaped IAC characters + + str + end # preprocess def waitfor(options) time_out = @options["Timeout"] @@ -417,41 +457,50 @@ class Telnet < SimpleDelegator end line = '' + buf = '' until(not IO::select([@sock], nil, nil, waittime) and prompt === line) raise TimeOut, "timed-out; wait for the next data" if not IO::select([@sock], nil, nil, time_out) - buf = '' begin - buf = @sock.sysread(1024 * 1024) - @dumplog.print(buf) if @options.include?("Dump_log") - buf = preprocess(buf) if @options["Telnetmode"] - rescue EOFError # End of file reached - break - ensure + c = @sock.sysread(1024 * 1024) + @dumplog.print(c) if @options.include?("Dump_log") + buf.concat c + if @options["Telnetmode"] + buf = preprocess(buf) + if /#{IAC}.?\z/no === buf + next + end + end @log.print(buf) if @options.include?("Output_log") yield buf if iterator? line.concat(buf) + buf = '' + rescue EOFError # End of file reached + break end end line end def print(string) - string.gsub!(/#{IAC}/no, IAC + IAC) if @options["Telnetmode"] - if @options["Binmode"] - @sock.write(string) - else + str = string.dup + "\n" + + str.gsub!(/#{IAC}/no, IAC + IAC) if @options["Telnetmode"] + + if not @options["Binmode"] if @telnet_option["BINARY"] and @telnet_option["SGA"] # IAC WILL SGA IAC DO BIN send EOL --> CR - @sock.write(string.gsub(/\n/, CR) + CR) + str.gsub!(/\n/n, CR) elsif @telnet_option["SGA"] # IAC WILL SGA send EOL --> CR+NULL - @sock.write(string.gsub(/\n/, CR + NULL) + CR + NULL) + str.gsub!(/\n/n, CR + NULL) else - # NONE send EOL --> LF - @sock.write(string.gsub(/\n/, LF) + LF) + # NONE send EOL --> CR+LF + str.gsub!(/\n/n, EOL) end end + + @sock.write(str) end def cmd(options) @@ -484,14 +533,14 @@ class Telnet < SimpleDelegator end if iterator? - line = waitfor(/login[: ]*\Z/){|c| yield c } + line = waitfor(/login[: ]*\z/n){|c| yield c } line.concat( cmd({"String" => username, - "Match" => /Password[: ]*\Z/}){|c| yield c } ) + "Match" => /Password[: ]*\z/n}){|c| yield c } ) line.concat( cmd(password){|c| yield c } ) else - line = waitfor(/login[: ]*\Z/) + line = waitfor(/login[: ]*\z/n) line.concat( cmd({"String" => username, - "Match" => /Password[: ]*\Z/}) ) + "Match" => /Password[: ]*\z/n}) ) line.concat( cmd(password) ) end line diff --git a/lib/tempfile.rb b/lib/tempfile.rb index 3fb7ff23d5..11a8fba979 100644 --- a/lib/tempfile.rb +++ b/lib/tempfile.rb @@ -28,15 +28,13 @@ class Tempfile < SimpleDelegator } end - def initialize(basename, tmpdir = nil) + def initialize(basename, tmpdir=ENV['TMPDIR']||ENV['TMP']||ENV['TEMP']||'/tmp') umask = File.umask(0177) - tmpname = lock = nil begin n = 0 while true begin - tmpdir ||= ENV['TMPDIR'] || ENV['TMP'] || ENV['TEMP'] || '/tmp' - tmpname = sprintf('%s/%s.%d.%d', tmpdir, basename, $$, n) + tmpname = sprintf('%s/%s%d.%d', tmpdir, basename, $$, n) lock = tmpname + '.lock' unless File.exist?(tmpname) or File.exist?(lock) Dir.mkdir(lock) -- cgit v1.2.3