aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Roberts <vieuxtech@gmail.com>2012-05-10 14:14:22 -0700
committerSam Roberts <vieuxtech@gmail.com>2012-05-10 14:14:22 -0700
commit156669c28bc62bfddbd5625c4bb4c1f8da94802b (patch)
tree074ea57dd044a9bed306464af8c9f141bdf0ca19
parent3d3e69c6e43f6431969e072e78df43b0ab73c48d (diff)
downloadluasocket-156669c28bc62bfddbd5625c4bb4c1f8da94802b.tar.gz
luasocket-156669c28bc62bfddbd5625c4bb4c1f8da94802b.tar.bz2
luasocket-156669c28bc62bfddbd5625c4bb4c1f8da94802b.zip
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.
-rw-r--r--doc/reference.html2
-rw-r--r--doc/socket.html11
-rw-r--r--src/inet.c54
-rw-r--r--src/inet.h3
-rw-r--r--src/socket.lua34
-rw-r--r--src/tcp.c11
-rw-r--r--src/usocket.c2
7 files changed, 69 insertions, 48 deletions
diff --git a/doc/reference.html b/doc/reference.html
index f069d47..e9bb5eb 100644
--- a/doc/reference.html
+++ b/doc/reference.html
@@ -145,6 +145,8 @@ Support, Manual">
145<blockquote> 145<blockquote>
146<a href="socket.html#bind">bind</a>, 146<a href="socket.html#bind">bind</a>,
147<a href="socket.html#connect">connect</a>, 147<a href="socket.html#connect">connect</a>,
148<a href="socket.html#connect">connect4</a>,
149<a href="socket.html#connect">connect6</a>,
148<a href="socket.html#debug">_DEBUG</a>, 150<a href="socket.html#debug">_DEBUG</a>,
149<a href="dns.html#dns">dns</a>, 151<a href="dns.html#dns">dns</a>,
150<a href="socket.html#gettime">gettime</a>, 152<a href="socket.html#gettime">gettime</a>,
diff --git a/doc/socket.html b/doc/socket.html
index dcf8b61..b9303cb 100644
--- a/doc/socket.html
+++ b/doc/socket.html
@@ -73,14 +73,19 @@ set to <tt><b>true</b></tt>.
73<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 73<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
74 74
75<p class=name id=connect> 75<p class=name id=connect>
76socket.<b>connect(</b>address, port [, locaddr, locport]<b>)</b> 76socket.<b>connect[46](</b>address, port [, locaddr] [, locport] [, family]<b>)</b>
77</p> 77</p>
78 78
79<p class=description> 79<p class=description>
80This function is a shortcut that creates and returns a TCP client object 80This function is a shortcut that creates and returns a TCP client object
81connected to a remote <tt>host</tt> at a given <tt>port</tt>. Optionally, 81connected to a remote <tt>address</tt> at a given <tt>port</tt>. Optionally,
82the user can also specify the local address and port to bind 82the user can also specify the local address and port to bind
83(<tt>locaddr</tt> and <tt>locport</tt>). 83(<tt>locaddr</tt> and <tt>locport</tt>), or restrict the socket family
84to "<tt>inet</tt>" or "<tt>inet6</tt>".
85Without specifying <tt>family</tt> to <tt>connect</tt>, whether a tcp or tcp6
86connection is created depends on your system configuration. Two variations
87of connect are defined as simple helper functions that restrict the
88<tt>family</tt>, <tt>socket.connect4</tt> and <tt>socket.connect6</tt>.
84</p> 89</p>
85 90
86<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 91<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
diff --git a/src/inet.c b/src/inet.c
index 55e89d7..e769cd8 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -143,6 +143,22 @@ static int inet_global_toip(lua_State *L)
143 return 2; 143 return 2;
144} 144}
145 145
146int inet_optfamily(lua_State* L, int narg, const char* def)
147{
148 static const char* optname[] = { "unspec", "inet", "inet6", NULL };
149 static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 };
150
151 return optvalue[luaL_checkoption(L, narg, def, optname)];
152}
153
154int inet_optsocktype(lua_State* L, int narg, const char* def)
155{
156 static const char* optname[] = { "stream", "dgram", NULL };
157 static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 };
158
159 return optvalue[luaL_checkoption(L, narg, def, optname)];
160}
161
146static int inet_global_getaddrinfo(lua_State *L) 162static int inet_global_getaddrinfo(lua_State *L)
147{ 163{
148 const char *hostname = luaL_checkstring(L, 1); 164 const char *hostname = luaL_checkstring(L, 1);
@@ -197,7 +213,7 @@ static int inet_global_gethostname(lua_State *L)
197 name[256] = '\0'; 213 name[256] = '\0';
198 if (gethostname(name, 256) < 0) { 214 if (gethostname(name, 256) < 0) {
199 lua_pushnil(L); 215 lua_pushnil(L);
200 lua_pushstring(L, "gethostname failed"); 216 lua_pushstring(L, socket_strerror(errno));
201 return 2; 217 return 2;
202 } else { 218 } else {
203 lua_pushstring(L, name); 219 lua_pushstring(L, name);
@@ -222,7 +238,7 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
222 char name[INET_ADDRSTRLEN]; 238 char name[INET_ADDRSTRLEN];
223 if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { 239 if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
224 lua_pushnil(L); 240 lua_pushnil(L);
225 lua_pushstring(L, "getpeername failed"); 241 lua_pushstring(L, socket_strerror(errno));
226 return 2; 242 return 2;
227 } else { 243 } else {
228 inet_ntop(family, &peer.sin_addr, name, sizeof(name)); 244 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)
238 char name[INET6_ADDRSTRLEN]; 254 char name[INET6_ADDRSTRLEN];
239 if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { 255 if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
240 lua_pushnil(L); 256 lua_pushnil(L);
241 lua_pushstring(L, "getpeername failed"); 257 lua_pushstring(L, socket_strerror(errno));
242 return 2; 258 return 2;
243 } else { 259 } else {
244 inet_ntop(family, &peer.sin6_addr, name, sizeof(name)); 260 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)
251 } 267 }
252 default: 268 default:
253 lua_pushnil(L); 269 lua_pushnil(L);
254 lua_pushstring(L, "unknown family"); 270 lua_pushfstring(L, "unknown family %d", family);
255 return 2; 271 return 2;
256 } 272 }
257} 273}
@@ -268,7 +284,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
268 char name[INET_ADDRSTRLEN]; 284 char name[INET_ADDRSTRLEN];
269 if (getsockname(*ps, (SA *) &local, &local_len) < 0) { 285 if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
270 lua_pushnil(L); 286 lua_pushnil(L);
271 lua_pushstring(L, "getsockname failed"); 287 lua_pushstring(L, socket_strerror(errno));
272 return 2; 288 return 2;
273 } else { 289 } else {
274 inet_ntop(family, &local.sin_addr, name, sizeof(name)); 290 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)
284 char name[INET6_ADDRSTRLEN]; 300 char name[INET6_ADDRSTRLEN];
285 if (getsockname(*ps, (SA *) &local, &local_len) < 0) { 301 if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
286 lua_pushnil(L); 302 lua_pushnil(L);
287 lua_pushstring(L, "getsockname failed"); 303 lua_pushstring(L, socket_strerror(errno));
288 return 2; 304 return 2;
289 } else { 305 } else {
290 inet_ntop(family, &local.sin6_addr, name, sizeof(name)); 306 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)
296 } 312 }
297 default: 313 default:
298 lua_pushnil(L); 314 lua_pushnil(L);
299 lua_pushstring(L, "unknown family"); 315 lua_pushfstring(L, "unknown family %d", family);
300 return 2; 316 return 2;
301 } 317 }
302} 318}
@@ -390,6 +406,7 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv,
390{ 406{
391 struct addrinfo *iterator = NULL, *resolved = NULL; 407 struct addrinfo *iterator = NULL, *resolved = NULL;
392 const char *err = NULL; 408 const char *err = NULL;
409 t_socket sock = *ps;
393 /* translate luasocket special values to C */ 410 /* translate luasocket special values to C */
394 if (strcmp(address, "*") == 0) address = NULL; 411 if (strcmp(address, "*") == 0) address = NULL;
395 if (!serv) serv = "0"; 412 if (!serv) serv = "0";
@@ -402,17 +419,30 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv,
402 } 419 }
403 /* iterate over resolved addresses until one is good */ 420 /* iterate over resolved addresses until one is good */
404 for (iterator = resolved; iterator; iterator = iterator->ai_next) { 421 for (iterator = resolved; iterator; iterator = iterator->ai_next) {
422 if(sock == SOCKET_INVALID) {
423 err = socket_strerror( socket_create(&sock, iterator->ai_family,
424 iterator->ai_socktype, iterator->ai_protocol));
425 if(err)
426 continue;
427 }
405 /* try binding to local address */ 428 /* try binding to local address */
406 err = socket_strerror(socket_bind(ps, 429 err = socket_strerror(socket_bind(&sock,
407 (SA *) iterator->ai_addr, 430 (SA *) iterator->ai_addr,
408 iterator->ai_addrlen)); 431 iterator->ai_addrlen));
409 /* if faiiled, we try the next one */ 432
410 if (err != NULL) socket_destroy(ps); 433 /* keep trying unless bind succeeded */
411 /* if success, we abort loop */ 434 if (err) {
412 else break; 435 if(sock != *ps)
436 socket_destroy(&sock);
437 } else {
438 /* remember what we connected to, particularly the family */
439 *bindhints = *iterator;
440 break;
441 }
413 } 442 }
414 /* cleanup and return error */ 443 /* cleanup and return error */
415 freeaddrinfo(resolved); 444 freeaddrinfo(resolved);
445 *ps = sock;
416 return err; 446 return err;
417} 447}
418 448
diff --git a/src/inet.h b/src/inet.h
index 1cbe4f4..05633bb 100644
--- a/src/inet.h
+++ b/src/inet.h
@@ -33,6 +33,9 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv,
33int inet_meth_getpeername(lua_State *L, p_socket ps, int family); 33int inet_meth_getpeername(lua_State *L, p_socket ps, int family);
34int inet_meth_getsockname(lua_State *L, p_socket ps, int family); 34int inet_meth_getsockname(lua_State *L, p_socket ps, int family);
35 35
36int inet_optfamily(lua_State* L, int narg, const char* def);
37int inet_optsocktype(lua_State* L, int narg, const char* def);
38
36#ifdef INET_ATON 39#ifdef INET_ATON
37int inet_aton(const char *cp, struct in_addr *inp); 40int inet_aton(const char *cp, struct in_addr *inp);
38#endif 41#endif
diff --git a/src/socket.lua b/src/socket.lua
index 8c5f231..e8def75 100644
--- a/src/socket.lua
+++ b/src/socket.lua
@@ -15,34 +15,12 @@ module("socket")
15----------------------------------------------------------------------------- 15-----------------------------------------------------------------------------
16-- Exported auxiliar functions 16-- Exported auxiliar functions
17----------------------------------------------------------------------------- 17-----------------------------------------------------------------------------
18function connect(address, port, laddress, lport) 18function connect4(address, port, laddress, lport)
19 if address == "*" then address = "0.0.0.0" end 19 return socket.connect(address, port, laddress, lport, "inet")
20 local addrinfo, err = socket.dns.getaddrinfo(address); 20end
21 if not addrinfo then return nil, err end 21
22 local sock, res 22function connect6(address, port, laddress, lport)
23 err = "no info on address" 23 return socket.connect(address, port, laddress, lport, "inet6")
24 for i, alt in base.ipairs(addrinfo) do
25 if alt.family == "inet" then
26 sock, err = socket.tcp()
27 else
28 sock, err = socket.tcp6()
29 end
30 if not sock then return nil, err end
31 if laddress then
32 res, err = sock:bind(laddress, lport)
33 if not res then
34 sock:close()
35 return nil, err
36 end
37 end
38 res, err = sock:connect(alt.addr, port)
39 if not res then
40 sock:close()
41 else
42 return sock
43 end
44 end
45 return nil, err
46end 24end
47 25
48function bind(host, port, backlog) 26function bind(host, port, backlog)
diff --git a/src/tcp.c b/src/tcp.c
index 94148c5..3a7f527 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -18,7 +18,7 @@
18\*=========================================================================*/ 18\*=========================================================================*/
19static int global_create(lua_State *L); 19static int global_create(lua_State *L);
20static int global_create6(lua_State *L); 20static int global_create6(lua_State *L);
21static int global_connect6(lua_State *L); 21static int global_connect(lua_State *L);
22static int meth_connect(lua_State *L); 22static int meth_connect(lua_State *L);
23static int meth_listen(lua_State *L); 23static int meth_listen(lua_State *L);
24static int meth_getfamily(lua_State *L); 24static int meth_getfamily(lua_State *L);
@@ -89,7 +89,7 @@ static t_opt optset[] = {
89static luaL_Reg func[] = { 89static luaL_Reg func[] = {
90 {"tcp", global_create}, 90 {"tcp", global_create},
91 {"tcp6", global_create6}, 91 {"tcp6", global_create6},
92 {"connect6", global_connect6}, 92 {"connect", global_connect},
93 {NULL, NULL} 93 {NULL, NULL}
94}; 94};
95 95
@@ -408,6 +408,7 @@ static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
408 freeaddrinfo(resolved); 408 freeaddrinfo(resolved);
409 return err; 409 return err;
410 } 410 }
411 tcp->family = iterator->ai_family;
411 /* all sockets initially non-blocking */ 412 /* all sockets initially non-blocking */
412 socket_setnonblocking(&tcp->sock); 413 socket_setnonblocking(&tcp->sock);
413 } 414 }
@@ -424,11 +425,12 @@ static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
424 return err; 425 return err;
425} 426}
426 427
427static int global_connect6(lua_State *L) { 428static int global_connect(lua_State *L) {
428 const char *remoteaddr = luaL_checkstring(L, 1); 429 const char *remoteaddr = luaL_checkstring(L, 1);
429 const char *remoteserv = luaL_checkstring(L, 2); 430 const char *remoteserv = luaL_checkstring(L, 2);
430 const char *localaddr = luaL_optstring(L, 3, NULL); 431 const char *localaddr = luaL_optstring(L, 3, NULL);
431 const char *localserv = luaL_optstring(L, 4, "0"); 432 const char *localserv = luaL_optstring(L, 4, "0");
433 int family = inet_optfamily(L, 5, "unspec");
432 p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); 434 p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
433 struct addrinfo bindhints, connecthints; 435 struct addrinfo bindhints, connecthints;
434 const char *err = NULL; 436 const char *err = NULL;
@@ -441,7 +443,7 @@ static int global_connect6(lua_State *L) {
441 /* allow user to pick local address and port */ 443 /* allow user to pick local address and port */
442 memset(&bindhints, 0, sizeof(bindhints)); 444 memset(&bindhints, 0, sizeof(bindhints));
443 bindhints.ai_socktype = SOCK_STREAM; 445 bindhints.ai_socktype = SOCK_STREAM;
444 bindhints.ai_family = PF_UNSPEC; 446 bindhints.ai_family = family;
445 bindhints.ai_flags = AI_PASSIVE; 447 bindhints.ai_flags = AI_PASSIVE;
446 if (localaddr) { 448 if (localaddr) {
447 err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints); 449 err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints);
@@ -450,6 +452,7 @@ static int global_connect6(lua_State *L) {
450 lua_pushstring(L, err); 452 lua_pushstring(L, err);
451 return 2; 453 return 2;
452 } 454 }
455 tcp->family = bindhints.ai_family;
453 } 456 }
454 /* try to connect to remote address and port */ 457 /* try to connect to remote address and port */
455 memset(&connecthints, 0, sizeof(connecthints)); 458 memset(&connecthints, 0, sizeof(connecthints));
diff --git a/src/usocket.c b/src/usocket.c
index a168bf6..7150996 100644
--- a/src/usocket.c
+++ b/src/usocket.c
@@ -447,7 +447,7 @@ const char *socket_gaistrerror(int err) {
447 case EAI_SERVICE: return "service not supported for socket type"; 447 case EAI_SERVICE: return "service not supported for socket type";
448 case EAI_SOCKTYPE: return "ai_socktype not supported"; 448 case EAI_SOCKTYPE: return "ai_socktype not supported";
449 case EAI_SYSTEM: return strerror(errno); 449 case EAI_SYSTEM: return strerror(errno);
450 default: return "unknown error"; 450 default: return gai_strerror(err);
451 } 451 }
452} 452}
453 453