545 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			545 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*=========================================================================*\
 | |
| * Internet domain functions
 | |
| * LuaSocket toolkit
 | |
| \*=========================================================================*/
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include "lua.h"
 | |
| #include "lauxlib.h"
 | |
| 
 | |
| #include "inet.h"
 | |
| 
 | |
|  #ifdef _WIN32
 | |
| #define gai_strerror gai_strerrorA
 | |
| #endif
 | |
| 
 | |
| namespace NS_SLUA {
 | |
| 
 | |
| /*=========================================================================*\
 | |
| * Internal function prototypes.
 | |
| \*=========================================================================*/
 | |
| static int inet_global_toip(lua_State *L);
 | |
| static int inet_global_getaddrinfo(lua_State *L);
 | |
| static int inet_global_tohostname(lua_State *L);
 | |
| static int inet_global_getnameinfo(lua_State *L);
 | |
| static void inet_pushresolved(lua_State *L, struct hostent *hp);
 | |
| static int inet_global_gethostname(lua_State *L);
 | |
| 
 | |
| /* DNS functions */
 | |
| static luaL_Reg inet_func[] = {
 | |
|     { "toip", inet_global_toip},
 | |
|     { "getaddrinfo", inet_global_getaddrinfo},
 | |
|     { "tohostname", inet_global_tohostname},
 | |
|     { "getnameinfo", inet_global_getnameinfo},
 | |
|     { "gethostname", inet_global_gethostname},
 | |
|     { NULL, NULL}
 | |
| };
 | |
| 
 | |
| /*=========================================================================*\
 | |
| * Exported functions
 | |
| \*=========================================================================*/
 | |
| /*-------------------------------------------------------------------------*\
 | |
| * Initializes module
 | |
| \*-------------------------------------------------------------------------*/
 | |
| int inet_open(lua_State *L)
 | |
| {
 | |
|     lua_pushstring(L, "dns");
 | |
|     lua_newtable(L);
 | |
| #if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
 | |
|     luaL_setfuncs(L, inet_func, 0);
 | |
| #else
 | |
|     luaL_openlib(L, NULL, inet_func, 0);
 | |
| #endif
 | |
|     lua_settable(L, -3);
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /*=========================================================================*\
 | |
| * Global Lua functions
 | |
| \*=========================================================================*/
 | |
| /*-------------------------------------------------------------------------*\
 | |
| * Returns all information provided by the resolver given a host name
 | |
| * or ip address
 | |
| \*-------------------------------------------------------------------------*/
 | |
| static int inet_gethost(const char *address, struct hostent **hp) {
 | |
|     struct in_addr addr;
 | |
|     if (inet_aton(address, &addr))
 | |
|         return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
 | |
|     else
 | |
|         return socket_gethostbyname(address, hp);
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*\
 | |
| * Returns all information provided by the resolver given a host name
 | |
| * or ip address
 | |
| \*-------------------------------------------------------------------------*/
 | |
| static int inet_global_tohostname(lua_State *L) {
 | |
|     const char *address = luaL_checkstring(L, 1);
 | |
|     struct hostent *hp = NULL;
 | |
|     int err = inet_gethost(address, &hp);
 | |
|     if (err != IO_DONE) {
 | |
|         lua_pushnil(L);
 | |
|         lua_pushstring(L, socket_hoststrerror(err));
 | |
|         return 2;
 | |
|     }
 | |
|     lua_pushstring(L, hp->h_name);
 | |
|     inet_pushresolved(L, hp);
 | |
|     return 2;
 | |
| }
 | |
| 
 | |
| 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;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*\
 | |
| * Returns all information provided by the resolver given a host name
 | |
| * or ip address
 | |
| \*-------------------------------------------------------------------------*/
 | |
| static int inet_global_toip(lua_State *L)
 | |
| {
 | |
|     const char *address = luaL_checkstring(L, 1);
 | |
|     struct hostent *hp = NULL;
 | |
|     int err = inet_gethost(address, &hp);
 | |
|     if (err != IO_DONE) {
 | |
|         lua_pushnil(L);
 | |
|         lua_pushstring(L, socket_hoststrerror(err));
 | |
|         return 2;
 | |
|     }
 | |
|     lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr)));
 | |
|     inet_pushresolved(L, hp);
 | |
|     return 2;
 | |
| }
 | |
| 
 | |
| int inet_optfamily(lua_State* L, int narg, const char* def)
 | |
| {
 | |
|     static const char* optname[] = { "unspec", "inet", "inet6", NULL };
 | |
|     static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 };
 | |
| 
 | |
|     return optvalue[luaL_checkoption(L, narg, def, optname)];
 | |
| }
 | |
| 
 | |
| int inet_optsocktype(lua_State* L, int narg, const char* def)
 | |
| {
 | |
|     static const char* optname[] = { "stream", "dgram", NULL };
 | |
|     static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 };
 | |
| 
 | |
|     return optvalue[luaL_checkoption(L, narg, def, optname)];
 | |
| }
 | |
| 
 | |
