diff options
author | Eric Wong <bofh@yhbt.net> | 2023-09-05 06:43:20 +0000 |
---|---|---|
committer | Eric Wong <bofh@yhbt.net> | 2024-01-15 01:45:45 +0000 |
commit | b652fa51c1342496bdcdecca8e567f1fb46c41c9 (patch) | |
tree | b10a1dd61bdf0c4b253600ab38dbfbc311da93ed /lib/unicorn/socket_helper.rb | |
parent | 31d0539878b0e2247a4f98bc0241e05d4738e500 (diff) | |
download | unicorn-b652fa51c1342496bdcdecca8e567f1fb46c41c9.tar.gz |
kgio is an extra download and shared object which costs users bandwidth, disk space, startup time and memory. Ruby 2.3+ provides `Socket#accept_nonblock(exception: false)' support in addition to `exception: false' support in IO#*_nonblock methods from Ruby 2.1. We no longer distinguish between TCPServer and UNIXServer as separate classes internally; instead favoring the `Socket' class of Ruby for both. This allows us to use `Socket#accept_nonblock' and get a populated `Addrinfo' object off accept4(2)/accept(2) without resorting to a getpeername(2) syscall (kgio avoided getpeername(2) in the same way). The downside is there's more Ruby-level argument passing and stack usage on our end with HttpRequest#read_headers (formerly HttpRequest#read). I chose this tradeoff since advancements in Ruby itself can theoretically mitigate the cost of argument passing, while syscalls are a high fixed cost given modern CPU vulnerability mitigations. Note: no benchmarks have been run since I don't have a suitable system.
Diffstat (limited to 'lib/unicorn/socket_helper.rb')
-rw-r--r-- | lib/unicorn/socket_helper.rb | 50 |
1 files changed, 5 insertions, 45 deletions
diff --git a/lib/unicorn/socket_helper.rb b/lib/unicorn/socket_helper.rb index c2ba75e..06ec2b2 100644 --- a/lib/unicorn/socket_helper.rb +++ b/lib/unicorn/socket_helper.rb @@ -3,32 +3,6 @@ require 'socket' module Unicorn - - # Instead of using a generic Kgio::Socket for everything, - # tag TCP sockets so we can use TCP_INFO under Linux without - # incurring extra syscalls for Unix domain sockets. - # TODO: remove these when we remove kgio - TCPClient = Class.new(Kgio::Socket) # :nodoc: - class TCPSrv < Kgio::TCPServer # :nodoc: - def kgio_tryaccept # :nodoc: - super(TCPClient) - end - end - - if IO.instance_method(:write).arity == 1 # Ruby <= 2.4 - require 'unicorn/write_splat' - UNIXClient = Class.new(Kgio::Socket) # :nodoc: - class UNIXSrv < Kgio::UNIXServer # :nodoc: - include Unicorn::WriteSplat - def kgio_tryaccept # :nodoc: - super(UNIXClient) - end - end - TCPClient.__send__(:include, Unicorn::WriteSplat) - else # Ruby 2.5+ - UNIXSrv = Kgio::UNIXServer - end - module SocketHelper # internal interface @@ -105,7 +79,7 @@ module Unicorn def set_server_sockopt(sock, opt) opt = DEFAULTS.merge(opt || {}) - TCPSocket === sock and set_tcp_sockopt(sock, opt) + set_tcp_sockopt(sock, opt) if sock.local_address.ip? rcvbuf, sndbuf = opt.values_at(:rcvbuf, :sndbuf) if rcvbuf || sndbuf @@ -149,7 +123,9 @@ module Unicorn end old_umask = File.umask(opt[:umask] || 0) begin - UNIXSrv.new(address) + s = Socket.new(:UNIX, :STREAM) + s.bind(Socket.sockaddr_un(address)) + s ensure File.umask(old_umask) end @@ -177,8 +153,7 @@ module Unicorn sock.setsockopt(:SOL_SOCKET, :SO_REUSEPORT, 1) end sock.bind(Socket.pack_sockaddr_in(port, addr)) - sock.autoclose = false - TCPSrv.for_fd(sock.fileno) + sock end # returns rfc2732-style (e.g. "[::1]:666") addresses for IPv6 @@ -194,10 +169,6 @@ module Unicorn def sock_name(sock) case sock when String then sock - when UNIXServer - Socket.unpack_sockaddr_un(sock.getsockname) - when TCPServer - tcp_name(sock) when Socket begin tcp_name(sock) @@ -210,16 +181,5 @@ module Unicorn end module_function :sock_name - - # casts a given Socket to be a TCPServer or UNIXServer - def server_cast(sock) - begin - Socket.unpack_sockaddr_in(sock.getsockname) - TCPSrv.for_fd(sock.fileno) - rescue ArgumentError - UNIXSrv.for_fd(sock.fileno) - end - end - end # module SocketHelper end # module Unicorn |