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