diff --git a/src/lua/bsdsocket.lua b/src/lua/bsdsocket.lua index 3c04efe5b0dad8e6ed5f0b93276194adbdb0dbaf..2d60b5fa14c31c47fae8a472b71b2e1c1bac68d9 100644 --- a/src/lua/bsdsocket.lua +++ b/src/lua/bsdsocket.lua @@ -6,6 +6,7 @@ local TIMEOUT_INFINITY = 500 * 365 * 86400 local ffi = require 'ffi' local os_remove = os.remove +local boxerrno = box.errno local internal = box.socket.internal box.socket.internal = nil package.loaded['box.socket.internal'] = nil @@ -1003,6 +1004,38 @@ local function tcp_server_usage() error('Usage: socket.tcp_server(host, port, handler | opts)') end +local function tcp_server_bind(s, addr) + if s:bind(addr.host, addr.port) then + return true + end + + if addr.family ~= 'AF_UNIX' then + return false + end + + if boxerrno() ~= boxerrno.EADDRINUSE then + return false + end + + local save_errno = boxerrno() + + local sc = tcp_connect(addr.host, addr.port) + if sc ~= nil then + sc:close() + boxerrno(save_errno) + return false + end + + if boxerrno() ~= boxerrno.ECONNREFUSED then + boxerrno(save_errno) + return false + end + + os_remove(addr.port) + return s:bind(addr.host, addr.port) +end + + local function tcp_server(host, port, opts, timeout) local server = {} if type(opts) == 'function' then @@ -1040,7 +1073,7 @@ local function tcp_server(host, port, opts, timeout) else s:setsockopt('SOL_SOCKET', 'SO_REUSEADDR', 1) -- ignore error end - if not s:bind(addr.host, addr.port) or not s:listen(backlog) then + if not tcp_server_bind(s, addr) or not s:listen(backlog) then local save_errno = box.errno() s:close() box.errno(save_errno) diff --git a/test/box/bsdsocket.result b/test/box/bsdsocket.result index 48db7bf91f5057caf08065454bc3d5b7bd25ba08..cf0e390627d7ba97602fea7de4ba474b62837352 100644 --- a/test/box/bsdsocket.result +++ b/test/box/bsdsocket.result @@ -222,7 +222,7 @@ lua s:getsockopt('SOL_SOCKET', 'SO_DEBUG') ... lua s:setsockopt('SOL_SOCKET', 'SO_ACCEPTCONN', 1) --- -error: '[string "-- bsdsocket.lua (internal file)..."]:347: Socket option SO_ACCEPTCONN is read only' +error: '[string "-- bsdsocket.lua (internal file)..."]:348: Socket option SO_ACCEPTCONN is read only' ... lua s:getsockopt('SOL_SOCKET', 'SO_RCVBUF') > 32 --- @@ -1149,3 +1149,37 @@ lua errno == box.errno.ECONNREFUSED --- - true ... +test bind unix socket if old socket is exists +lua s = box.socket('AF_UNIX', 'SOCK_STREAM', 0) +--- +... +lua s:bind('unix/', '/tmp/tarantool-test-socket') +--- + - true +... +lua s:listen() +--- + - true +... +lua s:close() +--- + - true +... +lua s = box.socket('AF_UNIX', 'SOCK_STREAM', 0) +--- +... +lua s:bind('unix/', '/tmp/tarantool-test-socket') +--- + - false +... +lua s = box.socket.tcp_server('unix/', '/tmp/tarantool-test-socket', function() end) +--- +... +lua s ~= nil +--- + - true +... +lua s:close() +--- + - true +... diff --git a/test/box/bsdsocket.test b/test/box/bsdsocket.test index 6fdd4dd077c953b220c8cf320ce9c57522ff9bde..0399c86939d262ee90f8f0f05f1cb20525bc7a5a 100644 --- a/test/box/bsdsocket.test +++ b/test/box/bsdsocket.test @@ -370,3 +370,18 @@ exec admin "lua collectgarbage('collect')" exec admin "lua client, errno = box.socket.tcp_connect('unix/', '{}'), box.errno()".format(path) exec admin "lua errno == box.errno.ECONNREFUSED" os.unlink(path) + +print 'test bind unix socket if old socket is exists' +exec admin "lua s = box.socket('AF_UNIX', 'SOCK_STREAM', 0)" +exec admin "lua s:bind('unix/', '{}')".format(path) +exec admin "lua s:listen()" +exec admin "lua s:close()" +if not os.path.exists(path): + print 'unix socket was removed: test failed' +exec admin "lua s = box.socket('AF_UNIX', 'SOCK_STREAM', 0)" +exec admin "lua s:bind('unix/', '{}')".format(path) +exec admin "lua s = box.socket.tcp_server('unix/', '{}', function() end)".format(path) +exec admin "lua s ~= nil" +exec admin "lua s:close()" +if os.path.exists(path): + print 'unix socket was not removed: test failed'