From 91678ba99a6eb4ded9e1179b2abff2181eb8dd88 Mon Sep 17 00:00:00 2001 From: daurnimator Date: Mon, 31 Oct 2016 09:26:09 +1100 Subject: [PATCH] socket: persist connect and listen errors Linux has been seen to not repeat errors on UDP sockets: socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 5 open("/dev/urandom", O_RDONLY|O_NOCTTY|O_NONBLOCK) = 6 fstat(6, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 9), ...}) = 0 poll([{fd=6, events=POLLIN}], 1, 10) = 1 ([{fd=6, revents=POLLIN}]) read(6, "#\361x\3\34\34\302\251\243\"\361\304\0\346\372eh [5K\303\347\27\334\371pY\376\231\2431", 32) = 32 close(6) = 0 getuid() = 1000 bind(5, {sa_family=AF_INET, sin_port=htons(12738), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 connect(5, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.1")}, 16) = 0 sendto(5, "\320O\1\0\0\1\0\0\0\0\0\0\5wrong\7invalid\0\0\1\0\1", 31, 0, NULL, 0) = 31 recvfrom(5, 0x13353ec, 768, 0, NULL, NULL) = -1 ECONNREFUSED (Connection refused) recvfrom(5, 0x13353ec, 768, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) --- src/socket.c | 128 ++++++++++++++++++++++++++++----------------------- 1 file changed, 71 insertions(+), 57 deletions(-) diff --git a/src/socket.c b/src/socket.c index 9d278ed..748c5d1 100644 --- a/src/socket.c +++ b/src/socket.c @@ -954,7 +954,10 @@ static lso_nargs_t lso_connect2(lua_State *L) { if ((error = lso_prepsocket(S))) goto error; - (void)so_connect(S->socket); + if ((error = so_connect(S->socket))) { + S->ibuf.error = error; + S->obuf.error = error; + } return 1; error: @@ -965,25 +968,6 @@ static lso_nargs_t lso_connect2(lua_State *L) { } /* lso_connect2() */ -static lso_nargs_t lso_connect1(lua_State *L) { - struct luasocket *S = lso_checkself(L, 1); - int error; - - so_clear(S->socket); - - if (!(error = so_connect(S->socket))) { - lua_pushvalue(L, 1); - - return 1; - } else { - lua_pushnil(L); - lua_pushinteger(L, error); - - return 2; - } -} /* lso_connect1() */ - - static lso_nargs_t lso_listen2(lua_State *L) { const char *host NOTUSED = NULL, *port NOTUSED = NULL; const char *path = NULL; @@ -1042,7 +1026,10 @@ static lso_nargs_t lso_listen2(lua_State *L) { if ((error = lso_prepsocket(S))) goto error; - (void)so_listen(S->socket); + if ((error = so_listen(S->socket))) { + S->ibuf.error = error; + S->obuf.error = error; + } return 1; error: @@ -1053,25 +1040,6 @@ static lso_nargs_t lso_listen2(lua_State *L) { } /* lso_listen2() */ -static lso_nargs_t lso_listen1(lua_State *L) { - struct luasocket *S = lso_checkself(L, 1); - int error; - - so_clear(S->socket); - - if (!(error = so_listen(S->socket))) { - lua_pushvalue(L, 1); - - return 1; - } else { - lua_pushnil(L); - lua_pushinteger(L, error); - - return 2; - } -} /* lso_listen1() */ - - /* luasec compat */ #define LSEC_MODE_INVALID 0 #define LSEC_MODE_SERVER 1 @@ -1660,6 +1628,69 @@ static lso_nargs_t lso_clearerr(struct lua_State *L) { } /* lso_clearerr() */ +#define LSO_CHECKERRS(L, iobuf) do { \ + if (!(iobuf).error) \ + return 0; \ + if (++(iobuf).numerrs > (iobuf).maxerrs) \ + luaL_error((L), "exceeded unchecked error limit (%s)", cqs_strerror((iobuf).error)); \ + return (iobuf).error; \ +} while (0) + +static lso_error_t lso_checkrcverrs(lua_State *L, struct luasocket *S) { + LSO_CHECKERRS(L, S->ibuf); +} /* lso_checkrcverrs() */ + +static lso_error_t lso_checksnderrs(lua_State *L, struct luasocket *S) { + LSO_CHECKERRS(L, S->obuf); +} /* lso_checksnderrs() */ + + +static lso_nargs_t lso_connect1(lua_State *L) { + struct luasocket *S = lso_checkself(L, 1); + int error; + + if ((error = lso_checkrcverrs(L, S)) || (error = lso_checksnderrs(L, S))) + goto error; + + so_clear(S->socket); + + if ((error = so_connect(S->socket))) + goto error; + + lua_pushvalue(L, 1); + + return 1; + +error: + lua_pushnil(L); + lua_pushinteger(L, error); + + return 2; +} /* lso_connect1() */ + + +static lso_nargs_t lso_listen1(lua_State *L) { + struct luasocket *S = lso_checkself(L, 1); + int error; + + if ((error = lso_checkrcverrs(L, S)) || (error = lso_checksnderrs(L, S))) + goto error; + + so_clear(S->socket); + + if ((error = so_listen(S->socket))) + goto error; + + return 1; + +error: + lua_pushnil(L); + lua_pushinteger(L, error); + + return 2; +} /* lso_listen1() */ + + static lso_error_t lso_fill(struct luasocket *S, size_t limit) { struct iovec iov; size_t prepbuf, count; @@ -1939,23 +1970,6 @@ static struct lso_rcvop lso_checkrcvop(lua_State *L, int index, int mode) { } /* lso_checkrcvop() */ -#define LSO_CHECKERRS(L, iobuf) do { \ - if (!(iobuf).error) \ - return 0; \ - if (++(iobuf).numerrs > (iobuf).maxerrs) \ - luaL_error((L), "exceeded unchecked error limit (%s)", cqs_strerror((iobuf).error)); \ - return (iobuf).error; \ -} while (0) - -static lso_error_t lso_checkrcverrs(lua_State *L, struct luasocket *S) { - LSO_CHECKERRS(L, S->ibuf); -} /* lso_checkrcverrs() */ - -static lso_error_t lso_checksnderrs(lua_State *L, struct luasocket *S) { - LSO_CHECKERRS(L, S->obuf); -} /* lso_checksnderrs() */ - - static lso_error_t lso_preprcv(lua_State *L, struct luasocket *S) { int error;