diff options
Diffstat (limited to 'src/inet.c')
-rw-r--r-- | src/inet.c | 145 |
1 files changed, 77 insertions, 68 deletions
@@ -94,7 +94,7 @@ static int inet_global_getnameinfo(lua_State *L) { | |||
94 | 94 | ||
95 | memset(&hints, 0, sizeof(hints)); | 95 | memset(&hints, 0, sizeof(hints)); |
96 | hints.ai_socktype = SOCK_STREAM; | 96 | hints.ai_socktype = SOCK_STREAM; |
97 | hints.ai_family = PF_UNSPEC; | 97 | hints.ai_family = AF_UNSPEC; |
98 | 98 | ||
99 | ret = getaddrinfo(host, serv, &hints, &resolved); | 99 | ret = getaddrinfo(host, serv, &hints, &resolved); |
100 | if (ret != 0) { | 100 | if (ret != 0) { |
@@ -105,8 +105,8 @@ static int inet_global_getnameinfo(lua_State *L) { | |||
105 | 105 | ||
106 | lua_newtable(L); | 106 | lua_newtable(L); |
107 | for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) { | 107 | for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) { |
108 | getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, | 108 | getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, |
109 | hbuf, host? (socklen_t) sizeof(hbuf): 0, | 109 | hbuf, host? (socklen_t) sizeof(hbuf): 0, |
110 | sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0); | 110 | sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0); |
111 | if (host) { | 111 | if (host) { |
112 | lua_pushnumber(L, i); | 112 | lua_pushnumber(L, i); |
@@ -146,7 +146,7 @@ static int inet_global_toip(lua_State *L) | |||
146 | int inet_optfamily(lua_State* L, int narg, const char* def) | 146 | int inet_optfamily(lua_State* L, int narg, const char* def) |
147 | { | 147 | { |
148 | static const char* optname[] = { "unspec", "inet", "inet6", NULL }; | 148 | static const char* optname[] = { "unspec", "inet", "inet6", NULL }; |
149 | static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 }; | 149 | static int optvalue[] = { AF_UNSPEC, AF_INET, AF_INET6, 0 }; |
150 | 150 | ||
151 | return optvalue[luaL_checkoption(L, narg, def, optname)]; | 151 | return optvalue[luaL_checkoption(L, narg, def, optname)]; |
152 | } | 152 | } |
@@ -167,7 +167,7 @@ static int inet_global_getaddrinfo(lua_State *L) | |||
167 | int i = 1, ret = 0; | 167 | int i = 1, ret = 0; |
168 | memset(&hints, 0, sizeof(hints)); | 168 | memset(&hints, 0, sizeof(hints)); |
169 | hints.ai_socktype = SOCK_STREAM; | 169 | hints.ai_socktype = SOCK_STREAM; |
170 | hints.ai_family = PF_UNSPEC; | 170 | hints.ai_family = AF_UNSPEC; |
171 | ret = getaddrinfo(hostname, NULL, &hints, &resolved); | 171 | ret = getaddrinfo(hostname, NULL, &hints, &resolved); |
172 | if (ret != 0) { | 172 | if (ret != 0) { |
173 | lua_pushnil(L); | 173 | lua_pushnil(L); |
@@ -177,7 +177,7 @@ static int inet_global_getaddrinfo(lua_State *L) | |||
177 | lua_newtable(L); | 177 | lua_newtable(L); |
178 | for (iterator = resolved; iterator; iterator = iterator->ai_next) { | 178 | for (iterator = resolved; iterator; iterator = iterator->ai_next) { |
179 | char hbuf[NI_MAXHOST]; | 179 | char hbuf[NI_MAXHOST]; |
180 | ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, | 180 | ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, |
181 | hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST); | 181 | hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST); |
182 | if (ret){ | 182 | if (ret){ |
183 | freeaddrinfo(resolved); | 183 | freeaddrinfo(resolved); |
@@ -198,6 +198,16 @@ static int inet_global_getaddrinfo(lua_State *L) | |||
198 | lua_pushliteral(L, "inet6"); | 198 | lua_pushliteral(L, "inet6"); |
199 | lua_settable(L, -3); | 199 | lua_settable(L, -3); |
200 | break; | 200 | break; |
201 | case AF_UNSPEC: | ||
202 | lua_pushliteral(L, "family"); | ||
203 | lua_pushliteral(L, "unspec"); | ||
204 | lua_settable(L, -3); | ||
205 | break; | ||
206 | default: | ||
207 | lua_pushliteral(L, "family"); | ||
208 | lua_pushliteral(L, "unknown"); | ||
209 | lua_settable(L, -3); | ||
210 | break; | ||
201 | } | 211 | } |
202 | lua_pushliteral(L, "addr"); | 212 | lua_pushliteral(L, "addr"); |
203 | lua_pushstring(L, hbuf); | 213 | lua_pushstring(L, hbuf); |
@@ -254,12 +264,11 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family) | |||
254 | } | 264 | } |
255 | lua_pushstring(L, name); | 265 | lua_pushstring(L, name); |
256 | lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10)); | 266 | lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10)); |
257 | if (family == PF_INET) { | 267 | switch (family) { |
258 | lua_pushliteral(L, "inet"); | 268 | case AF_INET: lua_pushliteral(L, "inet"); break; |
259 | } else if (family == PF_INET6) { | 269 | case AF_INET6: lua_pushliteral(L, "inet6"); break; |
260 | lua_pushliteral(L, "inet6"); | 270 | case AF_UNSPEC: lua_pushliteral(L, "unspec"); break; |
261 | } else { | 271 | default: lua_pushliteral(L, "unknown"); break; |
262 | lua_pushliteral(L, "uknown family"); | ||
263 | } | 272 | } |
264 | return 3; | 273 | return 3; |
265 | } | 274 | } |
@@ -279,7 +288,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family) | |||
279 | lua_pushstring(L, socket_strerror(errno)); | 288 | lua_pushstring(L, socket_strerror(errno)); |
280 | return 2; | 289 | return 2; |
281 | } | 290 | } |
282 | err=getnameinfo((struct sockaddr *)&peer, peer_len, | 291 | err=getnameinfo((struct sockaddr *)&peer, peer_len, |
283 | name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV); | 292 | name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV); |
284 | if (err) { | 293 | if (err) { |
285 | lua_pushnil(L); | 294 | lua_pushnil(L); |
@@ -288,12 +297,11 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family) | |||
288 | } | 297 | } |
289 | lua_pushstring(L, name); | 298 | lua_pushstring(L, name); |
290 | lua_pushstring(L, port); | 299 | lua_pushstring(L, port); |
291 | if (family == PF_INET) { | 300 | switch (family) { |
292 | lua_pushliteral(L, "inet"); | 301 | case AF_INET: lua_pushliteral(L, "inet"); break; |
293 | } else if (family == PF_INET6) { | 302 | case AF_INET6: lua_pushliteral(L, "inet6"); break; |
294 | lua_pushliteral(L, "inet6"); | 303 | case AF_UNSPEC: lua_pushliteral(L, "unspec"); break; |
295 | } else { | 304 | default: lua_pushliteral(L, "unknown"); break; |
296 | lua_pushliteral(L, "uknown family"); | ||
297 | } | 305 | } |
298 | return 3; | 306 | return 3; |
299 | } | 307 | } |
@@ -344,8 +352,13 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp) | |||
344 | /*-------------------------------------------------------------------------*\ | 352 | /*-------------------------------------------------------------------------*\ |
345 | * Tries to create a new inet socket | 353 | * Tries to create a new inet socket |
346 | \*-------------------------------------------------------------------------*/ | 354 | \*-------------------------------------------------------------------------*/ |
347 | const char *inet_trycreate(p_socket ps, int family, int type) { | 355 | const char *inet_trycreate(p_socket ps, int family, int type, int protocol) { |
348 | return socket_strerror(socket_create(ps, family, type, 0)); | 356 | const char *err = socket_strerror(socket_create(ps, family, type, protocol)); |
357 | if (err == NULL && family == AF_INET6) { | ||
358 | int yes = 1; | ||
359 | setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes)); | ||
360 | } | ||
361 | return err; | ||
349 | } | 362 | } |
350 | 363 | ||
351 | /*-------------------------------------------------------------------------*\ | 364 | /*-------------------------------------------------------------------------*\ |
@@ -354,21 +367,21 @@ const char *inet_trycreate(p_socket ps, int family, int type) { | |||
354 | const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm) | 367 | const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm) |
355 | { | 368 | { |
356 | switch (family) { | 369 | switch (family) { |
357 | case PF_INET: { | 370 | case AF_INET: { |
358 | struct sockaddr_in sin; | 371 | struct sockaddr_in sin; |
359 | memset((char *) &sin, 0, sizeof(sin)); | 372 | memset((char *) &sin, 0, sizeof(sin)); |
360 | sin.sin_family = AF_UNSPEC; | 373 | sin.sin_family = AF_UNSPEC; |
361 | sin.sin_addr.s_addr = INADDR_ANY; | 374 | sin.sin_addr.s_addr = INADDR_ANY; |
362 | return socket_strerror(socket_connect(ps, (SA *) &sin, | 375 | return socket_strerror(socket_connect(ps, (SA *) &sin, |
363 | sizeof(sin), tm)); | 376 | sizeof(sin), tm)); |
364 | } | 377 | } |
365 | case PF_INET6: { | 378 | case AF_INET6: { |
366 | struct sockaddr_in6 sin6; | 379 | struct sockaddr_in6 sin6; |
367 | struct in6_addr addrany = IN6ADDR_ANY_INIT; | 380 | struct in6_addr addrany = IN6ADDR_ANY_INIT; |
368 | memset((char *) &sin6, 0, sizeof(sin6)); | 381 | memset((char *) &sin6, 0, sizeof(sin6)); |
369 | sin6.sin6_family = AF_UNSPEC; | 382 | sin6.sin6_family = AF_UNSPEC; |
370 | sin6.sin6_addr = addrany; | 383 | sin6.sin6_addr = addrany; |
371 | return socket_strerror(socket_connect(ps, (SA *) &sin6, | 384 | return socket_strerror(socket_connect(ps, (SA *) &sin6, |
372 | sizeof(sin6), tm)); | 385 | sizeof(sin6), tm)); |
373 | } | 386 | } |
374 | } | 387 | } |
@@ -383,6 +396,7 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address, | |||
383 | { | 396 | { |
384 | struct addrinfo *iterator = NULL, *resolved = NULL; | 397 | struct addrinfo *iterator = NULL, *resolved = NULL; |
385 | const char *err = NULL; | 398 | const char *err = NULL; |
399 | int current_family = *family; | ||
386 | /* try resolving */ | 400 | /* try resolving */ |
387 | err = socket_gaistrerror(getaddrinfo(address, serv, | 401 | err = socket_gaistrerror(getaddrinfo(address, serv, |
388 | connecthints, &resolved)); | 402 | connecthints, &resolved)); |
@@ -397,23 +411,23 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address, | |||
397 | * that shows up while iterating. if there was a | 411 | * that shows up while iterating. if there was a |
398 | * bind, all families will be the same and we will | 412 | * bind, all families will be the same and we will |
399 | * not enter this branch. */ | 413 | * not enter this branch. */ |
400 | if (*family != iterator->ai_family) { | 414 | if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { |
401 | socket_destroy(ps); | 415 | socket_destroy(ps); |
402 | err = socket_strerror(socket_create(ps, iterator->ai_family, | 416 | err = inet_trycreate(ps, iterator->ai_family, |
403 | iterator->ai_socktype, iterator->ai_protocol)); | 417 | iterator->ai_socktype, iterator->ai_protocol); |
404 | if (err != NULL) { | 418 | if (err) continue; |
405 | freeaddrinfo(resolved); | 419 | current_family = iterator->ai_family; |
406 | return err; | 420 | /* set non-blocking before connect */ |
407 | } | ||
408 | *family = iterator->ai_family; | ||
409 | /* all sockets initially non-blocking */ | ||
410 | socket_setnonblocking(ps); | 421 | socket_setnonblocking(ps); |
411 | } | 422 | } |
412 | /* try connecting to remote address */ | 423 | /* try connecting to remote address */ |
413 | err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, | 424 | err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, |
414 | (socklen_t) iterator->ai_addrlen, tm)); | 425 | (socklen_t) iterator->ai_addrlen, tm)); |
415 | /* if success, break out of loop */ | 426 | /* if success, break out of loop */ |
416 | if (err == NULL) break; | 427 | if (err == NULL) { |
428 | *family = current_family; | ||
429 | break; | ||
430 | } | ||
417 | } | 431 | } |
418 | freeaddrinfo(resolved); | 432 | freeaddrinfo(resolved); |
419 | /* here, if err is set, we failed */ | 433 | /* here, if err is set, we failed */ |
@@ -423,29 +437,27 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address, | |||
423 | /*-------------------------------------------------------------------------*\ | 437 | /*-------------------------------------------------------------------------*\ |
424 | * Tries to accept a socket | 438 | * Tries to accept a socket |
425 | \*-------------------------------------------------------------------------*/ | 439 | \*-------------------------------------------------------------------------*/ |
426 | const char *inet_tryaccept(p_socket server, int family, p_socket client, | 440 | const char *inet_tryaccept(p_socket server, int family, p_socket client, |
427 | p_timeout tm) | 441 | p_timeout tm) { |
428 | { | ||
429 | socklen_t len; | 442 | socklen_t len; |
430 | t_sockaddr_storage addr; | 443 | t_sockaddr_storage addr; |
431 | if (family == PF_INET6) { | 444 | switch (family) { |
432 | len = sizeof(struct sockaddr_in6); | 445 | case AF_INET6: len = sizeof(struct sockaddr_in6); break; |
433 | } else { | 446 | case AF_INET: len = sizeof(struct sockaddr_in); break; |
434 | len = sizeof(struct sockaddr_in); | 447 | default: len = sizeof(addr); break; |
435 | } | 448 | } |
436 | return socket_strerror(socket_accept(server, client, (SA *) &addr, | 449 | return socket_strerror(socket_accept(server, client, (SA *) &addr, |
437 | &len, tm)); | 450 | &len, tm)); |
438 | } | 451 | } |
439 | 452 | ||
440 | /*-------------------------------------------------------------------------*\ | 453 | /*-------------------------------------------------------------------------*\ |
441 | * Tries to bind socket to (address, port) | 454 | * Tries to bind socket to (address, port) |
442 | \*-------------------------------------------------------------------------*/ | 455 | \*-------------------------------------------------------------------------*/ |
443 | const char *inet_trybind(p_socket ps, const char *address, const char *serv, | 456 | const char *inet_trybind(p_socket ps, int *family, const char *address, |
444 | struct addrinfo *bindhints) | 457 | const char *serv, struct addrinfo *bindhints) { |
445 | { | ||
446 | struct addrinfo *iterator = NULL, *resolved = NULL; | 458 | struct addrinfo *iterator = NULL, *resolved = NULL; |
447 | const char *err = NULL; | 459 | const char *err = NULL; |
448 | t_socket sock = *ps; | 460 | int current_family = *family; |
449 | /* translate luasocket special values to C */ | 461 | /* translate luasocket special values to C */ |
450 | if (strcmp(address, "*") == 0) address = NULL; | 462 | if (strcmp(address, "*") == 0) address = NULL; |
451 | if (!serv) serv = "0"; | 463 | if (!serv) serv = "0"; |
@@ -457,35 +469,32 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv, | |||
457 | } | 469 | } |
458 | /* iterate over resolved addresses until one is good */ | 470 | /* iterate over resolved addresses until one is good */ |
459 | for (iterator = resolved; iterator; iterator = iterator->ai_next) { | 471 | for (iterator = resolved; iterator; iterator = iterator->ai_next) { |
460 | if(sock == SOCKET_INVALID) { | 472 | if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { |
461 | err = socket_strerror(socket_create(&sock, iterator->ai_family, | 473 | socket_destroy(ps); |
462 | iterator->ai_socktype, iterator->ai_protocol)); | 474 | err = inet_trycreate(ps, iterator->ai_family, |
463 | if(err) | 475 | iterator->ai_socktype, iterator->ai_protocol); |
464 | continue; | 476 | if (err) continue; |
477 | current_family = iterator->ai_family; | ||
465 | } | 478 | } |
466 | /* try binding to local address */ | 479 | /* try binding to local address */ |
467 | err = socket_strerror(socket_bind(&sock, | 480 | err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr, |
468 | (SA *) iterator->ai_addr, | ||
469 | (socklen_t) iterator->ai_addrlen)); | 481 | (socklen_t) iterator->ai_addrlen)); |
470 | |||
471 | /* keep trying unless bind succeeded */ | 482 | /* keep trying unless bind succeeded */ |
472 | if (err) { | 483 | if (err == NULL) { |
473 | if(sock != *ps) | 484 | *family = current_family; |
474 | socket_destroy(&sock); | 485 | /* set to non-blocking after bind */ |
475 | } else { | 486 | socket_setnonblocking(ps); |
476 | /* remember what we connected to, particularly the family */ | ||
477 | *bindhints = *iterator; | ||
478 | break; | 487 | break; |
479 | } | 488 | } |
480 | } | 489 | } |
481 | /* cleanup and return error */ | 490 | /* cleanup and return error */ |
482 | freeaddrinfo(resolved); | 491 | freeaddrinfo(resolved); |
483 | *ps = sock; | 492 | /* here, if err is set, we failed */ |
484 | return err; | 493 | return err; |
485 | } | 494 | } |
486 | 495 | ||
487 | /*-------------------------------------------------------------------------*\ | 496 | /*-------------------------------------------------------------------------*\ |
488 | * Some systems do not provide these so that we provide our own. | 497 | * Some systems do not provide these so that we provide our own. |
489 | \*-------------------------------------------------------------------------*/ | 498 | \*-------------------------------------------------------------------------*/ |
490 | #ifdef LUASOCKET_INET_ATON | 499 | #ifdef LUASOCKET_INET_ATON |
491 | int inet_aton(const char *cp, struct in_addr *inp) | 500 | int inet_aton(const char *cp, struct in_addr *inp) |
@@ -510,7 +519,7 @@ int inet_aton(const char *cp, struct in_addr *inp) | |||
510 | #endif | 519 | #endif |
511 | 520 | ||
512 | #ifdef LUASOCKET_INET_PTON | 521 | #ifdef LUASOCKET_INET_PTON |
513 | int inet_pton(int af, const char *src, void *dst) | 522 | int inet_pton(int af, const char *src, void *dst) |
514 | { | 523 | { |
515 | struct addrinfo hints, *res; | 524 | struct addrinfo hints, *res; |
516 | int ret = 1; | 525 | int ret = 1; |
@@ -527,7 +536,7 @@ int inet_pton(int af, const char *src, void *dst) | |||
527 | } else { | 536 | } else { |
528 | ret = -1; | 537 | ret = -1; |
529 | } | 538 | } |
530 | freeaddrinfo(res); | 539 | freeaddrinfo(res); |
531 | return ret; | 540 | return ret; |
532 | } | 541 | } |
533 | 542 | ||