1 # -*- encoding: binary -*-
8 # prevents IO objects in here from being GC-ed
9 # kill this when we drop 1.8 support
12 # internal interface, only used by Rainbows!/Zbatery
14 # The semantics for TCP_DEFER_ACCEPT changed in Linux 2.6.32+
15 # with commit d1b99ba41d6c5aa1ed2fc634323449dd656899e9
16 # This change shouldn't affect Unicorn users behind nginx (a
17 # value of 1 remains an optimization), but Rainbows! users may
18 # want to use a higher value on Linux 2.6.32+ to protect against
19 # denial-of-service attacks
20 :tcp_defer_accept => 1,
22 # FreeBSD, we need to override this to 'dataready' if we
23 # eventually get HTTPS support
24 :accept_filter => 'httpready',
26 # same default value as Mongrel
29 # favor latency over bandwidth savings
34 # configure platform-specific options (only tested on Linux 2.6 so far)
36 [ af_name, nil ].pack('a16a240')
37 end if RUBY_PLATFORM =~ /freebsd/ && Socket.const_defined?(:SO_ACCEPTFILTER)
39 def prevent_autoclose(io)
40 if io.respond_to?(:autoclose=)
47 def set_tcp_sockopt(sock, opt)
48 # just in case, even LANs can break sometimes. Linux sysadmins
49 # can lower net.ipv4.tcp_keepalive_* sysctl knobs to very low values.
50 Socket.const_defined?(:SO_KEEPALIVE) and
51 sock.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, 1)
53 if Socket.const_defined?(:TCP_NODELAY)
54 val = opt[:tcp_nodelay]
55 val = DEFAULTS[:tcp_nodelay] if val.nil?
56 sock.setsockopt(:IPPROTO_TCP, :TCP_NODELAY, val ? 1 : 0)
59 val = opt[:tcp_nopush]
61 if Socket.const_defined?(:TCP_CORK) # Linux
62 sock.setsockopt(:IPPROTO_TCP, :TCP_CORK, val)
63 elsif Socket.const_defined?(:TCP_NOPUSH) # FreeBSD
64 sock.setsockopt(:IPPROTO_TCP, :TCP_NOPUSH, val)
68 # No good reason to ever have deferred accepts off
69 # (except maybe benchmarking)
70 if Socket.const_defined?(:TCP_DEFER_ACCEPT)
71 # this differs from nginx, since nginx doesn't allow us to
72 # configure the the timeout...
73 seconds = opt[:tcp_defer_accept]
74 seconds = DEFAULTS[:tcp_defer_accept] if [true,nil].include?(seconds)
75 seconds = 0 unless seconds # nil/false means disable this
76 sock.setsockopt(:IPPROTO_TCP, :TCP_DEFER_ACCEPT, seconds)
77 elsif respond_to?(:accf_arg)
78 name = opt[:accept_filter]
79 name = DEFAULTS[:accept_filter] if name.nil?
81 sock.setsockopt(:SOL_SOCKET, :SO_ACCEPTFILTER, accf_arg(name))
83 logger.error("#{sock_name(sock)} " \
84 "failed to set accept_filter=#{name} (#{e.inspect})")
89 def set_server_sockopt(sock, opt)
90 opt = DEFAULTS.merge(opt || {})
92 TCPSocket === sock and set_tcp_sockopt(sock, opt)
94 rcvbuf, sndbuf = opt.values_at(:rcvbuf, :sndbuf)
96 log_buffer_sizes(sock, "before: ")
97 sock.setsockopt(:SOL_SOCKET, :SO_RCVBUF, rcvbuf) if rcvbuf
98 sock.setsockopt(:SOL_SOCKET, :SO_SNDBUF, sndbuf) if sndbuf
99 log_buffer_sizes(sock, " after: ")
101 sock.listen(opt[:backlog])
103 Unicorn.log_error(logger, "#{sock_name(sock)} #{opt.inspect}", e)
106 def log_buffer_sizes(sock, pfx = '')
107 rcvbuf = sock.getsockopt(:SOL_SOCKET, :SO_RCVBUF).int
108 sndbuf = sock.getsockopt(:SOL_SOCKET, :SO_SNDBUF).int
109 logger.info "#{pfx}#{sock_name(sock)} rcvbuf=#{rcvbuf} sndbuf=#{sndbuf}"
112 # creates a new server, socket. address may be a HOST:PORT or
113 # an absolute path to a UNIX socket. address can even be a Socket
114 # object in which case it is immediately returned
115 def bind_listen(address = '0.0.0.0:8080', opt = {})
116 return address unless String === address
118 sock = if address[0] == ?/
119 if File.exist?(address)
120 if File.socket?(address)
122 UNIXSocket.new(address).close
123 # fall through, try to bind(2) and fail with EADDRINUSE
124 # (or succeed from a small race condition we can't sanely avoid).
125 rescue Errno::ECONNREFUSED
126 logger.info "unlinking existing socket=#{address}"
131 "socket=#{address} specified but it is not a socket!"
134 old_umask = File.umask(opt[:umask] || 0)
136 Kgio::UNIXServer.new(address)
138 File.umask(old_umask)
140 elsif /\A\[([a-fA-F0-9:]+)\]:(\d+)\z/ =~ address
141 new_tcp_server($1, $2.to_i, opt.merge(:ipv6=>true))
142 elsif /\A(\d+\.\d+\.\d+\.\d+):(\d+)\z/ =~ address
143 new_tcp_server($1, $2.to_i, opt)
145 raise ArgumentError, "Don't know how to bind: #{address}"
147 set_server_sockopt(sock, opt)
151 def new_tcp_server(addr, port, opt)
152 # n.b. we set FD_CLOEXEC in the workers
153 sock = Socket.new(opt[:ipv6] ? :AF_INET6 : :AF_INET, :SOCK_STREAM)
154 if opt.key?(:ipv6only)
155 Socket.const_defined?(:IPV6_V6ONLY) or
156 abort "Socket::IPV6_V6ONLY not defined, upgrade Ruby and/or your OS"
157 sock.setsockopt(:IPPROTO_IPV6, :IPV6_V6ONLY, opt[:ipv6only] ? 1 : 0)
159 sock.setsockopt(:SOL_SOCKET, :SO_REUSEADDR, 1)
160 if Socket.const_defined?(:SO_REUSEPORT) && opt[:reuseport]
161 sock.setsockopt(:SOL_SOCKET, :SO_REUSEPORT, 1)
163 sock.bind(Socket.pack_sockaddr_in(port, addr))
164 prevent_autoclose(sock)
165 Kgio::TCPServer.for_fd(sock.fileno)
168 # returns rfc2732-style (e.g. "[::1]:666") addresses for IPv6
170 port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
171 /:/ =~ addr ? "[#{addr}]:#{port}" : "#{addr}:#{port}"
173 module_function :tcp_name
175 # Returns the configuration name of a socket as a string. sock may
176 # be a string value, in which case it is returned as-is
177 # Warning: TCP sockets may not always return the name given to it.
180 when String then sock
182 Socket.unpack_sockaddr_un(sock.getsockname)
189 Socket.unpack_sockaddr_un(sock.getsockname)
192 raise ArgumentError, "Unhandled class #{sock.class}: #{sock.inspect}"
196 module_function :sock_name
198 # casts a given Socket to be a TCPServer or UNIXServer
199 def server_cast(sock)
201 Socket.unpack_sockaddr_in(sock.getsockname)
202 Kgio::TCPServer.for_fd(sock.fileno)
204 Kgio::UNIXServer.for_fd(sock.fileno)
208 end # module SocketHelper