mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* lib/webrick/ssl.rb: new file; SSL/TLS enhancement for GenericServer.
* lib/webrick/https.rb: SSLSocket handling is moved to webrick/ssl.rb. * lib/webrick/compat.rb (File::fnmatch): remove old migration code. * lib/webrick/httpserver.rb (HTTPServer#run): ditto. * lib/webrick/server.rb (GenericServer#listen): the body of this method is pull out as Utils::create_lisnteners. * lib/webrick/utils.rb (Utils::create_lisnteners): new method. * lib/webrick/server.rb (GenericServer#start): should not through unknown errors. and refine comments. * ext/openssl/lib/openssl/ssl.rb (SSLServer#accept): should close socket if SSLSocket raises error. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4409 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
90e010abb9
commit
65652ecdb5
8 changed files with 201 additions and 165 deletions
21
ChangeLog
21
ChangeLog
|
@ -1,3 +1,24 @@
|
||||||
|
Tue Aug 19 07:47:09 2003 GOTOU Yuuzou <gotoyuzo@notwork.org>
|
||||||
|
|
||||||
|
* lib/webrick/ssl.rb: new file; SSL/TLS enhancement for GenericServer.
|
||||||
|
|
||||||
|
* lib/webrick/https.rb: SSLSocket handling is moved to webrick/ssl.rb.
|
||||||
|
|
||||||
|
* lib/webrick/compat.rb (File::fnmatch): remove old migration code.
|
||||||
|
|
||||||
|
* lib/webrick/httpserver.rb (HTTPServer#run): ditto.
|
||||||
|
|
||||||
|
* lib/webrick/server.rb (GenericServer#listen): the body of this
|
||||||
|
method is pull out as Utils::create_lisnteners.
|
||||||
|
|
||||||
|
* lib/webrick/utils.rb (Utils::create_lisnteners): new method.
|
||||||
|
|
||||||
|
* lib/webrick/server.rb (GenericServer#start): should not
|
||||||
|
through unknown errors. and refine comments.
|
||||||
|
|
||||||
|
* ext/openssl/lib/openssl/ssl.rb (SSLServer#accept): should close
|
||||||
|
socket if SSLSocket raises error.
|
||||||
|
|
||||||
Tue Aug 19 11:19:33 2003 Shugo Maeda <shugo@ruby-lang.org>
|
Tue Aug 19 11:19:33 2003 Shugo Maeda <shugo@ruby-lang.org>
|
||||||
|
|
||||||
* io.c (next_argv): should not call GetOpenFile() if rb_stdout is
|
* io.c (next_argv): should not call GetOpenFile() if rb_stdout is
|
||||||
|
|
|
@ -69,11 +69,16 @@ module OpenSSL
|
||||||
|
|
||||||
def accept
|
def accept
|
||||||
sock = @svr.accept
|
sock = @svr.accept
|
||||||
|
begin
|
||||||
ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
|
ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
|
||||||
ssl.sync = true
|
ssl.sync = true
|
||||||
ssl.sync_close = true
|
ssl.sync_close = true
|
||||||
ssl.accept if @start_immediately
|
ssl.accept if @start_immediately
|
||||||
ssl
|
ssl
|
||||||
|
rescue SSLError => ex
|
||||||
|
sock.close
|
||||||
|
raise ex
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def close
|
def close
|
||||||
|
|
|
@ -13,18 +13,3 @@ module Errno
|
||||||
class ECONNRESET < SystemCallError; end
|
class ECONNRESET < SystemCallError; end
|
||||||
class ECONNABORTED < SystemCallError; end
|
class ECONNABORTED < SystemCallError; end
|
||||||
end
|
end
|
||||||
|
|
||||||
unless File.respond_to?(:fnmatch)
|
|
||||||
def File.fnmatch(pat, str)
|
|
||||||
case pat[0]
|
|
||||||
when nil
|
|
||||||
not str[0]
|
|
||||||
when ?*
|
|
||||||
fnmatch(pat[1..-1], str) || str[0] && fnmatch(pat, str[1..-1])
|
|
||||||
when ??
|
|
||||||
str[0] && fnmatch(pat[1..-1], str[1..-1])
|
|
||||||
else
|
|
||||||
pat[0] == str[0] && fnmatch(pat[1..-1], str[1..-1])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
|
@ -8,31 +8,11 @@
|
||||||
#
|
#
|
||||||
# $IPR: https.rb,v 1.15 2003/07/22 19:20:42 gotoyuzo Exp $
|
# $IPR: https.rb,v 1.15 2003/07/22 19:20:42 gotoyuzo Exp $
|
||||||
|
|
||||||
require 'webrick'
|
require 'webrick/ssl'
|
||||||
require 'openssl'
|
|
||||||
|
|
||||||
module WEBrick
|
module WEBrick
|
||||||
module Config
|
module Config
|
||||||
HTTP.update(
|
HTTP.update(SSL)
|
||||||
:SSLEnable => true,
|
|
||||||
:SSLCertificate => nil,
|
|
||||||
:SSLPrivateKey => nil,
|
|
||||||
:SSLClientCA => nil,
|
|
||||||
:SSLCACertificateFile => nil,
|
|
||||||
:SSLCACertificatePath => nil,
|
|
||||||
:SSLCertificateStore => nil,
|
|
||||||
:SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE,
|
|
||||||
:SSLVerifyDepth => nil,
|
|
||||||
:SSLVerifyCallback => nil, # custom verification
|
|
||||||
:SSLTimeout => nil,
|
|
||||||
:SSLOptions => nil,
|
|
||||||
# Must specify if you use auto generated certificate.
|
|
||||||
:SSLCertName => nil,
|
|
||||||
:SSLCertComment => "Generated by Ruby/OpenSSL"
|
|
||||||
)
|
|
||||||
|
|
||||||
osslv = ::OpenSSL::OPENSSL_VERSION.split[1]
|
|
||||||
HTTP[:ServerSoftware] << " OpenSSL/#{osslv}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class HTTPRequest
|
class HTTPRequest
|
||||||
|
@ -41,16 +21,18 @@ module WEBrick
|
||||||
alias orig_parse parse
|
alias orig_parse parse
|
||||||
|
|
||||||
def parse(socket=nil)
|
def parse(socket=nil)
|
||||||
orig_parse(socket)
|
if socket && socket.is_a?(OpenSSL::SSL::SSLSocket)
|
||||||
@cipher = socket.respond_to?(:cipher) ? socket.cipher : nil
|
|
||||||
@client_cert = socket.respond_to?(:peer_cert) ? socket.peer_cert : nil
|
|
||||||
@server_cert = @config[:SSLCertificate]
|
@server_cert = @config[:SSLCertificate]
|
||||||
|
@client_cert = socket.peer_cert
|
||||||
|
@cipher = socket.cipher
|
||||||
|
end
|
||||||
|
orig_parse(socket)
|
||||||
end
|
end
|
||||||
|
|
||||||
alias orig_parse_uri parse_uri
|
alias orig_parse_uri parse_uri
|
||||||
|
|
||||||
def parse_uri(str, scheme="https")
|
def parse_uri(str, scheme="https")
|
||||||
if @config[:SSLEnable]
|
if @server_cert
|
||||||
return orig_parse_uri(str, scheme)
|
return orig_parse_uri(str, scheme)
|
||||||
end
|
end
|
||||||
return orig_parse_uri(str)
|
return orig_parse_uri(str)
|
||||||
|
@ -60,100 +42,13 @@ module WEBrick
|
||||||
|
|
||||||
def meta_vars
|
def meta_vars
|
||||||
meta = orig_meta_vars
|
meta = orig_meta_vars
|
||||||
if @config[:SSLEnable]
|
if @server_cert
|
||||||
meta["HTTPS"] = "on"
|
meta["HTTPS"] = "on"
|
||||||
meta["SSL_CIPHER"] = @cipher ? @cipher[0] : ""
|
meta["SSL_SERVER_CERT"] = @server_cert.to_pem
|
||||||
meta["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : ""
|
meta["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : ""
|
||||||
meta["SSL_SERVER_CERT"] = @server_cert ? @server_cert.to_pem : ""
|
meta["SSL_CIPHER"] = @cipher[0]
|
||||||
end
|
end
|
||||||
meta
|
meta
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class HTTPServer
|
|
||||||
alias orig_init initialize
|
|
||||||
|
|
||||||
def initialize(*args)
|
|
||||||
orig_init(*args)
|
|
||||||
|
|
||||||
if @config[:SSLEnable]
|
|
||||||
unless @config[:SSLCertificate]
|
|
||||||
rsa = OpenSSL::PKey::RSA.new(512){|p, n|
|
|
||||||
case p
|
|
||||||
when 0; $stderr.putc "." # BN_generate_prime
|
|
||||||
when 1; $stderr.putc "+" # BN_generate_prime
|
|
||||||
when 2; $stderr.putc "*" # searching good prime,
|
|
||||||
# n = #of try,
|
|
||||||
# but also data from BN_generate_prime
|
|
||||||
when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q,
|
|
||||||
# but also data from BN_generate_prime
|
|
||||||
else; $stderr.putc "*" # BN_generate_prime
|
|
||||||
end
|
|
||||||
}
|
|
||||||
cert = OpenSSL::X509::Certificate.new
|
|
||||||
cert.version = 3
|
|
||||||
cert.serial = 0
|
|
||||||
name = OpenSSL::X509::Name.new(@config[:SSLCertName])
|
|
||||||
cert.subject = name
|
|
||||||
cert.issuer = name
|
|
||||||
cert.not_before = Time.now
|
|
||||||
cert.not_after = Time.now + (365*24*60*60)
|
|
||||||
cert.public_key = rsa.public_key
|
|
||||||
|
|
||||||
ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
|
|
||||||
cert.extensions = [
|
|
||||||
ef.create_extension("basicConstraints","CA:FALSE"),
|
|
||||||
ef.create_extension("subjectKeyIdentifier", "hash"),
|
|
||||||
ef.create_extension("extendedKeyUsage", "serverAuth")
|
|
||||||
]
|
|
||||||
ef.issuer_certificate = cert
|
|
||||||
ext = ef.create_extension("authorityKeyIdentifier",
|
|
||||||
"keyid:always,issuer:always")
|
|
||||||
cert.add_extension(ext)
|
|
||||||
if comment = @config[:SSLCertComment]
|
|
||||||
cert.add_extension(ef.create_extension("nsComment", comment))
|
|
||||||
end
|
|
||||||
cert.sign(rsa, OpenSSL::Digest::SHA1.new)
|
|
||||||
|
|
||||||
@config[:SSLPrivateKey] = rsa
|
|
||||||
@config[:SSLCertificate] = cert
|
|
||||||
@logger.info cert.to_s
|
|
||||||
end
|
|
||||||
@ctx = OpenSSL::SSL::SSLContext.new
|
|
||||||
set_ssl_context(@ctx, @config)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
alias orig_run run
|
|
||||||
|
|
||||||
def run(sock)
|
|
||||||
if @config[:SSLEnable]
|
|
||||||
ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
|
|
||||||
ssl.sync = true
|
|
||||||
ssl.accept
|
|
||||||
Thread.current[:WEBrickSocket] = ssl
|
|
||||||
orig_run(ssl)
|
|
||||||
Thread.current[:WEBrickSocket] = sock
|
|
||||||
ssl.close
|
|
||||||
else
|
|
||||||
orig_run(sock)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def set_ssl_context(ctx, config)
|
|
||||||
ctx.key = config[:SSLPrivateKey]
|
|
||||||
ctx.cert = config[:SSLCertificate]
|
|
||||||
ctx.client_ca = config[:SSLClientCA]
|
|
||||||
ctx.ca_file = config[:SSLCACertificateFile]
|
|
||||||
ctx.ca_path = config[:SSLCACertificatePath]
|
|
||||||
ctx.cert_store = config[:SSLCertificateStore]
|
|
||||||
ctx.verify_mode = config[:SSLVerifyClient]
|
|
||||||
ctx.verify_depth = config[:SSLVerifyDepth]
|
|
||||||
ctx.verify_callback = config[:SSLVerifyCallback]
|
|
||||||
ctx.timeout = config[:SSLTimeout]
|
|
||||||
ctx.options = config[:SSLOptions]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -58,7 +58,7 @@ module WEBrick
|
||||||
res.set_error(ex)
|
res.set_error(ex)
|
||||||
rescue HTTPStatus::Status => ex
|
rescue HTTPStatus::Status => ex
|
||||||
res.status = ex.code
|
res.status = ex.code
|
||||||
rescue StandardError, NameError => ex # for Ruby 1.6
|
rescue StandardError => ex
|
||||||
@logger.error(ex)
|
@logger.error(ex)
|
||||||
res.set_error(ex, true)
|
res.set_error(ex, true)
|
||||||
ensure
|
ensure
|
||||||
|
|
|
@ -55,10 +55,9 @@ module WEBrick
|
||||||
@logger.info("WEBrick #{webrickv}")
|
@logger.info("WEBrick #{webrickv}")
|
||||||
@logger.info("ruby #{rubyv}")
|
@logger.info("ruby #{rubyv}")
|
||||||
|
|
||||||
if @config[:DoNotListen]
|
|
||||||
@listeners = []
|
@listeners = []
|
||||||
else
|
unless @config[:DoNotListen]
|
||||||
@listeners = listen(@config[:BindAddress], @config[:Port])
|
listen(@config[:BindAddress], @config[:Port])
|
||||||
@config[:Listen].each{|addr, port|
|
@config[:Listen].each{|addr, port|
|
||||||
listen(addr, port).each{|sock| @listeners << sock }
|
listen(addr, port).each{|sock| @listeners << sock }
|
||||||
}
|
}
|
||||||
|
@ -70,26 +69,7 @@ module WEBrick
|
||||||
end
|
end
|
||||||
|
|
||||||
def listen(address, port)
|
def listen(address, port)
|
||||||
res = Socket::getaddrinfo(address, port,
|
@listeners += Utils::create_listeners(address, port, @logger)
|
||||||
Socket::AF_UNSPEC, # address family
|
|
||||||
Socket::SOCK_STREAM, # socket type
|
|
||||||
0, # protocol
|
|
||||||
Socket::AI_PASSIVE) # flag
|
|
||||||
last_error = nil
|
|
||||||
sockets = []
|
|
||||||
res.each{|ai|
|
|
||||||
begin
|
|
||||||
@logger.debug("TCPServer.new(#{ai[3]}, #{ai[1]})")
|
|
||||||
sock = TCPServer.new(ai[3], ai[1])
|
|
||||||
Utils::set_close_on_exec(sock)
|
|
||||||
sockets << sock
|
|
||||||
rescue => ex
|
|
||||||
@logger.warn("TCPServer Error: #{ex}")
|
|
||||||
last_error = ex
|
|
||||||
end
|
|
||||||
}
|
|
||||||
raise last_error if sockets.empty?
|
|
||||||
return sockets
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def start(&block)
|
def start(&block)
|
||||||
|
@ -117,12 +97,14 @@ module WEBrick
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
rescue Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPROTO => ex
|
rescue Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPROTO => ex
|
||||||
|
# TCP connection was established but RST segment was sent
|
||||||
|
# from peer before calling TCPServer#accept.
|
||||||
|
rescue Errno::EBADF => ex
|
||||||
|
# if the listening socket was closed in GenericServer#shutdown,
|
||||||
|
# IO::select raise it.
|
||||||
|
rescue => ex
|
||||||
msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
|
msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
|
||||||
@logger.error msg
|
@logger.error msg
|
||||||
rescue Errno::EBADF => ex # IO::select causes by shutdown
|
|
||||||
rescue => ex
|
|
||||||
@logger.error ex
|
|
||||||
break
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
124
lib/webrick/ssl.rb
Normal file
124
lib/webrick/ssl.rb
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
#
|
||||||
|
# ssl.rb -- SSL/TLS enhancement for GenericServer
|
||||||
|
#
|
||||||
|
# Copyright (c) 2003 GOTOU Yuuzou All rights reserved.
|
||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
|
||||||
|
require 'webrick'
|
||||||
|
require 'openssl'
|
||||||
|
|
||||||
|
module WEBrick
|
||||||
|
module Config
|
||||||
|
svrsoft = General[:ServerSoftware]
|
||||||
|
osslv = ::OpenSSL::OPENSSL_VERSION.split[1]
|
||||||
|
SSL = {
|
||||||
|
:ServerSoftware => "#{svrsoft} OpenSSL/#{osslv}",
|
||||||
|
:SSLEnable => true,
|
||||||
|
:SSLCertificate => nil,
|
||||||
|
:SSLPrivateKey => nil,
|
||||||
|
:SSLClientCA => nil,
|
||||||
|
:SSLCACertificateFile => nil,
|
||||||
|
:SSLCACertificatePath => nil,
|
||||||
|
:SSLCertificateStore => nil,
|
||||||
|
:SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE,
|
||||||
|
:SSLVerifyDepth => nil,
|
||||||
|
:SSLVerifyCallback => nil, # custom verification
|
||||||
|
:SSLTimeout => nil,
|
||||||
|
:SSLOptions => nil,
|
||||||
|
:SSLStartImmediately => true,
|
||||||
|
# Must specify if you use auto generated certificate.
|
||||||
|
:SSLCertName => nil,
|
||||||
|
:SSLCertComment => "Generated by Ruby/OpenSSL"
|
||||||
|
}
|
||||||
|
General.update(SSL)
|
||||||
|
end
|
||||||
|
|
||||||
|
module Utils
|
||||||
|
def create_self_signed_cert(bits, cn, comment)
|
||||||
|
rsa = OpenSSL::PKey::RSA.new(bits){|p, n|
|
||||||
|
case p
|
||||||
|
when 0; $stderr.putc "." # BN_generate_prime
|
||||||
|
when 1; $stderr.putc "+" # BN_generate_prime
|
||||||
|
when 2; $stderr.putc "*" # searching good prime,
|
||||||
|
# n = #of try,
|
||||||
|
# but also data from BN_generate_prime
|
||||||
|
when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q,
|
||||||
|
# but also data from BN_generate_prime
|
||||||
|
else; $stderr.putc "*" # BN_generate_prime
|
||||||
|
end
|
||||||
|
}
|
||||||
|
cert = OpenSSL::X509::Certificate.new
|
||||||
|
cert.version = 3
|
||||||
|
cert.serial = 0
|
||||||
|
name = OpenSSL::X509::Name.new(cn)
|
||||||
|
cert.subject = name
|
||||||
|
cert.issuer = name
|
||||||
|
cert.not_before = Time.now
|
||||||
|
cert.not_after = Time.now + (365*24*60*60)
|
||||||
|
cert.public_key = rsa.public_key
|
||||||
|
|
||||||
|
ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
|
||||||
|
ef.issuer_certificate = cert
|
||||||
|
cert.extensions = [
|
||||||
|
ef.create_extension("basicConstraints","CA:FALSE"),
|
||||||
|
ef.create_extension("keyUsage", "keyEncipherment"),
|
||||||
|
ef.create_extension("subjectKeyIdentifier", "hash"),
|
||||||
|
ef.create_extension("extendedKeyUsage", "serverAuth"),
|
||||||
|
ef.create_extension("nsComment", comment),
|
||||||
|
]
|
||||||
|
aki = ef.create_extension("authorityKeyIdentifier",
|
||||||
|
"keyid:always,issuer:always")
|
||||||
|
cert.add_extension(aki)
|
||||||
|
cert.sign(rsa, OpenSSL::Digest::SHA1.new)
|
||||||
|
|
||||||
|
return [ cert, rsa ]
|
||||||
|
end
|
||||||
|
module_function :create_self_signed_cert
|
||||||
|
end
|
||||||
|
|
||||||
|
class GenericServer
|
||||||
|
def ssl_context
|
||||||
|
@ssl_context ||= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def listen(address, port)
|
||||||
|
listeners = Utils::create_listeners(address, port, @logger)
|
||||||
|
if @config[:SSLEnable]
|
||||||
|
unless ssl_context
|
||||||
|
@ssl_context = setup_ssl_context(@config)
|
||||||
|
@logger.info("\n" + @config[:SSLCertificate].to_text)
|
||||||
|
end
|
||||||
|
listeners.collect!{|svr|
|
||||||
|
ssvr = ::OpenSSL::SSL::SSLServer.new(svr, ssl_context)
|
||||||
|
ssvr.start_immediately = @config[:SSLStartImmediately]
|
||||||
|
ssvr
|
||||||
|
}
|
||||||
|
end
|
||||||
|
@listeners += listeners
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup_ssl_context(config)
|
||||||
|
unless config[:SSLCertificate]
|
||||||
|
cn = config[:SSLCertName]
|
||||||
|
comment = config[:SSLCertComment]
|
||||||
|
cert, key = Utils::create_self_signed_cert(1024, cn, comment)
|
||||||
|
config[:SSLCertificate] = cert
|
||||||
|
config[:SSLPrivateKey] = key
|
||||||
|
end
|
||||||
|
ctx = OpenSSL::SSL::SSLContext.new
|
||||||
|
ctx.key = config[:SSLPrivateKey]
|
||||||
|
ctx.cert = config[:SSLCertificate]
|
||||||
|
ctx.client_ca = config[:SSLClientCA]
|
||||||
|
ctx.ca_file = config[:SSLCACertificateFile]
|
||||||
|
ctx.ca_path = config[:SSLCACertificatePath]
|
||||||
|
ctx.cert_store = config[:SSLCertificateStore]
|
||||||
|
ctx.verify_mode = config[:SSLVerifyClient]
|
||||||
|
ctx.verify_depth = config[:SSLVerifyDepth]
|
||||||
|
ctx.verify_callback = config[:SSLVerifyCallback]
|
||||||
|
ctx.timeout = config[:SSLTimeout]
|
||||||
|
ctx.options = config[:SSLOptions]
|
||||||
|
ctx
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -48,6 +48,30 @@ module WEBrick
|
||||||
end
|
end
|
||||||
module_function :getservername
|
module_function :getservername
|
||||||
|
|
||||||
|
def create_listeners(address, port, logger=nil)
|
||||||
|
res = Socket::getaddrinfo(address, port,
|
||||||
|
Socket::AF_UNSPEC, # address family
|
||||||
|
Socket::SOCK_STREAM, # socket type
|
||||||
|
0, # protocol
|
||||||
|
Socket::AI_PASSIVE) # flag
|
||||||
|
last_error = nil
|
||||||
|
sockets = []
|
||||||
|
res.each{|ai|
|
||||||
|
begin
|
||||||
|
logger.debug("TCPServer.new(#{ai[3]}, #{ai[1]})") if logger
|
||||||
|
sock = TCPServer.new(ai[3], ai[1])
|
||||||
|
Utils::set_close_on_exec(sock)
|
||||||
|
sockets << sock
|
||||||
|
rescue => ex
|
||||||
|
logger.warn("TCPServer Error: #{ex}") if logger
|
||||||
|
last_error = ex
|
||||||
|
end
|
||||||
|
}
|
||||||
|
raise last_error if sockets.empty?
|
||||||
|
return sockets
|
||||||
|
end
|
||||||
|
module_function :create_listeners
|
||||||
|
|
||||||
RAND_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
|
RAND_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
|
||||||
"0123456789" +
|
"0123456789" +
|
||||||
"abcdefghijklmnopqrstuvwxyz"
|
"abcdefghijklmnopqrstuvwxyz"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue