about summary refs log blame commit diff stats
path: root/arc/.traces/new-fn-arg-random-access
blob: 301f73f2b37367e2fc81c5b242d61b4a553e61d0 (plain) (tree)



















































































                                                                         
c{0: 0 (((1 integer)) <- ((copy)) ((1 literal))) -- nil
c{0: 1 (((2 integer)) <- ((copy)) ((3 literal))) -- nil
c{0: 2 (((test1)) ((1 integer)) ((2 integer))) -- nil
c{1: 0 ✓ (((1 integer)) <- ((copy)) ((1 literal)))
c{1: 1 ✓ (((2 integer)) <- ((copy)) ((3 literal)))
c{1: 2 ✓ (((test1)) ((1 integer)) ((2 integer)))
c{0: 0 (((5 integer)) <- ((input)) ((1 literal))) -- nil
c{0: 1 (((4 integer)) <- ((input)) ((0 literal))) -- nil
c{0: 2 (((3 integer)) <- ((add)) ((4 integer)) ((5 integer))) -- nil
c{0: 3 (((reply))) -- nil
c{0: 4 (((4 integer)) <- ((copy)) ((34 literal))) -- nil
c{1: 0 ✓ (((5 integer)) <- ((input)) ((1 literal)))
c{1: 1 ✓ (((4 integer)) <- ((input)) ((0 literal)))
c{1: 2 ✓ (((3 integer)) <- ((add)) ((4 integer)) ((5 integer)))
c{1: 3 ✓ (((reply)))
c{1: 4 ✓ (((4 integer)) <- ((copy)) ((34 literal)))
cn0: convert-names in main
cn0: (((1 integer)) <- ((copy)) ((1 literal))) nil nil
cn0: checking arg ((1 literal))
cn0: checking oarg ((1 integer))
maybe-add: ((1 integer))
cn0: (((2 integer)) <- ((copy)) ((3 literal))) nil nil
cn0: checking arg ((3 literal))
cn0: checking oarg ((2 integer))
maybe-add: ((2 integer))
cn0: (((test1)) ((1 integer)) ((2 integer))) nil nil
cn0: checking arg ((1 integer))
maybe-add: ((1 integer))
cn0: checking arg ((2 integer))
maybe-add: ((2 integer))
cn0: convert-names in test1
cn0: (((5 integer)) <- ((input)) ((1 literal))) nil nil
cn0: checking arg ((1 literal))
cn0: checking oarg ((5 integer))
maybe-add: ((5 integer))
cn0: (((4 integer)) <- ((input)) ((0 literal))) nil nil
cn0: checking arg ((0 literal))
cn0: checking oarg ((4 integer))
maybe-add: ((4 integer))
cn0: (((3 integer)) <- ((add)) ((4 integer)) ((5 integer))) nil nil
cn0: checking arg ((4 integer))
maybe-add: ((4 integer))
cn0: checking arg ((5 integer))
maybe-add: ((5 integer))
cn0: checking oarg ((3 integer))
maybe-add: ((3 integer))
cn0: (((reply))) nil nil
cn0: (((4 integer)) <- ((copy)) ((34 literal))) nil nil
cn0: checking arg ((34 literal))
cn0: checking oarg ((4 integer))
maybe-add: ((4 integer))
cn1: (((1 integer)) <- ((copy)) ((1 literal)))
cn1: (((2 integer)) <- ((copy)) ((3 literal)))
cn1: (((test1)) ((1 integer)) ((2 integer)))
cn1: (((5 integer)) <- ((input)) ((1 literal)))
cn1: (((4 integer)) <- ((input)) ((0 literal)))
cn1: (((3 integer)) <- ((add)) ((4 integer)) ((5 integer)))
cn1: (((reply)))
cn1: (((4 integer)) <- ((copy)) ((34 literal)))
schedule: main
run: main 0: (((1 integer)) <- ((copy)) ((1 literal)))
run: main 0: 1 => ((1 integer))
mem: ((1 integer)): 1 <= 1
run: main 1: (((2 integer)) <- ((copy)) ((3 literal)))
run: main 1: 3 => ((2 integer))
mem: ((2 integer)): 2 <= 3
run: main 2: (((test1)) ((1 integer)) ((2 integer)))
mem: ((1 integer)) => 1
mem: ((2 integer)) => 3
run: test1/main 0: (((5 integer)) <- ((input)) ((1 literal)))
arg: (((1 literal))) 1 (1 3)
run: test1/main 0: 3 => ((5 integer))
mem: ((5 integer)): 5 <= 3
run: test1/main 1: (((4 integer)) <- ((input)) ((0 literal)))
arg: (((0 literal))) 0 (1 3)
run: test1/main 1: 1 => ((4 integer))
mem: ((4 integer)): 4 <= 1
run: test1/main 2: (((3 integer)) <- ((add)) ((4 integer)) ((5 integer)))
mem: ((4 integer)) => 1
mem: ((5 integer)) => 3
run: test1/main 2: 4 => ((3 integer))
mem: ((3 integer)): 3 <= 4
run: test1/main 3: (((reply)))
schedule: done with routine nil
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
/*=========================================================================*\
* TCP object
* LuaSocket toolkit
\*=========================================================================*/
#include "luasocket.h"

#include "auxiliar.h"
#include "socket.h"
#include "inet.h"
#include "options.h"
#include "tcp.h"
#include "../teliva.h"

#include <string.h>

/*=========================================================================*\
* Internal function prototypes
\*=========================================================================*/
static int global_create(lua_State *L);
static int global_create4(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);
static int meth_setstats(lua_State *L);
static int meth_getsockname(lua_State *L);
static int meth_getpeername(lua_State *L);
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_gettimeout(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L);
static int meth_dirty(lua_State *L);

/* tcp object methods */
static luaL_Reg tcp_methods[] = {
    {"__gc",        meth_close},
    {"__tostring",  auxiliar_tostring},
    {"accept",      meth_accept},
    {"bind",        meth_bind},
    {"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},
    {"setstats",    meth_setstats},
    {"listen",      meth_listen},
    {"receive",     meth_receive},
    {"send",        meth_send},
    {"setfd",       meth_setfd},
    {"setoption",   meth_setoption},
    {"setpeername", meth_connect},
    {"setsockname", meth_bind},
    {"settimeout",  meth_settimeout},
    {"gettimeout",  meth_gettimeout},
    {"shutdown",    meth_shutdown},
    {NULL,          NULL}
};

/* socket option handlers */
static t_opt optget[] = {
    {"keepalive",   opt_get_keepalive},
    {"reuseaddr",   opt_get_reuseaddr},
    {"reuseport",   opt_get_reuseport},
    {"tcp-nodelay", opt_get_tcp_nodelay},
#ifdef TCP_KEEPIDLE
    {"tcp-keepidle", opt_get_tcp_keepidle},
#endif
#ifdef TCP_KEEPCNT
    {"tcp-keepcnt", opt_get_tcp_keepcnt},
#endif
#ifdef TCP_KEEPINTVL
    {"tcp-keepintvl", opt_get_tcp_keepintvl},
#endif
    {"linger",      opt_get_linger},
    {"error",       opt_get_error},
	{"recv-buffer-size",     opt_get_recv_buf_size},
	{"send-buffer-size",     opt_get_send_buf_size},
    {NULL,          NULL}
};

static t_opt optset[] = {
    {"keepalive",   opt_set_keepalive},
    {"reuseaddr",   opt_set_reuseaddr},
    {"reuseport",   opt_set_reuseport},
    {"tcp-nodelay", opt_set_tcp_nodelay},
#ifdef TCP_KEEPIDLE
    {"tcp-keepidle", opt_set_tcp_keepidle},
#endif
#ifdef TCP_KEEPCNT
    {"tcp-keepcnt", opt_set_tcp_keepcnt},
#endif
#ifdef TCP_KEEPINTVL
    {"tcp-keepintvl", opt_set_tcp_keepintvl},
#endif
    {"ipv6-v6only", opt_set_ip6_v6only},
    {"linger",      opt_set_linger},
	{"recv-buffer-size",     opt_set_recv_buf_size},
	{"send-buffer-size",     opt_set_send_buf_size},
    {NULL,          NULL}
};

/* functions in library namespace */
static luaL_Reg func[] = {
    {"tcp", global_create},
    {"tcp4", global_create4},
    {"tcp6", global_create6},
    {"connect", global_connect},
    {NULL, NULL}
};

/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int tcp_open(lua_State *L)
{
    /* create classes */
    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_setfuncs(L, func, 0);
    return 0;
}

/*=========================================================================*\
* Lua methods
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Just call buffered IO methods
\*-------------------------------------------------------------------------*/
static int meth_send(lua_State *L) {
    p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
    return buffer_meth_send(L, &tcp->buf);
}

static int meth_receive(lua_State *L) {
    p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
    return buffer_meth_receive(L, &tcp->buf);
}

static int meth_getstats(lua_State *L) {
    p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
    return buffer_meth_getstats(L, &tcp->buf);
}

static int meth_setstats(lua_State *L) {
    p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
    return buffer_meth_setstats(L, &tcp->buf);
}

/*-------------------------------------------------------------------------*\
* 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, optset, &tcp->sock);
}

/*-------------------------------------------------------------------------*\
* Select support methods
\*-------------------------------------------------------------------------*/
static int meth_getfd(lua_State *L)
{
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
    lua_pushnumber(L, (int) tcp->sock);
    return 1;
}

/* this is very dangerous, but can be handy for those that are brave enough */
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);
    return 0;
}

static int meth_dirty(lua_State *L)
{
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
    lua_pushboolean(L, !buffer_isempty(&tcp->buf));
    return 1;
}

/*-------------------------------------------------------------------------*\
* 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;
    append_to_audit_log(L,  "socket.accept()");
    const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm);
    /* if successful, push client socket */
    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,
                (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, err);
        return 2;
    }
}

/*-------------------------------------------------------------------------*\
* 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);
    const char *port = luaL_checkstring(L, 3);
    static char buffer[1024] = {0};
    memset(buffer, '\0', 1024);
    snprintf(buffer, 1020, "socket.bind(\"%s\", %s)", address, port);
    append_to_audit_log(L, buffer);
    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;
    err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints);
    if (err) {
        lua_pushnil(L);
        lua_pushstring(L, err);
        return 2;
    }
    lua_pushnumber(L, 1);
    return 1;
}

/*-------------------------------------------------------------------------*\
* Turns a master tcp object into a client object.
\*-------------------------------------------------------------------------*/
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);
    const char *port = luaL_checkstring(L, 3);
    struct addrinfo connecthints;
    const char *err;
    static char buffer[1024] = {0};
    memset(buffer, '\0', 1024);
    snprintf(buffer, 1020, "socket.connect(\"%s\", %s)", address, port);
    append_to_audit_log(L, buffer);
    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, &tcp->family, 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) {
        lua_pushnil(L);
        lua_pushstring(L, err);
        return 2;
    }
    lua_pushnumber(L, 1);
    return 1;
}

/*-------------------------------------------------------------------------*\
* Closes socket used by object
\*-------------------------------------------------------------------------*/
static int meth_close(lua_State *L)
{
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
    socket_destroy(&tcp->sock);
    lua_pushnumber(L, 1);
    return 1;
}

/*-------------------------------------------------------------------------*\
* 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 == AF_INET6) {
        lua_pushliteral(L, "inet6");
        return 1;
    } else if (tcp->family == AF_INET) {
        lua_pushliteral(L, "inet4");
        return 1;
    } else {
        lua_pushliteral(L, "inet4");
        return 1;
    }
}

/*-------------------------------------------------------------------------*\
* Puts the sockt in listen mode
\*-------------------------------------------------------------------------*/
static int meth_listen(lua_State *L)
{
    append_to_audit_log(L,  "socket.listen()");
    p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
    int backlog = (int) luaL_optnumber(L, 2, 32);
    int err = socket_listen(&tcp->sock, backlog);
    if (err != IO_DONE) {
        lua_pushnil(L);
        lua_pushstring(L, socket_strerror(err));
        return 2;
    }
    /* turn master object into a server object */
    auxiliar_setclass(L, "tcp{server}", 1);
    lua_pushnumber(L, 1);
    return 1;
}

/*-------------------------------------------------------------------------*\
* Shuts the connection down partially
\*-------------------------------------------------------------------------*/
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);
    int how = luaL_checkoption(L, 2, "both", methods);
    socket_shutdown(&tcp->sock, how);
    lua_pushnumber(L, 1);
    return 1;
}

/*-------------------------------------------------------------------------*\
* Just call inet methods
\*-------------------------------------------------------------------------*/
static int meth_getpeername(lua_State *L)
{
    append_to_audit_log(L,  "socket.getpeername()");
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
    return inet_meth_getpeername(L, &tcp->sock, tcp->family);
}

static int meth_getsockname(lua_State *L)
{
    append_to_audit_log(L,  "socket.getsockname()");
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
    return inet_meth_getsockname(L, &tcp->sock, tcp->family);
}

/*-------------------------------------------------------------------------*\
* Just call tm methods
\*-------------------------------------------------------------------------*/
static int meth_settimeout(lua_State *L)
{
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
    return timeout_meth_settimeout(L, &tcp->tm);
}

static int meth_gettimeout(lua_State *L)
{
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
    return timeout_meth_gettimeout(L, &tcp->tm);
}

/*=========================================================================*\
* Library functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Creates a master tcp object
\*-------------------------------------------------------------------------*/
static int tcp_create(lua_State *L, int family) {
    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);
    /* if family is AF_UNSPEC, we leave the socket invalid and
     * store AF_UNSPEC into family. This will allow it to later be
     * replaced with an AF_INET6 or AF_INET socket upon first use. */
    tcp->sock = SOCKET_INVALID;
    tcp->family = family;
    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);
    if (family != AF_UNSPEC) {
        const char *err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0);
        if (err != NULL) {
            lua_pushnil(L);
            lua_pushstring(L, err);
            return 2;
        }
        socket_setnonblocking(&tcp->sock);
    }
    return 1;
}

static int global_create(lua_State *L) {
    return tcp_create(L, AF_UNSPEC);
}

static int global_create4(lua_State *L) {
    return tcp_create(L, AF_INET);
}

static int global_create6(lua_State *L) {
    return tcp_create(L, AF_INET6);
}

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;
    tcp->family = AF_UNSPEC;
    /* 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, &tcp->family, localaddr,
            localserv, &bindhints);
        if (err) {
            lua_pushnil(L);
            lua_pushstring(L, err);
            return 2;
        }
    }
    /* 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 = tcp->family;
    err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv,
         &tcp->tm, &connecthints);
    if (err) {
        socket_destroy(&tcp->sock);
        lua_pushnil(L);
        lua_pushstring(L, err);
        return 2;
    }
    auxiliar_setclass(L, "tcp{client}", -1);
    return 1;
}