Add support for connecting to IPv6 hosts

This commit is contained in:
Florian Zeitz 2011-06-15 00:51:02 +02:00 committed by Sam Roberts
parent 5874d47f55
commit 594f826aa1
5 changed files with 86 additions and 59 deletions

View File

@ -252,25 +252,31 @@ const char *inet_trycreate(p_socket ps, int domain, int type) {
* Tries to connect to remote address (address, port) * Tries to connect to remote address (address, port)
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
const char *inet_tryconnect(p_socket ps, const char *address, 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; struct addrinfo *iterator = NULL, *resolved = NULL;
int err; const char *err = NULL;
memset(&remote, 0, sizeof(remote)); /* try resolving */
remote.sin_family = AF_INET; err = socket_gaistrerror(getaddrinfo(address, serv,
remote.sin_port = htons(port); connecthints, &resolved));
if (strcmp(address, "*")) { if (err != NULL) {
if (!inet_aton(address, &remote.sin_addr)) { if (resolved) freeaddrinfo(resolved);
struct hostent *hp = NULL; return err;
struct in_addr **addr; }
err = socket_gethostbyname(address, &hp); /* iterate over all returned addresses trying to connect */
if (err != IO_DONE) return socket_hoststrerror(err); for (iterator = resolved; iterator; iterator = iterator->ai_next) {
addr = (struct in_addr **) hp->h_addr_list; timeout_markstart(tm);
memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); /* try connecting to remote address */
} err = socket_strerror(socket_connect(ps,
} else remote.sin_family = AF_UNSPEC; (SA *) iterator->ai_addr,
err = socket_connect(ps, (SA *) &remote, sizeof(remote), tm); iterator->ai_addrlen, tm));
return socket_strerror(err); /* if success, break out of loop */
if (err == NULL) break;
}
freeaddrinfo(resolved);
/* here, if err is set, we failed */
return err;
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\

View File

@ -25,8 +25,8 @@
int inet_open(lua_State *L); 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 domain, int type);
const char *inet_tryconnect(p_socket ps, const char *address, 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);
const char *inet_trybind(p_socket ps, const char *address, const char *serv, const char *inet_trybind(p_socket ps, const char *address, const char *serv,
struct addrinfo *bindhints); struct addrinfo *bindhints);

View File

@ -17,7 +17,15 @@ module("socket")
-- Exported auxiliar functions -- Exported auxiliar functions
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
function connect(address, port, laddress, lport) 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 not sock then return nil, err end
if laddress then if laddress then
local res, err = sock:bind(laddress, lport, -1) local res, err = sock:bind(laddress, lport, -1)

View File

