summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir/luasocket/src/tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/luasocket/src/tcp.c')
-rw-r--r--Build/source/texk/web2c/luatexdir/luasocket/src/tcp.c252
1 files changed, 194 insertions, 58 deletions
diff --git a/Build/source/texk/web2c/luatexdir/luasocket/src/tcp.c b/Build/source/texk/web2c/luatexdir/luasocket/src/tcp.c
index 6b8a79b4bc5..6734dc0b497 100644
--- a/Build/source/texk/web2c/luatexdir/luasocket/src/tcp.c
+++ b/Build/source/texk/web2c/luatexdir/luasocket/src/tcp.c
@@ -1,10 +1,8 @@
/*=========================================================================*\
-* TCP object
+* TCP object
* LuaSocket toolkit
-*
-* RCS ID: $Id: tcp.c,v 1.41 2005/10/07 04:40:59 diego Exp $
\*=========================================================================*/
-#include <string.h>
+#include <string.h>
#include "lua.h"
#include "lauxlib.h"
@@ -19,8 +17,11 @@
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
+static int global_create6(lua_State *L);
+static int global_connect(lua_State *L);
static int meth_connect(lua_State *L);
static int meth_listen(lua_State *L);
+static int meth_getfamily(lua_State *L);
static int meth_bind(lua_State *L);
static int meth_send(lua_State *L);
static int meth_getstats(lua_State *L);
@@ -31,6 +32,7 @@ static int meth_shutdown(lua_State *L);
static int meth_receive(lua_State *L);
static int meth_accept(lua_State *L);
static int meth_close(lua_State *L);
+static int meth_getoption(lua_State *L);
static int meth_setoption(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
@@ -38,7 +40,7 @@ static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L);
/* tcp object methods */
-static luaL_reg tcp[] = {
+static luaL_Reg tcp_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"accept", meth_accept},
@@ -46,7 +48,9 @@ static luaL_reg tcp[] = {
{"close", meth_close},
{"connect", meth_connect},
{"dirty", meth_dirty},
+ {"getfamily", meth_getfamily},
{"getfd", meth_getfd},
+ {"getoption", meth_getoption},
{"getpeername", meth_getpeername},
{"getsockname", meth_getsockname},
{"getstats", meth_getstats},
@@ -64,17 +68,28 @@ static luaL_reg tcp[] = {
};
/* socket option handlers */
-static t_opt opt[] = {
- {"keepalive", opt_keepalive},
- {"reuseaddr", opt_reuseaddr},
- {"tcp-nodelay", opt_tcp_nodelay},
- {"linger", opt_linger},
+static t_opt optget[] = {
+ {"keepalive", opt_get_keepalive},
+ {"reuseaddr", opt_get_reuseaddr},
+ {"tcp-nodelay", opt_get_tcp_nodelay},
+ {"linger", opt_get_linger},
+ {NULL, NULL}
+};
+
+static t_opt optset[] = {
+ {"keepalive", opt_set_keepalive},
+ {"reuseaddr", opt_set_reuseaddr},
+ {"tcp-nodelay", opt_set_tcp_nodelay},
+ {"ipv6-v6only", opt_set_ip6_v6only},
+ {"linger", opt_set_linger},
{NULL, NULL}
};
/* functions in library namespace */
-static luaL_reg func[] = {
+static luaL_Reg func[] = {
{"tcp", global_create},
+ {"tcp6", global_create6},
+ {"connect", global_connect},
{NULL, NULL}
};
@@ -84,15 +99,15 @@ static luaL_reg func[] = {
int tcp_open(lua_State *L)
{
/* create classes */
- auxiliar_newclass(L, "tcp{master}", tcp);
- auxiliar_newclass(L, "tcp{client}", tcp);
- auxiliar_newclass(L, "tcp{server}", tcp);
+ auxiliar_newclass(L, "tcp{master}", tcp_methods);
+ auxiliar_newclass(L, "tcp{client}", tcp_methods);
+ auxiliar_newclass(L, "tcp{server}", tcp_methods);
/* create class groups */
auxiliar_add2group(L, "tcp{master}", "tcp{any}");
auxiliar_add2group(L, "tcp{client}", "tcp{any}");
auxiliar_add2group(L, "tcp{server}", "tcp{any}");
/* define library functions */
- luaL_openlib(L, NULL, func, 0);
+ luaL_openlib(L, NULL, func, 0);
return 0;
}
@@ -125,10 +140,16 @@ static int meth_setstats(lua_State *L) {
/*-------------------------------------------------------------------------*\
* Just call option handler
\*-------------------------------------------------------------------------*/
+static int meth_getoption(lua_State *L)
+{
+ p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
+ return opt_meth_getoption(L, optget, &tcp->sock);
+}
+
static int meth_setoption(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
- return opt_meth_setoption(L, opt, &tcp->sock);
+ return opt_meth_setoption(L, optset, &tcp->sock);
}
/*-------------------------------------------------------------------------*\
@@ -145,7 +166,7 @@ static int meth_getfd(lua_State *L)
static int meth_setfd(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
- tcp->sock = (t_socket) luaL_checknumber(L, 2);
+ tcp->sock = (t_socket) luaL_checknumber(L, 2);
return 0;
}
@@ -157,43 +178,52 @@ static int meth_dirty(lua_State *L)
}
/*-------------------------------------------------------------------------*\
-* Waits for and returns a client object attempting connection to the
-* server object
+* Waits for and returns a client object attempting connection to the
+* server object
\*-------------------------------------------------------------------------*/
static int meth_accept(lua_State *L)
{
p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1);
p_timeout tm = timeout_markstart(&server->tm);
t_socket sock;
- int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
+ const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm);
/* if successful, push client socket */
- if (err == IO_DONE) {
+ if (err == NULL) {
p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
auxiliar_setclass(L, "tcp{client}", -1);
/* initialize structure fields */
+ memset(clnt, 0, sizeof(t_tcp));
socket_setnonblocking(&sock);
clnt->sock = sock;
- io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv,
+ io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &clnt->sock);
timeout_init(&clnt->tm, -1, -1);
buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
+ clnt->family = server->family;
return 1;
} else {
- lua_pushnil(L);
- lua_pushstring(L, socket_strerror(err));
+ lua_pushnil(L);
+ lua_pushstring(L, err);
return 2;
}
}
/*-------------------------------------------------------------------------*\
-* Binds an object to an address
+* Binds an object to an address
\*-------------------------------------------------------------------------*/
static int meth_bind(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
const char *address = luaL_checkstring(L, 2);
- unsigned short port = (unsigned short) luaL_checknumber(L, 3);
- const char *err = inet_trybind(&tcp->sock, address, port);
+ const char *port = luaL_checkstring(L, 3);
+ const char *err;
+ struct addrinfo bindhints;
+ memset(&bindhints, 0, sizeof(bindhints));
+ bindhints.ai_socktype = SOCK_STREAM;
+ bindhints.ai_family = tcp->family;
+ bindhints.ai_flags = AI_PASSIVE;
+ address = strcmp(address, "*")? address: NULL;
+ err = inet_trybind(&tcp->sock, address, port, &bindhints);
if (err) {
lua_pushnil(L);
lua_pushstring(L, err);
@@ -210,9 +240,15 @@ static int meth_connect(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
const char *address = luaL_checkstring(L, 2);
- unsigned short port = (unsigned short) luaL_checknumber(L, 3);
- p_timeout tm = timeout_markstart(&tcp->tm);
- const char *err = inet_tryconnect(&tcp->sock, address, port, tm);
+ const char *port = luaL_checkstring(L, 3);
+ struct addrinfo connecthints;
+ const char *err;
+ memset(&connecthints, 0, sizeof(connecthints));
+ connecthints.ai_socktype = SOCK_STREAM;
+ /* make sure we try to connect only to the same family */
+ connecthints.ai_family = tcp->family;
+ timeout_markstart(&tcp->tm);
+ err = inet_tryconnect(&tcp->sock, address, port, &tcp->tm, &connecthints);
/* have to set the class even if it failed due to non-blocking connects */
auxiliar_setclass(L, "tcp{client}", 1);
if (err) {
@@ -220,13 +256,12 @@ static int meth_connect(lua_State *L)
lua_pushstring(L, err);
return 2;
}
- /* turn master object into a client object */
lua_pushnumber(L, 1);
return 1;
}
/*-------------------------------------------------------------------------*\
-* Closes socket used by object
+* Closes socket used by object
\*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L)
{
@@ -237,6 +272,21 @@ static int meth_close(lua_State *L)
}
/*-------------------------------------------------------------------------*\
+* Returns family as string
+\*-------------------------------------------------------------------------*/
+static int meth_getfamily(lua_State *L)
+{
+ p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
+ if (tcp->family == PF_INET6) {
+ lua_pushliteral(L, "inet6");
+ return 1;
+ } else {
+ lua_pushliteral(L, "inet4");
+ return 1;
+ }
+}
+
+/*-------------------------------------------------------------------------*\
* Puts the sockt in listen mode
\*-------------------------------------------------------------------------*/
static int meth_listen(lua_State *L)
@@ -260,27 +310,13 @@ static int meth_listen(lua_State *L)
\*-------------------------------------------------------------------------*/
static int meth_shutdown(lua_State *L)
{
+ /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
+ static const char* methods[] = { "receive", "send", "both", NULL };
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
- const char *how = luaL_optstring(L, 2, "both");
- switch (how[0]) {
- case 'b':
- if (strcmp(how, "both")) goto error;
- socket_shutdown(&tcp->sock, 2);
- break;
- case 's':
- if (strcmp(how, "send")) goto error;
- socket_shutdown(&tcp->sock, 1);
- break;
- case 'r':
- if (strcmp(how, "receive")) goto error;
- socket_shutdown(&tcp->sock, 0);
- break;
- }
+ int how = luaL_checkoption(L, 2, "both", methods);
+ socket_shutdown(&tcp->sock, how);
lua_pushnumber(L, 1);
return 1;
-error:
- luaL_argerror(L, 2, "invalid shutdown method");
- return 0;
}
/*-------------------------------------------------------------------------*\
@@ -289,13 +325,13 @@ error:
static int meth_getpeername(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
- return inet_meth_getpeername(L, &tcp->sock);
+ return inet_meth_getpeername(L, &tcp->sock, tcp->family);
}
static int meth_getsockname(lua_State *L)
{
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
- return inet_meth_getsockname(L, &tcp->sock);
+ return inet_meth_getsockname(L, &tcp->sock, tcp->family);
}
/*-------------------------------------------------------------------------*\
@@ -311,25 +347,31 @@ static int meth_settimeout(lua_State *L)
* Library functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
-* Creates a master tcp object
+* Creates a master tcp object
\*-------------------------------------------------------------------------*/
-static int global_create(lua_State *L)
-{
+static int tcp_create(lua_State *L, int family) {
t_socket sock;
- const char *err = inet_trycreate(&sock, SOCK_STREAM);
+ const char *err = inet_trycreate(&sock, family, SOCK_STREAM);
/* try to allocate a system socket */
- if (!err) {
+ if (!err) {
/* allocate tcp object */
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
+ memset(tcp, 0, sizeof(t_tcp));
/* set its type as master object */
auxiliar_setclass(L, "tcp{master}", -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
+ if (family == PF_INET6) {
+ int yes = 1;
+ setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
+ (void *)&yes, sizeof(yes));
+ }
tcp->sock = sock;
- io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
+ io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
(p_error) socket_ioerror, &tcp->sock);
timeout_init(&tcp->tm, -1, -1);
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
+ tcp->family = family;
return 1;
} else {
lua_pushnil(L);
@@ -337,3 +379,97 @@ static int global_create(lua_State *L)
return 2;
}
}
+
+static int global_create(lua_State *L) {
+ return tcp_create(L, AF_INET);
+}
+
+static int global_create6(lua_State *L) {
+ return tcp_create(L, AF_INET6);
+}
+
+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;
+}
+
+static int global_connect(lua_State *L) {
+ const char *remoteaddr = luaL_checkstring(L, 1);
+ const char *remoteserv = luaL_checkstring(L, 2);
+ const char *localaddr = luaL_optstring(L, 3, NULL);
+ const char *localserv = luaL_optstring(L, 4, "0");
+ int family = inet_optfamily(L, 5, "unspec");
+ p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
+ struct addrinfo bindhints, connecthints;
+ const char *err = NULL;
+ /* initialize tcp structure */
+ memset(tcp, 0, sizeof(t_tcp));
+ io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
+ (p_error) socket_ioerror, &tcp->sock);
+ timeout_init(&tcp->tm, -1, -1);
+ buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
+ tcp->sock = SOCKET_INVALID;
+ /* allow user to pick local address and port */
+ memset(&bindhints, 0, sizeof(bindhints));
+ bindhints.ai_socktype = SOCK_STREAM;
+ bindhints.ai_family = family;
+ bindhints.ai_flags = AI_PASSIVE;
+ if (localaddr) {
+ err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints);
+ if (err) {
+ lua_pushnil(L);
+ lua_pushstring(L, err);
+ return 2;
+ }
+ tcp->family = bindhints.ai_family;
+ }
+ /* try to connect to remote address and port */
+ memset(&connecthints, 0, sizeof(connecthints));
+ connecthints.ai_socktype = SOCK_STREAM;
+ /* make sure we try to connect only to the same family */
+ connecthints.ai_family = bindhints.ai_family;
+ err = tryconnect6(remoteaddr, remoteserv, &connecthints, tcp);
+ if (err) {
+ socket_destroy(&tcp->sock);
+ lua_pushnil(L);
+ lua_pushstring(L, err);
+ return 2;
+ }
+ auxiliar_setclass(L, "tcp{client}", -1);
+ return 1;
+}