diff --git a/src/lua/socket.lua b/src/lua/socket.lua index a334ad45ba31e1d4d92f02aa1763194430fd71e0..bbdef01e36c3dbe5dc1cb410704d280bfd04d9a3 100644 --- a/src/lua/socket.lua +++ b/src/lua/socket.lua @@ -73,12 +73,17 @@ local gc_socket_t = ffi.metatype(ffi.typeof('struct gc_socket'), { local socket_mt +local function socket_is_closed(socket) + -- The type of 'socket' is not checked because the function + -- is internal and the type must be checked outside if needed. + return socket._gc_socket.fd < 0 +end + local function check_socket(socket) local gc_socket = type(socket) == 'table' and socket._gc_socket if ffi.istype(gc_socket_t, gc_socket) then - local fd = gc_socket.fd - if fd >= 0 then - return fd + if not socket_is_closed(socket) then + return gc_socket.fd else error("attempt to use closed socket") end @@ -1082,6 +1087,9 @@ local function tcp_server_loop(server, s, addr) fiber.name(format("%s/%s:%s", server.name, addr.host, addr.port), {truncate = true}) log.info("started") while socket_readable(s) do + if socket_is_closed(s) then + break + end local sc, from = socket_accept(s) if sc == nil then local errno = s._errno diff --git a/test/app/socket.result b/test/app/socket.result index 9f0ea0a5da8d7b4b2d40e11fdb3bb04147a5b39e..6206848f2da87b0d8c2b67bb28d356be5c47da1f 100644 --- a/test/app/socket.result +++ b/test/app/socket.result @@ -2914,3 +2914,17 @@ srv:close() --- - true ... +-- +-- gh-4087: fix error while closing socket.tcp_server +-- +srv = socket.tcp_server('127.0.0.1', 0, function() end) +--- +... +srv:close() +--- +- true +... +test_run:wait_log('default', 'stopped', 1024, 0.01) +--- +- stopped +... diff --git a/test/app/socket.test.lua b/test/app/socket.test.lua index d1fe7ada686db0b825eaec95ca9a9700cadad57d..a399fca3eda5c4d37725d0b5bd67caf2a5657693 100644 --- a/test/app/socket.test.lua +++ b/test/app/socket.test.lua @@ -987,4 +987,9 @@ s:settimeout(1) s:receive('*a') s:close() srv:close() - +-- +-- gh-4087: fix error while closing socket.tcp_server +-- +srv = socket.tcp_server('127.0.0.1', 0, function() end) +srv:close() +test_run:wait_log('default', 'stopped', 1024, 0.01)