mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-12-27 04:48:21 +01:00
Rework binding IPv6 sockets by harmonizing it with the IPv4 variant
This commit is contained in:
parent
5c33ef9997
commit
923eef1929
48
src/inet.c
48
src/inet.c
@ -244,8 +244,8 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Tries to create a new inet socket
|
* Tries to create a new inet socket
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
const char *inet_trycreate(p_socket ps, int type) {
|
const char *inet_trycreate(p_socket ps, int domain, int type) {
|
||||||
return socket_strerror(socket_create(ps, AF_INET, type, 0));
|
return socket_strerror(socket_create(ps, domain, type, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@ -276,25 +276,35 @@ const char *inet_tryconnect(p_socket ps, const char *address,
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Tries to bind socket to (address, port)
|
* 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;
|
struct addrinfo *iterator = NULL, *resolved = NULL;
|
||||||
int err;
|
const char *err = NULL;
|
||||||
memset(&local, 0, sizeof(local));
|
/* translate luasocket special values to C */
|
||||||
/* address is either wildcard or a valid ip address */
|
if (strcmp(address, "*") == 0) address = NULL;
|
||||||
local.sin_addr.s_addr = htonl(INADDR_ANY);
|
if (!serv) serv = "0";
|
||||||
local.sin_port = htons(port);
|
/* try resolving */
|
||||||
local.sin_family = AF_INET;
|
err = socket_gaistrerror(getaddrinfo(address, serv,
|
||||||
if (strcmp(address, "*") && !inet_aton(address, &local.sin_addr)) {
|
bindhints, &resolved));
|
||||||
struct hostent *hp = NULL;
|
if (err) {
|
||||||
struct in_addr **addr;
|
if (resolved) freeaddrinfo(resolved);
|
||||||
err = socket_gethostbyname(address, &hp);
|
return err;
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
err = socket_bind(ps, (SA *) &local, sizeof(local));
|
/* iterate over resolved addresses until one is good */
|
||||||
return socket_strerror(err);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
|
@ -24,11 +24,11 @@
|
|||||||
|
|
||||||
int inet_open(lua_State *L);
|
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,
|
const char *inet_tryconnect(p_socket ps, const char *address,
|
||||||
unsigned short port, p_timeout tm);
|
unsigned short port, p_timeout tm);
|
||||||
const char *inet_trybind(p_socket ps, const char *address,
|
const char *inet_trybind(p_socket ps, const char *address, const char *serv,
|
||||||
unsigned short port);
|
struct addrinfo *bindhints);
|
||||||
|
|
||||||
int inet_meth_getpeername(lua_State *L, p_socket ps);
|
int inet_meth_getpeername(lua_State *L, p_socket ps);
|
||||||
int inet_meth_getsockname(lua_State *L, p_socket ps);
|
int inet_meth_getsockname(lua_State *L, p_socket ps);
|
||||||
|
109
src/tcp.c
109
src/tcp.c
@ -19,8 +19,8 @@
|
|||||||
* Internal function prototypes
|
* Internal function prototypes
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
static int global_create(lua_State *L);
|
static int global_create(lua_State *L);
|
||||||
|
static int global_create6(lua_State *L);
|
||||||
static int global_connect6(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_connect(lua_State *L);
|
||||||
static int meth_listen(lua_State *L);
|
static int meth_listen(lua_State *L);
|
||||||
static int meth_bind(lua_State *L);
|
static int meth_bind(lua_State *L);
|
||||||
@ -77,8 +77,8 @@ static t_opt optset[] = {
|
|||||||
/* functions in library namespace */
|
/* functions in library namespace */
|
||||||
static luaL_reg func[] = {
|
static luaL_reg func[] = {
|
||||||
{"tcp", global_create},
|
{"tcp", global_create},
|
||||||
|
{"tcp6", global_create6},
|
||||||
{"connect6", global_connect6},
|
{"connect6", global_connect6},
|
||||||
{"bind6", global_bind6},
|
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -196,8 +196,14 @@ static int meth_bind(lua_State *L)
|
|||||||
{
|
{
|
||||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
|
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 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);
|
||||||
const char *err = inet_trybind(&tcp->sock, address, port);
|
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) {
|
if (err) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, err);
|
lua_pushstring(L, err);
|
||||||
@ -317,9 +323,9 @@ static int meth_settimeout(lua_State *L)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Creates a master tcp object
|
* Creates a master tcp object
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int global_create(lua_State *L) {
|
static int tcp_create(lua_State *L, int domain) {
|
||||||
t_socket sock;
|
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 */
|
/* try to allocate a system socket */
|
||||||
if (!err) {
|
if (!err) {
|
||||||
/* allocate tcp object */
|
/* allocate tcp object */
|
||||||
@ -333,6 +339,7 @@ static int global_create(lua_State *L) {
|
|||||||
(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);
|
||||||
|
tcp->domain = domain;
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
@ -341,92 +348,12 @@ static int global_create(lua_State *L) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *trybind6(const char *localaddr, const char *localserv,
|
static int global_create(lua_State *L) {
|
||||||
struct addrinfo *bindhints, p_tcp tcp) {
|
return tcp_create(L, AF_INET);
|
||||||
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_bind6(lua_State *L) {
|
static int global_create6(lua_State *L) {
|
||||||
const char *localaddr = luaL_checkstring(L, 1);
|
return tcp_create(L, AF_INET6);
|
||||||
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 const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
|
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_family = PF_UNSPEC;
|
||||||
bindhints.ai_flags = AI_PASSIVE;
|
bindhints.ai_flags = AI_PASSIVE;
|
||||||
if (localaddr) {
|
if (localaddr) {
|
||||||
err = trybind6(localaddr, localserv, &bindhints, tcp);
|
err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints);
|
||||||
if (err) {
|
if (err) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, err);
|
lua_pushstring(L, err);
|
||||||
|
@ -25,6 +25,7 @@ typedef struct t_tcp_ {
|
|||||||
t_io io;
|
t_io io;
|
||||||
t_buffer buf;
|
t_buffer buf;
|
||||||
t_timeout tm;
|
t_timeout tm;
|
||||||
|
int domain;
|
||||||
} t_tcp;
|
} t_tcp;
|
||||||
|
|
||||||
typedef t_tcp *p_tcp;
|
typedef t_tcp *p_tcp;
|
||||||
|
27
src/udp.c
27
src/udp.c
@ -27,6 +27,7 @@
|
|||||||
* Internal function prototypes
|
* Internal function prototypes
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
static int global_create(lua_State *L);
|
static int global_create(lua_State *L);
|
||||||
|
static int global_create6(lua_State *L);
|
||||||
static int meth_send(lua_State *L);
|
static int meth_send(lua_State *L);
|
||||||
static int meth_sendto(lua_State *L);
|
static int meth_sendto(lua_State *L);
|
||||||
static int meth_receive(lua_State *L);
|
static int meth_receive(lua_State *L);
|
||||||
@ -89,6 +90,7 @@ static t_opt optget[] = {
|
|||||||
/* functions in library namespace */
|
/* functions in library namespace */
|
||||||
static luaL_reg func[] = {
|
static luaL_reg func[] = {
|
||||||
{"udp", global_create},
|
{"udp", global_create},
|
||||||
|
{"udp6", global_create6},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -317,8 +319,14 @@ static int meth_close(lua_State *L) {
|
|||||||
static int meth_setsockname(lua_State *L) {
|
static int meth_setsockname(lua_State *L) {
|
||||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
|
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 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);
|
||||||
const char *err = inet_trybind(&udp->sock, address, port);
|
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) {
|
if (err) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, err);
|
lua_pushstring(L, err);
|
||||||
@ -334,18 +342,19 @@ static int meth_setsockname(lua_State *L) {
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Creates a master udp object
|
* Creates a master udp object
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int global_create(lua_State *L) {
|
static int udp_create(lua_State *L, int domain) {
|
||||||
t_socket sock;
|
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 */
|
/* try to allocate a system socket */
|
||||||
if (!err) {
|
if (!err) {
|
||||||
/* allocate tcp 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);
|
||||||
/* initialize remaining structure fields */
|
/* initialize remaining structure fields */
|
||||||
socket_setnonblocking(&sock);
|
socket_setnonblocking(&sock);
|
||||||
udp->sock = sock;
|
udp->sock = sock;
|
||||||
timeout_init(&udp->tm, -1, -1);
|
timeout_init(&udp->tm, -1, -1);
|
||||||
|
udp->domain = domain;
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
@ -353,3 +362,11 @@ static int global_create(lua_State *L) {
|
|||||||
return 2;
|
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);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user