diff options
Diffstat (limited to 'lib/unicorn/socket_helper.rb')
-rw-r--r-- | lib/unicorn/socket_helper.rb | 66 |
1 files changed, 42 insertions, 24 deletions
diff --git a/lib/unicorn/socket_helper.rb b/lib/unicorn/socket_helper.rb index 9a4266d..9a155e1 100644 --- a/lib/unicorn/socket_helper.rb +++ b/lib/unicorn/socket_helper.rb @@ -1,11 +1,28 @@ # -*- encoding: binary -*- - +# :enddoc: require 'socket' module Unicorn module SocketHelper include Socket::Constants + # :stopdoc: + # internal interface, only used by Rainbows!/Zbatery + DEFAULTS = { + # The semantics for TCP_DEFER_ACCEPT changed in Linux 2.6.32+ + # with commit d1b99ba41d6c5aa1ed2fc634323449dd656899e9 + # This change shouldn't affect Unicorn users behind nginx (a + # value of 1 remains an optimization), but Rainbows! users may + # want to use a higher value on Linux 2.6.32+ to protect against + # denial-of-service attacks + :tcp_defer_accept => 1, + + # FreeBSD, we need to override this to 'dataready' when we + # eventually get HTTPS support + :accept_filter => 'httpready', + } + #:startdoc: + # configure platform-specific options (only tested on Linux 2.6 so far) case RUBY_PLATFORM when /linux/ @@ -14,22 +31,13 @@ module Unicorn # do not send out partial frames (Linux) TCP_CORK = 3 unless defined?(TCP_CORK) - when /freebsd(([1-4]\..{1,2})|5\.[0-4])/ - # Do nothing for httpready, just closing a bug when freebsd <= 5.4 - TCP_NOPUSH = 4 unless defined?(TCP_NOPUSH) # :nodoc: when /freebsd/ # do not send out partial frames (FreeBSD) TCP_NOPUSH = 4 unless defined?(TCP_NOPUSH) - # Use the HTTP accept filter if available. - # The struct made by pack() is defined in /usr/include/sys/socket.h - # as accept_filter_arg - unless `/sbin/sysctl -nq net.inet.accf.http`.empty? - # set set the "httpready" accept filter in FreeBSD if available - # if other protocols are to be supported, this may be - # String#replace-d with "dataready" arguments instead - FILTER_ARG = ['httpready', nil].pack('a16a240') - end + def accf_arg(af_name) + [ af_name, nil ].pack('a16a240') + end if defined?(SO_ACCEPTFILTER) end def set_tcp_sockopt(sock, opt) @@ -49,10 +57,25 @@ module Unicorn end # No good reason to ever have deferred accepts off + # (except maybe benchmarking) if defined?(TCP_DEFER_ACCEPT) - sock.setsockopt(SOL_TCP, TCP_DEFER_ACCEPT, 1) - elsif defined?(SO_ACCEPTFILTER) && defined?(FILTER_ARG) - sock.setsockopt(SOL_SOCKET, SO_ACCEPTFILTER, FILTER_ARG) + # this differs from nginx, since nginx doesn't allow us to + # configure the the timeout... + tmp = DEFAULTS.merge(opt) + seconds = tmp[:tcp_defer_accept] + seconds = DEFAULTS[:tcp_defer_accept] if seconds == true + seconds = 0 unless seconds # nil/false means disable this + sock.setsockopt(SOL_TCP, TCP_DEFER_ACCEPT, seconds) + elsif respond_to?(:accf_arg) + tmp = DEFAULTS.merge(opt) + if name = tmp[:accept_filter] + begin + sock.setsockopt(SOL_SOCKET, SO_ACCEPTFILTER, accf_arg(name)) + rescue => e + logger.error("#{sock_name(sock)} " \ + "failed to set accept_filter=#{name} (#{e.inspect})") + end + end end end @@ -69,14 +92,11 @@ module Unicorn end sock.listen(opt[:backlog] || 1024) rescue => e - if respond_to?(:logger) - logger.error "error setting socket options: #{e.inspect}" - logger.error e.backtrace.join("\n") - end + logger.error "error setting socket options: #{e.inspect}" + logger.error e.backtrace.join("\n") end def log_buffer_sizes(sock, pfx = '') - respond_to?(:logger) or return rcvbuf = sock.getsockopt(SOL_SOCKET, SO_RCVBUF).unpack('i') sndbuf = sock.getsockopt(SOL_SOCKET, SO_SNDBUF).unpack('i') logger.info "#{pfx}#{sock_name(sock)} rcvbuf=#{rcvbuf} sndbuf=#{sndbuf}" @@ -91,9 +111,7 @@ module Unicorn sock = if address[0] == ?/ if File.exist?(address) if File.socket?(address) - if self.respond_to?(:logger) - logger.info "unlinking existing socket=#{address}" - end + logger.info "unlinking existing socket=#{address}" File.unlink(address) else raise ArgumentError, |