From 923eef192925cae29223974dbf1addd59b4b0f28 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Tue, 14 Jun 2011 01:17:07 +0200 Subject: [PATCH] Rework binding IPv6 sockets by harmonizing it with the IPv4 variant --- src/inet.c | 58 ++++++++++++++++------------ src/inet.h | 6 +-- src/tcp.c | 111 +++++++++-------------------------------------------- src/tcp.h | 1 + src/udp.c | 27 ++++++++++--- src/udp.h | 1 + 6 files changed, 80 insertions(+), 124 deletions(-) diff --git a/src/inet.c b/src/inet.c index 21a97c9..95b7af3 100644 --- a/src/inet.c +++ b/src/inet.c @@ -56,7 +56,7 @@ static int inet_gethost(const char *address, struct hostent **hp) { struct in_addr addr; if (inet_aton(address, &addr)) return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp); - else + else return socket_gethostbyname(address, hp); } @@ -66,7 +66,7 @@ static int inet_gethost(const char *address, struct hostent **hp) { \*-------------------------------------------------------------------------*/ static int inet_global_tohostname(lua_State *L) { const char *address = luaL_checkstring(L, 1); - struct hostent *hp = NULL; + struct hostent *hp = NULL; int err = inet_gethost(address, &hp); if (err != IO_DONE) { lua_pushnil(L); @@ -85,7 +85,7 @@ static int inet_global_tohostname(lua_State *L) { static int inet_global_toip(lua_State *L) { const char *address = luaL_checkstring(L, 1); - struct hostent *hp = NULL; + struct hostent *hp = NULL; int err = inet_gethost(address, &hp); if (err != IO_DONE) { lua_pushnil(L); @@ -136,7 +136,7 @@ static int inet_global_toip6(lua_State *L) lua_settable(L, -3); lua_settable(L, -3); i++; - } + } freeaddrinfo(resolved); return 1; } @@ -244,14 +244,14 @@ 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 type) { - return socket_strerror(socket_create(ps, AF_INET, type, 0)); +const char *inet_trycreate(p_socket ps, int domain, int type) { + return socket_strerror(socket_create(ps, domain, type, 0)); } /*-------------------------------------------------------------------------*\ * 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) { struct sockaddr_in remote; @@ -276,25 +276,35 @@ const char *inet_tryconnect(p_socket ps, const char *address, /*-------------------------------------------------------------------------*\ * Tries to bind socket to (address, port) \*-------------------------------------------------------------------------*/ -const char *inet_trybind(p_socket ps, const char *address, unsigned short port) +const char *inet_trybind(p_socket ps, const char *address, const char *serv, + struct addrinfo *bindhints) { - struct sockaddr_in local; - int err; - memset(&local, 0, sizeof(local)); - /* address is either wildcard or a valid ip address */ - local.sin_addr.s_addr = htonl(INADDR_ANY); - local.sin_port = htons(port); - local.sin_family = AF_INET; - if (strcmp(address, "*") && !inet_aton(address, &local.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(&local.sin_addr, *addr, sizeof(struct in_addr)); + struct addrinfo *iterator = NULL, *resolved = NULL; + const char *err = NULL; + /* translate luasocket special values to C */ + if (strcmp(address, "*") == 0) address = NULL; + if (!serv) serv = "0"; + /* try resolving */ + err = socket_gaistrerror(getaddrinfo(address, serv, + bindhints, &resolved)); + if (err) { + if (resolved) freeaddrinfo(resolved); + return err; } - err = socket_bind(ps, (SA *) &local, sizeof(local)); - return socket_strerror(err); + /* iterate over resolved addresses until one is good */ + for (iterator = resolved; iterator; iterator = iterator->ai_next) { + /* try binding to local address */ + err = socket_strerror(socket_bind(ps, + (SA *) iterator->ai_addr, + iterator->ai_addrlen)); + /* if faiiled, we try the next one */ + if (err != NULL) socket_destroy(ps); + /* if success, we abort loop */ + else break; + } + /* cleanup and return error */ + freeaddrinfo(resolved); + return err; } /*-------------------------------------------------------------------------*\ diff --git a/src/inet.h b/src/inet.h index dbc160c..e008844 100644 --- a/src/inet.h +++ b/src/inet.h @@ -24,11 +24,11 @@ int inet_open(lua_State *L); -const char *inet_trycreate(p_socket ps, int type); +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_trybind(p_socket ps, const char *address, - unsigned short port); +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); diff --git a/src/tcp.c b/src/tcp.c index 658f255..155f3bf 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -19,8 +19,8 @@ * Internal function prototypes \*=========================================================================*/ static int global_create(lua_State *L); +static int global_create6(lua_State *L); static int global_connect6(lua_State *L); -static int global_bind6(lua_State *L); static int meth_connect(lua_State *L); static int meth_listen(lua_State *L); static int meth_bind(lua_State *L); @@ -77,8 +77,8 @@ static t_opt optset[] = { /* functions in library namespace */ static luaL_reg func[] = { {"tcp", global_create}, + {"tcp6", global_create6}, {"connect6", global_connect6}, - {"bind6", global_bind6}, {NULL, NULL} }; @@ -196,8 +196,14 @@ 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); - unsigned short port = (unsigned short) luaL_checknumber(L, 3); - const char *err = inet_trybind(&tcp->sock, address, port); + const char *port = luaL_checkstring(L, 3); + const char *err; + struct addrinfo bindhints; + memset(&bindhints, 0, sizeof(bindhints)); + bindhints.ai_socktype = SOCK_STREAM; + bindhints.ai_family = tcp->domain; + bindhints.ai_flags = AI_PASSIVE; + err = inet_trybind(&tcp->sock, address, port, &bindhints); if (err) { lua_pushnil(L); lua_pushstring(L, err); @@ -317,11 +323,11 @@ static int meth_settimeout(lua_State *L) /*-------------------------------------------------------------------------*\ * Creates a master tcp object \*-------------------------------------------------------------------------*/ -static int global_create(lua_State *L) { +static int tcp_create(lua_State *L, int domain) { t_socket sock; - const char *err = inet_trycreate(&sock, SOCK_STREAM); + const char *err = inet_trycreate(&sock, domain, SOCK_STREAM); /* try to allocate a system socket */ - if (!err) { + if (!err) { /* allocate tcp object */ p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); /* set its type as master object */ @@ -333,6 +339,7 @@ static int global_create(lua_State *L) { (p_error) socket_ioerror, &tcp->sock); timeout_init(&tcp->tm, -1, -1); buffer_init(&tcp->buf, &tcp->io, &tcp->tm); + tcp->domain = domain; return 1; } else { lua_pushnil(L); @@ -341,92 +348,12 @@ static int global_create(lua_State *L) { } } -static const char *trybind6(const char *localaddr, const char *localserv, - struct addrinfo *bindhints, p_tcp tcp) { - struct addrinfo *iterator = NULL, *resolved = NULL; - const char *err = NULL; - /* translate luasocket special values to C */ - if (strcmp(localaddr, "*") == 0) localaddr = NULL; - if (!localserv) localserv = "0"; - /* try resolving */ - err = socket_gaistrerror(getaddrinfo(localaddr, localserv, - bindhints, &resolved)); - if (err) { - if (resolved) freeaddrinfo(resolved); - return err; - } - /* iterate over resolved addresses until one is good */ - for (iterator = resolved; iterator; iterator = iterator->ai_next) { - /* create a new socket each time because parameters - * may have changed */ - err = socket_strerror(socket_create(&tcp->sock, - iterator->ai_family, iterator->ai_socktype, - iterator->ai_protocol)); - /* if failed to create socket, bail out */ - if (err != NULL) { - freeaddrinfo(resolved); - return err; - } - /* all sockets are set as non-blocking initially */ - socket_setnonblocking(&tcp->sock); - /* try binding to local address */ - err = socket_strerror(socket_bind(&tcp->sock, - (SA *) iterator->ai_addr, - iterator->ai_addrlen)); - /* if faiiled, we try the next one */ - if (err != NULL) socket_destroy(&tcp->sock); - /* if success, we abort loop */ - else break; - } - /* at this point, if err is not set, se succeeded */ - if (err == NULL) { - /* save family of chosen local address */ - bindhints->ai_family = iterator->ai_family; - } - /* cleanup and return error */ - freeaddrinfo(resolved); - return err; +static int global_create(lua_State *L) { + return tcp_create(L, AF_INET); } -static int global_bind6(lua_State *L) { - const char *localaddr = luaL_checkstring(L, 1); - const char *localserv = luaL_checkstring(L, 2); - int backlog = luaL_checkint(L, 3); - p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); - struct addrinfo bindhints; - const char *err = NULL; - /* initialize tcp structure */ - 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->sock = SOCKET_INVALID; - /* try binding to local address */ - memset(&bindhints, 0, sizeof(bindhints)); - bindhints.ai_socktype = SOCK_STREAM; - bindhints.ai_family = PF_UNSPEC; - bindhints.ai_flags = AI_PASSIVE; - err = trybind6(localaddr, localserv, &bindhints, tcp); - if (err == NULL) { - /* all server sockets initially with reuseaddr set */ - int val = 1; - setsockopt(tcp->sock, SOL_SOCKET, SO_REUSEADDR, - (char *) &val, sizeof(val)); - /* set the backlog and listen */ - err = socket_strerror(socket_listen(&tcp->sock, backlog)); - if (err) { - socket_destroy(&tcp->sock); - lua_pushnil(L); - lua_pushstring(L, err); - return 2; - } - auxiliar_setclass(L, "tcp{server}", -1); - return 1; - } else { - lua_pushnil(L); - lua_pushstring(L, err); - return 2; - } +static int global_create6(lua_State *L) { + return tcp_create(L, AF_INET6); } static const char *tryconnect6(const char *remoteaddr, const char *remoteserv, @@ -488,7 +415,7 @@ static int global_connect6(lua_State *L) { bindhints.ai_family = PF_UNSPEC; bindhints.ai_flags = AI_PASSIVE; if (localaddr) { - err = trybind6(localaddr, localserv, &bindhints, tcp); + err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints); if (err) { lua_pushnil(L); lua_pushstring(L, err); diff --git a/src/tcp.h b/src/tcp.h index a536b49..4dc9c4a 100644 --- a/src/tcp.h +++ b/src/tcp.h @@ -25,6 +25,7 @@ typedef struct t_tcp_ { t_io io; t_buffer buf; t_timeout tm; + int domain; } t_tcp; typedef t_tcp *p_tcp; diff --git a/src/udp.c b/src/udp.c index 0f9b7cc..94bf125 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_create6(lua_State *L); static int meth_send(lua_State *L); static int meth_sendto(lua_State *L); static int meth_receive(lua_State *L); @@ -89,6 +90,7 @@ static t_opt optget[] = { /* functions in library namespace */ static luaL_reg func[] = { {"udp", global_create}, + {"udp6", global_create6}, {NULL, NULL} }; @@ -317,8 +319,14 @@ static int meth_close(lua_State *L) { static int meth_setsockname(lua_State *L) { p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); const char *address = luaL_checkstring(L, 2); - unsigned short port = (unsigned short) luaL_checknumber(L, 3); - const char *err = inet_trybind(&udp->sock, address, port); + const char *port = luaL_checkstring(L, 3); + const char *err; + struct addrinfo bindhints; + memset(&bindhints, 0, sizeof(bindhints)); + bindhints.ai_socktype = SOCK_DGRAM; + bindhints.ai_family = udp->domain; + bindhints.ai_flags = AI_PASSIVE; + err = inet_trybind(&udp->sock, address, port, &bindhints); if (err) { lua_pushnil(L); lua_pushstring(L, err); @@ -334,18 +342,19 @@ static int meth_setsockname(lua_State *L) { /*-------------------------------------------------------------------------*\ * Creates a master udp object \*-------------------------------------------------------------------------*/ -static int global_create(lua_State *L) { +static int udp_create(lua_State *L, int domain) { t_socket sock; - const char *err = inet_trycreate(&sock, SOCK_DGRAM); + const char *err = inet_trycreate(&sock, domain, SOCK_DGRAM); /* try to allocate a system socket */ if (!err) { - /* allocate tcp object */ + /* 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); udp->sock = sock; timeout_init(&udp->tm, -1, -1); + udp->domain = domain; return 1; } else { lua_pushnil(L); @@ -353,3 +362,11 @@ static int global_create(lua_State *L) { return 2; } } + +static int global_create(lua_State *L) { + return udp_create(L, AF_INET); +} + +static int global_create6(lua_State *L) { + return udp_create(L, AF_INET6); +} diff --git a/src/udp.h b/src/udp.h index 358d9e1..c5b8688 100644 --- a/src/udp.h +++ b/src/udp.h @@ -23,6 +23,7 @@ typedef struct t_udp_ { t_socket sock; t_timeout tm; + int domain; } t_udp; typedef t_udp *p_udp;