Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #12 from sam-github/fix-connect6-and-do-connect-in-c

socket.connect now implemented in the C core
  • Loading branch information...
commit 399bdb7f412bd9cc565090f30e3872d8b72d66d8 2 parents 3d3e69c + 156669c
@diegonehab authored
View
2  doc/reference.html
@@ -145,6 +145,8 @@
<blockquote>
<a href="socket.html#bind">bind</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="dns.html#dns">dns</a>,
<a href="socket.html#gettime">gettime</a>,
View
11 doc/socket.html
@@ -73,14 +73,19 @@ <h2 id=socket>The socket namespace</h2>
<!-- 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 class=description>
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
-(<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>
<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
View
54 src/inet.c
@@ -143,6 +143,22 @@ static int inet_global_toip(lua_State *L)
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)
{
const char *hostname = luaL_checkstring(L, 1);
@@ -197,7 +213,7 @@ static int inet_global_gethostname(lua_State *L)
name[256] = '\0';
if (gethostname(name, 256) < 0) {
lua_pushnil(L);
- lua_pushstring(L, "gethostname failed");
+ lua_pushstring(L, socket_strerror(errno));
return 2;
} else {
lua_pushstring(L, name);
@@ -222,7 +238,7 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
char name[INET_ADDRSTRLEN];
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
lua_pushnil(L);
- lua_pushstring(L, "getpeername failed");
+ lua_pushstring(L, socket_strerror(errno));
return 2;
} else {
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];
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
lua_pushnil(L);
- lua_pushstring(L, "getpeername failed");
+ lua_pushstring(L, socket_strerror(errno));
return 2;
} else {
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:
lua_pushnil(L);
- lua_pushstring(L, "unknown family");
+ lua_pushfstring(L, "unknown family %d", family);
return 2;
}
}
@@ -268,7 +284,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
char name[INET_ADDRSTRLEN];
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
lua_pushnil(L);
- lua_pushstring(L, "getsockname failed");
+ lua_pushstring(L, socket_strerror(errno));
return 2;
} else {
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];
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
lua_pushnil(L);
- lua_pushstring(L, "getsockname failed");
+ lua_pushstring(L, socket_strerror(errno));
return 2;
} else {
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:
lua_pushnil(L);
- lua_pushstring(L, "unknown family");
+ lua_pushfstring(L, "unknown family %d", family);
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;
const char *err = NULL;
+ t_socket sock = *ps;
/* translate luasocket special values to C */
if (strcmp(address, "*") == 0) address = NULL;
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 */
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 */
- err = socket_strerror(socket_bind(ps,
+ err = socket_strerror(socket_bind(&sock,
(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;
+
+ /* keep trying unless bind succeeded */
+ if (err) {
+ if(sock != *ps)
+ socket_destroy(&sock);
+ } else {
+ /* remember what we connected to, particularly the family */
+ *bindhints = *iterator;
+ break;
+ }
}
/* cleanup and return error */
freeaddrinfo(resolved);
+ *ps = sock;
return err;
}
View
3  src/inet.h
@@ -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_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
int inet_aton(const char *cp, struct in_addr *inp);
#endif
View
34 src/socket.lua
@@ -15,34 +15,12 @@ module("socket")
-----------------------------------------------------------------------------
-- Exported auxiliar functions
-----------------------------------------------------------------------------
-function connect(address, port, laddress, lport)
- 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, res
- err = "no info on address"
- 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
+function connect4(address, port, laddress, lport)
+ return socket.connect(address, port, laddress, lport, "inet")
+end
+
+function connect6(address, port, laddress, lport)
+ return socket.connect(address, port, laddress, lport, "inet6")
end
function bind(host, port, backlog)
View
11 src/tcp.c
@@ -18,7 +18,7 @@
\*=========================================================================*/
static int global_create(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_listen(lua_State *L);
static int meth_getfamily(lua_State *L);
@@ -89,7 +89,7 @@ static t_opt optset[] = {
static luaL_Reg func[] = {
{"tcp", global_create},
{"tcp6", global_create6},
- {"connect6", global_connect6},
+ {"connect", global_connect},
{NULL, NULL}
};
@@ -408,6 +408,7 @@ static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
freeaddrinfo(resolved);
return err;
}
+ tcp->family = iterator->ai_family;
/* all sockets initially non-blocking */
socket_setnonblocking(&tcp->sock);
}
@@ -424,11 +425,12 @@ static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
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 *remoteserv = luaL_checkstring(L, 2);
const char *localaddr = luaL_optstring(L, 3, NULL);
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));
struct addrinfo bindhints, connecthints;
const char *err = NULL;
@@ -441,7 +443,7 @@ static int global_connect6(lua_State *L) {
/* allow user to pick local address and port */
memset(&bindhints, 0, sizeof(bindhints));
bindhints.ai_socktype = SOCK_STREAM;
- bindhints.ai_family = PF_UNSPEC;
+ bindhints.ai_family = family;
bindhints.ai_flags = AI_PASSIVE;
if (localaddr) {
err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints);
@@ -450,6 +452,7 @@ static int global_connect6(lua_State *L) {
lua_pushstring(L, err);
return 2;
}
+ tcp->family = bindhints.ai_family;
}
/* try to connect to remote address and port */
memset(&connecthints, 0, sizeof(connecthints));
View
2  src/usocket.c
@@ -447,7 +447,7 @@ const char *socket_gaistrerror(int err) {
case EAI_SERVICE: return "service not supported for socket type";
case EAI_SOCKTYPE: return "ai_socktype not supported";
case EAI_SYSTEM: return strerror(errno);
- default: return "unknown error";
+ default: return gai_strerror(err);
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.