diff options
author | Diego Nehab <diego@impa.br> | 2015-08-22 19:52:01 -0300 |
---|---|---|
committer | Diego Nehab <diego@impa.br> | 2015-08-22 19:52:01 -0300 |
commit | 96965b179c7311f850f72a8629b9ba6d3a31d117 (patch) | |
tree | 05c93629654f686a99ee8923ef2361b7d2244ca8 /src/tcp.c | |
parent | b211838648c1cb092e96e3ae721932a212808d96 (diff) | |
download | luasocket-96965b179c7311f850f72a8629b9ba6d3a31d117.tar.gz luasocket-96965b179c7311f850f72a8629b9ba6d3a31d117.tar.bz2 luasocket-96965b179c7311f850f72a8629b9ba6d3a31d117.zip |
New agnostic IPv4 IPv6 functions.
Also dealing with EPROTOTYPE Yosemite seems to be throwing
at us for no reason.
Diffstat (limited to 'src/tcp.c')
-rw-r--r-- | src/tcp.c | 85 |
1 files changed, 25 insertions, 60 deletions
@@ -18,6 +18,7 @@ | |||
18 | * Internal function prototypes | 18 | * Internal function prototypes |
19 | \*=========================================================================*/ | 19 | \*=========================================================================*/ |
20 | static int global_create(lua_State *L); | 20 | static int global_create(lua_State *L); |
21 | static int global_create4(lua_State *L); | ||
21 | static int global_create6(lua_State *L); | 22 | static int global_create6(lua_State *L); |
22 | static int global_connect(lua_State *L); | 23 | static int global_connect(lua_State *L); |
23 | static int meth_connect(lua_State *L); | 24 | static int meth_connect(lua_State *L); |
@@ -90,6 +91,7 @@ static t_opt optset[] = { | |||
90 | /* functions in library namespace */ | 91 | /* functions in library namespace */ |
91 | static luaL_Reg func[] = { | 92 | static luaL_Reg func[] = { |
92 | {"tcp", global_create}, | 93 | {"tcp", global_create}, |
94 | {"tcp4", global_create4}, | ||
93 | {"tcp6", global_create6}, | 95 | {"tcp6", global_create6}, |
94 | {"connect", global_connect}, | 96 | {"connect", global_connect}, |
95 | {NULL, NULL} | 97 | {NULL, NULL} |
@@ -213,8 +215,7 @@ static int meth_accept(lua_State *L) | |||
213 | /*-------------------------------------------------------------------------*\ | 215 | /*-------------------------------------------------------------------------*\ |
214 | * Binds an object to an address | 216 | * Binds an object to an address |
215 | \*-------------------------------------------------------------------------*/ | 217 | \*-------------------------------------------------------------------------*/ |
216 | static int meth_bind(lua_State *L) | 218 | static int meth_bind(lua_State *L) { |
217 | { | ||
218 | p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); | 219 | p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); |
219 | const char *address = luaL_checkstring(L, 2); | 220 | const char *address = luaL_checkstring(L, 2); |
220 | const char *port = luaL_checkstring(L, 3); | 221 | const char *port = luaL_checkstring(L, 3); |
@@ -224,7 +225,7 @@ static int meth_bind(lua_State *L) | |||
224 | bindhints.ai_socktype = SOCK_STREAM; | 225 | bindhints.ai_socktype = SOCK_STREAM; |
225 | bindhints.ai_family = tcp->family; | 226 | bindhints.ai_family = tcp->family; |
226 | bindhints.ai_flags = AI_PASSIVE; | 227 | bindhints.ai_flags = AI_PASSIVE; |
227 | err = inet_trybind(&tcp->sock, address, port, &bindhints); | 228 | err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints); |
228 | if (err) { | 229 | if (err) { |
229 | lua_pushnil(L); | 230 | lua_pushnil(L); |
230 | lua_pushstring(L, err); | 231 | lua_pushstring(L, err); |
@@ -237,8 +238,7 @@ static int meth_bind(lua_State *L) | |||
237 | /*-------------------------------------------------------------------------*\ | 238 | /*-------------------------------------------------------------------------*\ |
238 | * Turns a master tcp object into a client object. | 239 | * Turns a master tcp object into a client object. |
239 | \*-------------------------------------------------------------------------*/ | 240 | \*-------------------------------------------------------------------------*/ |
240 | static int meth_connect(lua_State *L) | 241 | static int meth_connect(lua_State *L) { |
241 | { | ||
242 | p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); | 242 | p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); |
243 | const char *address = luaL_checkstring(L, 2); | 243 | const char *address = luaL_checkstring(L, 2); |
244 | const char *port = luaL_checkstring(L, 3); | 244 | const char *port = luaL_checkstring(L, 3); |
@@ -249,7 +249,7 @@ static int meth_connect(lua_State *L) | |||
249 | /* make sure we try to connect only to the same family */ | 249 | /* make sure we try to connect only to the same family */ |
250 | connecthints.ai_family = tcp->family; | 250 | connecthints.ai_family = tcp->family; |
251 | timeout_markstart(&tcp->tm); | 251 | timeout_markstart(&tcp->tm); |
252 | err = inet_tryconnect(&tcp->sock, &tcp->family, address, port, | 252 | err = inet_tryconnect(&tcp->sock, &tcp->family, address, port, |
253 | &tcp->tm, &connecthints); | 253 | &tcp->tm, &connecthints); |
254 | /* have to set the class even if it failed due to non-blocking connects */ | 254 | /* have to set the class even if it failed due to non-blocking connects */ |
255 | auxiliar_setclass(L, "tcp{client}", 1); | 255 | auxiliar_setclass(L, "tcp{client}", 1); |
@@ -279,9 +279,12 @@ static int meth_close(lua_State *L) | |||
279 | static int meth_getfamily(lua_State *L) | 279 | static int meth_getfamily(lua_State *L) |
280 | { | 280 | { |
281 | p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); | 281 | p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); |
282 | if (tcp->family == PF_INET6) { | 282 | if (tcp->family == AF_INET6) { |
283 | lua_pushliteral(L, "inet6"); | 283 | lua_pushliteral(L, "inet6"); |
284 | return 1; | 284 | return 1; |
285 | } else if (tcp->family == AF_INET) { | ||
286 | lua_pushliteral(L, "inet4"); | ||
287 | return 1; | ||
285 | } else { | 288 | } else { |
286 | lua_pushliteral(L, "inet4"); | 289 | lua_pushliteral(L, "inet4"); |
287 | return 1; | 290 | return 1; |
@@ -353,7 +356,12 @@ static int meth_settimeout(lua_State *L) | |||
353 | \*-------------------------------------------------------------------------*/ | 356 | \*-------------------------------------------------------------------------*/ |
354 | static int tcp_create(lua_State *L, int family) { | 357 | static int tcp_create(lua_State *L, int family) { |
355 | t_socket sock; | 358 | t_socket sock; |
356 | const char *err = inet_trycreate(&sock, family, SOCK_STREAM); | 359 | /* if family is AF_UNSPEC, we create an AF_INET socket |
360 | * but store AF_UNSPEC into tcp-family. This will allow it | ||
361 | * later be replaced with an AF_INET6 socket if | ||
362 | * trybind or tryconnect prefer it instead. */ | ||
363 | const char *err = inet_trycreate(&sock, family == AF_UNSPEC? | ||
364 | AF_INET: family, SOCK_STREAM); | ||
357 | /* try to allocate a system socket */ | 365 | /* try to allocate a system socket */ |
358 | if (!err) { | 366 | if (!err) { |
359 | /* allocate tcp object */ | 367 | /* allocate tcp object */ |
@@ -363,7 +371,7 @@ static int tcp_create(lua_State *L, int family) { | |||
363 | auxiliar_setclass(L, "tcp{master}", -1); | 371 | auxiliar_setclass(L, "tcp{master}", -1); |
364 | /* initialize remaining structure fields */ | 372 | /* initialize remaining structure fields */ |
365 | socket_setnonblocking(&sock); | 373 | socket_setnonblocking(&sock); |
366 | if (family == PF_INET6) { | 374 | if (family == AF_INET6) { |
367 | int yes = 1; | 375 | int yes = 1; |
368 | setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, | 376 | setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, |
369 | (void *)&yes, sizeof(yes)); | 377 | (void *)&yes, sizeof(yes)); |
@@ -383,6 +391,10 @@ static int tcp_create(lua_State *L, int family) { | |||
383 | } | 391 | } |
384 | 392 | ||
385 | static int global_create(lua_State *L) { | 393 | static int global_create(lua_State *L) { |
394 | return tcp_create(L, AF_UNSPEC); | ||
395 | } | ||
396 | |||
397 | static int global_create4(lua_State *L) { | ||
386 | return tcp_create(L, AF_INET); | 398 | return tcp_create(L, AF_INET); |
387 | } | 399 | } |
388 | 400 | ||
@@ -390,53 +402,6 @@ static int global_create6(lua_State *L) { | |||
390 | return tcp_create(L, AF_INET6); | 402 | return tcp_create(L, AF_INET6); |
391 | } | 403 | } |
392 | 404 | ||
393 | #if 0 | ||
394 | static const char *tryconnect6(const char *remoteaddr, const char *remoteserv, | ||
395 | struct addrinfo *connecthints, p_tcp tcp) { | ||
396 | struct addrinfo *iterator = NULL, *resolved = NULL; | ||
397 | const char *err = NULL; | ||
398 | /* try resolving */ | ||
399 | err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv, | ||
400 | connecthints, &resolved)); | ||
401 | if (err != NULL) { | ||
402 | if (resolved) freeaddrinfo(resolved); | ||
403 | return err; | ||
404 | } | ||
405 | /* iterate over all returned addresses trying to connect */ | ||
406 | for (iterator = resolved; iterator; iterator = iterator->ai_next) { | ||
407 | p_timeout tm = timeout_markstart(&tcp->tm); | ||
408 | /* create new socket if necessary. if there was no | ||
409 | * bind, we need to create one for every new family | ||
410 | * that shows up while iterating. if there was a | ||
411 | * bind, all families will be the same and we will | ||
412 | * not enter this branch. */ | ||
413 | if (tcp->family != iterator->ai_family) { | ||
414 | socket_destroy(&tcp->sock); | ||
415 | err = socket_strerror(socket_create(&tcp->sock, | ||
416 | iterator->ai_family, iterator->ai_socktype, | ||
417 | iterator->ai_protocol)); | ||
418 | if (err != NULL) { | ||
419 | freeaddrinfo(resolved); | ||
420 | return err; | ||
421 | } | ||
422 | tcp->family = iterator->ai_family; | ||
423 | /* all sockets initially non-blocking */ | ||
424 | socket_setnonblocking(&tcp->sock); | ||
425 | } | ||
426 | /* finally try connecting to remote address */ | ||
427 | err = socket_strerror(socket_connect(&tcp->sock, | ||
428 | (SA *) iterator->ai_addr, | ||
429 | (socklen_t) iterator->ai_addrlen, tm)); | ||
430 | /* if success, break out of loop */ | ||
431 | if (err == NULL) break; | ||
432 | } | ||
433 | |||
434 | freeaddrinfo(resolved); | ||
435 | /* here, if err is set, we failed */ | ||
436 | return err; | ||
437 | } | ||
438 | #endif | ||
439 | |||
440 | static int global_connect(lua_State *L) { | 405 | static int global_connect(lua_State *L) { |
441 | const char *remoteaddr = luaL_checkstring(L, 1); | 406 | const char *remoteaddr = luaL_checkstring(L, 1); |
442 | const char *remoteserv = luaL_checkstring(L, 2); | 407 | const char *remoteserv = luaL_checkstring(L, 2); |
@@ -453,26 +418,26 @@ static int global_connect(lua_State *L) { | |||
453 | timeout_init(&tcp->tm, -1, -1); | 418 | timeout_init(&tcp->tm, -1, -1); |
454 | buffer_init(&tcp->buf, &tcp->io, &tcp->tm); | 419 | buffer_init(&tcp->buf, &tcp->io, &tcp->tm); |
455 | tcp->sock = SOCKET_INVALID; | 420 | tcp->sock = SOCKET_INVALID; |
456 | tcp->family = PF_UNSPEC; | 421 | tcp->family = AF_UNSPEC; |
457 | /* allow user to pick local address and port */ | 422 | /* allow user to pick local address and port */ |
458 | memset(&bindhints, 0, sizeof(bindhints)); | 423 | memset(&bindhints, 0, sizeof(bindhints)); |
459 | bindhints.ai_socktype = SOCK_STREAM; | 424 | bindhints.ai_socktype = SOCK_STREAM; |
460 | bindhints.ai_family = family; | 425 | bindhints.ai_family = family; |
461 | bindhints.ai_flags = AI_PASSIVE; | 426 | bindhints.ai_flags = AI_PASSIVE; |
462 | if (localaddr) { | 427 | if (localaddr) { |
463 | err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints); | 428 | err = inet_trybind(&tcp->sock, &tcp->family, localaddr, |
429 | localserv, &bindhints); | ||
464 | if (err) { | 430 | if (err) { |
465 | lua_pushnil(L); | 431 | lua_pushnil(L); |
466 | lua_pushstring(L, err); | 432 | lua_pushstring(L, err); |
467 | return 2; | 433 | return 2; |
468 | } | 434 | } |
469 | tcp->family = bindhints.ai_family; | ||
470 | } | 435 | } |
471 | /* try to connect to remote address and port */ | 436 | /* try to connect to remote address and port */ |
472 | memset(&connecthints, 0, sizeof(connecthints)); | 437 | memset(&connecthints, 0, sizeof(connecthints)); |
473 | connecthints.ai_socktype = SOCK_STREAM; | 438 | connecthints.ai_socktype = SOCK_STREAM; |
474 | /* make sure we try to connect only to the same family */ | 439 | /* make sure we try to connect only to the same family */ |
475 | connecthints.ai_family = bindhints.ai_family; | 440 | connecthints.ai_family = tcp->family; |
476 | err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv, | 441 | err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv, |
477 | &tcp->tm, &connecthints); | 442 | &tcp->tm, &connecthints); |
478 | if (err) { | 443 | if (err) { |