From 77bba625d7aaa0f9e118879163687fcbcb0b5a7b Mon Sep 17 00:00:00 2001
From: Diego Nehab
+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)