From 594f826aa129f8b497c37fe08429eff5651dac9d Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Wed, 15 Jun 2011 00:51:02 +0200 Subject: [PATCH] Add support for connecting to IPv6 hosts --- src/inet.c | 42 +++++++++++++++++++++++----------------- src/inet.h | 4 ++-- src/socket.lua | 10 +++++++++- src/tcp.c | 52 ++++++++++++++++++++++++++++---------------------- src/udp.c | 37 ++++++++++++++++++++--------------- 5 files changed, 86 insertions(+), 59 deletions(-) diff --git a/src/inet.c b/src/inet.c index 962acec..ecec363 100644 --- a/src/inet.c +++ b/src/inet.c @@ -252,25 +252,31 @@ const char *inet_trycreate(p_socket ps, int domain, int type) { * Tries to connect to remote address (address, port) \*-------------------------------------------------------------------------*/ const char *inet_tryconnect(p_socket ps, const char *address, - unsigned short port, p_timeout tm) + const char *serv, p_timeout tm, struct addrinfo *connecthints) { - struct sockaddr_in remote; - int err; - memset(&remote, 0, sizeof(remote)); - remote.sin_family = AF_INET; - remote.sin_port = htons(port); - if (strcmp(address, "*")) { - if (!inet_aton(address, &remote.sin_addr)) { - struct hostent *hp = NULL; - struct in_addr **addr; - err = socket_gethostbyname(address, &hp); - if (err != IO_DONE) return socket_hoststrerror(err); - addr = (struct in_addr **) hp->h_addr_list; - memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); - } - } else remote.sin_family = AF_UNSPEC; - err = socket_connect(ps, (SA *) &remote, sizeof(remote), tm); - return socket_strerror(err); + struct addrinfo *iterator = NULL, *resolved = NULL; + const char *err = NULL; + /* try resolving */ + err = socket_gaistrerror(getaddrinfo(address, serv, + 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) { + timeout_markstart(tm); + /* try connecting to remote address */ + err = socket_strerror(socket_connect(ps, + (SA *) iterator->ai_addr, + 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; } /*-------------------------------------------------------------------------*\ diff --git a/src/inet.h b/src/inet.h index e008844..0f32ff1 100644 --- a/src/inet.h +++ b/src/inet.h @@ -25,8 +25,8 @@ int inet_open(lua_State *L); const char *inet_trycreate(p_socket ps, int domain, int type); -const char *inet_tryconnect(p_socket ps, const char *address, - unsigned short port, p_timeout tm); +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); diff --git a/src/socket.lua b/src/socket.lua index 7a77fbc..734da3c 100644 --- a/src/socket.lua +++ b/src/socket.lua @@ -17,7 +17,15 @@ module("socket") -- Exported auxiliar functions ----------------------------------------------------------------------------- function connect(address, port, laddress, lport) - local sock, err = socket.tcp() + if address == "*" then address = "0.0.0.0" end + local addrinfo, err = socket.dns.getaddrinfo(address); + if not addrinfo then return nil, err end + local sock, err; + if addrinfo[1].family == "inet" then + sock, err = socket.tcp() + else + sock, err = socket.tcp6() + end if not sock then return nil, err end if laddress then local res, err = sock:bind(laddress, lport, -1) diff --git a/src/tcp.c b/src/tcp.c index 4f5eea9..b069136 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -1,10 +1,10 @@ /*=========================================================================*\ -* TCP object +* TCP object * LuaSocket toolkit * * RCS ID: $Id: tcp.c,v 1.42 2009/05/27 09:31:35 diego Exp $ \*=========================================================================*/ -#include +#include #include "lua.h" #include "lauxlib.h" @@ -97,7 +97,7 @@ int tcp_open(lua_State *L) auxiliar_add2group(L, "tcp{client}", "tcp{any}"); auxiliar_add2group(L, "tcp{server}", "tcp{any}"); /* define library functions */ - luaL_openlib(L, NULL, func, 0); + luaL_openlib(L, NULL, func, 0); return 0; } @@ -150,7 +150,7 @@ static int meth_getfd(lua_State *L) static int meth_setfd(lua_State *L) { p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); - tcp->sock = (t_socket) luaL_checknumber(L, 2); + tcp->sock = (t_socket) luaL_checknumber(L, 2); return 0; } @@ -162,8 +162,8 @@ static int meth_dirty(lua_State *L) } /*-------------------------------------------------------------------------*\ -* Waits for and returns a client object attempting connection to the -* server object +* Waits for and returns a client object attempting connection to the +* server object \*-------------------------------------------------------------------------*/ static int meth_accept(lua_State *L) { @@ -178,20 +178,20 @@ static int meth_accept(lua_State *L) /* initialize structure fields */ socket_setnonblocking(&sock); clnt->sock = sock; - io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv, + io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv, (p_error) socket_ioerror, &clnt->sock); timeout_init(&clnt->tm, -1, -1); buffer_init(&clnt->buf, &clnt->io, &clnt->tm); return 1; } else { - lua_pushnil(L); + lua_pushnil(L); lua_pushstring(L, socket_strerror(err)); return 2; } } /*-------------------------------------------------------------------------*\ -* Binds an object to an address +* Binds an object to an address \*-------------------------------------------------------------------------*/ static int meth_bind(lua_State *L) { @@ -219,12 +219,18 @@ static int meth_bind(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); - unsigned short port = (unsigned short) luaL_checknumber(L, 3); - p_timeout tm = timeout_markstart(&tcp->tm); - const char *err = inet_tryconnect(&tcp->sock, address, port, tm); + const char *port = luaL_checkstring(L, 3); + struct addrinfo connecthints; + const char *err; + memset(&connecthints, 0, sizeof(connecthints)); + connecthints.ai_socktype = SOCK_STREAM; + /* make sure we try to connect only to the same family */ + connecthints.ai_family = tcp->domain; + timeout_markstart(&tcp->tm); + err = inet_tryconnect(&tcp->sock, 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); if (err) { @@ -237,7 +243,7 @@ static int meth_connect(lua_State *L) } /*-------------------------------------------------------------------------*\ -* Closes socket used by object +* Closes socket used by object \*-------------------------------------------------------------------------*/ static int meth_close(lua_State *L) { @@ -322,7 +328,7 @@ static int meth_settimeout(lua_State *L) * Library functions \*=========================================================================*/ /*-------------------------------------------------------------------------*\ -* Creates a master tcp object +* Creates a master tcp object \*-------------------------------------------------------------------------*/ static int tcp_create(lua_State *L, int domain) { t_socket sock; @@ -341,7 +347,7 @@ static int tcp_create(lua_State *L, int domain) { (void *)&yes, sizeof(yes)); } tcp->sock = sock; - io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, + 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); @@ -367,19 +373,19 @@ static const char *tryconnect6(const char *remoteaddr, const char *remoteserv, struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; /* try resolving */ - err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv, + err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv, connecthints, &resolved)); if (err != NULL) { if (resolved) freeaddrinfo(resolved); - return err; + 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 one wasn't created by the bind stage */ if (tcp->sock == SOCKET_INVALID) { - err = socket_strerror(socket_create(&tcp->sock, - iterator->ai_family, iterator->ai_socktype, + err = socket_strerror(socket_create(&tcp->sock, + iterator->ai_family, iterator->ai_socktype, iterator->ai_protocol)); if (err != NULL) { freeaddrinfo(resolved); @@ -389,7 +395,7 @@ static const char *tryconnect6(const char *remoteaddr, const char *remoteserv, socket_setnonblocking(&tcp->sock); } /* finally try connecting to remote address */ - err = socket_strerror(socket_connect(&tcp->sock, + err = socket_strerror(socket_connect(&tcp->sock, (SA *) iterator->ai_addr, iterator->ai_addrlen, tm)); /* if success, break out of loop */ @@ -410,7 +416,7 @@ static int global_connect6(lua_State *L) { struct addrinfo bindhints, connecthints; const char *err = NULL; /* initialize tcp structure */ - io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, + 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); @@ -432,7 +438,7 @@ static int global_connect6(lua_State *L) { 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 = bindhints.ai_family; err = tryconnect6(remoteaddr, remoteserv, &connecthints, tcp); if (err) { socket_destroy(&tcp->sock); diff --git a/src/udp.c b/src/udp.c index fcfbbb7..cc04fc8 100644 --- a/src/udp.c +++ b/src/udp.c @@ -1,10 +1,10 @@ /*=========================================================================*\ -* UDP object +* UDP object * LuaSocket toolkit * * RCS ID: $Id: udp.c,v 1.30 2009/05/27 09:31:35 diego Exp $ \*=========================================================================*/ -#include +#include #include "lua.h" #include "lauxlib.h" @@ -18,10 +18,10 @@ /* min and max macros */ #ifndef MIN #define MIN(x, y) ((x) < (y) ? x : y) -#endif +#endif #ifndef MAX #define MAX(x, y) ((x) > (y) ? x : y) -#endif +#endif /*=========================================================================*\ * Internal function prototypes @@ -109,7 +109,7 @@ int udp_open(lua_State *L) auxiliar_add2group(L, "udp{connected}", "select{able}"); auxiliar_add2group(L, "udp{unconnected}", "select{able}"); /* define library functions */ - luaL_openlib(L, NULL, func, 0); + luaL_openlib(L, NULL, func, 0); return 0; } @@ -156,12 +156,12 @@ static int meth_sendto(lua_State *L) { struct sockaddr_in addr; int err; memset(&addr, 0, sizeof(addr)); - if (!inet_aton(ip, &addr.sin_addr)) + if (!inet_aton(ip, &addr.sin_addr)) luaL_argerror(L, 3, "invalid ip address"); addr.sin_family = AF_INET; addr.sin_port = htons(port); timeout_markstart(tm); - err = socket_sendto(&udp->sock, data, count, &sent, + err = socket_sendto(&udp->sock, data, count, &sent, (SA *) &addr, sizeof(addr), tm); if (err != IO_DONE) { lua_pushnil(L); @@ -206,7 +206,7 @@ static int meth_receivefrom(lua_State *L) { p_timeout tm = &udp->tm; timeout_markstart(tm); count = MIN(count, sizeof(buffer)); - err = socket_recvfrom(&udp->sock, buffer, count, &got, + err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, &addr_len, tm); if (err == IO_DONE) { lua_pushlstring(L, buffer, got); @@ -288,10 +288,17 @@ static int meth_setpeername(lua_State *L) { p_timeout tm = &udp->tm; const char *address = luaL_checkstring(L, 2); int connecting = strcmp(address, "*"); - unsigned short port = connecting ? - (unsigned short) luaL_checknumber(L, 3) : - (unsigned short) luaL_optnumber(L, 3, 0); - const char *err = inet_tryconnect(&udp->sock, address, port, tm); + const char *port = connecting ? + luaL_checkstring(L, 3) : + luaL_optstring(L, 3, "0"); + struct addrinfo connecthints; + const char *err; + memset(&connecthints, 0, sizeof(connecthints)); + connecthints.ai_socktype = SOCK_DGRAM; + /* make sure we try to connect only to the same family */ + connecthints.ai_family = udp->domain; + err = inet_tryconnect(&udp->sock, address, port, + tm, &connecthints); if (err) { lua_pushnil(L); lua_pushstring(L, err); @@ -305,7 +312,7 @@ static int meth_setpeername(lua_State *L) { } /*-------------------------------------------------------------------------*\ -* Closes socket used by object +* Closes socket used by object \*-------------------------------------------------------------------------*/ static int meth_close(lua_State *L) { p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); @@ -341,13 +348,13 @@ static int meth_setsockname(lua_State *L) { * Library functions \*=========================================================================*/ /*-------------------------------------------------------------------------*\ -* Creates a master udp object +* Creates a master udp object \*-------------------------------------------------------------------------*/ static int udp_create(lua_State *L, int domain) { t_socket sock; const char *err = inet_trycreate(&sock, domain, SOCK_DGRAM); /* try to allocate a system socket */ - if (!err) { + if (!err) { /* allocate udp object */ p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); auxiliar_setclass(L, "udp{unconnected}", -1);