diff --git a/TODO b/TODO index ae290f2..2c68d67 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,4 @@ - document bind and connect behavior. -- getsockname should also support IPv6, no? - shouldn't we instead make the code compatible to Lua 5.2 without any compat stuff, and use a compatibility layer to make it work on 5.1? @@ -16,6 +15,11 @@ Done: +- added IPv6 support to getsockname +- simplified getpeername implementation +- added family to return of getsockname and getpeername + and added modification to the manual to describe + - connect and bind try all adresses returned by getaddrinfo - document headers.lua? - update copyright date everywhere? diff --git a/doc/index.html b/doc/index.html index 833c9a8..56c958f 100644 --- a/doc/index.html +++ b/doc/index.html @@ -134,7 +134,8 @@ and Lua 5.2 compatibility.
-Returns a string with the IP address of the peer, followed by the -port number that peer is using for the connection. +Returns a string with the IP address of the peer, the +port number that peer is using for the connection, +and a string with the family ("inet" or "inet6"). In case of error, the method returns nil.
@@ -247,8 +248,10 @@ Returns the local address information associated to the object.-The method returns a string with local IP address and a number with -the port. In case of error, the method returns nil. +The method returns a string with local IP address, a number with +the local port, +and a string with the family ("inet" or "inet6"). +In case of error, the method returns nil.
diff --git a/doc/udp.html b/doc/udp.html index 4a334b7..554fa31 100644 --- a/doc/udp.html +++ b/doc/udp.html @@ -140,8 +140,12 @@ Retrieves information about the peer associated with a connected UDP object. --Returns the IP address and port number of the peer. + +
+Returns a string with the IP address of the peer, the +port number that peer is using for the connection, +and a string with the family ("inet" or "inet6"). +In case of error, the method returns nil.
@@ -159,10 +163,12 @@ unconnected:getsockname() Returns the local address information associated to the object.
--The method returns a string with local IP -address and a number with the port. In case of error, the method -returns nil. + +
+The method returns a string with local IP address, a number with +the local port, +and a string with the family ("inet" or "inet6"). +In case of error, the method returns nil.
diff --git a/src/inet.c b/src/inet.c index fd16506..5823c36 100644 --- a/src/inet.c +++ b/src/inet.c @@ -165,61 +165,92 @@ static int inet_global_gethostname(lua_State *L) /*-------------------------------------------------------------------------*\ * Retrieves socket peer name \*-------------------------------------------------------------------------*/ -int inet_meth_getpeername(lua_State *L, p_socket ps) +int inet_meth_getpeername(lua_State *L, p_socket ps, int family) { - union { - struct sockaddr_storage sas; - struct sockaddr sa; - struct sockaddr_in sa4; - struct sockaddr_in6 sa6; - } peer; - socklen_t peer_len = sizeof(peer); - - if (getpeername(*ps, &peer.sa, &peer_len) < 0) { - lua_pushnil(L); - lua_pushfstring(L, "getpeername failed (%d): %s", errno, - strerror(errno)); - } else { - char ipaddr[INET6_ADDRSTRLEN] = ""; - unsigned short port = 0; - - switch (peer.sa.sa_family) { - case AF_INET: - inet_ntop(AF_INET, &peer.sa4.sin_addr, ipaddr, sizeof(ipaddr)); - port = ntohs(peer.sa4.sin_port); - break; - case AF_INET6: - inet_ntop(AF_INET6, &peer.sa6.sin6_addr, ipaddr, sizeof(ipaddr)); - port = ntohs(peer.sa6.sin6_port); - break; + switch (family) { + case PF_INET: { + struct sockaddr_in peer; + socklen_t peer_len = sizeof(peer); + char name[INET_ADDRSTRLEN]; + if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { + lua_pushnil(L); + lua_pushstring(L, "getpeername failed"); + return 2; + } else { + inet_ntop(family, &peer.sin_addr, name, sizeof(name)); + lua_pushstring(L, name); + lua_pushnumber(L, ntohs(peer.sin_port)); + lua_pushliteral(L, "inet"); + return 3; + } + } + case PF_INET6: { + struct sockaddr_in6 peer; + socklen_t peer_len = sizeof(peer); + char name[INET6_ADDRSTRLEN]; + if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { + lua_pushnil(L); + lua_pushstring(L, "getpeername failed"); + return 2; + } else { + inet_ntop(family, &peer.sin6_addr, name, sizeof(name)); + lua_pushstring(L, name); + lua_pushnumber(L, ntohs(peer.sin6_port)); + lua_pushliteral(L, "inet6"); + return 3; + } + return 2; + } default: lua_pushnil(L); - lua_pushfstring(L, "Unknown address family %d", peer.sa.sa_family); + lua_pushstring(L, "unknown family"); return 2; - break; - } - - lua_pushstring(L, ipaddr); - lua_pushnumber(L, port); } - return 2; } /*-------------------------------------------------------------------------*\ * Retrieves socket local name \*-------------------------------------------------------------------------*/ -int inet_meth_getsockname(lua_State *L, p_socket ps) +int inet_meth_getsockname(lua_State *L, p_socket ps, int family) { - struct sockaddr_in local; - socklen_t local_len = sizeof(local); - if (getsockname(*ps, (SA *) &local, &local_len) < 0) { - lua_pushnil(L); - lua_pushstring(L, "getsockname failed"); - } else { - lua_pushstring(L, inet_ntoa(local.sin_addr)); - lua_pushnumber(L, ntohs(local.sin_port)); + switch (family) { + case PF_INET: { + struct sockaddr_in local; + socklen_t local_len = sizeof(local); + char name[INET_ADDRSTRLEN]; + if (getsockname(*ps, (SA *) &local, &local_len) < 0) { + lua_pushnil(L); + lua_pushstring(L, "getsockname failed"); + return 2; + } else { + inet_ntop(family, &local.sin_addr, name, sizeof(name)); + lua_pushstring(L, name); + lua_pushnumber(L, ntohs(local.sin_port)); + lua_pushliteral(L, "inet"); + return 3; + } + } + case PF_INET6: { + struct sockaddr_in6 local; + socklen_t local_len = sizeof(local); + char name[INET6_ADDRSTRLEN]; + if (getsockname(*ps, (SA *) &local, &local_len) < 0) { + lua_pushnil(L); + lua_pushstring(L, "getsockname failed"); + return 2; + } else { + inet_ntop(family, &local.sin6_addr, name, sizeof(name)); + lua_pushstring(L, name); + lua_pushnumber(L, ntohs(local.sin6_port)); + lua_pushliteral(L, "inet6"); + return 3; + } + } + default: + lua_pushnil(L); + lua_pushstring(L, "unknown family"); + return 2; } - return 2; } /*=========================================================================*\ diff --git a/src/inet.h b/src/inet.h index 0f32ff1..1cbe4f4 100644 --- a/src/inet.h +++ b/src/inet.h @@ -24,14 +24,14 @@ int inet_open(lua_State *L); -const char *inet_trycreate(p_socket ps, int domain, int type); +const char *inet_trycreate(p_socket ps, int family, int type); const char *inet_tryconnect(p_socket ps, 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); -int inet_meth_getpeername(lua_State *L, p_socket ps); -int inet_meth_getsockname(lua_State *L, p_socket ps); +int inet_meth_getpeername(lua_State *L, p_socket ps, int family); +int inet_meth_getsockname(lua_State *L, p_socket ps, int family); #ifdef INET_ATON int inet_aton(const char *cp, struct in_addr *inp); diff --git a/src/tcp.c b/src/tcp.c index 872b1c6..9e1e2bd 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -337,13 +337,13 @@ error: static int meth_getpeername(lua_State *L) { p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - return inet_meth_getpeername(L, &tcp->sock); + return inet_meth_getpeername(L, &tcp->sock, tcp->family); } static int meth_getsockname(lua_State *L) { p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - return inet_meth_getsockname(L, &tcp->sock); + return inet_meth_getsockname(L, &tcp->sock, tcp->family); } /*-------------------------------------------------------------------------*\ diff --git a/src/udp.c b/src/udp.c index bfa934f..0241cc5 100644 --- a/src/udp.c +++ b/src/udp.c @@ -269,12 +269,12 @@ static int meth_dirty(lua_State *L) { \*-------------------------------------------------------------------------*/ static int meth_getpeername(lua_State *L) { p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1); - return inet_meth_getpeername(L, &udp->sock); + return inet_meth_getpeername(L, &udp->sock, udp->family); } static int meth_getsockname(lua_State *L) { p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); - return inet_meth_getsockname(L, &udp->sock); + return inet_meth_getsockname(L, &udp->sock, udp->family); } /*-------------------------------------------------------------------------*\