[tarantool-patches] [PATCH] lua: return getaddrinfo() errors

Roman Khabibov roman.habibov at tarantool.org
Sat Jun 15 19:58:29 MSK 2019


Before this patch, branch when coio_getaddrinfo() returns
getaddrinfo() errors has never reached. Add this errors into the
socket and thenet.box modules.

Closes #4138
---

Branch: https://github.com/tarantool/tarantool/tree/romanhabibov/gh-4138-getaddrinfo
Issue: https://github.com/tarantool/tarantool/issues/4138

 src/box/lua/net_box.lua   |  7 +++++--
 src/lib/core/coio_task.c  |  2 +-
 src/lua/socket.c          |  6 ++++++
 src/lua/socket.lua        | 35 ++++++++++++++++++++++-------------
 test/app/socket.result    | 31 ++++++++++++++++++++++++++++---
 test/app/socket.test.lua  | 19 ++++++++++++++++++-
 test/box/net.box.result   | 21 ++++++++++++++++++++-
 test/box/net.box.test.lua | 15 +++++++++++++++
 8 files changed, 115 insertions(+), 21 deletions(-)

diff --git a/src/box/lua/net_box.lua b/src/box/lua/net_box.lua
index 251ad407a..4e3497ed9 100644
--- a/src/box/lua/net_box.lua
+++ b/src/box/lua/net_box.lua
@@ -142,9 +142,12 @@ local function next_id(id) return band(id + 1, 0x7FFFFFFF) end
 local function establish_connection(host, port, timeout)
     local timeout = timeout or DEFAULT_CONNECT_TIMEOUT
     local begin = fiber.clock()
-    local s = socket.tcp_connect(host, port, timeout)
+    local s, err = socket.tcp_connect(host, port, timeout)
     if not s then
-        return nil, errno.strerror(errno())
+        if not err then
+            return nil, errno.strerror(errno())
+        end
+        return nil, err
     end
     local msg = s:read({chunk = IPROTO_GREETING_SIZE},
                         timeout - (fiber.clock() - begin))
