mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-11-16 02:08:21 +01:00
socket.connect now implemented in the C core
This avoid socket.lua duplicating the iteration over the results of getaddrinfo(). Some problems with the C implementation not initializing sockets or the luasocket family have also been fixed, and error reporting made more robust.
This commit is contained in:
parent
3d3e69c6e4
commit
156669c28b
@ -145,6 +145,8 @@ Support, Manual">
|
|||||||
<blockquote>
|
<blockquote>
|
||||||
<a href="socket.html#bind">bind</a>,
|
<a href="socket.html#bind">bind</a>,
|
||||||
<a href="socket.html#connect">connect</a>,
|
<a href="socket.html#connect">connect</a>,
|
||||||
|
<a href="socket.html#connect">connect4</a>,
|
||||||
|
<a href="socket.html#connect">connect6</a>,
|
||||||
<a href="socket.html#debug">_DEBUG</a>,
|
<a href="socket.html#debug">_DEBUG</a>,
|
||||||
<a href="dns.html#dns">dns</a>,
|
<a href="dns.html#dns">dns</a>,
|
||||||
<a href="socket.html#gettime">gettime</a>,
|
<a href="socket.html#gettime">gettime</a>,
|
||||||
|
@ -73,14 +73,19 @@ set to <tt><b>true</b></tt>.
|
|||||||
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
|
||||||
<p class=name id=connect>
|
<p class=name id=connect>
|
||||||
socket.<b>connect(</b>address, port [, locaddr, locport]<b>)</b>
|
socket.<b>connect[46](</b>address, port [, locaddr] [, locport] [, family]<b>)</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class=description>
|
<p class=description>
|
||||||
This function is a shortcut that creates and returns a TCP client object
|
This function is a shortcut that creates and returns a TCP client object
|
||||||
connected to a remote <tt>host</tt> at a given <tt>port</tt>. Optionally,
|
connected to a remote <tt>address</tt> at a given <tt>port</tt>. Optionally,
|
||||||
the user can also specify the local address and port to bind
|
the user can also specify the local address and port to bind
|
||||||
(<tt>locaddr</tt> and <tt>locport</tt>).
|
(<tt>locaddr</tt> and <tt>locport</tt>), or restrict the socket family
|
||||||
|
to "<tt>inet</tt>" or "<tt>inet6</tt>".
|
||||||
|
Without specifying <tt>family</tt> to <tt>connect</tt>, whether a tcp or tcp6
|
||||||
|
connection is created depends on your system configuration. Two variations
|
||||||
|
of connect are defined as simple helper functions that restrict the
|
||||||
|
<tt>family</tt>, <tt>socket.connect4</tt> and <tt>socket.connect6</tt>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
|
||||||
|
54
src/inet.c
54
src/inet.c
@ -143,6 +143,22 @@ static int inet_global_toip(lua_State *L)
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int inet_optfamily(lua_State* L, int narg, const char* def)
|
||||||
|
{
|
||||||
|
static const char* optname[] = { "unspec", "inet", "inet6", NULL };
|
||||||
|
static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 };
|
||||||
|
|
||||||
|
return optvalue[luaL_checkoption(L, narg, def, optname)];
|
||||||
|
}
|
||||||
|
|
||||||
|
int inet_optsocktype(lua_State* L, int narg, const char* def)
|
||||||
|
{
|
||||||
|
static const char* optname[] = { "stream", "dgram", NULL };
|
||||||
|
static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 };
|
||||||
|
|
||||||
|
return optvalue[luaL_checkoption(L, narg, def, optname)];
|
||||||
|
}
|
||||||
|
|
||||||
static int inet_global_getaddrinfo(lua_State *L)
|
static int inet_global_getaddrinfo(lua_State *L)
|
||||||
{
|
{
|
||||||
const char *hostname = luaL_checkstring(L, 1);
|
const char *hostname = luaL_checkstring(L, 1);
|
||||||
@ -197,7 +213,7 @@ static int inet_global_gethostname(lua_State *L)
|
|||||||
name[256] = '\0';
|
name[256] = '\0';
|
||||||
if (gethostname(name, 256) < 0) {
|
if (gethostname(name, 256) < 0) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, "gethostname failed");
|
lua_pushstring(L, socket_strerror(errno));
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else {
|
||||||
lua_pushstring(L, name);
|
lua_pushstring(L, name);
|
||||||
@ -222,7 +238,7 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
|
|||||||
char name[INET_ADDRSTRLEN];
|
char name[INET_ADDRSTRLEN];
|
||||||
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
|
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, "getpeername failed");
|
lua_pushstring(L, socket_strerror(errno));
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else {
|
||||||
inet_ntop(family, &peer.sin_addr, name, sizeof(name));
|
inet_ntop(family, &peer.sin_addr, name, sizeof(name));
|
||||||
@ -238,7 +254,7 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
|
|||||||
char name[INET6_ADDRSTRLEN];
|
char name[INET6_ADDRSTRLEN];
|
||||||
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
|
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, "getpeername failed");
|
lua_pushstring(L, socket_strerror(errno));
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else {
|
||||||
inet_ntop(family, &peer.sin6_addr, name, sizeof(name));
|
inet_ntop(family, &peer.sin6_addr, name, sizeof(name));
|
||||||
@ -251,7 +267,7 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, "unknown family");
|
lua_pushfstring(L, "unknown family %d", family);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,7 +284,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
|
|||||||
char name[INET_ADDRSTRLEN];
|
char name[INET_ADDRSTRLEN];
|
||||||
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
|
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, "getsockname failed");
|
lua_pushstring(L, socket_strerror(errno));
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else {
|
||||||
inet_ntop(family, &local.sin_addr, name, sizeof(name));
|
inet_ntop(family, &local.sin_addr, name, sizeof(name));
|
||||||
@ -284,7 +300,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
|
|||||||
char name[INET6_ADDRSTRLEN];
|
char name[INET6_ADDRSTRLEN];
|
||||||
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
|
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, "getsockname failed");
|
lua_pushstring(L, socket_strerror(errno));
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else {
|
||||||
inet_ntop(family, &local.sin6_addr, name, sizeof(name));
|
inet_ntop(family, &local.sin6_addr, name, sizeof(name));
|
||||||
@ -296,7 +312,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, "unknown family");
|
lua_pushfstring(L, "unknown family %d", family);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -390,6 +406,7 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv,
|
|||||||
{
|
{
|
||||||
struct addrinfo *iterator = NULL, *resolved = NULL;
|
struct addrinfo *iterator = NULL, *resolved = NULL;
|
||||||
const char *err = NULL;
|
const char *err = NULL;
|
||||||
|
t_socket sock = *ps;
|
||||||
/* translate luasocket special values to C */
|
/* translate luasocket special values to C */
|
||||||
if (strcmp(address, "*") == 0) address = NULL;
|
if (strcmp(address, "*") == 0) address = NULL;
|
||||||
if (!serv) serv = "0";
|
if (!serv) serv = "0";
|
||||||
@ -402,17 +419,30 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv,
|
|||||||
}
|
}
|
||||||
/* iterate over resolved addresses until one is good */
|
/* iterate over resolved addresses until one is good */
|
||||||
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
||||||
|
if(sock == SOCKET_INVALID) {
|
||||||
|
err = socket_strerror( socket_create(&sock, iterator->ai_family,
|
||||||
|
iterator->ai_socktype, iterator->ai_protocol));
|
||||||
|
if(err)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
/* try binding to local address */
|
/* try binding to local address */
|
||||||
err = socket_strerror(socket_bind(ps,
|
err = socket_strerror(socket_bind(&sock,
|
||||||
(SA *) iterator->ai_addr,
|
(SA *) iterator->ai_addr,
|
||||||
iterator->ai_addrlen));
|
iterator->ai_addrlen));
|
||||||
/* if faiiled, we try the next one */
|
|
||||||
if (err != NULL) socket_destroy(ps);
|
/* keep trying unless bind succeeded */
|
||||||
/* if success, we abort loop */
|
if (err) {
|
||||||
else break;
|
if(sock != *ps)
|
||||||
|
socket_destroy(&sock);
|
||||||
|
} else {
|
||||||
|
/* remember what we connected to, particularly the family */
|
||||||
|
*bindhints = *iterator;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* cleanup and return error */
|
/* cleanup and return error */
|
||||||
freeaddrinfo(resolved);
|
freeaddrinfo(resolved);
|
||||||
|
*ps = sock;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,9 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv,
|
|||||||
int inet_meth_getpeername(lua_State *L, p_socket ps, int family);
|
int inet_meth_getpeername(lua_State *L, p_socket ps, int family);
|
||||||
int inet_meth_getsockname(lua_State *L, p_socket ps, int family);
|
int inet_meth_getsockname(lua_State *L, p_socket ps, int family);
|
||||||
|
|
||||||
|
int inet_optfamily(lua_State* L, int narg, const char* def);
|
||||||
|
int inet_optsocktype(lua_State* L, int narg, const char* def);
|
||||||
|
|
||||||
#ifdef INET_ATON
|
#ifdef INET_ATON
|
||||||
int inet_aton(const char *cp, struct in_addr *inp);
|
int inet_aton(const char *cp, struct in_addr *inp);
|
||||||
#endif
|
#endif
|
||||||
|
@ -15,34 +15,12 @@ module("socket")
|
|||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
-- Exported auxiliar functions
|
-- Exported auxiliar functions
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
function connect(address, port, laddress, lport)
|
function connect4(address, port, laddress, lport)
|
||||||
if address == "*" then address = "0.0.0.0" end
|
return socket.connect(address, port, laddress, lport, "inet")
|
||||||
local addrinfo, err = socket.dns.getaddrinfo(address);
|
end
|
||||||
if not addrinfo then return nil, err end
|
|
||||||
local sock, res
|
function connect6(address, port, laddress, lport)
|
||||||
err = "no info on address"
|
return socket.connect(address, port, laddress, lport, "inet6")
|
||||||
for i, alt in base.ipairs(addrinfo) do
|
|
||||||
if alt.family == "inet" then
|
|
||||||
sock, err = socket.tcp()
|
|
||||||
else
|
|
||||||
sock, err = socket.tcp6()
|
|
||||||
end
|
|
||||||
if not sock then return nil, err end
|
|
||||||
if laddress then
|
|
||||||
res, err = sock:bind(laddress, lport)
|
|
||||||
if not res then
|
|
||||||
sock:close()
|
|
||||||
return nil, err
|
|
||||||
end
|
|
||||||
end
|
|
||||||
res, err = sock:connect(alt.addr, port)
|
|
||||||
if not res then
|
|
||||||
sock:close()
|
|
||||||
else
|
|
||||||
return sock
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil, err
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function bind(host, port, backlog)
|
function bind(host, port, backlog)
|
||||||
|
11
src/tcp.c
11
src/tcp.c
@ -18,7 +18,7 @@
|
|||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
static int global_create(lua_State *L);
|
static int global_create(lua_State *L);
|
||||||
static int global_create6(lua_State *L);
|
static int global_create6(lua_State *L);
|
||||||
static int global_connect6(lua_State *L);
|
static int global_connect(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_getfamily(lua_State *L);
|
static int meth_getfamily(lua_State *L);
|
||||||
@ -89,7 +89,7 @@ static t_opt optset[] = {
|
|||||||
static luaL_Reg func[] = {
|
static luaL_Reg func[] = {
|
||||||
{"tcp", global_create},
|
{"tcp", global_create},
|
||||||
{"tcp6", global_create6},
|
{"tcp6", global_create6},
|
||||||
{"connect6", global_connect6},
|
{"connect", global_connect},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -408,6 +408,7 @@ static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
|
|||||||
freeaddrinfo(resolved);
|
freeaddrinfo(resolved);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
tcp->family = iterator->ai_family;
|
||||||
/* all sockets initially non-blocking */
|
/* all sockets initially non-blocking */
|
||||||
socket_setnonblocking(&tcp->sock);
|
socket_setnonblocking(&tcp->sock);
|
||||||
}
|
}
|
||||||
@ -424,11 +425,12 @@ static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int global_connect6(lua_State *L) {
|
static int global_connect(lua_State *L) {
|
||||||
const char *remoteaddr = luaL_checkstring(L, 1);
|
const char *remoteaddr = luaL_checkstring(L, 1);
|
||||||
const char *remoteserv = luaL_checkstring(L, 2);
|
const char *remoteserv = luaL_checkstring(L, 2);
|
||||||
const char *localaddr = luaL_optstring(L, 3, NULL);
|
const char *localaddr = luaL_optstring(L, 3, NULL);
|
||||||
const char *localserv = luaL_optstring(L, 4, "0");
|
const char *localserv = luaL_optstring(L, 4, "0");
|
||||||
|
int family = inet_optfamily(L, 5, "unspec");
|
||||||
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
||||||
struct addrinfo bindhints, connecthints;
|
struct addrinfo bindhints, connecthints;
|
||||||
const char *err = NULL;
|
const char *err = NULL;
|
||||||
@ -441,7 +443,7 @@ static int global_connect6(lua_State *L) {
|
|||||||
/* allow user to pick local address and port */
|
/* allow user to pick local address and port */
|
||||||
memset(&bindhints, 0, sizeof(bindhints));
|
memset(&bindhints, 0, sizeof(bindhints));
|
||||||
bindhints.ai_socktype = SOCK_STREAM;
|
bindhints.ai_socktype = SOCK_STREAM;
|
||||||
bindhints.ai_family = PF_UNSPEC;
|
bindhints.ai_family = family;
|
||||||
bindhints.ai_flags = AI_PASSIVE;
|
bindhints.ai_flags = AI_PASSIVE;
|
||||||
if (localaddr) {
|
if (localaddr) {
|
||||||
err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints);
|
err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints);
|
||||||
@ -450,6 +452,7 @@ static int global_connect6(lua_State *L) {
|
|||||||
lua_pushstring(L, err);
|
lua_pushstring(L, err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
tcp->family = bindhints.ai_family;
|
||||||
}
|
}
|
||||||
/* try to connect to remote address and port */
|
/* try to connect to remote address and port */
|
||||||
memset(&connecthints, 0, sizeof(connecthints));
|
memset(&connecthints, 0, sizeof(connecthints));
|
||||||
|
@ -447,7 +447,7 @@ const char *socket_gaistrerror(int err) {
|
|||||||
case EAI_SERVICE: return "service not supported for socket type";
|
case EAI_SERVICE: return "service not supported for socket type";
|
||||||
case EAI_SOCKTYPE: return "ai_socktype not supported";
|
case EAI_SOCKTYPE: return "ai_socktype not supported";
|
||||||
case EAI_SYSTEM: return strerror(errno);
|
case EAI_SYSTEM: return strerror(errno);
|
||||||
default: return "unknown error";
|
default: return gai_strerror(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user