diff --git a/changelogs/unreleased/gh-7256-iostream-shutdown.md b/changelogs/unreleased/gh-7256-iostream-shutdown.md new file mode 100644 index 0000000000000000000000000000000000000000..fc2eccbc9e9cd4c3b9809420ef045d1c86ca5e43 --- /dev/null +++ b/changelogs/unreleased/gh-7256-iostream-shutdown.md @@ -0,0 +1,6 @@ +## bugfix/core + +* Fixed a bug because of which a net.box connection was not properly terminated + when the process had a child (for example, started with `popen`) sharing the + connection socket fd. The bug could lead to a server hanging at exit while + executing the graceful shutdown protocol (gh-7256). diff --git a/src/lib/core/iostream.c b/src/lib/core/iostream.c index ae99185bbfea60968411947ad158850fde3e1892..f53a86906a0c95e51b35c1d45b9e0d1dfaab1835 100644 --- a/src/lib/core/iostream.c +++ b/src/lib/core/iostream.c @@ -9,6 +9,7 @@ #include <assert.h> #include <errno.h> #include <stddef.h> +#include <sys/socket.h> #include <sys/types.h> #include <unistd.h> @@ -33,6 +34,12 @@ iostream_close(struct iostream *io) { int fd = io->fd; iostream_destroy(io); + /* + * Explicitly shut down the socket before closing its fd so that + * the connection will be terminated even if the Tarantool process + * forked and the child process did not close parent fds. + */ + shutdown(fd, SHUT_RDWR); close(fd); } diff --git a/test/box-luatest/graceful_shutdown_test.lua b/test/box-luatest/graceful_shutdown_test.lua index db263e4c8e907687311c68b6de9c65835aa9400d..7cc123d083e066ac4208a51846e545892d27811f 100644 --- a/test/box-luatest/graceful_shutdown_test.lua +++ b/test/box-luatest/graceful_shutdown_test.lua @@ -1,5 +1,6 @@ local fiber = require('fiber') local net = require('net.box') +local popen = require('popen') local server = require('test.luatest_helpers.server') local t = require('luatest') local g = t.group() @@ -524,3 +525,17 @@ g.test_net_box_callback_garbage_collected = function() g.server:stop() conn:close() end + +-- Checks that the client closes the connection socket fd even if there is +-- a child processes that shares it (gh-6820). +g.test_graceful_shutdown_and_fork = function() + g.server:exec(function() + box.ctl.set_on_shutdown_timeout(9000) + end) + local c = net.connect(g.server.net_box_uri) + local p = popen.new({'/usr/bin/sleep', '9000'}, {close_fds = false}) + t.assert(p) + c:close() + g.server:stop() + p:close() +end