| 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 = PF_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){
 | |
|           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;
 | |
|         }
 | |
|         lua_pushliteral(L, "addr");
 | |
|         lua_pushstring(L, hbuf);
 | |
|         lua_settable(L, -3);
 | |
|         lua_settable(L, -3);
 | |
|         i++;
 | |
|     }
 | |
|     freeaddrinfo(resolved);
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*\
 | |
| * Gets the host name
 | |
| \*-------------------------------------------------------------------------*/
 | |
| static int inet_global_gethostname(lua_State *L)
 | |
| {
 | |
|     char name[257];
 | |
|     name[256] = '\0';
 | |
|     if (gethostname(name, 256) < 0) {
 | |
|         lua_pushnil(L);
 | |
|         lua_pushstring(L, socket_strerror(errno));
 | |
|         return 2;
 | |
|     } else {
 | |
|         lua_pushstring(L, name);
 | |
|         return 1;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*=========================================================================*\
 | |
| * Lua methods
 | |
| \*=========================================================================*/
 | |
| /*-------------------------------------------------------------------------*\
 | |
| * Retrieves socket peer name
 | |
| \*-------------------------------------------------------------------------*/
 | |
| int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
 | |
| {
 | |
|     int err;
 | |
|     struct sockaddr_storage peer;
 | |
|     socklen_t peer_len = sizeof(peer);
 | |
|     char name[INET6_ADDRSTRLEN];
 | |
|     char port[6]; /* 65535 = 5 bytes + 0 to terminate it */
 | |
|     if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
 | |
|         lua_pushnil(L);
 | |
|         lua_pushstring(L, socket_strerror(errno));
 | |
|         return 2;
 | |
|     }
 | |
| 	err = getnameinfo((struct sockaddr *) &peer, peer_len,
 | |
|         name, INET6_ADDRSTRLEN,
 | |
|         port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
 | |
|     if (err) {
 | |
|         lua_pushnil(L);
 | |
|         lua_pushstring(L, gai_strerror(err));
 | |
|         return 2;
 | |
|     }
 | |
|     lua_pushstring(L, name);
 | |
|     lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10));
 | |
|     if (family == PF_INET) {
 | |
|         lua_pushliteral(L, "inet");
 | |
|     } else if (family == PF_INET6) {
 | |
|         lua_pushliteral(L, "inet6");
 | |
|     } else {
 | |
|         lua_pushliteral(L, "uknown family");
 | |
|     }
 | |
|     return 3;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*\
 | |
| * Retrieves socket local name
 | |
| \*-------------------------------------------------------------------------*/
 | |
| int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
 | |
| {
 | |
|     int err;
 | |
|     struct sockaddr_storage peer;
 | |
|     socklen_t peer_len = sizeof(peer);
 | |
|     char name[INET6_ADDRSTRLEN];
 | |
|     char port[6]; /* 65535 = 5 bytes + 0 to terminate it */
 | |
|     if (getsockname(*ps, (SA *) &peer, &peer_len) < 0) {
 | |
|         lua_pushnil(L);
 | |
|         lua_pushstring(L, socket_strerror(errno));
 | |
|         return 2;
 | |
|     }
 | |
| 	err=getnameinfo((struct sockaddr *)&peer, peer_len, 
 | |
| 		name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
 | |
|     if (err) {
 | |
|         lua_pushnil(L);
 | |
|         lua_pushstring(L, gai_strerror(err));
 | |
|         return 2;
 | |
|     }
 | |
|     lua_pushstring(L, name);
 | |
|     lua_pushstring(L, port);
 | |
|     if (family == PF_INET) {
 | |
|         lua_pushliteral(L, "inet");
 | |
|     } else if (family == PF_INET6) {
 | |
|         lua_pushliteral(L, "inet6");
 | |
|     } else {
 | |
|         lua_pushliteral(L, "uknown family");
 | |
|     }
 | |
|     return 3;
 | |
| }
 | |
| 
 | |
| /*=========================================================================*\
 | |
| * Internal functions
 | |
| \*=========================================================================*/
 | |
| /*-------------------------------------------------------------------------*\
 | |
| * Passes all resolver information to Lua as a table
 | |
| \*-------------------------------------------------------------------------*/
 | |
| static void inet_pushresolved(lua_State *L, struct hostent *hp)
 | |
| {
 | |
|     char **alias;
 | |
|     struct in_addr **addr;
 | |
|     int i, resolved;
 | |
|     lua_newtable(L); resolved = lua_gettop(L);
 | |
|     lua_pushstring(L, "name");
 | |
|     lua_pushstring(L, hp->h_name);
 | |
|     lua_settable(L, resolved);
 | |
|     lua_pushstring(L, "ip");
 | |
|     lua_pushstring(L, "alias");
 | |
|     i = 1;
 | |
|     alias = hp->h_aliases;
 | |
|     lua_newtable(L);
 | |
|     if (alias) {
 | |
|         while (*alias) {
 | |
|             lua_pushnumber(L, i);
 | |
|             lua_pushstring(L, *alias);
 | |
|             lua_settable(L, -3);
 | |
|             i++; alias++;
 | |
|         }
 | |
|     }
 | |
|     lua_settable(L, resolved);
 | |
|     i = 1;
 | |
|     lua_newtable(L);
 | |
|     addr = (struct in_addr **) hp->h_addr_list;
 | |
|     if (addr) {
 | |
|         while (*addr) {
 | |
|             lua_pushnumber(L, i);
 | |
|             lua_pushstring(L, inet_ntoa(**addr));
 | |
|             lua_settable(L, -3);
 | |
|             i++; addr++;
 | |
|         }
 | |
|     }
 | |
|     lua_settable(L, resolved);
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*\
 | |
| * Tries to create a new inet socket
 | |
| \*-------------------------------------------------------------------------*/
 | |
| const char *inet_trycreate(p_socket ps, int family, int type) {
 | |
|     return socket_strerror(socket_create(ps, family, type, 0));
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*\
 | |
| * "Disconnects" a DGRAM socket
 | |
| \*-------------------------------------------------------------------------*/
 | |
| const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
 | |
| {
 | |
|     switch (family) {
 | |
|         case PF_INET: {
 | |
|             struct sockaddr_in sin;
 | |
|             memset((char *) &sin, 0, sizeof(sin));
 | |
|             sin.sin_family = AF_UNSPEC;
 | |
|             sin.sin_addr.s_addr = INADDR_ANY;
 | |
|             return socket_strerror(socket_connect(ps, (SA *) &sin, 
 | |
|                 sizeof(sin), tm));
 | |
|         }
 | |
|         case PF_INET6: {
 | |
|             struct sockaddr_in6 sin6;
 | |
|             struct in6_addr addrany = IN6ADDR_ANY_INIT; 
 | |
|             memset((char *) &sin6, 0, sizeof(sin6));
 | |
|             sin6.sin6_family = AF_UNSPEC;
 | |
|             sin6.sin6_addr = addrany;
 | |
|             return socket_strerror(socket_connect(ps, (SA *) &sin6, 
 | |
|                 sizeof(sin6), tm));
 | |
|         }
 | |
|     }
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*\
 | |
| * 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;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*\
 | |
| * Tries to accept a socket
 | |
| \*-------------------------------------------------------------------------*/
 | |
| const char *inet_tryaccept(p_socket server, int family, p_socket client, 
 | |
|     p_timeout tm)
 | |
| {
 | |
| 	socklen_t len;
 | |
| 	t_sockaddr_storage addr;
 | |
| 	if (family == PF_INET6) {
 | |
| 		len = sizeof(struct sockaddr_in6);
 | |
| 	} else {
 | |
| 		len = sizeof(struct sockaddr_in);
 | |
| 	}
 | |
| 	return socket_strerror(socket_accept(server, client, (SA *) &addr, 
 | |
|         &len, tm));
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*\
 | |
| * 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;
 | |
| }
 | |
| 
 | |
| /*-------------------------------------------------------------------------*\
 | |
| * Some systems do not provide these so that we provide our own. 
 | |
| \*-------------------------------------------------------------------------*/
 | |
| #ifdef LUASOCKET_INET_ATON
 | |
| int inet_aton(const char *cp, struct in_addr *inp)
 | |
| {
 | |
|     unsigned int a = 0, b = 0, c = 0, d = 0;
 | |
|     int n = 0, r;
 | |
|     unsigned long int addr = 0;
 | |
|     r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n);
 | |
|     if (r == 0 || n == 0) return 0;
 | |
|     cp += n;
 | |
|     if (*cp) return 0;
 | |
|     if (a > 255 || b > 255 || c > 255 || d > 255) return 0;
 | |
|     if (inp) {
 | |
|         addr += a; addr <<= 8;
 | |
|         addr += b; addr <<= 8;
 | |
|         addr += c; addr <<= 8;
 | |
|         addr += d;
 | |
|         inp->s_addr = htonl(addr);
 | |
|     }
 | |
|     return 1;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #ifdef LUASOCKET_INET_PTON
 | |
| int inet_pton(int af, const char *src, void *dst) 
 | |
| {
 | |
|     struct addrinfo hints, *res;
 | |
|     int ret = 1;
 | |
|     memset(&hints, 0, sizeof(struct addrinfo));
 | |
|     hints.ai_family = af;
 | |
|     hints.ai_flags = AI_NUMERICHOST;
 | |
|     if (getaddrinfo(src, NULL, &hints, &res) != 0) return -1;
 | |
|     if (af == AF_INET) {
 | |
|         struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr;
 | |
|         memcpy(dst, &in->sin_addr, sizeof(in->sin_addr));
 | |
|     } else if (af == AF_INET6) {
 | |
|         struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr;
 | |
|         memcpy(dst, &in->sin6_addr, sizeof(in->sin6_addr));
 | |
|     } else {
 | |
|         ret = -1;
 | |
|     }
 | |
|     freeaddrinfo(res); 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| } // end NS_SLUA
 |