diff options
author | Eric Wong <normalperson@yhbt.net> | 2009-04-10 13:52:46 -0700 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2009-04-10 13:55:34 -0700 |
commit | 0bd8cb742eadf45969133c13ebc5252b5234ef92 (patch) | |
tree | bd9a84635ff6edc7514fd62147355bed9c603653 | |
parent | d26976166a5d3ea5711f0ffd0811ee912723bdab (diff) | |
download | unicorn-0bd8cb742eadf45969133c13ebc5252b5234ef92.tar.gz |
Sockets may be unintentionally unlinked on the filesystem. When reloading our config, ensure that the socket exists on the filesystem. If not, close the listener (since it's unusable by outside apps) and reopen it.
-rw-r--r-- | lib/unicorn.rb | 17 | ||||
-rw-r--r-- | test/exec/test_exec.rb | 32 |
2 files changed, 45 insertions, 4 deletions
diff --git a/lib/unicorn.rb b/lib/unicorn.rb index 02419e7..2883bc2 100644 --- a/lib/unicorn.rb +++ b/lib/unicorn.rb @@ -105,16 +105,25 @@ module Unicorn # replaces current listener set with +listeners+. This will # close the socket if it will not exist in the new listener set def listeners=(listeners) - cur_names = listener_names + cur_names, dead_names = [], [] + listener_names.each do |name| + if "/" == name[0..0] + # mark unlinked sockets as dead so we can rebind them + (File.socket?(name) ? cur_names : dead_names) << name + else + cur_names << name + end + end set_names = listener_names(listeners) - dead_names = cur_names - set_names + dead_names += cur_names - set_names + dead_names.uniq! @listeners.delete_if do |io| if dead_names.include?(sock_name(io)) @io_purgatory.delete_if do |pio| - pio.fileno == io.fileno && (pio.close rescue nil).nil? + pio.fileno == io.fileno && (pio.close rescue nil).nil? # true end - (io.close rescue nil).nil? + (io.close rescue nil).nil? # true else false end diff --git a/test/exec/test_exec.rb b/test/exec/test_exec.rb index 336dc53..ec00fac 100644 --- a/test/exec/test_exec.rb +++ b/test/exec/test_exec.rb @@ -439,6 +439,38 @@ end reexec_basic_test(pid, pid_file) end + def test_socket_unlinked_restore + results = nil + sock = Tempfile.new('unicorn_test_sock') + sock_path = sock.path + sock.close! + ucfg = Tempfile.new('unicorn_test_config') + ucfg.syswrite("listen \"#{sock_path}\"\n") + + File.open("config.ru", "wb") { |fp| fp.syswrite(HI) } + pid = xfork { redirect_test_io { exec($unicorn_bin, "-c#{ucfg.path}") } } + wait_for_file(sock_path) + assert File.socket?(sock_path) + assert_nothing_raised do + sock = UNIXSocket.new(sock_path) + sock.syswrite("GET / HTTP/1.0\r\n\r\n") + results = sock.sysread(4096) + end + assert_equal String, results.class + assert_nothing_raised do + File.unlink(sock_path) + Process.kill(:HUP, pid) + end + wait_for_file(sock_path) + assert File.socket?(sock_path) + assert_nothing_raised do + sock = UNIXSocket.new(sock_path) + sock.syswrite("GET / HTTP/1.0\r\n\r\n") + results = sock.sysread(4096) + end + assert_equal String, results.class + end + def test_unicorn_config_file pid_file = "#{@tmpdir}/test.pid" sock = Tempfile.new('unicorn_test_sock') |