@ -1,10 +1,10 @@
/*=========================================================================*\ /*=========================================================================*\
* TCP object * TCP object
* LuaSocket toolkit * LuaSocket toolkit
* *
* RCS ID: $Id: tcp.c,v 1.42 2009/05/27 09:31:35 diego Exp $ * RCS ID: $Id: tcp.c,v 1.42 2009/05/27 09:31:35 diego Exp $
\*=========================================================================*/ \*=========================================================================*/
#include <string.h> #include <string.h>
#include "lua.h" #include "lua.h"
#include "lauxlib.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{client}", "tcp{any}");
auxiliar_add2group(L, "tcp{server}", "tcp{any}"); auxiliar_add2group(L, "tcp{server}", "tcp{any}");
/* define library functions */ /* define library functions */
luaL_openlib(L, NULL, func, 0); luaL_openlib(L, NULL, func, 0);
return 0; return 0;
} }
@ -150,7 +150,7 @@ static int meth_getfd(lua_State *L)
static int meth_setfd(lua_State *L) static int meth_setfd(lua_State *L)
{ {
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); 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; return 0;
} }
@ -162,8 +162,8 @@ static int meth_dirty(lua_State *L)
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Waits for and returns a client object attempting connection to the * Waits for and returns a client object attempting connection to the
* server object * server object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_accept(lua_State *L) static int meth_accept(lua_State *L)
{ {
@ -178,20 +178,20 @@ static int meth_accept(lua_State *L)
/* initialize structure fields */ /* initialize structure fields */
socket_setnonblocking(&sock); socket_setnonblocking(&sock);
clnt->sock = 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); (p_error) socket_ioerror, &clnt->sock);
timeout_init(&clnt->tm, -1, -1); timeout_init(&clnt->tm, -1, -1);
buffer_init(&clnt->buf, &clnt->io, &clnt->tm); buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
return 1; return 1;
} else { } else {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, socket_strerror(err)); lua_pushstring(L, socket_strerror(err));
return 2; return 2;
} }
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Binds an object to an address * Binds an object to an address
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int meth_bind(lua_State *L) 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) static int meth_connect(lua_State *L)
{ {
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
const char *address = luaL_checkstring(L, 2); const char *address = luaL_checkstring(L, 2);
unsigned short port = (unsigned short) luaL_checknumber(L, 3); const char *port = luaL_checkstring(L, 3);
p_timeout tm = timeout_markstart(&tcp->tm); struct addrinfo connecthints;
const char *err = inet_tryconnect(&tcp->sock, address, port, tm); 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 */ /* have to set the class even if it failed due to non-blocking connects */
auxiliar_setclass(L, "tcp{client}", 1); auxiliar_setclass(L, "tcp{client}", 1);
if (err) { 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) static int meth_close(lua_State *L)
{ {
@ -322,7 +328,7 @@ static int meth_settimeout(lua_State *L)
* Library functions * Library functions
\*=========================================================================*/ \*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Creates a master tcp object * Creates a master tcp object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int tcp_create(lua_State *L, int domain) { static int tcp_create(lua_State *L, int domain) {
t_socket sock; t_socket sock;
@ -341,7 +347,7 @@ static int tcp_create(lua_State *L, int domain) {
(void *)&yes, sizeof(yes)); (void *)&yes, sizeof(yes));
} }
tcp->sock = sock; 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); (p_error) socket_ioerror, &tcp->sock);
timeout_init(&tcp->tm, -1, -1); timeout_init(&tcp->tm, -1, -1);
buffer_init(&tcp->buf, &tcp->io, &tcp->tm); 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; struct addrinfo *iterator = NULL, *resolved = NULL;
const char *err = NULL; const char *err = NULL;
/* try resolving */ /* try resolving */
err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv, err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv,
connecthints, &resolved)); connecthints, &resolved));
if (err != NULL) { if (err != NULL) {
if (resolved) freeaddrinfo(resolved); if (resolved) freeaddrinfo(resolved);
return err; return err;
} }
/* iterate over all returned addresses trying to connect */ /* iterate over all returned addresses trying to connect */
for (iterator = resolved; iterator; iterator = iterator->ai_next) { for (iterator = resolved; iterator; iterator = iterator->ai_next) {
p_timeout tm = timeout_markstart(&tcp->tm); p_timeout tm = timeout_markstart(&tcp->tm);
/* create new socket if one wasn't created by the bind stage */ /* create new socket if one wasn't created by the bind stage */
if (tcp->sock == SOCKET_INVALID) { if (tcp->sock == SOCKET_INVALID) {
err = socket_strerror(socket_create(&tcp->sock, err = socket_strerror(socket_create(&tcp->sock,
iterator->ai_family, iterator->ai_socktype, iterator->ai_family, iterator->ai_socktype,
iterator->ai_protocol)); iterator->ai_protocol));
if (err != NULL) { if (err != NULL) {
freeaddrinfo(resolved); freeaddrinfo(resolved);
@ -389,7 +395,7 @@ static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
socket_setnonblocking(&tcp->sock); socket_setnonblocking(&tcp->sock);
} }
/* finally try connecting to remote address */ /* finally try connecting to remote address */
err = socket_strerror(socket_connect(&tcp->sock, err = socket_strerror(socket_connect(&tcp->sock,
(SA *) iterator->ai_addr, (SA *) iterator->ai_addr,
iterator->ai_addrlen, tm)); iterator->ai_addrlen, tm));
/* if success, break out of loop */ /* if success, break out of loop */
@ -410,7 +416,7 @@ static int global_connect6(lua_State *L) {
struct addrinfo bindhints, connecthints; struct addrinfo bindhints, connecthints;
const char *err = NULL; const char *err = NULL;
/* initialize tcp structure */ /* 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); (p_error) socket_ioerror, &tcp->sock);
timeout_init(&tcp->tm, -1, -1); timeout_init(&tcp->tm, -1, -1);
buffer_init(&tcp->buf, &tcp->io, &tcp->tm); buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
@ -432,7 +438,7 @@ static int global_connect6(lua_State *L) {
memset(&connecthints, 0, sizeof(connecthints)); memset(&connecthints, 0, sizeof(connecthints));
connecthints.ai_socktype = SOCK_STREAM; connecthints.ai_socktype = SOCK_STREAM;
/* make sure we try to connect only to the same family */ /* 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); err = tryconnect6(remoteaddr, remoteserv, &connecthints, tcp);
if (err) { if (err) {
socket_destroy(&tcp->sock); socket_destroy(&tcp->sock);

View File

@ -1,10 +1,10 @@
/*=========================================================================*\ /*=========================================================================*\
* UDP object * UDP object
* LuaSocket toolkit * LuaSocket toolkit
* *
* RCS ID: $Id: udp.c,v 1.30 2009/05/27 09:31:35 diego Exp $ * RCS ID: $Id: udp.c,v 1.30 2009/05/27 09:31:35 diego Exp $
\*=========================================================================*/ \*=========================================================================*/
#include <string.h> #include <string.h>
#include "lua.h" #include "lua.h"
#include "lauxlib.h" #include "lauxlib.h"
@ -18,10 +18,10 @@
/* min and max macros */ /* min and max macros */
#ifndef MIN #ifndef MIN
#define MIN(x, y) ((x) < (y) ? x : y) #define MIN(x, y) ((x) < (y) ? x : y)
#endif #endif
#ifndef MAX #ifndef MAX
#define MAX(x, y) ((x) > (y) ? x : y) #define MAX(x, y) ((x) > (y) ? x : y)
#endif #endif
/*=========================================================================*\ /*=========================================================================*\
* Internal function prototypes * Internal function prototypes
@ -109,7 +109,7 @@ int udp_open(lua_State *L)
auxiliar_add2group(L, "udp{connected}", "select{able}"); auxiliar_add2group(L, "udp{connected}", "select{able}");
auxiliar_add2group(L, "udp{unconnected}", "select{able}"); auxiliar_add2group(L, "udp{unconnected}", "select{able}");
/* define library functions */ /* define library functions */
luaL_openlib(L, NULL, func, 0); luaL_openlib(L, NULL, func, 0);
return 0; return 0;
} }
@ -156,12 +156,12 @@ static int meth_sendto(lua_State *L) {
struct sockaddr_in addr; struct sockaddr_in addr;
int err; int err;
memset(&addr, 0, sizeof(addr)); 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"); luaL_argerror(L, 3, "invalid ip address");
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_port = htons(port); addr.sin_port = htons(port);
timeout_markstart(tm); timeout_markstart(tm);
err = socket_sendto(&udp->sock, data, count, &sent, err = socket_sendto(&udp->sock, data, count, &sent,
(SA *) &addr, sizeof(addr), tm); (SA *) &addr, sizeof(addr), tm);
if (err != IO_DONE) { if (err != IO_DONE) {
lua_pushnil(L); lua_pushnil(L);
@ -206,7 +206,7 @@ static int meth_receivefrom(lua_State *L) {
p_timeout tm = &udp->tm; p_timeout tm = &udp->tm;
timeout_markstart(tm); timeout_markstart(tm);
count = MIN(count, sizeof(buffer)); 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); (SA *) &addr, &addr_len, tm);
if (err == IO_DONE) { if (err == IO_DONE) {
lua_pushlstring(L, buffer, got); lua_pushlstring(L, buffer, got);
@ -288,10 +288,17 @@ static int meth_setpeername(lua_State *L) {
p_timeout tm = &udp->tm; p_timeout tm = &udp->tm;
const char *address = luaL_checkstring(L, 2); const char *address = luaL_checkstring(L, 2);
int connecting = strcmp(address, "*"); int connecting = strcmp(address, "*");
unsigned short port = connecting ? const char *port = connecting ?
(unsigned short) luaL_checknumber(L, 3) : luaL_checkstring(L, 3) :
(unsigned short) luaL_optnumber(L, 3, 0); luaL_optstring(L, 3, "0");
const char *err = inet_tryconnect(&udp->sock, address, port, tm); 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) { if (err) {
lua_pushnil(L); lua_pushnil(L);
lua_pushstring(L, err); 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) { static int meth_close(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
@ -341,13 +348,13 @@ static int meth_setsockname(lua_State *L) {
* Library functions * Library functions
\*=========================================================================*/ \*=========================================================================*/
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* Creates a master udp object * Creates a master udp object
\*-------------------------------------------------------------------------*/ \*-------------------------------------------------------------------------*/
static int udp_create(lua_State *L, int domain) { static int udp_create(lua_State *L, int domain) {
t_socket sock; t_socket sock;
const char *err = inet_trycreate(&sock, domain, SOCK_DGRAM); const char *err = inet_trycreate(&sock, domain, SOCK_DGRAM);
/* try to allocate a system socket */ /* try to allocate a system socket */
if (!err) { if (!err) {
/* allocate udp object */ /* allocate udp object */
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
auxiliar_setclass(L, "udp{unconnected}", -1); auxiliar_setclass(L, "udp{unconnected}", -1);