module WEBrick::Utils

def create_listeners(address, port)

It will create IPV4 and IPV6 sockets on all interfaces.

Creates TCP server sockets bound to +address+:+port+ and returns them.
#
def create_listeners(address, port)
  unless port
    raise ArgumentError, "must specify port"
  end
  sockets = Socket.tcp_server_sockets(address, port)
  sockets = sockets.map {|s|
    s.autoclose = false
    ts = TCPServer.for_fd(s.fileno)
    s.close
    ts
  }
  return sockets
end

def create_self_signed_cert(bits, cn, comment)

def create_self_signed_cert(bits, cn, comment)
  rsa = if $VERBOSE
    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
    }
  else
    OpenSSL::PKey::RSA.new(bits)
  end
  cert = OpenSSL::X509::Certificate.new
  cert.version = 2
  cert.serial = 1
  name = (cn.kind_of? String) ? OpenSSL::X509::Name.parse(cn)
                              : 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, digitalSignature, keyAgreement, dataEncipherment"),
    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, "SHA256")
  return [ cert, rsa ]
end

def getservername

The server hostname
#
def getservername
  Socket::gethostname
end

def random_string(len)

Generates a random string of length +len+
#
def random_string(len)
  rand_max = RAND_CHARS.bytesize
  ret = +""
  len.times{ ret << RAND_CHARS[rand(rand_max)] }
  ret
end

def set_close_on_exec(io)

Sets the close on exec flag for +io+
#
def set_close_on_exec(io)
  io.close_on_exec = true if io.respond_to?(:close_on_exec=)
end

def set_non_blocking(io)

Sets IO operations on +io+ to be non-blocking
#
def set_non_blocking(io)
  io.nonblock = true if io.respond_to?(:nonblock=)
end

def su(user)

Changes the process's uid and gid to the ones of +user+
#
def su(user)
  if pw = Etc.getpwnam(user)
    Process::initgroups(user, pw.gid)
    Process::Sys::setgid(pw.gid)
    Process::Sys::setuid(pw.uid)
  else
    warn("WEBrick::Utils::su doesn't work on this platform", uplevel: 1)
  end
end

def timeout(seconds, exception=Timeout::Error)

If +seconds+ is zero or nil, simply executes the block

than +seconds+.
Executes the passed block and raises +exception+ if execution takes more
#
def timeout(seconds, exception=Timeout::Error)
  return yield if seconds.nil? or seconds.zero?
  # raise ThreadError, "timeout within critical session" if Thread.critical
  id = TimeoutHandler.register(seconds, exception)
  begin
    yield(seconds)
  ensure
    TimeoutHandler.cancel(id)
  end
end