2002-03-21 14:52:38 +01:00
|
|
|
/*=========================================================================*\
|
2003-05-25 03:54:13 +02:00
|
|
|
* Internet domain functions
|
2003-06-26 20:47:49 +02:00
|
|
|
* LuaSocket toolkit
|
2002-03-21 14:52:38 +01:00
|
|
|
\*=========================================================================*/
|
2003-06-26 20:47:49 +02:00
|
|
|
#include <stdio.h>
|
2013-05-30 10:20:34 +02:00
|
|
|
#include <stdlib.h>
|
2002-03-21 14:52:38 +01:00
|
|
|
#include <string.h>
|
|
|
|
|
2005-09-29 08:11:42 +02:00
|
|
|
#include "lua.h"
|
|
|
|
#include "lauxlib.h"
|
2015-08-21 20:39:34 +02:00
|
|
|
#include "compat.h"
|
2002-03-21 14:52:38 +01:00
|
|
|
|
2003-05-25 03:54:13 +02:00
|
|
|
#include "inet.h"
|
2002-03-21 14:52:38 +01:00
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* Internal function prototypes.
|
|
|
|
\*=========================================================================*/
|
2003-05-25 03:54:13 +02:00
|
|
|
static int inet_global_toip(lua_State *L);
|
2011-06-14 01:40:11 +02:00
|
|
|
static int inet_global_getaddrinfo(lua_State *L);
|
2003-05-25 03:54:13 +02:00
|
|
|
static int inet_global_tohostname(lua_State *L);
|
2012-05-05 02:13:56 +02:00
|
|
|
static int inet_global_getnameinfo(lua_State *L);
|
2002-03-21 14:52:38 +01:00
|
|
|
static void inet_pushresolved(lua_State *L, struct hostent *hp);
|
2004-01-24 03:47:24 +01:00
|
|
|
static int inet_global_gethostname(lua_State *L);
|
2002-03-21 14:52:38 +01:00
|
|
|
|
2003-08-16 02:06:04 +02:00
|
|
|
/* DNS functions */
|
2011-07-05 00:31:14 +02:00
|
|
|
static luaL_Reg func[] = {
|
2012-04-11 22:21:25 +02:00
|
|
|
{ "toip", inet_global_toip},
|
2011-06-14 01:40:11 +02:00
|
|
|
{ "getaddrinfo", inet_global_getaddrinfo},
|
2012-04-11 22:21:25 +02:00
|
|
|
{ "tohostname", inet_global_tohostname},
|
2012-05-05 02:13:56 +02:00
|
|
|
{ "getnameinfo", inet_global_getnameinfo},
|
2004-01-24 03:47:24 +01:00
|
|
|
{ "gethostname", inet_global_gethostname},
|
2003-05-25 03:54:13 +02:00
|
|
|
{ NULL, NULL}
|
|
|
|
};
|
|
|
|
|
2002-03-21 14:52:38 +01:00
|
|
|
/*=========================================================================*\
|
|
|
|
* Exported functions
|
|
|
|
\*=========================================================================*/
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Initializes module
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2004-02-04 15:29:11 +01:00
|
|
|
int inet_open(lua_State *L)
|
2002-03-21 14:52:38 +01:00
|
|
|
{
|
2003-08-16 02:06:04 +02:00
|
|
|
lua_pushstring(L, "dns");
|
|
|
|
lua_newtable(L);
|
2013-05-29 10:56:56 +02:00
|
|
|
luaL_setfuncs(L, func, 0);
|
2003-08-16 02:06:04 +02:00
|
|
|
lua_settable(L, -3);
|
2004-03-26 01:18:41 +01:00
|
|
|
return 0;
|
2002-03-21 14:52:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* Global Lua functions
|
|
|
|
\*=========================================================================*/
|
|
|
|
/*-------------------------------------------------------------------------*\
|
2002-07-03 21:06:55 +02:00
|
|
|
* Returns all information provided by the resolver given a host name
|
|
|
|
* or ip address
|
2002-03-21 14:52:38 +01:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2004-07-15 08:11:53 +02:00
|
|
|
static int inet_gethost(const char *address, struct hostent **hp) {
|
2002-03-21 14:52:38 +01:00
|
|
|
struct in_addr addr;
|
|
|
|
if (inet_aton(address, &addr))
|
2005-10-07 06:40:59 +02:00
|
|
|
return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
|
2011-06-14 01:17:07 +02:00
|
|
|
else
|
2005-10-07 06:40:59 +02:00
|
|
|
return socket_gethostbyname(address, hp);
|
2004-07-15 08:11:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* 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);
|
2011-06-14 01:17:07 +02:00
|
|
|
struct hostent *hp = NULL;
|
2004-07-15 08:11:53 +02:00
|
|
|
int err = inet_gethost(address, &hp);
|
|
|
|
if (err != IO_DONE) {
|
2002-03-21 14:52:38 +01:00
|
|
|
lua_pushnil(L);
|
2005-10-07 06:40:59 +02:00
|
|
|
lua_pushstring(L, socket_hoststrerror(err));
|
2002-03-21 14:52:38 +01:00
|
|
|
return 2;
|
|
|
|
}
|
2004-07-15 08:11:53 +02:00
|
|
|
lua_pushstring(L, hp->h_name);
|
2002-03-21 14:52:38 +01:00
|
|
|
inet_pushresolved(L, hp);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2012-05-05 02:13:56 +02:00
|
|
|
static int inet_global_getnameinfo(lua_State *L) {
|
2013-05-27 15:05:48 +02:00
|
|
|
char hbuf[NI_MAXHOST];
|
|
|
|
char sbuf[NI_MAXSERV];
|
2012-05-05 02:13:56 +02:00
|
|
|
int i, ret;
|
|
|
|
struct addrinfo hints;
|
|
|
|
struct addrinfo *resolved, *iter;
|
2013-05-27 15:05:48 +02:00
|
|
|
const char *host = luaL_optstring(L, 1, NULL);
|
|
|
|
const char *serv = luaL_optstring(L, 2, NULL);
|
2012-05-05 02:13:56 +02:00
|
|
|
|
2013-05-27 15:05:48 +02:00
|
|
|
if (!(host || serv))
|
|
|
|
luaL_error(L, "host and serv cannot be both nil");
|
2012-05-05 02:13:56 +02:00
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
2015-08-23 00:52:01 +02:00
|
|
|
hints.ai_family = AF_UNSPEC;
|
2012-05-05 02:13:56 +02:00
|
|
|
|
2013-05-27 15:05:48 +02:00
|
|
|
ret = getaddrinfo(host, serv, &hints, &resolved);
|
2012-05-05 02:13:56 +02:00
|
|
|
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) {
|
2015-08-23 00:52:01 +02:00
|
|
|
getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen,
|
|
|
|
hbuf, host? (socklen_t) sizeof(hbuf): 0,
|
2013-05-27 15:05:48 +02:00
|
|
|
sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0);
|
|
|
|
if (host) {
|
2012-05-05 02:13:56 +02:00
|
|
|
lua_pushnumber(L, i);
|
2013-05-27 15:05:48 +02:00
|
|
|
lua_pushstring(L, hbuf);
|
2012-05-05 02:13:56 +02:00
|
|
|
lua_settable(L, -3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
freeaddrinfo(resolved);
|
|
|
|
|
2013-05-27 15:05:48 +02:00
|
|
|
if (serv) {
|
|
|
|
lua_pushstring(L, sbuf);
|
2012-05-05 02:13:56 +02:00
|
|
|
return 2;
|
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-03-21 14:52:38 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
2002-07-03 21:06:55 +02:00
|
|
|
* Returns all information provided by the resolver given a host name
|
|
|
|
* or ip address
|
2002-03-21 14:52:38 +01:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2004-07-15 08:11:53 +02:00
|
|
|
static int inet_global_toip(lua_State *L)
|
2002-03-21 14:52:38 +01:00
|
|
|
{
|
2003-05-25 03:54:13 +02:00
|
|
|
const char *address = luaL_checkstring(L, 1);
|
2011-06-14 01:17:07 +02:00
|
|
|
struct hostent *hp = NULL;
|
2004-07-15 08:11:53 +02:00
|
|
|
int err = inet_gethost(address, &hp);
|
|
|
|
if (err != IO_DONE) {
|
2002-03-21 14:52:38 +01:00
|
|
|
lua_pushnil(L);
|
2005-10-07 06:40:59 +02:00
|
|
|
lua_pushstring(L, socket_hoststrerror(err));
|
2002-03-21 14:52:38 +01:00
|
|
|
return 2;
|
|
|
|
}
|
2004-07-15 08:11:53 +02:00
|
|
|
lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr)));
|
2002-03-21 14:52:38 +01:00
|
|
|
inet_pushresolved(L, hp);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2012-05-10 23:14:22 +02:00
|
|
|
int inet_optfamily(lua_State* L, int narg, const char* def)
|
|
|
|
{
|
|
|
|
static const char* optname[] = { "unspec", "inet", "inet6", NULL };
|
2015-08-23 00:52:01 +02:00
|
|
|
static int optvalue[] = { AF_UNSPEC, AF_INET, AF_INET6, 0 };
|
2012-05-10 23:14:22 +02:00
|
|
|
|
|
|
|
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)];
|
|
|
|
}
|
|
|
|
|
2011-06-14 01:40:11 +02:00
|
|
|
static int inet_global_getaddrinfo(lua_State *L)
|
2012-04-11 22:21:25 +02:00
|
|
|
{
|
|
|
|
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;
|
2015-08-23 00:52:01 +02:00
|
|
|
hints.ai_family = AF_UNSPEC;
|
2012-04-11 22:21:25 +02:00
|
|
|
ret = getaddrinfo(hostname, NULL, &hints, &resolved);
|
|
|
|
if (ret != 0) {
|
|
|
|
lua_pushnil(L);
|
2011-06-14 20:30:40 +02:00
|
|
|
lua_pushstring(L, socket_gaistrerror(ret));
|
2012-04-11 22:21:25 +02:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
lua_newtable(L);
|
|
|
|
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
2013-05-27 15:05:48 +02:00
|
|
|
char hbuf[NI_MAXHOST];
|
2015-08-23 00:52:01 +02:00
|
|
|
ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen,
|
2013-05-27 15:05:48 +02:00
|
|
|
hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
|
|
|
|
if (ret){
|
2015-02-18 23:54:27 +01:00
|
|
|
freeaddrinfo(resolved);
|
2013-05-27 09:20:52 +02:00
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, socket_gaistrerror(ret));
|
|
|
|
return 2;
|
|
|
|
}
|
2012-04-11 22:21:25 +02:00
|
|
|
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);
|
2013-06-04 10:26:49 +02:00
|
|
|
break;
|
2015-08-23 00:52:01 +02:00
|
|
|
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;
|
2012-04-11 22:21:25 +02:00
|
|
|
}
|
|
|
|
lua_pushliteral(L, "addr");
|
|
|
|
lua_pushstring(L, hbuf);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
i++;
|
2011-06-14 01:17:07 +02:00
|
|
|
}
|
2012-04-11 22:21:25 +02:00
|
|
|
freeaddrinfo(resolved);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2004-01-24 03:47:24 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* 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);
|
2012-05-10 23:14:22 +02:00
|
|
|
lua_pushstring(L, socket_strerror(errno));
|
2004-01-24 03:47:24 +01:00
|
|
|
return 2;
|
|
|
|
} else {
|
|
|
|
lua_pushstring(L, name);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-03-21 14:52:38 +01:00
|
|
|
/*=========================================================================*\
|
2002-07-03 21:06:55 +02:00
|
|
|
* Lua methods
|
2002-03-21 14:52:38 +01:00
|
|
|
\*=========================================================================*/
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Retrieves socket peer name
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2012-04-23 18:47:30 +02:00
|
|
|
int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
|
2002-03-21 14:52:38 +01:00
|
|
|
{
|
2013-05-30 10:20:34 +02:00
|
|
|
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;
|
|
|
|
}
|
2013-05-30 10:50:28 +02:00
|
|
|
err = getnameinfo((struct sockaddr *) &peer, peer_len,
|
2013-05-30 10:20:34 +02:00
|
|
|
name, INET6_ADDRSTRLEN,
|
2013-05-30 10:50:28 +02:00
|
|
|
port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
|
|
|
|
if (err) {
|
2013-05-30 10:20:34 +02:00
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, gai_strerror(err));
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
lua_pushstring(L, name);
|
|
|
|
lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10));
|
2015-08-23 00:52:01 +02:00
|
|
|
switch (family) {
|
|
|
|
case AF_INET: lua_pushliteral(L, "inet"); break;
|
|
|
|
case AF_INET6: lua_pushliteral(L, "inet6"); break;
|
|
|
|
case AF_UNSPEC: lua_pushliteral(L, "unspec"); break;
|
|
|
|
default: lua_pushliteral(L, "unknown"); break;
|
2002-03-21 14:52:38 +01:00
|
|
|
}
|
2013-05-30 10:20:34 +02:00
|
|
|
return 3;
|
2002-03-21 14:52:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Retrieves socket local name
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2012-04-23 18:47:30 +02:00
|
|
|
int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
|
2002-03-21 14:52:38 +01:00
|
|
|
{
|
2013-05-30 10:20:34 +02:00
|
|
|
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;
|
|
|
|
}
|
2015-08-23 00:52:01 +02:00
|
|
|
err=getnameinfo((struct sockaddr *)&peer, peer_len,
|
2013-05-30 10:50:28 +02:00
|
|
|
name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
|
|
|
|
if (err) {
|
2013-05-30 10:20:34 +02:00
|
|
|
lua_pushnil(L);
|
|
|
|
lua_pushstring(L, gai_strerror(err));
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
lua_pushstring(L, name);
|
|
|
|
lua_pushstring(L, port);
|
2015-08-23 00:52:01 +02:00
|
|
|
switch (family) {
|
|
|
|
case AF_INET: lua_pushliteral(L, "inet"); break;
|
|
|
|
case AF_INET6: lua_pushliteral(L, "inet6"); break;
|
|
|
|
case AF_UNSPEC: lua_pushliteral(L, "unspec"); break;
|
|
|
|
default: lua_pushliteral(L, "unknown"); break;
|
2002-03-21 14:52:38 +01:00
|
|
|
}
|
2013-05-30 10:20:34 +02:00
|
|
|
return 3;
|
2002-03-21 14:52:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* 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);
|
2005-06-14 06:29:23 +02:00
|
|
|
if (alias) {
|
|
|
|
while (*alias) {
|
|
|
|
lua_pushnumber(L, i);
|
|
|
|
lua_pushstring(L, *alias);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
i++; alias++;
|
|
|
|
}
|
2002-03-21 14:52:38 +01:00
|
|
|
}
|
|
|
|
lua_settable(L, resolved);
|
|
|
|
i = 1;
|
|
|
|
lua_newtable(L);
|
|
|
|
addr = (struct in_addr **) hp->h_addr_list;
|
2005-06-14 06:29:23 +02:00
|
|
|
if (addr) {
|
|
|
|
while (*addr) {
|
|
|
|
lua_pushnumber(L, i);
|
|
|
|
lua_pushstring(L, inet_ntoa(**addr));
|
|
|
|
lua_settable(L, -3);
|
|
|
|
i++; addr++;
|
|
|
|
}
|
2002-03-21 14:52:38 +01:00
|
|
|
}
|
|
|
|
lua_settable(L, resolved);
|
|
|
|
}
|
|
|
|
|
2004-01-21 19:40:52 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Tries to create a new inet socket
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2015-08-25 20:41:40 +02:00
|
|
|
const char *inet_trycreate(p_socket ps, int family, int type, int protocol) {
|
|
|
|
const char *err = socket_strerror(socket_create(ps, family, type, protocol));
|
|
|
|
if (err == NULL && family == AF_INET6) {
|
|
|
|
int yes = 1;
|
|
|
|
setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes));
|
|
|
|
}
|
|
|
|
return err;
|
2004-01-21 19:40:52 +01:00
|
|
|
}
|
|
|
|
|
2012-08-24 00:31:15 +02:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* "Disconnects" a DGRAM socket
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
|
|
|
|
{
|
|
|
|
switch (family) {
|
2015-08-23 00:52:01 +02:00
|
|
|
case AF_INET: {
|
2012-08-24 00:31:15 +02:00
|
|
|
struct sockaddr_in sin;
|
|
|
|
memset((char *) &sin, 0, sizeof(sin));
|
|
|
|
sin.sin_family = AF_UNSPEC;
|
|
|
|
sin.sin_addr.s_addr = INADDR_ANY;
|
2015-08-23 00:52:01 +02:00
|
|
|
return socket_strerror(socket_connect(ps, (SA *) &sin,
|
2012-08-24 00:31:15 +02:00
|
|
|
sizeof(sin), tm));
|
|
|
|
}
|
2015-08-23 00:52:01 +02:00
|
|
|
case AF_INET6: {
|
2012-08-24 00:31:15 +02:00
|
|
|
struct sockaddr_in6 sin6;
|
2015-08-23 00:52:01 +02:00
|
|
|
struct in6_addr addrany = IN6ADDR_ANY_INIT;
|
2012-08-24 00:31:15 +02:00
|
|
|
memset((char *) &sin6, 0, sizeof(sin6));
|
|
|
|
sin6.sin6_family = AF_UNSPEC;
|
|
|
|
sin6.sin6_addr = addrany;
|
2015-08-23 00:52:01 +02:00
|
|
|
return socket_strerror(socket_connect(ps, (SA *) &sin6,
|
2012-08-24 00:31:15 +02:00
|
|
|
sizeof(sin6), tm));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2002-03-21 14:52:38 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
2003-05-25 03:54:13 +02:00
|
|
|
* Tries to connect to remote address (address, port)
|
2002-03-21 14:52:38 +01:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2013-05-26 15:26:26 +02:00
|
|
|
const char *inet_tryconnect(p_socket ps, int *family, const char *address,
|
2011-06-15 00:51:02 +02:00
|
|
|
const char *serv, p_timeout tm, struct addrinfo *connecthints)
|
2002-03-21 14:52:38 +01:00
|
|
|
{
|
2011-06-15 00:51:02 +02:00
|
|
|
struct addrinfo *iterator = NULL, *resolved = NULL;
|
|
|
|
const char *err = NULL;
|
2015-08-23 00:52:01 +02:00
|
|
|
int current_family = *family;
|
2011-06-15 00:51:02 +02:00
|
|
|
/* 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);
|
2013-05-26 15:26:26 +02:00
|
|
|
/* 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. */
|
2015-08-23 00:52:01 +02:00
|
|
|
if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
|
2013-05-26 15:26:26 +02:00
|
|
|
socket_destroy(ps);
|
2015-08-25 20:41:40 +02:00
|
|
|
err = inet_trycreate(ps, iterator->ai_family,
|
|
|
|
iterator->ai_socktype, iterator->ai_protocol);
|
2015-08-23 00:52:01 +02:00
|
|
|
if (err) continue;
|
|
|
|
current_family = iterator->ai_family;
|
|
|
|
/* set non-blocking before connect */
|
2013-05-26 15:26:26 +02:00
|
|
|
socket_setnonblocking(ps);
|
|
|
|
}
|
2011-06-15 00:51:02 +02:00
|
|
|
/* try connecting to remote address */
|
2015-08-23 00:52:01 +02:00
|
|
|
err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
|
2012-12-11 20:43:49 +01:00
|
|
|
(socklen_t) iterator->ai_addrlen, tm));
|
2015-12-03 15:56:18 +01:00
|
|
|
/* if success or timeout is zero, break out of loop */
|
|
|
|
if (err == NULL || timeout_iszero(tm)) {
|
2015-08-23 00:52:01 +02:00
|
|
|
*family = current_family;
|
|
|
|
break;
|
|
|
|
}
|
2011-06-15 00:51:02 +02:00
|
|
|
}
|
|
|
|
freeaddrinfo(resolved);
|
|
|
|
/* here, if err is set, we failed */
|
|
|
|
return err;
|
2002-03-21 14:52:38 +01:00
|
|
|
}
|
|
|
|
|
2012-12-11 19:35:27 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Tries to accept a socket
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2015-08-23 00:52:01 +02:00
|
|
|
const char *inet_tryaccept(p_socket server, int family, p_socket client,
|
|
|
|
p_timeout tm) {
|
2012-12-11 19:35:27 +01:00
|
|
|
socklen_t len;
|
|
|
|
t_sockaddr_storage addr;
|
2015-08-23 00:52:01 +02:00
|
|
|
switch (family) {
|
|
|
|
case AF_INET6: len = sizeof(struct sockaddr_in6); break;
|
|
|
|
case AF_INET: len = sizeof(struct sockaddr_in); break;
|
|
|
|
default: len = sizeof(addr); break;
|
|
|
|
}
|
|
|
|
return socket_strerror(socket_accept(server, client, (SA *) &addr,
|
2013-05-30 10:20:34 +02:00
|
|
|
&len, tm));
|
2012-12-11 19:35:27 +01:00
|
|
|
}
|
|
|
|
|
2002-03-21 14:52:38 +01:00
|
|
|
/*-------------------------------------------------------------------------*\
|
2003-05-25 03:54:13 +02:00
|
|
|
* Tries to bind socket to (address, port)
|
2002-03-21 14:52:38 +01:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2015-08-23 00:52:01 +02:00
|
|
|
const char *inet_trybind(p_socket ps, int *family, const char *address,
|
|
|
|
const char *serv, struct addrinfo *bindhints) {
|
2011-06-14 01:17:07 +02:00
|
|
|
struct addrinfo *iterator = NULL, *resolved = NULL;
|
|
|
|
const char *err = NULL;
|
2015-08-23 00:52:01 +02:00
|
|
|
int current_family = *family;
|
2013-05-27 09:25:31 +02:00
|
|
|
/* translate luasocket special values to C */
|
|
|
|
if (strcmp(address, "*") == 0) address = NULL;
|
|
|
|
if (!serv) serv = "0";
|
2011-06-14 01:17:07 +02:00
|
|
|
/* try resolving */
|
2012-08-24 00:31:15 +02:00
|
|
|
err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved));
|
2011-06-14 01:17:07 +02:00
|
|
|
if (err) {
|
|
|
|
if (resolved) freeaddrinfo(resolved);
|
|
|
|
return err;
|
2002-07-03 21:06:55 +02:00
|
|
|
}
|
2011-06-14 01:17:07 +02:00
|
|
|
/* iterate over resolved addresses until one is good */
|
|
|
|
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
2015-08-23 00:52:01 +02:00
|
|
|
if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
|
|
|
|
socket_destroy(ps);
|
2015-08-25 20:41:40 +02:00
|
|
|
err = inet_trycreate(ps, iterator->ai_family,
|
|
|
|
iterator->ai_socktype, iterator->ai_protocol);
|
2015-08-23 00:52:01 +02:00
|
|
|
if (err) continue;
|
|
|
|
current_family = iterator->ai_family;
|
2012-05-10 23:14:22 +02:00
|
|
|
}
|
2011-06-14 01:17:07 +02:00
|
|
|
/* try binding to local address */
|
2015-08-23 00:52:01 +02:00
|
|
|
err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr,
|
2012-12-11 20:43:49 +01:00
|
|
|
(socklen_t) iterator->ai_addrlen));
|
2012-05-10 23:14:22 +02:00
|
|
|
/* keep trying unless bind succeeded */
|
2015-08-23 00:52:01 +02:00
|
|
|
if (err == NULL) {
|
|
|
|
*family = current_family;
|
|
|
|
/* set to non-blocking after bind */
|
|
|
|
socket_setnonblocking(ps);
|
2012-05-10 23:14:22 +02:00
|
|
|
break;
|
|
|
|
}
|
2011-06-14 01:17:07 +02:00
|
|
|
}
|
|
|
|
/* cleanup and return error */
|
|
|
|
freeaddrinfo(resolved);
|
2015-08-23 00:52:01 +02:00
|
|
|
/* here, if err is set, we failed */
|
2011-06-14 01:17:07 +02:00
|
|
|
return err;
|
2002-03-21 14:52:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
2015-08-23 00:52:01 +02:00
|
|
|
* Some systems do not provide these so that we provide our own.
|
2002-03-21 14:52:38 +01:00
|
|
|
\*-------------------------------------------------------------------------*/
|
2013-05-27 14:30:06 +02:00
|
|
|
#ifdef LUASOCKET_INET_ATON
|
2003-06-11 03:42:18 +02:00
|
|
|
int inet_aton(const char *cp, struct in_addr *inp)
|
2002-03-21 14:52:38 +01:00
|
|
|
{
|
|
|
|
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
|
2003-06-26 20:47:49 +02:00
|
|
|
|
2013-05-27 14:30:06 +02:00
|
|
|
#ifdef LUASOCKET_INET_PTON
|
2015-08-23 00:52:01 +02:00
|
|
|
int inet_pton(int af, const char *src, void *dst)
|
2013-04-07 21:39:56 +02:00
|
|
|
{
|
2013-05-27 18:09:30 +02:00
|
|
|
struct addrinfo hints, *res;
|
2013-05-28 11:27:06 +02:00
|
|
|
int ret = 1;
|
2013-05-25 12:07:38 +02:00
|
|
|
memset(&hints, 0, sizeof(struct addrinfo));
|
|
|
|
hints.ai_family = af;
|
2013-05-27 18:09:30 +02:00
|
|
|
hints.ai_flags = AI_NUMERICHOST;
|
2013-05-28 11:27:06 +02:00
|
|
|
if (getaddrinfo(src, NULL, &hints, &res) != 0) return -1;
|
2013-05-27 18:09:30 +02:00
|
|
|
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 {
|
2013-05-28 11:27:06 +02:00
|
|
|
ret = -1;
|
2013-05-25 12:07:38 +02:00
|
|
|
}
|
2015-08-23 00:52:01 +02:00
|
|
|
freeaddrinfo(res);
|
2013-05-28 11:27:06 +02:00
|
|
|
return ret;
|
2013-04-07 21:39:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|