diff --git a/src/lib/core/coio_task.c b/src/lib/core/coio_task.c
index 908b336ed..83f669d05 100644
--- a/src/lib/core/coio_task.c
+++ b/src/lib/core/coio_task.c
@@ -413,7 +413,7 @@ coio_getaddrinfo(const char *host, const char *port,
 		return -1; /* timed out or cancelled */
 
 	/* Task finished */
-	if (task->rc < 0) {
+	if (task->rc != 0) {
 		/* getaddrinfo() failed */
 		errno = EIO;
 		diag_set(SystemError, "getaddrinfo: %s",
diff --git a/src/lua/socket.c b/src/lua/socket.c
index 130378caf..5a8469ddf 100644
--- a/src/lua/socket.c
+++ b/src/lua/socket.c
@@ -54,6 +54,7 @@
 #include <fiber.h>
 #include "lua/utils.h"
 #include "lua/fiber.h"
+#include "reflection.h"
 
 extern int coio_wait(int fd, int event, double timeout);
 
@@ -816,6 +817,11 @@ lbox_socket_getaddrinfo(struct lua_State *L)
 
 	if (dns_res != 0) {
 		lua_pushnil(L);
+		struct error *err = diag_get()->last;
+		if (strcmp(err->type->name, "SystemError") == 0) {
+			lua_pushstring(L, err->errmsg);
+			return 2;
+		}
 		return 1;
 	}
 
diff --git a/src/lua/socket.lua b/src/lua/socket.lua
index 2dba0a8d2..f0b432925 100644
--- a/src/lua/socket.lua
+++ b/src/lua/socket.lua
@@ -1028,11 +1028,14 @@ local function tcp_connect(host, port, timeout)
     end
     local timeout = timeout or TIMEOUT_INFINITY
     local stop = fiber.clock() + timeout
-    local dns = getaddrinfo(host, port, timeout, { type = 'SOCK_STREAM',
+    local dns, err = getaddrinfo(host, port, timeout, { type = 'SOCK_STREAM',
         protocol = 'tcp' })
     if dns == nil or #dns == 0 then
-        boxerrno(boxerrno.EINVAL)
-        return nil
+        if not err then
+            boxerrno(boxerrno.EINVAL)
+            return nil
+        end
+        return nil, err
     end
     for i, remote in pairs(dns) do
         timeout = stop - fiber.clock()
@@ -1147,15 +1150,15 @@ end
 
 local function tcp_server_bind(host, port, prepare, timeout)
     timeout = timeout and tonumber(timeout) or TIMEOUT_INFINITY
-    local dns
+    local dns, err
     if host == 'unix/' then
         dns = {{host = host, port = port, family = 'AF_UNIX', protocol = 0,
             type = 'SOCK_STREAM' }}
     else
-        dns = getaddrinfo(host, port, timeout, { type = 'SOCK_STREAM',
+        dns, err = getaddrinfo(host, port, timeout, { type = 'SOCK_STREAM',
             flags = 'AI_PASSIVE'})
         if dns == nil then
-            return nil
+            return nil, err
         end
     end
 
@@ -1347,10 +1350,10 @@ local function lsocket_tcp_connect(self, host, port)
     -- This function is broken by design
     local ga_opts = { family = 'AF_INET', type = 'SOCK_STREAM' }
     local timeout = deadline - fiber.clock()
-    local dns = getaddrinfo(host, port, timeout, ga_opts)
+    local dns, err = getaddrinfo(host, port, timeout, ga_opts)
     if dns == nil or #dns == 0 then
-        self._errno = boxerrno.EINVAL
-        return nil, socket_error(self)
+         self._errno = boxerrno.EINVAL
+        return nil, err
     end
     for _, remote in ipairs(dns) do
         timeout = deadline - fiber.clock()
@@ -1534,9 +1537,12 @@ local function lsocket_connect(host, port)
     if host == nil or port == nil then
         error("Usage: luasocket.connect(host, port)")
     end
-    local s = tcp_connect(host, port)
+    local s, err = tcp_connect(host, port)
     if not s then
-        return nil, boxerrno.strerror()
+        if not err then
+            return nil, boxerrno.strerror()
+        end
+        return nil, err
     end
     setmetatable(s, lsocket_tcp_client_mt)
     return s
@@ -1547,9 +1553,12 @@ local function lsocket_bind(host, port, backlog)
         error("Usage: luasocket.bind(host, port [, backlog])")
     end
     local function prepare(s) return backlog end
-    local s = tcp_server_bind(host, port, prepare)
+    local s, err = tcp_server_bind(host, port, prepare)
     if not s then
-        return nil, boxerrno.strerror()
+        if not err then
+            return nil, boxerrno.strerror()
+        end
+        return nil, err
     end
     return setmetatable(s, lsocket_tcp_server_mt)
 end
diff --git a/test/app/socket.result b/test/app/socket.result
index 0d029039a..6a78b92a4 100644
--- a/test/app/socket.result
+++ b/test/app/socket.result
@@ -942,7 +942,7 @@ sc:close()
 ...
 -- tcp_connect
 -- test timeout
-socket.tcp_connect('127.0.0.1', 80, 0.00000000001)
+socket.tcp_connect('127.0.0.1', 80, 0.00000000000001)
 ---
 - null
 ...
@@ -1664,7 +1664,7 @@ fio.stat(path) == nil
 { socket.tcp_connect('abrakadabra#123') == nil, errno.strerror() }
 ---
 - - true
-  - Invalid argument
+  - Input/output error
 ...
 -- wrong options for getaddrinfo
 socket.getaddrinfo('host', 'port', { type = 'WRONG' }) == nil and errno() == errno.EINVAL
@@ -2870,7 +2870,32 @@ server:close()
 ---
 - true
 ...
-test_run:cmd("clear filter")
+--gh-4138 Check getaddrinfo() error.
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+function check_err(err)
+    if err == 'getaddrinfo: nodename nor servname provided, or not known' or
+       err == 'getaddrinfo: Servname not supported for ai_socktype' or
+       err == 'getaddrinfo: Name or service not known' then
+            return true
+    end
+    return false
+end;
+---
+...
+s, err = socket:connect('hostname:3301');
+---
+...
+check_err(err);
+---
+- true
+...
+s, err = socket:bind('hostname:3301');
+---
+...
+check_err(err);
 ---
 - true
 ...
diff --git a/test/app/socket.test.lua b/test/app/socket.test.lua
index dab168f90..140baf22f 100644
--- a/test/app/socket.test.lua
+++ b/test/app/socket.test.lua
@@ -301,7 +301,7 @@ sc:close()
 -- tcp_connect
 
 -- test timeout
-socket.tcp_connect('127.0.0.1', 80, 0.00000000001)
+socket.tcp_connect('127.0.0.1', 80, 0.00000000000001)
 
 -- AF_INET
 s = socket('AF_INET', 'SOCK_STREAM', 'tcp')
@@ -982,4 +982,21 @@ fiber.cancel(echo_fiber)
 client:read(1, 5) == ''
 server:close()
 
+--gh-4138 Check getaddrinfo() error.
+
+test_run:cmd("setopt delimiter ';'")
+function check_err(err)
+    if err == 'getaddrinfo: nodename nor servname provided, or not known' or
+       err == 'getaddrinfo: Servname not supported for ai_socktype' or
+       err == 'getaddrinfo: Name or service not known' then
+            return true
+    end
+    return false
+end;
+
+s, err = socket:connect('hostname:3301');
+check_err(err);
+s, err = socket:bind('hostname:3301');
+check_err(err);
+
 test_run:cmd("clear filter")
diff --git a/test/box/net.box.result b/test/box/net.box.result
index 474297af3..8a9b26411 100644
--- a/test/box/net.box.result
+++ b/test/box/net.box.result
@@ -3796,6 +3796,25 @@ test_run:grep_log('default', '00000040:.*')
 ---
 - null
 ...
-box.cfg{log_level=log_level}
+--gh-4138 Check getaddrinfo() error.
+test_run:cmd("setopt delimiter ';'")
+---
+- true
+...
+function check_err(err)
+    if err == 'getaddrinfo: nodename nor servname provided, or not known' or
+       err == 'getaddrinfo: Servname not supported for ai_socktype' or
+       err == 'getaddrinfo: Name or service not known' then
+            return true
+    end
+    return false
+end;
 ---
 ...
+s = remote.connect('hostname:3301');
+---
+...
+check_err(s['error']);
+---
+- true
+...
diff --git a/test/box/net.box.test.lua b/test/box/net.box.test.lua
index bea43002d..13ed4e200 100644
--- a/test/box/net.box.test.lua
+++ b/test/box/net.box.test.lua
@@ -1538,4 +1538,19 @@ test_run:grep_log('default', '00000020:.*')
 test_run:grep_log('default', '00000030:.*')
 test_run:grep_log('default', '00000040:.*')
 
+--gh-4138 Check getaddrinfo() error.
+test_run:cmd("setopt delimiter ';'")
+
+function check_err(err)
+    if err == 'getaddrinfo: nodename nor servname provided, or not known' or
+       err == 'getaddrinfo: Servname not supported for ai_socktype' or
+       err == 'getaddrinfo: Name or service not known' then
+            return true
+    end
+    return false
+end;
+
+s = remote.connect('hostname:3301');
+check_err(s['error']);
+
 box.cfg{log_level=log_level}
-- 
2.20.1 (Apple Git-117)





More information about the Tarantool-patches mailing list