From 96965b179c7311f850f72a8629b9ba6d3a31d117 Mon Sep 17 00:00:00 2001 From: Diego Nehab Date: Sat, 22 Aug 2015 19:52:01 -0300 Subject: New agnostic IPv4 IPv6 functions. Also dealing with EPROTOTYPE Yosemite seems to be throwing at us for no reason. --- src/buffer.c | 24 +++++------ src/inet.c | 132 +++++++++++++++++++++++++++++---------------------------- src/inet.h | 10 ++--- src/io.h | 2 +- src/socket.lua | 10 ++--- src/tcp.c | 85 +++++++++++-------------------------- src/udp.c | 19 +++++++-- src/usocket.c | 9 +++- 8 files changed, 139 insertions(+), 152 deletions(-) (limited to 'src') diff --git a/src/buffer.c b/src/buffer.c index 8fc1166..fff1634 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -38,7 +38,7 @@ int buffer_open(lua_State *L) { } /*-------------------------------------------------------------------------*\ -* Initializes C structure +* Initializes C structure \*-------------------------------------------------------------------------*/ void buffer_init(p_buffer buf, p_io io, p_timeout tm) { buf->first = buf->last = 0; @@ -62,8 +62,8 @@ int buffer_meth_getstats(lua_State *L, p_buffer buf) { * object:setstats() interface \*-------------------------------------------------------------------------*/ int buffer_meth_setstats(lua_State *L, p_buffer buf) { - buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received); - buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent); + buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received); + buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent); if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4); lua_pushnumber(L, 1); return 1; @@ -88,7 +88,7 @@ int buffer_meth_send(lua_State *L, p_buffer buf) { /* check if there was an error */ if (err != IO_DONE) { lua_pushnil(L); - lua_pushstring(L, buf->io->error(buf->io->ctx, err)); + lua_pushstring(L, buf->io->error(buf->io->ctx, err)); lua_pushnumber(L, (lua_Number) (sent+start-1)); } else { lua_pushnumber(L, (lua_Number) (sent+start-1)); @@ -111,7 +111,7 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) { size_t size; const char *part = luaL_optlstring(L, 3, "", &size); timeout_markstart(buf->tm); - /* initialize buffer with optional extra prefix + /* initialize buffer with optional extra prefix * (useful for concatenating previous partial results) */ luaL_buffinit(L, &b); luaL_addlstring(&b, part, size); @@ -119,12 +119,12 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) { if (!lua_isnumber(L, 2)) { const char *p= luaL_optstring(L, 2, "*l"); if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b); - else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); + else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); else luaL_argcheck(L, 0, 2, "invalid receive pattern"); - /* get a fixed number of bytes (minus what was already partially + /* get a fixed number of bytes (minus what was already partially * received) */ } else { - double n = lua_tonumber(L, 2); + double n = lua_tonumber(L, 2); size_t wanted = (size_t) n; luaL_argcheck(L, n >= 0, 2, "invalid receive pattern"); if (size == 0 || wanted > size) @@ -135,8 +135,8 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) { /* we can't push anyting in the stack before pushing the * contents of the buffer. this is the reason for the complication */ luaL_pushresult(&b); - lua_pushstring(L, buf->io->error(buf->io->ctx, err)); - lua_pushvalue(L, -2); + lua_pushstring(L, buf->io->error(buf->io->ctx, err)); + lua_pushvalue(L, -2); lua_pushnil(L); lua_replace(L, -4); } else { @@ -219,7 +219,7 @@ static int recvall(p_buffer buf, luaL_Buffer *b) { } /*-------------------------------------------------------------------------*\ -* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF +* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF * are not returned by the function and are discarded from the buffer \*-------------------------------------------------------------------------*/ static int recvline(p_buffer buf, luaL_Buffer *b) { @@ -249,7 +249,7 @@ static int recvline(p_buffer buf, luaL_Buffer *b) { static void buffer_skip(p_buffer buf, size_t count) { buf->received += count; buf->first += count; - if (buffer_isempty(buf)) + if (buffer_isempty(buf)) buf->first = buf->last = 0; } diff --git a/src/inet.c b/src/inet.c index 68087db..8f0fac2 100644 --- a/src/inet.c +++ b/src/inet.c @@ -94,7 +94,7 @@ static int inet_global_getnameinfo(lua_State *L) { memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; - hints.ai_family = PF_UNSPEC; + hints.ai_family = AF_UNSPEC; ret = getaddrinfo(host, serv, &hints, &resolved); if (ret != 0) { @@ -105,8 +105,8 @@ static int inet_global_getnameinfo(lua_State *L) { lua_newtable(L); for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) { - getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, - hbuf, host? (socklen_t) sizeof(hbuf): 0, + getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, + hbuf, host? (socklen_t) sizeof(hbuf): 0, sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0); if (host) { lua_pushnumber(L, i); @@ -146,7 +146,7 @@ static int inet_global_toip(lua_State *L) int inet_optfamily(lua_State* L, int narg, const char* def) { static const char* optname[] = { "unspec", "inet", "inet6", NULL }; - static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 }; + static int optvalue[] = { AF_UNSPEC, AF_INET, AF_INET6, 0 }; return optvalue[luaL_checkoption(L, narg, def, optname)]; } @@ -167,7 +167,7 @@ static int inet_global_getaddrinfo(lua_State *L) int i = 1, ret = 0; memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; - hints.ai_family = PF_UNSPEC; + hints.ai_family = AF_UNSPEC; ret = getaddrinfo(hostname, NULL, &hints, &resolved); if (ret != 0) { lua_pushnil(L); @@ -177,7 +177,7 @@ static int inet_global_getaddrinfo(lua_State *L) lua_newtable(L); for (iterator = resolved; iterator; iterator = iterator->ai_next) { char hbuf[NI_MAXHOST]; - ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, + ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST); if (ret){ freeaddrinfo(resolved); @@ -198,6 +198,16 @@ static int inet_global_getaddrinfo(lua_State *L) lua_pushliteral(L, "inet6"); lua_settable(L, -3); break; + case AF_UNSPEC: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "unspec"); + lua_settable(L, -3); + break; + default: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "unknown"); + lua_settable(L, -3); + break; } lua_pushliteral(L, "addr"); lua_pushstring(L, hbuf); @@ -254,12 +264,11 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family) } lua_pushstring(L, name); lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10)); - if (family == PF_INET) { - lua_pushliteral(L, "inet"); - } else if (family == PF_INET6) { - lua_pushliteral(L, "inet6"); - } else { - lua_pushliteral(L, "uknown family"); + switch (family) { + case AF_INET: lua_pushliteral(L, "inet"); break; + case AF_INET6: lua_pushliteral(L, "inet6"); break; + case AF_UNSPEC: lua_pushliteral(L, "unspec"); break; + default: lua_pushliteral(L, "unknown"); break; } return 3; } @@ -279,7 +288,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family) lua_pushstring(L, socket_strerror(errno)); return 2; } - err=getnameinfo((struct sockaddr *)&peer, peer_len, + err=getnameinfo((struct sockaddr *)&peer, peer_len, name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV); if (err) { lua_pushnil(L); @@ -288,12 +297,11 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family) } lua_pushstring(L, name); lua_pushstring(L, port); - if (family == PF_INET) { - lua_pushliteral(L, "inet"); - } else if (family == PF_INET6) { - lua_pushliteral(L, "inet6"); - } else { - lua_pushliteral(L, "uknown family"); + switch (family) { + case AF_INET: lua_pushliteral(L, "inet"); break; + case AF_INET6: lua_pushliteral(L, "inet6"); break; + case AF_UNSPEC: lua_pushliteral(L, "unspec"); break; + default: lua_pushliteral(L, "unknown"); break; } return 3; } @@ -354,21 +362,21 @@ const char *inet_trycreate(p_socket ps, int family, int type) { const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm) { switch (family) { - case PF_INET: { + case AF_INET: { struct sockaddr_in sin; memset((char *) &sin, 0, sizeof(sin)); sin.sin_family = AF_UNSPEC; sin.sin_addr.s_addr = INADDR_ANY; - return socket_strerror(socket_connect(ps, (SA *) &sin, + return socket_strerror(socket_connect(ps, (SA *) &sin, sizeof(sin), tm)); } - case PF_INET6: { + case AF_INET6: { struct sockaddr_in6 sin6; - struct in6_addr addrany = IN6ADDR_ANY_INIT; + struct in6_addr addrany = IN6ADDR_ANY_INIT; memset((char *) &sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_UNSPEC; sin6.sin6_addr = addrany; - return socket_strerror(socket_connect(ps, (SA *) &sin6, + return socket_strerror(socket_connect(ps, (SA *) &sin6, sizeof(sin6), tm)); } } @@ -383,6 +391,7 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address, { struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; + int current_family = *family; /* try resolving */ err = socket_gaistrerror(getaddrinfo(address, serv, connecthints, &resolved)); @@ -397,23 +406,23 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address, * that shows up while iterating. if there was a * bind, all families will be the same and we will * not enter this branch. */ - if (*family != iterator->ai_family) { + if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { socket_destroy(ps); - err = socket_strerror(socket_create(ps, iterator->ai_family, + err = socket_strerror(socket_create(ps, iterator->ai_family, iterator->ai_socktype, iterator->ai_protocol)); - if (err != NULL) { - freeaddrinfo(resolved); - return err; - } - *family = iterator->ai_family; - /* all sockets initially non-blocking */ + if (err) continue; + current_family = iterator->ai_family; + /* set non-blocking before connect */ socket_setnonblocking(ps); } /* try connecting to remote address */ - err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, + err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen, tm)); /* if success, break out of loop */ - if (err == NULL) break; + if (err == NULL) { + *family = current_family; + break; + } } freeaddrinfo(resolved); /* here, if err is set, we failed */ @@ -423,29 +432,27 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address, /*-------------------------------------------------------------------------*\ * Tries to accept a socket \*-------------------------------------------------------------------------*/ -const char *inet_tryaccept(p_socket server, int family, p_socket client, - p_timeout tm) -{ +const char *inet_tryaccept(p_socket server, int family, p_socket client, + p_timeout tm) { socklen_t len; t_sockaddr_storage addr; - if (family == PF_INET6) { - len = sizeof(struct sockaddr_in6); - } else { - len = sizeof(struct sockaddr_in); - } - return socket_strerror(socket_accept(server, client, (SA *) &addr, + switch (family) { + case AF_INET6: len = sizeof(struct sockaddr_in6); break; + case AF_INET: len = sizeof(struct sockaddr_in); break; + default: len = sizeof(addr); break; + } + return socket_strerror(socket_accept(server, client, (SA *) &addr, &len, tm)); } /*-------------------------------------------------------------------------*\ * Tries to bind socket to (address, port) \*-------------------------------------------------------------------------*/ -const char *inet_trybind(p_socket ps, const char *address, const char *serv, - struct addrinfo *bindhints) -{ +const char *inet_trybind(p_socket ps, int *family, const char *address, + const char *serv, struct addrinfo *bindhints) { struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; - t_socket sock = *ps; + int current_family = *family; /* translate luasocket special values to C */ if (strcmp(address, "*") == 0) address = NULL; if (!serv) serv = "0"; @@ -457,35 +464,32 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv, } /* iterate over resolved addresses until one is good */ for (iterator = resolved; iterator; iterator = iterator->ai_next) { - if(sock == SOCKET_INVALID) { - err = socket_strerror(socket_create(&sock, iterator->ai_family, + if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { + socket_destroy(ps); + err = socket_strerror(socket_create(ps, iterator->ai_family, iterator->ai_socktype, iterator->ai_protocol)); - if(err) - continue; + if (err) continue; + current_family = iterator->ai_family; } /* try binding to local address */ - err = socket_strerror(socket_bind(&sock, - (SA *) iterator->ai_addr, + err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen)); - /* keep trying unless bind succeeded */ - if (err) { - if(sock != *ps) - socket_destroy(&sock); - } else { - /* remember what we connected to, particularly the family */ - *bindhints = *iterator; + if (err == NULL) { + *family = current_family; + /* set to non-blocking after bind */ + socket_setnonblocking(ps); break; } } /* cleanup and return error */ freeaddrinfo(resolved); - *ps = sock; + /* here, if err is set, we failed */ return err; } /*-------------------------------------------------------------------------*\ -* Some systems do not provide these so that we provide our own. +* Some systems do not provide these so that we provide our own. \*-------------------------------------------------------------------------*/ #ifdef LUASOCKET_INET_ATON int inet_aton(const char *cp, struct in_addr *inp) @@ -510,7 +514,7 @@ int inet_aton(const char *cp, struct in_addr *inp) #endif #ifdef LUASOCKET_INET_PTON -int inet_pton(int af, const char *src, void *dst) +int inet_pton(int af, const char *src, void *dst) { struct addrinfo hints, *res; int ret = 1; @@ -527,7 +531,7 @@ int inet_pton(int af, const char *src, void *dst) } else { ret = -1; } - freeaddrinfo(res); + freeaddrinfo(res); return ret; } diff --git a/src/inet.h b/src/inet.h index 1f1a96a..b85c20e 100644 --- a/src/inet.h +++ b/src/inet.h @@ -1,12 +1,12 @@ -#ifndef INET_H -#define INET_H +#ifndef INET_H +#define INET_H /*=========================================================================*\ * Internet domain functions * LuaSocket toolkit * * This module implements the creation and connection of internet domain * sockets, on top of the socket.h interface, and the interface of with the -* resolver. +* resolver. * * The function inet_aton is provided for the platforms where it is not * available. The module also implements the interface of the internet @@ -27,8 +27,8 @@ int inet_open(lua_State *L); const char *inet_trycreate(p_socket ps, int family, int type); const char *inet_tryconnect(p_socket ps, int *family, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints); -const char *inet_trybind(p_socket ps, const char *address, const char *serv, - struct addrinfo *bindhints); +const char *inet_trybind(p_socket ps, int *family, const char *address, + const char *serv, struct addrinfo *bindhints); const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm); const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm); diff --git a/src/io.h b/src/io.h index 76a3e58..8cca08a 100644 --- a/src/io.h +++ b/src/io.h @@ -22,7 +22,7 @@ enum { IO_DONE = 0, /* operation completed successfully */ IO_TIMEOUT = -1, /* operation timed out */ IO_CLOSED = -2, /* the connection has been closed */ - IO_UNKNOWN = -3 + IO_UNKNOWN = -3 }; /* interface to error message function */ diff --git a/src/socket.lua b/src/socket.lua index 3913e6f..d1c0b16 100644 --- a/src/socket.lua +++ b/src/socket.lua @@ -32,23 +32,23 @@ function _M.bind(host, port, backlog) err = "no info on address" for i, alt in base.ipairs(addrinfo) do if alt.family == "inet" then - sock, err = socket.tcp() + sock, err = socket.tcp4() else sock, err = socket.tcp6() end if not sock then return nil, err end sock:setoption("reuseaddr", true) res, err = sock:bind(alt.addr, port) - if not res then + if not res then sock:close() - else + else res, err = sock:listen(backlog) - if not res then + if not res then sock:close() else return sock end - end + end end return nil, err end diff --git a/src/tcp.c b/src/tcp.c index dcac0c8..4d12f08 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -18,6 +18,7 @@ * Internal function prototypes \*=========================================================================*/ static int global_create(lua_State *L); +static int global_create4(lua_State *L); static int global_create6(lua_State *L); static int global_connect(lua_State *L); static int meth_connect(lua_State *L); @@ -90,6 +91,7 @@ static t_opt optset[] = { /* functions in library namespace */ static luaL_Reg func[] = { {"tcp", global_create}, + {"tcp4", global_create4}, {"tcp6", global_create6}, {"connect", global_connect}, {NULL, NULL} @@ -213,8 +215,7 @@ static int meth_accept(lua_State *L) /*-------------------------------------------------------------------------*\ * Binds an object to an address \*-------------------------------------------------------------------------*/ -static int meth_bind(lua_State *L) -{ +static int meth_bind(lua_State *L) { p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); const char *address = luaL_checkstring(L, 2); const char *port = luaL_checkstring(L, 3); @@ -224,7 +225,7 @@ static int meth_bind(lua_State *L) bindhints.ai_socktype = SOCK_STREAM; bindhints.ai_family = tcp->family; bindhints.ai_flags = AI_PASSIVE; - err = inet_trybind(&tcp->sock, address, port, &bindhints); + err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints); if (err) { lua_pushnil(L); lua_pushstring(L, err); @@ -237,8 +238,7 @@ static int meth_bind(lua_State *L) /*-------------------------------------------------------------------------*\ * Turns a master tcp object into a client object. \*-------------------------------------------------------------------------*/ -static int meth_connect(lua_State *L) -{ +static int meth_connect(lua_State *L) { p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); const char *address = luaL_checkstring(L, 2); const char *port = luaL_checkstring(L, 3); @@ -249,7 +249,7 @@ static int meth_connect(lua_State *L) /* make sure we try to connect only to the same family */ connecthints.ai_family = tcp->family; timeout_markstart(&tcp->tm); - err = inet_tryconnect(&tcp->sock, &tcp->family, address, port, + err = inet_tryconnect(&tcp->sock, &tcp->family, address, port, &tcp->tm, &connecthints); /* have to set the class even if it failed due to non-blocking connects */ auxiliar_setclass(L, "tcp{client}", 1); @@ -279,9 +279,12 @@ static int meth_close(lua_State *L) static int meth_getfamily(lua_State *L) { p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - if (tcp->family == PF_INET6) { + if (tcp->family == AF_INET6) { lua_pushliteral(L, "inet6"); return 1; + } else if (tcp->family == AF_INET) { + lua_pushliteral(L, "inet4"); + return 1; } else { lua_pushliteral(L, "inet4"); return 1; @@ -353,7 +356,12 @@ static int meth_settimeout(lua_State *L) \*-------------------------------------------------------------------------*/ static int tcp_create(lua_State *L, int family) { t_socket sock; - const char *err = inet_trycreate(&sock, family, SOCK_STREAM); + /* if family is AF_UNSPEC, we create an AF_INET socket + * but store AF_UNSPEC into tcp-family. This will allow it + * later be replaced with an AF_INET6 socket if + * trybind or tryconnect prefer it instead. */ + const char *err = inet_trycreate(&sock, family == AF_UNSPEC? + AF_INET: family, SOCK_STREAM); /* try to allocate a system socket */ if (!err) { /* allocate tcp object */ @@ -363,7 +371,7 @@ static int tcp_create(lua_State *L, int family) { auxiliar_setclass(L, "tcp{master}", -1); /* initialize remaining structure fields */ socket_setnonblocking(&sock); - if (family == PF_INET6) { + if (family == AF_INET6) { int yes = 1; setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes)); @@ -383,6 +391,10 @@ static int tcp_create(lua_State *L, int family) { } static int global_create(lua_State *L) { + return tcp_create(L, AF_UNSPEC); +} + +static int global_create4(lua_State *L) { return tcp_create(L, AF_INET); } @@ -390,53 +402,6 @@ static int global_create6(lua_State *L) { return tcp_create(L, AF_INET6); } -#if 0 -static const char *tryconnect6(const char *remoteaddr, const char *remoteserv, - struct addrinfo *connecthints, p_tcp tcp) { - struct addrinfo *iterator = NULL, *resolved = NULL; - const char *err = NULL; - /* try resolving */ - err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv, - connecthints, &resolved)); - if (err != NULL) { - if (resolved) freeaddrinfo(resolved); - return err; - } - /* iterate over all returned addresses trying to connect */ - for (iterator = resolved; iterator; iterator = iterator->ai_next) { - p_timeout tm = timeout_markstart(&tcp->tm); - /* create new socket if necessary. if there was no - * bind, we need to create one for every new family - * that shows up while iterating. if there was a - * bind, all families will be the same and we will - * not enter this branch. */ - if (tcp->family != iterator->ai_family) { - socket_destroy(&tcp->sock); - err = socket_strerror(socket_create(&tcp->sock, - iterator->ai_family, iterator->ai_socktype, - iterator->ai_protocol)); - if (err != NULL) { - freeaddrinfo(resolved); - return err; - } - tcp->family = iterator->ai_family; - /* all sockets initially non-blocking */ - socket_setnonblocking(&tcp->sock); - } - /* finally try connecting to remote address */ - err = socket_strerror(socket_connect(&tcp->sock, - (SA *) iterator->ai_addr, - (socklen_t) iterator->ai_addrlen, tm)); - /* if success, break out of loop */ - if (err == NULL) break; - } - - freeaddrinfo(resolved); - /* here, if err is set, we failed */ - return err; -} -#endif - static int global_connect(lua_State *L) { const char *remoteaddr = luaL_checkstring(L, 1); const char *remoteserv = luaL_checkstring(L, 2); @@ -453,26 +418,26 @@ static int global_connect(lua_State *L) { timeout_init(&tcp->tm, -1, -1); buffer_init(&tcp->buf, &tcp->io, &tcp->tm); tcp->sock = SOCKET_INVALID; - tcp->family = PF_UNSPEC; + tcp->family = AF_UNSPEC; /* allow user to pick local address and port */ memset(&bindhints, 0, sizeof(bindhints)); bindhints.ai_socktype = SOCK_STREAM; bindhints.ai_family = family; bindhints.ai_flags = AI_PASSIVE; if (localaddr) { - err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints); + err = inet_trybind(&tcp->sock, &tcp->family, localaddr, + localserv, &bindhints); if (err) { lua_pushnil(L); lua_pushstring(L, err); return 2; } - tcp->family = bindhints.ai_family; } /* try to connect to remote address and port */ memset(&connecthints, 0, sizeof(connecthints)); connecthints.ai_socktype = SOCK_STREAM; /* make sure we try to connect only to the same family */ - connecthints.ai_family = bindhints.ai_family; + connecthints.ai_family = tcp->family; err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv, &tcp->tm, &connecthints); if (err) { diff --git a/src/udp.c b/src/udp.c index 7ff00f5..6600859 100644 --- a/src/udp.c +++ b/src/udp.c @@ -27,6 +27,7 @@ * Internal function prototypes \*=========================================================================*/ static int global_create(lua_State *L); +static int global_create4(lua_State *L); static int global_create6(lua_State *L); static int meth_send(lua_State *L); static int meth_sendto(lua_State *L); @@ -107,6 +108,7 @@ static t_opt optget[] = { /* functions in library namespace */ static luaL_Reg func[] = { {"udp", global_create}, + {"udp4", global_create4}, {"udp6", global_create6}, {NULL, NULL} }; @@ -264,7 +266,7 @@ static int meth_receivefrom(lua_State *L) static int meth_getfamily(lua_State *L) { p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); - if (udp->family == PF_INET6) { + if (udp->family == AF_INET6) { lua_pushliteral(L, "inet6"); return 1; } else { @@ -391,7 +393,7 @@ static int meth_setsockname(lua_State *L) { bindhints.ai_socktype = SOCK_DGRAM; bindhints.ai_family = udp->family; bindhints.ai_flags = AI_PASSIVE; - err = inet_trybind(&udp->sock, address, port, &bindhints); + err = inet_trybind(&udp->sock, &udp->family, address, port, &bindhints); if (err) { lua_pushnil(L); lua_pushstring(L, err); @@ -409,7 +411,12 @@ static int meth_setsockname(lua_State *L) { \*-------------------------------------------------------------------------*/ static int udp_create(lua_State *L, int family) { t_socket sock; - const char *err = inet_trycreate(&sock, family, SOCK_DGRAM); + /* if family is AF_UNSPEC, we create an AF_INET socket + * but store AF_UNSPEC into tcp-family. This will allow it + * later be replaced with an AF_INET6 socket if + * trybind or tryconnect prefer it instead. */ + const char *err = inet_trycreate(&sock, family == AF_UNSPEC? + AF_INET: family, SOCK_DGRAM); /* try to allocate a system socket */ if (!err) { /* allocate udp object */ @@ -417,7 +424,7 @@ static int udp_create(lua_State *L, int family) { auxiliar_setclass(L, "udp{unconnected}", -1); /* initialize remaining structure fields */ socket_setnonblocking(&sock); - if (family == PF_INET6) { + if (family == AF_INET6) { int yes = 1; setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes)); @@ -434,6 +441,10 @@ static int udp_create(lua_State *L, int family) { } static int global_create(lua_State *L) { + return udp_create(L, AF_UNSPEC); +} + +static int global_create4(lua_State *L) { return udp_create(L, AF_INET); } diff --git a/src/usocket.c b/src/usocket.c index 99e551b..8adc573 100644 --- a/src/usocket.c +++ b/src/usocket.c @@ -211,6 +211,8 @@ int socket_send(p_socket ps, const char *data, size_t count, err = errno; /* EPIPE means the connection was closed */ if (err == EPIPE) return IO_CLOSED; + /* EPROTOTYPE means the connection is being closed (on Yosemite!)*/ + if (err == EPROTOTYPE) continue; /* we call was interrupted, just try again */ if (err == EINTR) continue; /* if failed fatal reason, report error */ @@ -239,6 +241,7 @@ int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, } err = errno; if (err == EPIPE) return IO_CLOSED; + if (err == EPROTOTYPE) continue; if (err == EINTR) continue; if (err != EAGAIN) return err; if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; @@ -317,6 +320,8 @@ int socket_write(p_socket ps, const char *data, size_t count, err = errno; /* EPIPE means the connection was closed */ if (err == EPIPE) return IO_CLOSED; + /* EPROTOTYPE means the connection is being closed (on Yosemite!)*/ + if (err == EPROTOTYPE) continue; /* we call was interrupted, just try again */ if (err == EINTR) continue; /* if failed fatal reason, report error */ @@ -410,7 +415,9 @@ const char *socket_strerror(int err) { case ECONNABORTED: return PIE_CONNABORTED; case ECONNRESET: return PIE_CONNRESET; case ETIMEDOUT: return PIE_TIMEDOUT; - default: return strerror(err); + default: { + return strerror(err); + } } } -- cgit v1.2.3-55-g6feb From 77bba625d7aaa0f9e118879163687fcbcb0b5a7b Mon Sep 17 00:00:00 2001 From: Diego Nehab Date: Tue, 25 Aug 2015 15:41:40 -0300 Subject: Fixes suggested by @Florob in #147. --- doc/tcp.html | 6 ++++++ doc/udp.html | 6 ++++++ src/inet.c | 17 +++++++++++------ src/inet.h | 2 +- src/tcp.c | 52 +++++++++++++++++++++------------------------------- src/udp.c | 52 +++++++++++++++++++++------------------------------- test/testclnt.lua | 19 ++++++++++++------- 7 files changed, 78 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/doc/tcp.html b/doc/tcp.html index 6fc9900..fb627a1 100644 --- a/doc/tcp.html +++ b/doc/tcp.html @@ -65,6 +65,12 @@ href=#bind>connect, depending on the address family obtained from the resolver.

+

+Note: Before the choice between IPv4 and IPv6 happens, +the internal socket object is invalid and therefore setoption will fail. +

+

diff --git a/doc/udp.html b/doc/udp.html index e313af4..a300f2f 100644 --- a/doc/udp.html +++ b/doc/udp.html @@ -76,6 +76,12 @@ href=#setsockname>sockname, depending on the address family obtained from the resolver.

+

+Note: Before the choice between IPv4 and IPv6 happens, +the internal socket object is invalid and therefore setoption will fail. +

+

diff --git a/src/inet.c b/src/inet.c index 8f0fac2..331b800 100644 --- a/src/inet.c +++ b/src/inet.c @@ -352,8 +352,13 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp) /*-------------------------------------------------------------------------*\ * Tries to create a new inet socket \*-------------------------------------------------------------------------*/ -const char *inet_trycreate(p_socket ps, int family, int type) { - return socket_strerror(socket_create(ps, family, type, 0)); +const char *inet_trycreate(p_socket ps, int family, int type, int protocol) { + const char *err = socket_strerror(socket_create(ps, family, type, protocol)); + if (err == NULL && family == AF_INET6) { + int yes = 1; + setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes)); + } + return err; } /*-------------------------------------------------------------------------*\ @@ -408,8 +413,8 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address, * not enter this branch. */ if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { socket_destroy(ps); - err = socket_strerror(socket_create(ps, iterator->ai_family, - iterator->ai_socktype, iterator->ai_protocol)); + err = inet_trycreate(ps, iterator->ai_family, + iterator->ai_socktype, iterator->ai_protocol); if (err) continue; current_family = iterator->ai_family; /* set non-blocking before connect */ @@ -466,8 +471,8 @@ const char *inet_trybind(p_socket ps, int *family, const char *address, for (iterator = resolved; iterator; iterator = iterator->ai_next) { if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { socket_destroy(ps); - err = socket_strerror(socket_create(ps, iterator->ai_family, - iterator->ai_socktype, iterator->ai_protocol)); + err = inet_trycreate(ps, iterator->ai_family, + iterator->ai_socktype, iterator->ai_protocol); if (err) continue; current_family = iterator->ai_family; } diff --git a/src/inet.h b/src/inet.h index b85c20e..feb3541 100644 --- a/src/inet.h +++ b/src/inet.h @@ -24,7 +24,7 @@ int inet_open(lua_State *L); -const char *inet_trycreate(p_socket ps, int family, int type); +const char *inet_trycreate(p_socket ps, int family, int type, int protocol); const char *inet_tryconnect(p_socket ps, int *family, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints); const char *inet_trybind(p_socket ps, int *family, const char *address, diff --git a/src/tcp.c b/src/tcp.c index 4d12f08..7bf1af5 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -355,39 +355,29 @@ static int meth_settimeout(lua_State *L) * Creates a master tcp object \*-------------------------------------------------------------------------*/ static int tcp_create(lua_State *L, int family) { - t_socket sock; - /* if family is AF_UNSPEC, we create an AF_INET socket - * but store AF_UNSPEC into tcp-family. This will allow it - * later be replaced with an AF_INET6 socket if - * trybind or tryconnect prefer it instead. */ - const char *err = inet_trycreate(&sock, family == AF_UNSPEC? - AF_INET: family, SOCK_STREAM); - /* try to allocate a system socket */ - if (!err) { - /* allocate tcp object */ - p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); - memset(tcp, 0, sizeof(t_tcp)); - /* set its type as master object */ - auxiliar_setclass(L, "tcp{master}", -1); - /* initialize remaining structure fields */ - socket_setnonblocking(&sock); - if (family == AF_INET6) { - int yes = 1; - setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, - (void *)&yes, sizeof(yes)); + p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); + memset(tcp, 0, sizeof(t_tcp)); + /* set its type as master object */ + auxiliar_setclass(L, "tcp{master}", -1); + /* if family is AF_UNSPEC, we leave the socket invalid and + * store AF_UNSPEC into family. This will allow it to later be + * replaced with an AF_INET6 or AF_INET socket upon first use. */ + tcp->sock = SOCKET_INVALID; + tcp->family = family; + io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, + (p_error) socket_ioerror, &tcp->sock); + timeout_init(&tcp->tm, -1, -1); + buffer_init(&tcp->buf, &tcp->io, &tcp->tm); + if (family != AF_UNSPEC) { + const char *err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0); + if (err != NULL) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; } - tcp->sock = sock; - io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, - (p_error) socket_ioerror, &tcp->sock); - timeout_init(&tcp->tm, -1, -1); - buffer_init(&tcp->buf, &tcp->io, &tcp->tm); - tcp->family = family; - return 1; - } else { - lua_pushnil(L); - lua_pushstring(L, err); - return 2; + socket_setnonblocking(&tcp->sock); } + return 1; } static int global_create(lua_State *L) { diff --git a/src/udp.c b/src/udp.c index 6600859..17d932a 100644 --- a/src/udp.c +++ b/src/udp.c @@ -185,7 +185,7 @@ static int meth_sendto(lua_State *L) { return 2; } timeout_markstart(tm); - err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, + err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, (socklen_t) ai->ai_addrlen, tm); freeaddrinfo(ai); if (err != IO_DONE) { @@ -237,7 +237,7 @@ static int meth_receivefrom(lua_State *L) char portstr[6]; timeout_markstart(tm); count = MIN(count, sizeof(buffer)); - err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, + err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, &addr_len, tm); /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ if (err == IO_CLOSED) @@ -247,7 +247,7 @@ static int meth_receivefrom(lua_State *L) lua_pushstring(L, udp_strerror(err)); return 2; } - err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, + err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV); if (err) { lua_pushnil(L); @@ -351,7 +351,7 @@ static int meth_setpeername(lua_State *L) { /* make sure we try to connect only to the same family */ connecthints.ai_family = udp->family; if (connecting) { - err = inet_tryconnect(&udp->sock, &udp->family, address, + err = inet_tryconnect(&udp->sock, &udp->family, address, port, tm, &connecthints); if (err) { lua_pushnil(L); @@ -365,7 +365,6 @@ static int meth_setpeername(lua_State *L) { inet_trydisconnect(&udp->sock, udp->family, tm); auxiliar_setclass(L, "udp{unconnected}", 1); } - /* change class to connected or unconnected depending on address */ lua_pushnumber(L, 1); return 1; } @@ -410,34 +409,25 @@ static int meth_setsockname(lua_State *L) { * Creates a master udp object \*-------------------------------------------------------------------------*/ static int udp_create(lua_State *L, int family) { - t_socket sock; - /* if family is AF_UNSPEC, we create an AF_INET socket - * but store AF_UNSPEC into tcp-family. This will allow it - * later be replaced with an AF_INET6 socket if - * trybind or tryconnect prefer it instead. */ - const char *err = inet_trycreate(&sock, family == AF_UNSPEC? - AF_INET: family, SOCK_DGRAM); - /* try to allocate a system socket */ - if (!err) { - /* allocate udp object */ - p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); - auxiliar_setclass(L, "udp{unconnected}", -1); - /* initialize remaining structure fields */ - socket_setnonblocking(&sock); - if (family == AF_INET6) { - int yes = 1; - setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, - (void *)&yes, sizeof(yes)); + /* allocate udp object */ + p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); + auxiliar_setclass(L, "udp{unconnected}", -1); + /* if family is AF_UNSPEC, we leave the socket invalid and + * store AF_UNSPEC into family. This will allow it to later be + * replaced with an AF_INET6 or AF_INET socket upon first use. */ + udp->sock = SOCKET_INVALID; + timeout_init(&udp->tm, -1, -1); + udp->family = family; + if (family != AF_UNSPEC) { + const char *err = inet_trycreate(&udp->sock, family, SOCK_DGRAM, 0); + if (err != NULL) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; } - udp->sock = sock; - timeout_init(&udp->tm, -1, -1); - udp->family = family; - return 1; - } else { - lua_pushnil(L); - lua_pushstring(L, err); - return 2; + socket_setnonblocking(&udp->sock); } + return 1; } static int global_create(lua_State *L) { diff --git a/test/testclnt.lua b/test/testclnt.lua index abf9608..ee1201f 100644 --- a/test/testclnt.lua +++ b/test/testclnt.lua @@ -304,15 +304,20 @@ function isclosed(c) end function active_close() - reconnect() - if isclosed(data) then fail("should not be closed") end - data:close() - if not isclosed(data) then fail("should be closed") end - data = nil - local udp = socket.udp() + local tcp = socket.tcp4() + if isclosed(tcp) then fail("should not be closed") end + tcp:close() + if not isclosed(tcp) then fail("should be closed") end + tcp = socket.tcp() + if not isclosed(tcp) then fail("should be closed") end + tcp = nil + local udp = socket.udp4() if isclosed(udp) then fail("should not be closed") end udp:close() if not isclosed(udp) then fail("should be closed") end + udp = socket.udp() + if not isclosed(udp) then fail("should be closed") end + udp = nil pass("ok") end @@ -368,7 +373,7 @@ function test_selectbugs() pass("invalid input: ok") local toomany = {} for i = 1, socket._SETSIZE+1 do - toomany[#toomany+1] = socket.udp() + toomany[#toomany+1] = socket.udp4() end if #toomany > socket._SETSIZE then local e = pcall(socket.select, toomany, nil, 0.1) -- cgit v1.2.3-55-g6feb