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
 |