mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	:DoNotReverseLookup. * lib/webrick/server.rb (WEBrick::GenericServer#accept): call do_not_reverse_lookup for each socket if :DoNotReverseLookup is set. [ruby-code:02357] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5941 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			180 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			180 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
#
 | 
						|
# server.rb -- GenericServer Class
 | 
						|
#
 | 
						|
# Author: IPR -- Internet Programming with Ruby -- writers
 | 
						|
# Copyright (c) 2000, 2001 TAKAHASHI Masayoshi, GOTOU Yuuzou
 | 
						|
# Copyright (c) 2002 Internet Programming with Ruby writers. All rights
 | 
						|
# reserved.
 | 
						|
#
 | 
						|
# $IPR: server.rb,v 1.62 2003/07/22 19:20:43 gotoyuzo Exp $
 | 
						|
 | 
						|
require 'thread'
 | 
						|
require 'socket'
 | 
						|
require 'timeout'
 | 
						|
require 'webrick/config'
 | 
						|
require 'webrick/log'
 | 
						|
 | 
						|
module WEBrick
 | 
						|
 | 
						|
  class ServerError < StandardError; end
 | 
						|
 | 
						|
  class SimpleServer
 | 
						|
    def SimpleServer.start
 | 
						|
      yield
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  class Daemon
 | 
						|
    def Daemon.start
 | 
						|
      exit!(0) if fork
 | 
						|
      Process::setsid
 | 
						|
      exit!(0) if fork
 | 
						|
      Dir::chdir("/")
 | 
						|
      File::umask(0)
 | 
						|
      [ STDIN, STDOUT, STDERR ].each{|io|
 | 
						|
        io.reopen("/dev/null", "r+")
 | 
						|
      }
 | 
						|
      yield if block_given?
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  class GenericServer
 | 
						|
    attr_reader :status, :config, :logger, :tokens, :listeners
 | 
						|
 | 
						|
    def initialize(config={}, default=Config::General)
 | 
						|
      @config = default.dup.update(config)
 | 
						|
      @status = :Stop
 | 
						|
      @config[:Logger] ||= Log::new
 | 
						|
      @logger = @config[:Logger]
 | 
						|
 | 
						|
      @tokens = SizedQueue.new(@config[:MaxClients])
 | 
						|
      @config[:MaxClients].times{ @tokens.push(nil) }
 | 
						|
 | 
						|
      webrickv = WEBrick::VERSION
 | 
						|
      rubyv = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
 | 
						|
      @logger.info("WEBrick #{webrickv}")
 | 
						|
      @logger.info("ruby #{rubyv}")
 | 
						|
 | 
						|
      @listeners = []
 | 
						|
      unless @config[:DoNotListen]
 | 
						|
        if @config[:Listen]
 | 
						|
          warn(":Listen option is deprecated; use GenericServer#listen")
 | 
						|
        end
 | 
						|
        listen(@config[:BindAddress], @config[:Port])
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    def [](key)
 | 
						|
      @config[key]
 | 
						|
    end
 | 
						|
 | 
						|
    def listen(address, port)
 | 
						|
      @listeners += Utils::create_listeners(address, port, @logger)
 | 
						|
    end
 | 
						|
 | 
						|
    def start(&block)
 | 
						|
      raise ServerError, "already started." if @status != :Stop
 | 
						|
      server_type = @config[:ServerType] || SimpleServer
 | 
						|
 | 
						|
      server_type.start{
 | 
						|
        @logger.info \
 | 
						|
          "#{self.class}#start: pid=#{$$} port=#{@config[:Port]}"
 | 
						|
        call_callback(:StartCallback)
 | 
						|
 | 
						|
        thgroup = ThreadGroup.new
 | 
						|
        @status = :Running
 | 
						|
        while @status == :Running
 | 
						|
          begin
 | 
						|
            if svrs = IO.select(@listeners, nil, nil, 2.0)
 | 
						|
              svrs[0].each{|svr|
 | 
						|
                @tokens.pop          # blocks while no token is there.
 | 
						|
                sock = svr.accept
 | 
						|
                sock.sync = true
 | 
						|
                if @config[:DoNotReverseLookup]
 | 
						|
                  sock.do_not_reverse_lookup = true
 | 
						|
                end
 | 
						|
                Utils::set_close_on_exec(sock)
 | 
						|
                th = start_thread(sock, &block)
 | 
						|
                th[:WEBrickThread] = true
 | 
						|
                thgroup.add(th)
 | 
						|
              }
 | 
						|
            end
 | 
						|
          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, IOError => ex
 | 
						|
            # if the listening socket was closed in GenericServer#shutdown,
 | 
						|
            # IO::select raise it.
 | 
						|
          rescue Exception => ex
 | 
						|
            msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
 | 
						|
            @logger.error msg
 | 
						|
          end
 | 
						|
        end
 | 
						|
 | 
						|
        @logger.info "going to shutdown ..."
 | 
						|
        thgroup.list.each{|th| th.join if th[:WEBrickThread] }
 | 
						|
        call_callback(:StopCallback)
 | 
						|
        @logger.info "#{self.class}#start done."
 | 
						|
        @status = :Stop
 | 
						|
      }
 | 
						|
    end
 | 
						|
 | 
						|
    def stop
 | 
						|
      if @status == :Running
 | 
						|
        @status = :Shutdown
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    def shutdown
 | 
						|
      stop
 | 
						|
      @listeners.each{|s|
 | 
						|
        if @logger.debug?
 | 
						|
          addr = s.addr
 | 
						|
          @logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})")
 | 
						|
        end
 | 
						|
        s.close
 | 
						|
      }
 | 
						|
      @listeners.clear
 | 
						|
    end
 | 
						|
 | 
						|
    def run(sock)
 | 
						|
      @logger.fatal "run() must be provided by user."
 | 
						|
    end
 | 
						|
 | 
						|
    private
 | 
						|
 | 
						|
    def start_thread(sock, &block)
 | 
						|
      Thread.start{
 | 
						|
        begin
 | 
						|
          Thread.current[:WEBrickSocket] = sock
 | 
						|
          addr = sock.peeraddr
 | 
						|
          @logger.debug "accept: #{addr[3]}:#{addr[1]}"
 | 
						|
          call_callback(:AcceptCallback, sock)
 | 
						|
          block ? block.call(sock) : run(sock)
 | 
						|
        rescue Errno::ENOTCONN
 | 
						|
          @logger.debug "Errno::ENOTCONN raised"
 | 
						|
        rescue ServerError => ex
 | 
						|
          msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
 | 
						|
          @logger.error msg
 | 
						|
        rescue Exception => ex
 | 
						|
          @logger.error ex
 | 
						|
        ensure
 | 
						|
          Thread.current[:WEBrickSocket] = nil
 | 
						|
          if addr
 | 
						|
            @logger.debug "close: #{addr[3]}:#{addr[1]}"
 | 
						|
          else
 | 
						|
            @logger.debug "close: <address unknown>"
 | 
						|
          end
 | 
						|
          sock.close
 | 
						|
        end
 | 
						|
        @tokens.push(nil)
 | 
						|
      }
 | 
						|
    end
 | 
						|
 | 
						|
    def call_callback(callback_name, *args)
 | 
						|
      if cb = @config[callback_name]
 | 
						|
        cb.call(*args)
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end    # end of GenericServer
 | 
						|
end
 |