about summary refs log tree commit homepage
path: root/lib/unicorn/socket_helper.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/unicorn/socket_helper.rb')
-rw-r--r--lib/unicorn/socket_helper.rb74
1 files changed, 44 insertions, 30 deletions
diff --git a/lib/unicorn/socket_helper.rb b/lib/unicorn/socket_helper.rb
index 1d03eab..9f2d55c 100644
--- a/lib/unicorn/socket_helper.rb
+++ b/lib/unicorn/socket_helper.rb
@@ -17,9 +17,16 @@ module Unicorn
       # denial-of-service attacks
       :tcp_defer_accept => 1,
 
-      # FreeBSD, we need to override this to 'dataready' when we
+      # FreeBSD, we need to override this to 'dataready' if we
       # eventually get HTTPS support
       :accept_filter => 'httpready',
+
+      # same default value as Mongrel
+      :backlog => 1024,
+
+      # since we don't do keepalive, we'll always flush-on-close and
+      # this saves packets for everyone.
+      :tcp_nopush => true,
     }
     #:startdoc:
 
@@ -41,19 +48,20 @@ module Unicorn
     end
 
     def set_tcp_sockopt(sock, opt)
-
       # highly portable, but off by default because we don't do keepalive
-      if defined?(TCP_NODELAY) && ! (val = opt[:tcp_nodelay]).nil?
+      if defined?(TCP_NODELAY)
+        val = opt[:tcp_nodelay]
+        val = DEFAULTS[:tcp_nodelay] if nil == val
         sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, val ? 1 : 0)
       end
 
-      unless (val = opt[:tcp_nopush]).nil?
-        val = val ? 1 : 0
-        if defined?(TCP_CORK) # Linux
-          sock.setsockopt(IPPROTO_TCP, TCP_CORK, val)
-        elsif defined?(TCP_NOPUSH) # TCP_NOPUSH is untested (FreeBSD)
-          sock.setsockopt(IPPROTO_TCP, TCP_NOPUSH, val)
-        end
+      val = opt[:tcp_nopush]
+      val = DEFAULTS[:tcp_nopush] if nil == val
+      val = val ? 1 : 0
+      if defined?(TCP_CORK) # Linux
+        sock.setsockopt(IPPROTO_TCP, TCP_CORK, val)
+      elsif defined?(TCP_NOPUSH) # TCP_NOPUSH is untested (FreeBSD)
+        sock.setsockopt(IPPROTO_TCP, TCP_NOPUSH, val)
       end
 
       # No good reason to ever have deferred accepts off
@@ -61,26 +69,24 @@ module Unicorn
       if defined?(TCP_DEFER_ACCEPT)
         # 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 = opt[:tcp_defer_accept]
+        seconds = DEFAULTS[:tcp_defer_accept] if [true,nil].include?(seconds)
         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
+        name = opt[:accept_filter]
+        name = DEFAULTS[:accept_filter] if nil == name
+        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
 
     def set_server_sockopt(sock, opt)
-      opt ||= {}
+      opt = DEFAULTS.merge(opt || {})
 
       TCPSocket === sock and set_tcp_sockopt(sock, opt)
 
@@ -90,7 +96,7 @@ module Unicorn
         sock.setsockopt(SOL_SOCKET, SO_SNDBUF, opt[:sndbuf]) if opt[:sndbuf]
         log_buffer_sizes(sock, " after: ")
       end
-      sock.listen(opt[:backlog] || 1024)
+      sock.listen(opt[:backlog])
       rescue => e
         logger.error "error setting socket options: #{e.inspect}"
         logger.error e.backtrace.join("\n")
@@ -126,12 +132,13 @@ module Unicorn
         end
         old_umask = File.umask(opt[:umask] || 0)
         begin
-          UNIXServer.new(address)
+          Kgio::UNIXServer.new(address)
         ensure
           File.umask(old_umask)
         end
-      elsif address =~ /^(\d+\.\d+\.\d+\.\d+):(\d+)$/
-        TCPServer.new($1, $2.to_i)
+      elsif /\A(\d+\.\d+\.\d+\.\d+):(\d+)\z/ =~ address ||
+            /\A\[([a-fA-F0-9:]+)\]:(\d+)\z/ =~ address
+        Kgio::TCPServer.new($1, $2.to_i)
       else
         raise ArgumentError, "Don't know how to bind: #{address}"
       end
@@ -139,6 +146,13 @@ module Unicorn
       sock
     end
 
+    # returns rfc2732-style (e.g. "[::1]:666") addresses for IPv6
+    def tcp_name(sock)
+      port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
+      /:/ =~ addr ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
+    end
+    module_function :tcp_name
+
     # Returns the configuration name of a socket as a string.  sock may
     # be a string value, in which case it is returned as-is
     # Warning: TCP sockets may not always return the name given to it.
@@ -148,10 +162,10 @@ module Unicorn
       when UNIXServer
         Socket.unpack_sockaddr_un(sock.getsockname)
       when TCPServer
-        Socket.unpack_sockaddr_in(sock.getsockname).reverse!.join(':')
+        tcp_name(sock)
       when Socket
         begin
-          Socket.unpack_sockaddr_in(sock.getsockname).reverse!.join(':')
+          tcp_name(sock)
         rescue ArgumentError
           Socket.unpack_sockaddr_un(sock.getsockname)
         end
@@ -166,9 +180,9 @@ module Unicorn
     def server_cast(sock)
       begin
         Socket.unpack_sockaddr_in(sock.getsockname)
-        TCPServer.for_fd(sock.fileno)
+        Kgio::TCPServer.for_fd(sock.fileno)
       rescue ArgumentError
-        UNIXServer.for_fd(sock.fileno)
+        Kgio::UNIXServer.for_fd(sock.fileno)
       end
     end