4 # non-portable Socket code goes here:
7 # configure platform-specific options (only tested on Linux 2.6 so far)
10 # from /usr/include/linux/tcp.h
11 TCP_DEFER_ACCEPT = 9 unless defined?(TCP_DEFER_ACCEPT)
12 TCP_CORK = 3 unless defined?(TCP_CORK)
13 when /freebsd(([1-4]\..{1,2})|5\.[0-4])/
15 # Use the HTTP accept filter if available.
16 # The struct made by pack() is defined in /usr/include/sys/socket.h
17 # as accept_filter_arg
18 unless `/sbin/sysctl -nq net.inet.accf.http`.empty?
19 unless defined?(SO_ACCEPTFILTER_HTTPREADY)
20 SO_ACCEPTFILTER_HTTPREADY = ['httpready',nil].pack('a16a240').freeze
29 UNICORN_PEERADDR = '127.0.0.1'.freeze
43 include Socket::Constants
45 def set_client_sockopt(sock)
46 sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1) if defined?(TCP_NODELAY)
47 sock.setsockopt(SOL_TCP, TCP_CORK, 1) if defined?(TCP_CORK)
50 def set_server_sockopt(sock, opt)
52 if opt[:rcvbuf] || opt[:sndbuf]
53 log_buffer_sizes(sock, "before: ")
54 sock.setsockopt(SOL_SOCKET, SO_RCVBUF, opt[:rcvbuf]) if opt[:rcvbuf]
55 sock.setsockopt(SOL_SOCKET, SO_SNDBUF, opt[:sndbuf]) if opt[:sndbuf]
56 log_buffer_sizes(sock, " after: ")
58 sock.listen(opt[:backlog] || 1024)
59 return if sock_name(sock)[0..0] == "/"
61 if defined?(TCP_DEFER_ACCEPT)
62 sock.setsockopt(SOL_TCP, TCP_DEFER_ACCEPT, 1) rescue nil
64 if defined?(SO_ACCEPTFILTER_HTTPREADY)
65 sock.setsockopt(SOL_SOCKET, SO_ACCEPTFILTER,
66 SO_ACCEPTFILTER_HTTPREADY) rescue nil
70 def log_buffer_sizes(sock, pfx = '')
71 respond_to?(:logger) or return
72 rcvbuf = sock.getsockopt(SOL_SOCKET, SO_RCVBUF).unpack('i')
73 sndbuf = sock.getsockopt(SOL_SOCKET, SO_SNDBUF).unpack('i')
74 logger.info "#{pfx}#{sock_name(sock)} rcvbuf=#{rcvbuf} sndbuf=#{sndbuf}"
77 # creates a new server, socket. address may be a HOST:PORT or
78 # an absolute path to a UNIX socket. address can even be a Socket
79 # object in which case it is immediately returned
80 def bind_listen(address = '0.0.0.0:8080', opt = { :backlog => 1024 })
81 return address unless String === address
83 sock = if address[0..0] == "/"
84 if File.exist?(address)
85 if File.socket?(address)
86 if self.respond_to?(:logger)
87 logger.info "unlinking existing socket=#{address}"
92 "socket=#{address} specified but it is not a socket!"
95 old_umask = File.umask(0)
97 UNIXServer.new(address)
101 elsif address =~ /^(\d+\.\d+\.\d+\.\d+):(\d+)$/
102 TCPServer.new($1, $2.to_i)
104 raise ArgumentError, "Don't know how to bind: #{address}"
106 set_server_sockopt(sock, opt)
110 # Returns the configuration name of a socket as a string. sock may
111 # be a string value, in which case it is returned as-is
112 # Warning: TCP sockets may not always return the name given to it.
115 when String then sock
117 Socket.unpack_sockaddr_un(sock.getsockname)
119 Socket.unpack_sockaddr_in(sock.getsockname).reverse!.join(':')
122 Socket.unpack_sockaddr_in(sock.getsockname).reverse!.join(':')
124 Socket.unpack_sockaddr_un(sock.getsockname)
127 raise ArgumentError, "Unhandled class #{sock.class}: #{sock.inspect}"
131 # casts a given Socket to be a TCPServer or UNIXServer
132 def server_cast(sock)
134 Socket.unpack_sockaddr_in(sock.getsockname)
135 TCPServer.for_fd(sock.fileno)
137 UNIXServer.for_fd(sock.fileno)
141 end # module SocketHelper