aboutsummaryrefslogtreecommitdiff
path: root/src/tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tcp.c')
-rw-r--r--src/tcp.c181
1 files changed, 177 insertions, 4 deletions
diff --git a/src/tcp.c b/src/tcp.c
index 06d687b..3204b40 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -2,7 +2,7 @@
2* TCP object 2* TCP object
3* LuaSocket toolkit 3* LuaSocket toolkit
4* 4*
5* RCS ID: $Id$ 5* RCS ID: $Id: tcp.c,v 1.42 2009/05/27 09:31:35 diego Exp $
6\*=========================================================================*/ 6\*=========================================================================*/
7#include <string.h> 7#include <string.h>
8 8
@@ -19,6 +19,8 @@
19* Internal function prototypes 19* Internal function prototypes
20\*=========================================================================*/ 20\*=========================================================================*/
21static int global_create(lua_State *L); 21static int global_create(lua_State *L);
22static int global_connect6(lua_State *L);
23static int global_bind6(lua_State *L);
22static int meth_connect(lua_State *L); 24static int meth_connect(lua_State *L);
23static int meth_listen(lua_State *L); 25static int meth_listen(lua_State *L);
24static int meth_bind(lua_State *L); 26static int meth_bind(lua_State *L);
@@ -75,6 +77,8 @@ static t_opt optset[] = {
75/* functions in library namespace */ 77/* functions in library namespace */
76static luaL_reg func[] = { 78static luaL_reg func[] = {
77 {"tcp", global_create}, 79 {"tcp", global_create},
80 {"connect6", global_connect6},
81 {"bind6", global_bind6},
78 {NULL, NULL} 82 {NULL, NULL}
79}; 83};
80 84
@@ -208,6 +212,7 @@ static int meth_bind(lua_State *L)
208\*-------------------------------------------------------------------------*/ 212\*-------------------------------------------------------------------------*/
209static int meth_connect(lua_State *L) 213static int meth_connect(lua_State *L)
210{ 214{
215
211 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); 216 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
212 const char *address = luaL_checkstring(L, 2); 217 const char *address = luaL_checkstring(L, 2);
213 unsigned short port = (unsigned short) luaL_checknumber(L, 3); 218 unsigned short port = (unsigned short) luaL_checknumber(L, 3);
@@ -220,7 +225,6 @@ static int meth_connect(lua_State *L)
220 lua_pushstring(L, err); 225 lua_pushstring(L, err);
221 return 2; 226 return 2;
222 } 227 }
223 /* turn master object into a client object */
224 lua_pushnumber(L, 1); 228 lua_pushnumber(L, 1);
225 return 1; 229 return 1;
226} 230}
@@ -313,8 +317,7 @@ static int meth_settimeout(lua_State *L)
313/*-------------------------------------------------------------------------*\ 317/*-------------------------------------------------------------------------*\
314* Creates a master tcp object 318* Creates a master tcp object
315\*-------------------------------------------------------------------------*/ 319\*-------------------------------------------------------------------------*/
316static int global_create(lua_State *L) 320static int global_create(lua_State *L) {
317{
318 t_socket sock; 321 t_socket sock;
319 const char *err = inet_trycreate(&sock, SOCK_STREAM); 322 const char *err = inet_trycreate(&sock, SOCK_STREAM);
320 /* try to allocate a system socket */ 323 /* try to allocate a system socket */
@@ -337,3 +340,173 @@ static int global_create(lua_State *L)
337 return 2; 340 return 2;
338 } 341 }
339} 342}
343
344static const char *trybind6(const char *localaddr, const char *localserv,
345 struct addrinfo *bindhints, p_tcp tcp) {
346 struct addrinfo *iterator = NULL, *resolved = NULL;
347 const char *err = NULL;
348 /* translate luasocket special values to C */
349 if (strcmp(localaddr, "*") == 0) localaddr = NULL;
350 if (!localserv) localserv = "0";
351 /* try resolving */
352 err = socket_gaistrerror(getaddrinfo(localaddr, localserv,
353 bindhints, &resolved));
354 if (err) {
355 if (resolved) freeaddrinfo(resolved);
356 return err;
357 }
358 /* iterate over resolved addresses until one is good */
359 for (iterator = resolved; iterator; iterator = iterator->ai_next) {
360 /* create a new socket each time because parameters
361 * may have changed */
362 const char *err = socket_strerror(socket_create(&tcp->sock,
363 iterator->ai_family, iterator->ai_socktype,
364 iterator->ai_protocol));
365 /* if failed to create socket, bail out */
366 if (err != NULL) {
367 freeaddrinfo(resolved);
368 return err;
369 }
370 /* all sockets are set as non-blocking initially */
371 socket_setnonblocking(&tcp->sock);
372 /* try binding to local address */
373 err = socket_strerror(socket_bind(&tcp->sock,
374 (SA *) iterator->ai_addr,
375 iterator->ai_addrlen));
376 /* if faiiled, we try the next one */
377 if (err != NULL) socket_destroy(&tcp->sock);
378 /* if success, we abort loop */
379 else break;
380 }
381 /* at this point, if err is not set, se succeeded */
382 if (err == NULL) {
383 /* save family of chosen local address */
384 bindhints->ai_family = iterator->ai_family;
385 }
386 /* cleanup and return error */
387 freeaddrinfo(resolved);
388 return err;
389}
390
391static int global_bind6(lua_State *L) {
392 const char *localaddr = luaL_checkstring(L, 1);
393 const char *localserv = luaL_checkstring(L, 2);
394 int backlog = luaL_checkint(L, 3);
395 p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
396 struct addrinfo bindhints;
397 const char *err = NULL;
398 /* initialize tcp structure */
399 io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
400 (p_error) socket_ioerror, &tcp->sock);
401 timeout_init(&tcp->tm, -1, -1);
402 buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
403 tcp->sock = SOCKET_INVALID;
404 /* try binding to local address */
405 memset(&bindhints, 0, sizeof(bindhints));
406 bindhints.ai_socktype = SOCK_STREAM;
407 bindhints.ai_family = PF_UNSPEC;
408 bindhints.ai_flags = AI_PASSIVE;
409 err = trybind6(localaddr, localserv, &bindhints, tcp);
410 if (err == NULL) {
411 /* all server sockets initially with reuseaddr set */
412 int val = 1;
413 setsockopt(tcp->sock, SOL_SOCKET, SO_REUSEADDR,
414 (char *) &val, sizeof(val));
415 /* set the backlog and listen */
416 err = socket_strerror(socket_listen(&tcp->sock, backlog));
417 if (err) {
418 socket_destroy(&tcp->sock);
419 lua_pushnil(L);
420 lua_pushstring(L, err);
421 return 2;
422 }
423 auxiliar_setclass(L, "tcp{server}", -1);
424 return 1;
425 } else {
426 lua_pushnil(L);
427 lua_pushstring(L, err);
428 return 2;
429 }
430}
431
432static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
433 struct addrinfo *connecthints, p_tcp tcp) {
434 struct addrinfo *iterator = NULL, *resolved = NULL;
435 const char *err = NULL;
436 /* try resolving */
437 err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv,
438 connecthints, &resolved));
439 if (err != NULL) {
440 if (resolved) freeaddrinfo(resolved);
441 return err;
442 }
443 /* iterate over all returned addresses trying to connect */
444 for (iterator = resolved; iterator; iterator = iterator->ai_next) {
445 p_timeout tm = timeout_markstart(&tcp->tm);
446 /* create new socket if one wasn't created by the bind stage */
447 if (tcp->sock == SOCKET_INVALID) {
448 const char *err = socket_strerror(socket_create(&tcp->sock,
449 iterator->ai_family, iterator->ai_socktype,
450 iterator->ai_protocol));
451 if (err != NULL) {
452 freeaddrinfo(resolved);
453 return err;
454 }
455 /* all sockets initially non-blocking */
456 socket_setnonblocking(&tcp->sock);
457 }
458 /* finally try connecting to remote address */
459 err = socket_strerror(socket_connect(&tcp->sock,
460 (SA *) iterator->ai_addr,
461 iterator->ai_addrlen, tm));
462 /* if success, break out of loop */
463 if (err == NULL) break;
464 }
465
466 freeaddrinfo(resolved);
467 /* here, if err is set, we failed */
468 return err;
469}
470
471static int global_connect6(lua_State *L) {
472 const char *remoteaddr = luaL_checkstring(L, 1);
473 const char *remoteserv = luaL_checkstring(L, 2);
474 const char *localaddr = luaL_optstring(L, 3, NULL);
475 const char *localserv = luaL_optstring(L, 4, "0");
476 p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
477 struct addrinfo bindhints, connecthints;
478 const char *err = NULL;
479 /* initialize tcp structure */
480 io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
481 (p_error) socket_ioerror, &tcp->sock);
482 timeout_init(&tcp->tm, -1, -1);
483 buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
484 tcp->sock = SOCKET_INVALID;
485 /* allow user to pick local address and port */
486 memset(&bindhints, 0, sizeof(bindhints));
487 bindhints.ai_socktype = SOCK_STREAM;
488 bindhints.ai_family = PF_UNSPEC;
489 bindhints.ai_flags = AI_PASSIVE;
490 if (localaddr) {
491 err = trybind6(localaddr, localserv, &bindhints, tcp);
492 if (err) {
493 lua_pushnil(L);
494 lua_pushstring(L, err);
495 return 2;
496 }
497 }
498 /* try to connect to remote address and port */
499 memset(&connecthints, 0, sizeof(connecthints));
500 connecthints.ai_socktype = SOCK_STREAM;
501 /* make sure we try to connect only to the same family */
502 connecthints.ai_family = bindhints.ai_family;
503 err = tryconnect6(remoteaddr, remoteserv, &connecthints, tcp);
504 if (err) {
505 socket_destroy(&tcp->sock);
506 lua_pushnil(L);
507 lua_pushstring(L, err);
508 return 2;
509 }
510 auxiliar_setclass(L, "tcp{client}", -1);
511 return 1;
512}