1 # -*- encoding: binary -*-
3 require 'test/test_helper'
6 class TestSocketHelper < Test::Unit::TestCase
7 include Unicorn::SocketHelper
9 GET_SLASH = "GET / HTTP/1.0\r\n\r\n".freeze
12 @log_tmp = Tempfile.new 'logger'
13 @logger = Logger.new(@log_tmp.path)
14 @test_addr = ENV['UNICORN_TEST_ADDR'] || '127.0.0.1'
15 @test6_addr = ENV['UNICORN_TEST6_ADDR'] || '::1'
23 def test_bind_listen_tcp
24 port = unused_port @test_addr
25 @tcp_listener_name = "#@test_addr:#{port}"
26 @tcp_listener = bind_listen(@tcp_listener_name)
27 assert TCPServer === @tcp_listener
28 assert_equal @tcp_listener_name, sock_name(@tcp_listener)
31 def test_bind_listen_options
32 port = unused_port @test_addr
33 tcp_listener_name = "#@test_addr:#{port}"
34 tmp = Tempfile.new 'unix.sock'
35 unix_listener_name = tmp.path
37 [ { :backlog => 5 }, { :sndbuf => 4096 }, { :rcvbuf => 4096 },
38 { :backlog => 16, :rcvbuf => 4096, :sndbuf => 4096 }
40 tcp_listener = bind_listen(tcp_listener_name, opts)
41 assert TCPServer === tcp_listener
43 unix_listener = bind_listen(unix_listener_name, opts)
44 assert UNIXServer === unix_listener
49 def test_bind_listen_unix
50 old_umask = File.umask(0777)
51 tmp = Tempfile.new 'unix.sock'
52 @unix_listener_path = tmp.path
53 File.unlink(@unix_listener_path)
54 @unix_listener = bind_listen(@unix_listener_path)
55 assert UNIXServer === @unix_listener
56 assert_equal @unix_listener_path, sock_name(@unix_listener)
57 assert File.readable?(@unix_listener_path), "not readable"
58 assert File.writable?(@unix_listener_path), "not writable"
59 assert_equal 0777, File.umask
64 def test_bind_listen_unix_umask
65 old_umask = File.umask(0777)
66 tmp = Tempfile.new 'unix.sock'
67 @unix_listener_path = tmp.path
68 File.unlink(@unix_listener_path)
69 @unix_listener = bind_listen(@unix_listener_path, :umask => 077)
70 assert UNIXServer === @unix_listener
71 assert_equal @unix_listener_path, sock_name(@unix_listener)
72 assert_equal 0140700, File.stat(@unix_listener_path).mode
73 assert_equal 0777, File.umask
78 def test_bind_listen_unix_idempotent
80 a = bind_listen(@unix_listener)
81 assert_equal a.fileno, @unix_listener.fileno
82 unix_server = server_cast(@unix_listener)
83 assert UNIXServer === unix_server
84 a = bind_listen(unix_server)
85 assert_equal a.fileno, unix_server.fileno
86 assert_equal a.fileno, @unix_listener.fileno
89 def test_bind_listen_tcp_idempotent
91 a = bind_listen(@tcp_listener)
92 assert_equal a.fileno, @tcp_listener.fileno
93 tcp_server = server_cast(@tcp_listener)
94 assert TCPServer === tcp_server
95 a = bind_listen(tcp_server)
96 assert_equal a.fileno, tcp_server.fileno
97 assert_equal a.fileno, @tcp_listener.fileno
100 def test_bind_listen_unix_rebind
101 test_bind_listen_unix
103 assert_raises(Errno::EADDRINUSE) do
104 new_listener = bind_listen(@unix_listener_path)
107 File.unlink(@unix_listener_path)
108 new_listener = bind_listen(@unix_listener_path)
110 assert UNIXServer === new_listener
111 assert new_listener.fileno != @unix_listener.fileno
112 assert_equal sock_name(new_listener), sock_name(@unix_listener)
113 assert_equal @unix_listener_path, sock_name(new_listener)
115 client = server_cast(new_listener).accept
116 client.syswrite('abcde')
119 s = UNIXSocket.new(@unix_listener_path)
121 assert_equal 'abcde', s.sysread(5)
122 pid, status = Process.waitpid2(pid)
123 assert status.success?
127 test_bind_listen_unix
129 unix_listener_socket = Socket.for_fd(@unix_listener.fileno)
130 assert Socket === unix_listener_socket
131 @unix_server = server_cast(unix_listener_socket)
132 assert_equal @unix_listener.fileno, @unix_server.fileno
133 assert UNIXServer === @unix_server
134 assert_equal(@unix_server.path, @unix_listener.path,
135 "##{@unix_server.path} != #{@unix_listener.path}")
136 assert File.socket?(@unix_server.path)
137 assert_equal @unix_listener_path, sock_name(@unix_server)
139 tcp_listener_socket = Socket.for_fd(@tcp_listener.fileno)
140 assert Socket === tcp_listener_socket
141 @tcp_server = server_cast(tcp_listener_socket)
142 assert_equal @tcp_listener.fileno, @tcp_server.fileno
143 assert TCPServer === @tcp_server
144 assert_equal @tcp_listener_name, sock_name(@tcp_server)
149 sock_name(@unix_server)
152 def test_tcp_defer_accept_default
153 port = unused_port @test_addr
154 name = "#@test_addr:#{port}"
155 sock = bind_listen(name)
156 cur = sock.getsockopt(Socket::SOL_TCP, TCP_DEFER_ACCEPT).unpack('i')[0]
158 end if defined?(TCP_DEFER_ACCEPT)
160 def test_tcp_defer_accept_disable
161 port = unused_port @test_addr
162 name = "#@test_addr:#{port}"
163 sock = bind_listen(name, :tcp_defer_accept => false)
164 cur = sock.getsockopt(Socket::SOL_TCP, TCP_DEFER_ACCEPT).unpack('i')[0]
166 end if defined?(TCP_DEFER_ACCEPT)
168 def test_tcp_defer_accept_nr
169 port = unused_port @test_addr
170 name = "#@test_addr:#{port}"
171 sock = bind_listen(name, :tcp_defer_accept => 60)
172 cur = sock.getsockopt(Socket::SOL_TCP, TCP_DEFER_ACCEPT).unpack('i')[0]
174 end if defined?(TCP_DEFER_ACCEPT)
178 unused_port "#@test6_addr"
182 sock = bind_listen "[#@test6_addr]:#{port}", :ipv6only => true
183 cur = sock.getsockopt(:IPPROTO_IPV6, :IPV6_V6ONLY).unpack('i')[0]
185 rescue Errno::EAFNOSUPPORT
186 end if RUBY_VERSION >= "1.9.2"
189 port = unused_port @test_addr
190 name = "#@test_addr:#{port}"
191 sock = bind_listen(name, :reuseport => true)
192 cur = sock.getsockopt(Socket::SOL_SOCKET, SO_REUSEPORT).unpack('i')[0]
193 assert_operator cur, :>, 0
194 rescue Errno::ENOPROTOOPT
195 # kernel does not support SO_REUSEPORT (older Linux)