static int inet_global_getaddrinfo(lua_State *L) { const char *hostname = luaL_checkstring(L, 1); struct addrinfo *iterator = NULL, *resolved = NULL; struct addrinfo hints; int i = 1, ret = 0; memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; ret = getaddrinfo(hostname, NULL, &hints, &resolved); if (ret != 0) { lua_pushnil(L); lua_pushstring(L, socket_gaistrerror(ret)); return 2; } lua_newtable(L); for (iterator = resolved; iterator; iterator = iterator->ai_next) { char hbuf[NI_MAXHOST]; ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST); if (ret){ freeaddrinfo(resolved); lua_pushnil(L); lua_pushstring(L, socket_gaistrerror(ret)); return 2; } lua_pushnumber(L, i); lua_newtable(L); switch (iterator->ai_family) { case AF_INET: lua_pushliteral(L, "family"); lua_pushliteral(L, "inet"); lua_settable(L, -3); break; case AF_INET6: lua_pushliteral(L, "family"); lua_pushliteral(L, "inet6"); lua_settable(L, -3); break; case AF_UNSPEC: lua_pushliteral(L, "family"); lua_pushliteral(L, "unspec"); lua_settable(L, -3); break; default: lua_pushliteral(L, "family"); lua_pushliteral(L, "unknown"); lua_settable(L, -3); break; } lua_pushliteral(L, "addr"); lua_pushstring(L, hbuf); lua_settable(L, -3); lua_settable(L, -3); i++; } freeaddrinfo(resolved); return 1; }
/*-------------------------------------------------------------------------*\ * Tries to connect to remote address (address, port) \*-------------------------------------------------------------------------*/ const char *inet_tryconnect(p_socket ps, int *family, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints) { #ifdef LUASOCKET_SECURITY_SANDBOX if (luasocket_ip_allowed(address)) return "connect restricted"; #endif // LUASOCKET_SECURITY_SANDBOX struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; int current_family = *family; /* try resolving */ err = socket_gaistrerror(getaddrinfo(address, serv, connecthints, &resolved)); if (err != NULL) { if (resolved) freeaddrinfo(resolved); return err; } for (iterator = resolved; iterator; iterator = iterator->ai_next) { timeout_markstart(tm); /* create new socket if necessary. if there was no * bind, we need to create one for every new family * that shows up while iterating. if there was a * bind, all families will be the same and we will * not enter this branch. */ if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { socket_destroy(ps); err = inet_trycreate(ps, iterator->ai_family, iterator->ai_socktype, iterator->ai_protocol); if (err) continue; current_family = iterator->ai_family; /* set non-blocking before connect */ socket_setnonblocking(ps); } /* try connecting to remote address */ err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen, tm)); /* if success or timeout is zero, break out of loop */ if (err == NULL || timeout_iszero(tm)) { *family = current_family; break; } } freeaddrinfo(resolved); /* here, if err is set, we failed */ return err; }
static int inet_global_getnameinfo(lua_State *L) { int i, ret; char host[1024]; char serv[32]; struct addrinfo hints; struct addrinfo *resolved, *iter; const char *node = luaL_optstring(L, 1, NULL); const char *service = luaL_optstring(L, 2, NULL); if (!(node || service)) luaL_error(L, "You have to specify a hostname, a service, or both"); memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = PF_UNSPEC; /* getaddrinfo must get a node and a service argument */ ret = getaddrinfo(node ? node : "127.0.0.1", service ? service : "7", &hints, &resolved); if (ret != 0) { lua_pushnil(L); lua_pushstring(L, socket_gaistrerror(ret)); return 2; } lua_newtable(L); for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) { getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, host, node ? (socklen_t) sizeof(host) : 0, serv, service ? (socklen_t) sizeof(serv) : 0, 0); if (node) { lua_pushnumber(L, i); lua_pushstring(L, host); lua_settable(L, -3); } } freeaddrinfo(resolved); if (service) { lua_pushstring(L, serv); return 2; } else { return 1; } }
static int inet_global_getnameinfo(lua_State *L) { char hbuf[NI_MAXHOST]; char sbuf[NI_MAXSERV]; int i, ret; struct addrinfo hints; struct addrinfo *resolved, *iter; const char *host = luaL_optstring(L, 1, NULL); const char *serv = luaL_optstring(L, 2, NULL); if (!(host || serv)) luaL_error(L, "host and serv cannot be both nil"); memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = PF_UNSPEC; ret = getaddrinfo(host, serv, &hints, &resolved); if (ret != 0) { lua_pushnil(L); lua_pushstring(L, socket_gaistrerror(ret)); return 2; } lua_newtable(L); for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) { getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, hbuf, host? (socklen_t) sizeof(hbuf): 0, sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0); if (host) { lua_pushnumber(L, i); lua_pushstring(L, hbuf); lua_settable(L, -3); } } freeaddrinfo(resolved); if (serv) { lua_pushstring(L, sbuf); return 2; } else { return 1; } }
/*-------------------------------------------------------------------------*\ * Tries to bind socket to (address, port) \*-------------------------------------------------------------------------*/ const char *inet_trybind(p_socket ps, const char *address, const char *serv, struct addrinfo *bindhints) { 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"; /* try resolving */ err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved)); if (err) { if (resolved) freeaddrinfo(resolved); return err; } /* 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(&sock, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen)); /* 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; }
/*-------------------------------------------------------------------------*\ * Tries to bind socket to (address, port) \*-------------------------------------------------------------------------*/ const char *inet_trybind(p_socket ps, int *family, const char *address, const char *serv, struct addrinfo *bindhints) { #ifdef LUASOCKET_SECURITY_SANDBOX if (luasocket_ip_allowed(address)) return "bind restricted"; #endif // LUASOCKET_SECURITY_SANDBOX struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; int current_family = *family; /* translate luasocket special values to C */ if (strcmp(address, "*") == 0) address = NULL; if (!serv) serv = "0"; /* try resolving */ err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved)); if (err) { if (resolved) freeaddrinfo(resolved); return err; } /* iterate over resolved addresses until one is good */ for (iterator = resolved; iterator; iterator = iterator->ai_next) { if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { socket_destroy(ps); err = inet_trycreate(ps, iterator->ai_family, iterator->ai_socktype, iterator->ai_protocol); if (err) continue; current_family = iterator->ai_family; } /* try binding to local address */ err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen)); /* keep trying unless bind succeeded */ if (err == NULL) { *family = current_family; /* set to non-blocking after bind */ socket_setnonblocking(ps); break; } } /* cleanup and return error */ freeaddrinfo(resolved); /* here, if err is set, we failed */ return err; }
/*-------------------------------------------------------------------------*\ * Tries to connect to remote address (address, port) \*-------------------------------------------------------------------------*/ const char *inet_tryconnect(p_socket ps, int *family, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints) { struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; /* try resolving */ err = socket_gaistrerror(getaddrinfo(address, serv, connecthints, &resolved)); if (err != NULL) { if (resolved) freeaddrinfo(resolved); return err; } for (iterator = resolved; iterator; iterator = iterator->ai_next) { timeout_markstart(tm); /* create new socket if necessary. if there was no * bind, we need to create one for every new family * that shows up while iterating. if there was a * bind, all families will be the same and we will * not enter this branch. */ if (*family != iterator->ai_family) { socket_destroy(ps); err = socket_strerror(socket_create(ps, iterator->ai_family, iterator->ai_socktype, iterator->ai_protocol)); if (err != NULL) { freeaddrinfo(resolved); return err; } *family = iterator->ai_family; /* all sockets initially non-blocking */ socket_setnonblocking(ps); } /* try connecting to remote address */ err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen, tm)); /* if success, break out of loop */ if (err == NULL) break; } freeaddrinfo(resolved); /* here, if err is set, we failed */ return err; }
static const char *tryconnect6(const char *remoteaddr, const char *remoteserv, struct addrinfo *connecthints, p_tcp tcp) { struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; /* try resolving */ err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv, connecthints, &resolved)); if (err != NULL) { if (resolved) freeaddrinfo(resolved); return err; } /* iterate over all returned addresses trying to connect */ for (iterator = resolved; iterator; iterator = iterator->ai_next) { p_timeout tm = timeout_markstart(&tcp->tm); /* create new socket if one wasn't created by the bind stage */ if (tcp->sock == SOCKET_INVALID) { err = socket_strerror(socket_create(&tcp->sock, iterator->ai_family, iterator->ai_socktype, iterator->ai_protocol)); if (err != NULL) { freeaddrinfo(resolved); return err; } tcp->family = iterator->ai_family; /* all sockets initially non-blocking */ socket_setnonblocking(&tcp->sock); } /* finally try connecting to remote address */ err = socket_strerror(socket_connect(&tcp->sock, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen, tm)); /* if success, break out of loop */ if (err == NULL) break; } freeaddrinfo(resolved); /* here, if err is set, we failed */ return err; }
/*-------------------------------------------------------------------------*\ * Tries to connect to remote address (address, port) \*-------------------------------------------------------------------------*/ const char *inet_tryconnect(p_socket ps, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints) { struct addrinfo *iterator = NULL, *resolved = NULL; const char *err = NULL; /* try resolving */ err = socket_gaistrerror(getaddrinfo(address, serv, connecthints, &resolved)); if (err != NULL) { if (resolved) freeaddrinfo(resolved); return err; } for (iterator = resolved; iterator; iterator = iterator->ai_next) { timeout_markstart(tm); /* try connecting to remote address */ err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, (socklen_t) iterator->ai_addrlen, tm)); /* if success, break out of loop */ if (err == NULL) break; } freeaddrinfo(resolved); /* here, if err is set, we failed */ return err; }