module Unicorn::SocketHelper
Constants
- FILTER_ARG
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
- TCP_CORK
do not send out partial frames (Linux)
- TCP_DEFER_ACCEPT
from /usr/include/linux/tcp.h
Public Instance Methods
bind_listen(address = '0.0.0.0:8080', opt = {})
click to toggle source
creates a new server, socket. address may be a HOST:PORT or an absolute path to a UNIX socket. address can even be a Socket object in which case it is immediately returned
# File lib/unicorn/socket_helper.rb, line 87 def bind_listen(address = '0.0.0.0:8080', opt = {}) return address unless String === address sock = if address[0] == ?/ if File.exist?(address) if File.socket?(address) if self.respond_to?(:logger) logger.info "unlinking existing socket=#{address}" end File.unlink(address) else raise ArgumentError, "socket=#{address} specified but it is not a socket!" end end old_umask = File.umask(opt[:umask] || 0) begin UNIXServer.new(address) ensure File.umask(old_umask) end elsif address =~ /^(\d+\.\d+\.\d+\.\d+):(\d+)$/ TCPServer.new($1, $2.to_i) else raise ArgumentError, "Don't know how to bind: #{address}" end set_server_sockopt(sock, opt) sock end
log_buffer_sizes(sock, pfx = '')
click to toggle source
# File lib/unicorn/socket_helper.rb, line 77 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}" end
server_cast(sock)
click to toggle source
casts a given Socket to be a TCPServer or UNIXServer
# File lib/unicorn/socket_helper.rb, line 139 def server_cast(sock) begin Socket.unpack_sockaddr_in(sock.getsockname) TCPServer.for_fd(sock.fileno) rescue ArgumentError UNIXServer.for_fd(sock.fileno) end end
set_server_sockopt(sock, opt)
click to toggle source
# File lib/unicorn/socket_helper.rb, line 58 def set_server_sockopt(sock, opt) opt ||= {} TCPSocket === sock and set_tcp_sockopt(sock, opt) if opt[:rcvbuf] || opt[:sndbuf] log_buffer_sizes(sock, "before: ") sock.setsockopt(SOL_SOCKET, SO_RCVBUF, opt[:rcvbuf]) if opt[:rcvbuf] sock.setsockopt(SOL_SOCKET, SO_SNDBUF, opt[:sndbuf]) if opt[:sndbuf] log_buffer_sizes(sock, " after: ") 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 end
set_tcp_sockopt(sock, opt)
click to toggle source
# File lib/unicorn/socket_helper.rb, line 34 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? 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 end # No good reason to ever have deferred accepts off 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) end end
sock_name(sock)
click to toggle source
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.
# File lib/unicorn/socket_helper.rb, line 120 def sock_name(sock) case sock when String then sock when UNIXServer Socket.unpack_sockaddr_un(sock.getsockname) when TCPServer Socket.unpack_sockaddr_in(sock.getsockname).reverse!.join(':') when Socket begin Socket.unpack_sockaddr_in(sock.getsockname).reverse!.join(':') rescue ArgumentError Socket.unpack_sockaddr_un(sock.getsockname) end else raise ArgumentError, "Unhandled class #{sock.class}: #{sock.inspect}" end end