From df9a7e548f83b0694d7e4096e004858a43ab8a28 Mon Sep 17 00:00:00 2001 From: Diego Nehab Date: Wed, 27 Dec 2000 19:19:22 +0000 Subject: [PATCH] Added new receive pattern "*a" Added new bind pattern "*" that binds to INADDR_ANY bind now also returns the ip and port bound to. --- src/luasocket.c | 588 +++++++++++++++++++++++++++++++----------------- 1 file changed, 386 insertions(+), 202 deletions(-) diff --git a/src/luasocket.c b/src/luasocket.c index 027afa3..ab44490 100644 --- a/src/luasocket.c +++ b/src/luasocket.c @@ -3,7 +3,7 @@ * Diego Nehab * 26/11/1999 * -* Module: LSOCK.C +* Module: LUASOCKET.C * * This module is part of an effort to make the most important features * of the TCP/IP protocol available for Lua scripts. @@ -29,13 +29,11 @@ #include -#define LUA_REENTRANT - #include #include #include -#include "lsock.h" +#include "luasocket.h" /*=========================================================================*\ * WinSock2 include files @@ -108,22 +106,21 @@ * function connect, and implementing the methods send, receive, timeout * and close. A server socket is an object created by the function bind, * and implementing the methods listen, accept and close. Lua tag values -* for these objects are created in the lua_socklibopen function, and +* for these objects are created in the lua_socketlibopen function, and * passed as closure values (first argumnents to every library function, # because we can't have any global variables. \*-------------------------------------------------------------------------*/ -#define CLIENT_TAG 1 -#define SERVER_TAG 2 -#define FIRST_PAR 3 +#define CLIENT_TAG -2 +#define SERVER_TAG -1 /*-------------------------------------------------------------------------*\ * Both socket types are stored in the same structure to simplify * implementation. The tag value used is different, though. The timeout * fields are not used for the server socket object. * There are two timeout values. The block timeout specifies the maximum -* time the any IO operation performed by luasock can be blocked waiting +* time the any IO operation performed by luasocket can be blocked waiting * for completion. The return timeout specifies the maximum time a Lua script -* can be blocked waiting for an luasock IO operation to complete. +* can be blocked waiting for an luasocket IO operation to complete. \*-------------------------------------------------------------------------*/ typedef struct t_sock { SOCKET sock; /* operating system socket object */ @@ -136,9 +133,6 @@ typedef t_sock *p_sock; /*-------------------------------------------------------------------------*\ * Macros and internal declarations \*-------------------------------------------------------------------------*/ -/* internal function prototypes */ -#include "sock.h" - /* return time since marked start in ms */ #define time_since(start) (get_time()-start) @@ -150,6 +144,66 @@ typedef t_sock *p_sock; #define max(x, y) ((x) > (y) ? x : y) #endif +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +/* luasocket API functions */ +static int net_connect(lua_State *L); +static int net_bind(lua_State *L); +static int net_listen(lua_State *L); +static int net_accept(lua_State *L); +static int net_send(lua_State *L); +static int net_receive(lua_State *L); +static int net_timeout(lua_State *L); +static int net_close(lua_State *L); + +/* fallbacks */ +static int server_gettable(lua_State *L); +static int client_gettable(lua_State *L); +static int sock_gc(lua_State *L); + +/* argument checking routines */ +static p_sock check_client(lua_State *L, int numArg, int client_tag); +static p_sock check_server(lua_State *L, int numArg, int server_tag); +static p_sock check_sock(lua_State *L, int numArg, int server_tag, + int client_tag); +static void pop_tags(lua_State *L, int *client_tag, int *server_tag); +static void push_tags(lua_State *L, int client_tag, int server_tag); + +/* result handling routines */ +static char *host_strerror(void); +static char *bind_strerror(void); +static char *sock_strerror(void); +static char *connect_strerror(void); + +static void push_error(lua_State *L, int err); +static void push_client(lua_State *L, p_sock sock, int client_tag); +static void push_server(lua_State *L, p_sock sock, int server_tag); + +/* plataform specific functions */ +static int get_time(void); +static void set_blocking(p_sock sock); +static void set_nonblocking(p_sock sock); + +/* auxiliary functions */ +static p_sock create_sock(void); +static p_sock create_tcpsock(void); +static int fill_sockaddr(struct sockaddr_in *server, const char *hostname, + unsigned short port); +static int get_timeout(p_sock sock, int elapsed); +static int read_or_timeout(p_sock sock, int elapsed); +static int write_or_timeout(p_sock sock, int elapsed); +static int send_raw(p_sock sock, const char *data, int wanted, + int start, int *err, int *end); +static void receive_raw(lua_State *L, p_sock sock, int wanted, + int start, int *err, int *end); +static void receive_dosline(lua_State *L, p_sock sock, int start, + int *err, int *end); +static void receive_unixline(lua_State *L, p_sock sock, int start, + int *err, int *end); +static void receive_all(lua_State *L, p_sock sock, int start, + int *err, int *end); + /*=========================================================================*\ * Test support functions \*=========================================================================*/ @@ -157,17 +211,18 @@ typedef t_sock *p_sock; /*-------------------------------------------------------------------------*\ * Returns the time the system has been up, in secconds. \*-------------------------------------------------------------------------*/ -static void net_time(lua_State *L); -static void net_time(lua_State *L) +static int net_time(lua_State *L); +static int net_time(lua_State *L) { lua_pushnumber(L, get_time()/1000.0); + return 1; } /*-------------------------------------------------------------------------*\ * Causes a Lua script to sleep for the specified number of secconds \*-------------------------------------------------------------------------*/ -static void net_sleep(lua_State *L); -static void net_sleep(lua_State *L) +static int net_sleep(lua_State *L); +static int net_sleep(lua_State *L) { int sec = (int) luaL_check_number(L, 1); #ifdef WIN32 @@ -175,6 +230,7 @@ static void net_sleep(lua_State *L) #else sleep(sec); #endif + return 0; } #endif @@ -194,15 +250,19 @@ static void net_sleep(lua_State *L) * On success: client socket * On error: nil, followed by an error message \*-------------------------------------------------------------------------*/ -static void net_connect(lua_State *L) +static int net_connect(lua_State *L) { - const char *hostname = luaL_check_string(L, FIRST_PAR); - unsigned short port = (unsigned short) luaL_check_number(L, FIRST_PAR+1); + const char *hostname = luaL_check_string(L, 1); + unsigned short port = (unsigned short) luaL_check_number(L, 2); + int client_tag, server_tag; struct sockaddr_in server; - p_sock sock = create_tcpsock(); + p_sock sock; + pop_tags(L, &client_tag, &server_tag); + sock = create_tcpsock(); if (!sock) { lua_pushnil(L); lua_pushstring(L, sock_strerror()); + return 2; } /* fills the sockaddr structure with the information needed to ** connect our socket with the remote host */ @@ -210,17 +270,18 @@ static void net_connect(lua_State *L) free(sock); lua_pushnil(L); lua_pushstring(L, host_strerror()); - return; + return 2; } if (connect(sock->sock,(struct sockaddr *)&server,sizeof(server)) < 0) { /* no connection? we close the socket to free the descriptor */ closesocket(sock->sock); lua_pushnil(L); lua_pushstring(L, connect_strerror()); - return; + return 2; } - push_client(L, sock); - /* no need to push second return value, since it would be nil anyways */ + push_client(L, sock, client_tag); + lua_pushnil(L); + return 2; } /*-------------------------------------------------------------------------*\ @@ -232,14 +293,21 @@ static void net_connect(lua_State *L) * On success: nil * On error: an error message \*-------------------------------------------------------------------------*/ -static void net_listen(lua_State *L) +static int net_listen(lua_State *L) { - p_sock sock = check_server(L, FIRST_PAR); - unsigned int backlog = (unsigned int) luaL_check_number(L, FIRST_PAR+1); - - if (listen(sock->sock, backlog) < 0) + p_sock sock; + int client_tag, server_tag; + unsigned int backlog; + pop_tags(L, &client_tag, &server_tag); + sock = check_server(L, 1, server_tag); + backlog = (unsigned int) luaL_check_number(L, 2); + if (listen(sock->sock, backlog) < 0) { lua_pushstring(L, "listen error"); - /* no need to push return value, since it would be nil anyways */ + return 1; + } else { + lua_pushnil(L); + return 1; + } } /*-------------------------------------------------------------------------*\ @@ -251,13 +319,16 @@ static void net_listen(lua_State *L) * On success: client socket attempting connection * On error: nil followed by an error message \*-------------------------------------------------------------------------*/ -static void net_accept(lua_State *L) +static int net_accept(lua_State *L) { struct sockaddr_in client_addr; - p_sock server = check_server(L, FIRST_PAR); + int client_tag, server_tag; + p_sock server; int client_sock = -1; unsigned int client_len = sizeof(client_addr); p_sock client; + pop_tags(L, &client_tag, &server_tag); + server = check_server(L, 1, server_tag); /* waits for a connection */ client_sock = accept(server->sock, (struct sockaddr *) &client_addr, &client_len); @@ -267,10 +338,13 @@ static void net_accept(lua_State *L) if (!client) { lua_pushnil(L); lua_pushstring(L, "out of memory"); - return; + return 2; + } else { + client->sock = client_sock; + push_client(L, client, client_tag); + lua_pushnil(L); + return 2; } - client->sock = client_sock; - push_client(L, client); } /*-------------------------------------------------------------------------*\ @@ -281,42 +355,56 @@ static void net_accept(lua_State *L) * backlog: optional parameter specifying the number of connections * to keep waiting before refuse a connection. the default value is 1. * Returns -* On success: server socket bound to address +* On success: server socket bound to address, the ip address and port bound * On error: nil, followed by an error message \*-------------------------------------------------------------------------*/ -static void net_bind(lua_State *L) +static int net_bind(lua_State *L) { - const char *hostname = luaL_check_string(L, FIRST_PAR); - unsigned short port = (unsigned short) luaL_check_number(L, FIRST_PAR+1); - unsigned int backlog = (unsigned int) luaL_opt_number(L, FIRST_PAR+2, 1.0); + const char *hostname = luaL_check_string(L, 1); + unsigned short port = (unsigned short) luaL_check_number(L, 2); + unsigned int backlog = (unsigned int) luaL_opt_number(L, 3, 1.0); struct sockaddr_in server; + int server_size = sizeof(server); + int client_tag, server_tag; p_sock sock = create_tcpsock(); + pop_tags(L, &client_tag, &server_tag); if (!sock) { lua_pushnil(L); lua_pushstring(L, sock_strerror()); + return 2; } /* fills the sockaddr structure with the information needed to ** connect our socket with local address */ - if (!fill_sockaddr(&server, hostname, port)) { + else if (!fill_sockaddr(&server, hostname, port)) { free(sock); lua_pushnil(L); lua_pushstring(L, host_strerror()); - return; + return 2; } - if (bind(sock->sock,(struct sockaddr *)&server,sizeof(server)) < 0) { + else if (bind(sock->sock,(struct sockaddr *)&server, server_size) < 0) { lua_pushnil(L); lua_pushstring(L, bind_strerror()); - return; + return 2; } /* define the connection waiting queue length */ - if (listen(sock->sock, backlog) < 0) { + else if (listen(sock->sock, backlog) < 0) { lua_pushnil(L); lua_pushstring(L, "listen error"); - return; - } + return 2; + } /* pass the created socket to Lua, as a server socket */ - push_server(L, sock); - /* no need to push return value, since it would be nil anyways */ + else { + /* pass server */ + push_server(L, sock, server_tag); + /* get used address and port */ + getsockname(sock->sock, (struct sockaddr *)&server, &server_size); + /* pass ip number */ + lua_pushstring(L, inet_ntoa(server.sin_addr)); + /* pass port number */ + lua_pushnumber(L, ntohs(server.sin_port)); + lua_pushnil(L); + return 4; + } } /*-------------------------------------------------------------------------*\ @@ -331,11 +419,16 @@ static void net_bind(lua_State *L) * Returns * no return value \*-------------------------------------------------------------------------*/ -static void net_timeout(lua_State *L) +static int net_timeout(lua_State *L) { - p_sock sock = check_client(L, FIRST_PAR); - int ms = (int) (luaL_check_number(L, FIRST_PAR+1)*1000.0); - const char *mode = luaL_opt_string(L, FIRST_PAR+2, "b"); + int client_tag, server_tag; + p_sock sock; + int ms; + const char *mode; + pop_tags(L, &client_tag, &server_tag); + sock = check_client(L, 1, client_tag); + ms = (int) (luaL_check_number(L, 2)*1000.0); + mode = luaL_opt_string(L, 3, "b"); switch (*mode) { case 'b': sock->b = ms; @@ -344,9 +437,10 @@ static void net_timeout(lua_State *L) sock->r = ms; break; default: - luaL_arg_check(L, 0, FIRST_PAR+2, "invalid timeout mode"); + luaL_arg_check(L, 0, 3, "invalid timeout mode"); break; } + return 0; } /*-------------------------------------------------------------------------*\ @@ -358,33 +452,44 @@ static void net_timeout(lua_State *L) * Returns * On success: nil, followed by the total number of bytes sent * On error: NET_TIMEOUT if the connection timedout, or NET_CLOSED if -* the connection has been closed +* the connection has been closed, followed by the total number of +* bytes sent \*-------------------------------------------------------------------------*/ -static void net_send(lua_State *L) +static int net_send(lua_State *L) { - p_sock sock = check_client(L, FIRST_PAR); + p_sock sock; const char *data; - long size; + size_t size; int start = get_time(); long total = 0; - int arg = FIRST_PAR+1; + int arg; int err = NET_DONE; int end; + int top; + int client_tag, server_tag; + pop_tags(L, &client_tag, &server_tag); + top = lua_gettop(L); + sock = check_client(L, 1, client_tag); #ifdef _DEBUG_BLOCK -printf("luasock: send start\n"); +printf("luasocket: send start\n"); #endif - while ((data = luaL_opt_lstr(L, arg++, NULL, &size)) && err == NET_DONE) + for (arg = 2; arg <= top; arg++) { + data = luaL_opt_lstr(L, arg, NULL, &size); + if (!data || err != NET_DONE) + break; total += send_raw(sock, data, size, start, &err, &end); + } push_error(L, err); lua_pushnumber(L, (double) total); #ifdef _DEBUG_BLOCK -printf("luasock: send end\n"); +printf("luasocket: send end\n"); #endif #ifdef _DEBUG /* pass the time elapsed during function execution to Lua, so that ** the test script can make sure we respected the timeouts */ lua_pushnumber(L, (end-start)/1000.0); #endif + return lua_gettop(L) - top; } /*-------------------------------------------------------------------------*\ @@ -399,57 +504,73 @@ lua_pushnumber(L, (end-start)/1000.0); * number: reads 'number' characters from the socket * Returns * On success: one string for each pattern -* On error: all strings for which there was no error, followed by on +* On error: all strings for which there was no error, followed by one * nil value for each failed string, followed by an error code \*-------------------------------------------------------------------------*/ -static void net_receive(lua_State *L) +static int net_receive(lua_State *L) { - static const char *const modenames[] = {"*l", "*lu", NULL}; - p_sock sock = check_client(L, FIRST_PAR); - int err = NET_DONE, arg = FIRST_PAR+1, got = 0; - char *data = NULL; + static const char *const modenames[] = {"*l", "*lu", "*a", NULL}; + int err = NET_DONE, arg = 2; int start = get_time(); - const char *mode = luaL_opt_string(L, arg++, "*l"); int end; + int client_tag, server_tag; + int top; + p_sock sock; + const char *mode; + pop_tags(L, &client_tag, &server_tag); + sock = check_client(L, 1, client_tag); #ifdef _DEBUG_BLOCK -printf("luasock: receive start\n"); +printf("luasocket: receive start\n"); #endif - do { + /* push default pattern */ + top = lua_gettop(L); + if (top < 2) { + lua_pushstring(L, "*l"); + top++; + } + for (arg = 2; arg <= top; arg++) { /* if one pattern failed, we just skip all other patterns */ if (err != NET_DONE) { lua_pushnil(L); continue; } - /* get next pattern */ - switch (luaL_findstring(mode, modenames)) { - /* DOS line mode */ - case 0: - got = receive_dosline(L, sock, &data, start, &err, &end); - break; - /* Unix line mode */ - case 2: - got = receive_unixline(L, sock, &data, start, &err, &end); - break; - /* else it must be a number, raw mode */ - default: { - long size = (long) luaL_check_number(L, arg-1); - got = receive_raw(L, sock, size, &data, start, &err, &end); - break; + if (lua_isnumber(L, arg)) { + long size = (long) lua_tonumber(L, arg); + receive_raw(L, sock, size, start, &err, &end); + } else { + mode = luaL_opt_string(L, arg, NULL); + /* get next pattern */ + switch (luaL_findstring(mode, modenames)) { + /* DOS line mode */ + case 0: + receive_dosline(L, sock, start, &err, &end); + break; + /* Unix line mode */ + case 1: + receive_unixline(L, sock, start, &err, &end); + break; + /* 'Til closed mode */ + case 2: + receive_all(L, sock, start, &err, &end); + break; + /* else it must be a number, raw mode */ + default: + luaL_arg_check(L, 0, arg, "invalid receive pattern"); + break; } } - /* pass result */ - lua_pushlstring(L, data, got); - } while ((mode = luaL_opt_string(L, arg++, NULL))); + } /* last return is an error code */ push_error(L, err); #ifdef _DEBUG_BLOCK -printf("luasock: receive end\n"); +printf("luasocket: receive end\n"); #endif #ifdef _DEBUG /* pass the time elapsed during function execution to Lua, so that ** the test script can make sure we respected the timeouts */ lua_pushnumber(L, (end-start)/1000.0); #endif + return lua_gettop(L) - top; } /*-------------------------------------------------------------------------*\ @@ -457,13 +578,17 @@ lua_pushnumber(L, (end-start)/1000.0); * Input * sock: socket to be closed \*-------------------------------------------------------------------------*/ -static void net_close(lua_State *L) +static int net_close(lua_State *L) { - p_sock sock = check_sock(L, FIRST_PAR); + int client_tag, server_tag; + p_sock sock; + pop_tags(L, &client_tag, &server_tag); + sock = check_sock(L, 1, client_tag, server_tag); closesocket(sock->sock); /* set value to -1 so that we can later detect the use of a ** closed socket */ sock->sock = -1; + return 0; } /*-------------------------------------------------------------------------*\ @@ -471,36 +596,35 @@ static void net_close(lua_State *L) * alternative interface client:receive, client:send etc for the client * socket methods. \*-------------------------------------------------------------------------*/ -static void client_gettable(lua_State *L) +static int client_gettable(lua_State *L) { static const char *const net_api[] = {"receive","send","timeout","close", "connect", NULL}; - const char *idx = luaL_check_string(L, FIRST_PAR+1); + const char *idx = luaL_check_string(L, 2); + int server_tag, client_tag; + pop_tags(L, &client_tag, &server_tag); switch (luaL_findstring(idx, net_api)) { case 0: - lua_pushnumber(L, get_tag(L, CLIENT_TAG)); - lua_pushnumber(L, get_tag(L, SERVER_TAG)); + push_tags(L, client_tag, server_tag); lua_pushcclosure(L, net_receive, 2); break; case 1: - lua_pushnumber(L, get_tag(L, CLIENT_TAG)); - lua_pushnumber(L, get_tag(L, SERVER_TAG)); + push_tags(L, client_tag, server_tag); lua_pushcclosure(L, net_send, 2); break; case 2: - lua_pushnumber(L, get_tag(L, CLIENT_TAG)); - lua_pushnumber(L, get_tag(L, SERVER_TAG)); + push_tags(L, client_tag, server_tag); lua_pushcclosure(L, net_timeout, 2); break; case 3: - lua_pushnumber(L, get_tag(L, CLIENT_TAG)); - lua_pushnumber(L, get_tag(L, SERVER_TAG)); + push_tags(L, client_tag, server_tag); lua_pushcclosure(L, net_close, 2); break; default: lua_pushnil(L); break; } + return 1; } /*-------------------------------------------------------------------------*\ @@ -508,30 +632,30 @@ static void client_gettable(lua_State *L) * alternative interface server:listen, server:accept etc for the server * socket methods. \*-------------------------------------------------------------------------*/ -static void server_gettable(lua_State *L) +static int server_gettable(lua_State *L) { static const char *const net_api[] = {"listen","accept","close", NULL}; - const char *idx = luaL_check_string(L, FIRST_PAR+1); + const char *idx = luaL_check_string(L, 2); + int server_tag, client_tag; + pop_tags(L, &client_tag, &server_tag); switch (luaL_findstring(idx, net_api)) { case 0: - lua_pushnumber(L, get_tag(L, CLIENT_TAG)); - lua_pushnumber(L, get_tag(L, SERVER_TAG)); + push_tags(L, client_tag, server_tag); lua_pushcclosure(L, net_listen, 2); break; case 1: - lua_pushnumber(L, get_tag(L, CLIENT_TAG)); - lua_pushnumber(L, get_tag(L, SERVER_TAG)); + push_tags(L, client_tag, server_tag); lua_pushcclosure(L, net_accept, 2); break; case 2: - lua_pushnumber(L, get_tag(L, CLIENT_TAG)); - lua_pushnumber(L, get_tag(L, SERVER_TAG)); + push_tags(L, client_tag, server_tag); lua_pushcclosure(L, net_close, 2); break; default: lua_pushnil(L); break; } + return 1; } /*-------------------------------------------------------------------------*\ @@ -539,12 +663,16 @@ static void server_gettable(lua_State *L) * makes sure that all collected sockets are closed and that the memory * used by the C structure t_sock is properly released. \*-------------------------------------------------------------------------*/ -static void sock_gc(lua_State *L) +static int sock_gc(lua_State *L) { - p_sock sock = check_sock(L, FIRST_PAR); + int server_tag, client_tag; + p_sock sock; + pop_tags(L, &client_tag, &server_tag); + sock = check_sock(L, 1, client_tag, server_tag); if (sock->sock >= 0) closesocket(sock->sock); free(sock); + return 1; } /*=========================================================================*\ @@ -637,19 +765,24 @@ static int fill_sockaddr(struct sockaddr_in *address, const char *hostname, { struct hostent *host = NULL; unsigned long addr = inet_addr(hostname); - /* BSD says we could have used gethostbyname even if the hostname is - ** in ip address form, but WinSock2 says we can't. Therefore we - ** choose a method that works on both plataforms */ - if (addr == INADDR_NONE) - host = gethostbyname(hostname); - else - host = gethostbyaddr((char * ) &addr, sizeof(unsigned long), AF_INET); - if (!host) - return 0; memset(address, 0, sizeof(struct sockaddr_in)); + if (strcmp(hostname, "*")) { + /* BSD says we could have used gethostbyname even if the hostname is + ** in ip address form, but WinSock2 says we can't. Therefore we + ** choose a method that works on both plataforms */ + if (addr == INADDR_NONE) + host = gethostbyname(hostname); + else + host = gethostbyaddr((char * ) &addr, sizeof(unsigned long), + AF_INET); + if (!host) + return 0; + memcpy(&(address->sin_addr), host->h_addr, (unsigned) host->h_length); + } else { + address->sin_addr.s_addr = htonl(INADDR_ANY); + } address->sin_family = AF_INET; address->sin_port = htons(port); - memcpy(&(address->sin_addr), host->h_addr, (unsigned) host->h_length); return 1; } @@ -776,7 +909,7 @@ static int send_raw(p_sock sock, const char *data, int wanted, #ifdef _DEBUG /* the lua_pushlstring function can take a long time to pass a large block ** to Lua, therefore, we mark the time before passing the result. -** also, the call to write of read might take longer then the time we had +** also, the call to write or read might take longer then the time we had ** left, so that the end of the operation is marked before the last call ** to the OS */ *end = get_time(); @@ -795,7 +928,7 @@ static int send_raw(p_sock sock, const char *data, int wanted, return total; } #ifdef _DEBUG_BLOCK -printf("luasock: sent %d bytes, %dms elapsed\n", put, time_since(start)); +printf("luasocket: sent %d bytes, %dms elapsed\n", put, time_since(start)); #endif wanted -= put; data += put; @@ -813,46 +946,84 @@ printf("luasock: sent %d bytes, %dms elapsed\n", put, time_since(start)); * wanted: number of bytes to be read * start: time the operation started, in ms * Output -* data: pointer to an internal buffer containing the data read * err: operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED * Returns * Number of bytes read \*-------------------------------------------------------------------------*/ -static int receive_raw(lua_State *L, p_sock sock, int wanted, char **data, - int start, int *err, int *end) +#define MIN(x,y) ((x)<(y)?(x):(y)) +static void receive_raw(lua_State *L, p_sock sock, int wanted, int start, + int *err, int *end) { int got = 0; char *buffer = NULL; + luaL_Buffer b; *end = start; - luaL_resetbuffer(L); + luaL_buffinit(L, &b); while (wanted > 0) { - buffer = luaL_openspace(L, wanted); if(!read_or_timeout(sock, time_since(start))) { #ifdef _DEBUG *end = get_time(); #endif - *data = luaL_buffer(L); *err = NET_TIMEOUT; - return luaL_getsize(L); + luaL_pushresult(&b); + return; } #ifdef _DEBUG *end = get_time(); #endif - got = recv(sock->sock, buffer, wanted, 0); + buffer = luaL_prepbuffer(&b); + got = recv(sock->sock, buffer, MIN(wanted, LUAL_BUFFERSIZE), 0); #ifdef _DEBUG_BLOCK -printf("luasock: wanted %d, got %d, %dms elapsed\n", wanted, got, time_since(start)); +printf("luasocket: wanted %d, got %d, %dms elapsed\n", wanted, got, time_since(start)); #endif if (got <= 0) { - *data = luaL_buffer(L); *err = NET_CLOSED; - return luaL_getsize(L); + luaL_pushresult(&b); + return; } wanted -= got; - luaL_addsize(L,got); + luaL_addsize(&b, got); } - *data = luaL_buffer(L); *err = NET_DONE; - return luaL_getsize(L); + luaL_pushresult(&b); +} + +/*-------------------------------------------------------------------------*\ +* Reads everything until the connection is closed +* Input +* sock: socket structure being used in operation +* start: time the operation started, in ms +* Output +* err: operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED +* Result +* a string is pushed into the Lua stack with the line just read +\*-------------------------------------------------------------------------*/ +static void receive_all(lua_State *L, p_sock sock, int start, + int *err, int *end) +{ + int got; + char *buffer; + luaL_Buffer b; + *end = start; + luaL_buffinit(L, &b); + for ( ;; ) { + buffer = luaL_prepbuffer(&b); + if (read_or_timeout(sock, time_since(start))) { +#ifdef _DEBUG +*end = get_time(); +#endif + got = recv(sock->sock, buffer, LUAL_BUFFERSIZE, 0); + if (got <= 0) { + *err = NET_DONE; + break; + } + luaL_addsize(&b, got); + } else { + *err = NET_TIMEOUT; + break; + } + } + luaL_pushresult(&b); } /*-------------------------------------------------------------------------*\ @@ -866,17 +1037,18 @@ printf("luasock: wanted %d, got %d, %dms elapsed\n", wanted, got, time_since(sta * Output * data: pointer to an internal buffer containing the data read * err: operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED -* Returns -* Number of bytes read +* Result +* a string is pushed into the Lua stack with the line just read \*-------------------------------------------------------------------------*/ -static long receive_dosline(lua_State *L, p_sock sock, char **data, - int start, int *err, int *end) +static void receive_dosline(lua_State *L, p_sock sock, int start, + int *err, int *end) { char c = ' '; long got = 0; + luaL_Buffer b; *end = start; - luaL_resetbuffer(L); - while (c != '\n') { + luaL_buffinit(L, &b); + for ( ;; ) { if (read_or_timeout(sock, time_since(start))) { #ifdef _DEBUG *end = get_time(); @@ -884,21 +1056,20 @@ static long receive_dosline(lua_State *L, p_sock sock, char **data, got = recv(sock->sock, &c, 1, 0); if (got <= 0) { *err = NET_CLOSED; - *data = luaL_buffer(L); - return luaL_getsize(L); + break; + } + if (c != '\n') { + if (c != '\r') luaL_putchar(&b, c); + } else { + *err = NET_DONE; + break; } - luaL_addchar(L, c); } else { *err = NET_TIMEOUT; - *data = luaL_buffer(L); - return luaL_getsize(L); + break; } } - *err = NET_DONE; - *data = luaL_buffer(L); - got = luaL_getsize(L); - if ((*data)[got-2] == '\r') return got-2; - else return got-1; + luaL_pushresult(&b); } /*-------------------------------------------------------------------------*\ @@ -915,43 +1086,50 @@ static long receive_dosline(lua_State *L, p_sock sock, char **data, * Returns * Number of bytes read \*-------------------------------------------------------------------------*/ -static long receive_unixline(lua_State *L, p_sock sock, char **data, - int start, int *err, int *end) +static void receive_unixline(lua_State *L, p_sock sock, int start, + int *err, int *end) { char c = ' '; + long got = 0; + long size = 0; + luaL_Buffer b; *end = start; - luaL_resetbuffer(L); - while (c != '\n') { + luaL_buffinit(L, &b); + for ( ;; ) { if (read_or_timeout(sock, time_since(start))) { #ifdef _DEBUG *end = get_time(); #endif - if (recv(sock->sock, &c, 1, 0) <= 0) { + got = recv(sock->sock, &c, 1, 0); + if (got <= 0) { *err = NET_CLOSED; - *data = luaL_buffer(L); - return luaL_getsize(L); + break; + } + if (c != '\n') { + luaL_putchar(&b, c); + size++; + } else { + *err = NET_DONE; + break; } - luaL_addchar(L, c); } else { *err = NET_TIMEOUT; - *data = luaL_buffer(L); - return luaL_getsize(L); + break; } } - *err = NET_DONE; - *data = luaL_buffer(L); - return luaL_getsize(L) - 1; + luaL_pushresult(&b); } /*-------------------------------------------------------------------------*\ -* Gets a tag from a closure parameter +* Pops tags from closures * Input * L: lua environment -* par: parameter number \*-------------------------------------------------------------------------*/ -static int get_tag(lua_State *L, int par) +static void pop_tags(lua_State *L, int *client_tag, int *server_tag) { - return (int) lua_getnumber(L, lua_getparam(L, par)); + *client_tag = (int) lua_tonumber(L, CLIENT_TAG); + *server_tag = (int) lua_tonumber(L, SERVER_TAG); + lua_pop(L, 2); } /*-------------------------------------------------------------------------*\ @@ -974,6 +1152,17 @@ static void push_error(lua_State *L, int err) } } +/*-------------------------------------------------------------------------*\ +* Passes socket tags to lua in correct order +* Input: +* client_tag, server_tag +\*-------------------------------------------------------------------------*/ +static void push_tags(lua_State *L, int client_tag, int server_tag) +{ + lua_pushnumber(L, client_tag); + lua_pushnumber(L, server_tag); +} + /*-------------------------------------------------------------------------*\ * Passes a client socket to Lua. * Must be called from a closure receiving the socket tags as its @@ -982,9 +1171,9 @@ static void push_error(lua_State *L, int err) * L: lua environment * sock: pointer to socket structure to be used \*-------------------------------------------------------------------------*/ -static void push_client(lua_State *L, p_sock sock) +static void push_client(lua_State *L, p_sock sock, int client_tag) { - lua_pushusertag(L, (void *) sock, get_tag(L, CLIENT_TAG)); + lua_pushusertag(L, (void *) sock, client_tag); } /*-------------------------------------------------------------------------*\ @@ -995,9 +1184,9 @@ static void push_client(lua_State *L, p_sock sock) * L: lua environment * sock: pointer to socket structure to be used \*-------------------------------------------------------------------------*/ -static void push_server(lua_State *L, p_sock sock) +static void push_server(lua_State *L, p_sock sock, int server_tag) { - lua_pushusertag(L, (void *) sock, get_tag(L, SERVER_TAG)); + lua_pushusertag(L, (void *) sock, server_tag); } /*=========================================================================*\ @@ -1233,7 +1422,7 @@ static char *connect_strerror(void) * Initializes the library interface with Lua and the socket library. * Defines the symbols exported to Lua. \*-------------------------------------------------------------------------*/ -void lua_socklibopen(lua_State *L) +void lua_socketlibopen(lua_State *L) { int client_tag, server_tag; static struct luaL_reg funcs[] = { @@ -1256,29 +1445,24 @@ void lua_socklibopen(lua_State *L) server_tag = lua_newtag(L); /* Lua exported functions */ for (i = 0; i < sizeof(funcs)/sizeof(funcs[0]); i++) { - lua_pushnumber(L, client_tag); - lua_pushnumber(L, server_tag); - lua_pushcclosure(L, funcs[i].func, 2 ); - lua_setglobal(L, funcs[i].name ); + push_tags(L, client_tag, server_tag); + lua_pushcclosure(L, funcs[i].func, 2); + lua_setglobal(L, funcs[i].name); } /* fallbacks */ - lua_pushnumber(L, client_tag); - lua_pushnumber(L, server_tag); + push_tags(L, client_tag, server_tag); lua_pushcclosure(L, client_gettable, 2); lua_settagmethod(L, client_tag, "gettable"); - lua_pushnumber(L, client_tag); - lua_pushnumber(L, server_tag); + push_tags(L, client_tag, server_tag); lua_pushcclosure(L, server_gettable, 2); lua_settagmethod(L, server_tag, "gettable"); - lua_pushnumber(L, client_tag); - lua_pushnumber(L, server_tag); + push_tags(L, client_tag, server_tag); lua_pushcclosure(L, sock_gc, 2); lua_settagmethod(L, client_tag, "gc"); - lua_pushnumber(L, client_tag); - lua_pushnumber(L, server_tag); + push_tags(L, client_tag, server_tag); lua_pushcclosure(L, sock_gc, 2); lua_settagmethod(L, server_tag, "gc"); @@ -1308,13 +1492,12 @@ lua_pushcfunction(L, net_time); lua_setglobal(L, "time"); * Returns * pointer to client socket, or doesn't return in case of error \*-------------------------------------------------------------------------*/ -static p_sock check_client(lua_State *L, int numArg) +static p_sock check_client(lua_State *L, int numArg, int client_tag) { p_sock sock; - lua_Object o = lua_getparam(L, numArg); - luaL_arg_check(L, lua_tag(L, o) == get_tag(L, CLIENT_TAG), + luaL_arg_check(L, lua_tag(L, numArg) == client_tag, numArg, "client socket expected"); - sock = (p_sock) lua_getuserdata(L, o); + sock = (p_sock) lua_touserdata(L, numArg); if (sock->sock < 0) lua_error(L, "operation on closed socket"); return sock; @@ -1328,13 +1511,12 @@ static p_sock check_client(lua_State *L, int numArg) * Returns * pointer to server socket, or doesn't return in case of error \*-------------------------------------------------------------------------*/ -static p_sock check_server(lua_State *L, int numArg) +static p_sock check_server(lua_State *L, int numArg, int server_tag) { p_sock sock; - lua_Object o = lua_getparam(L, numArg); - luaL_arg_check(L, lua_tag(L, o) == get_tag(L, SERVER_TAG), + luaL_arg_check(L, lua_tag(L, numArg) == server_tag, numArg, "server socket expected"); - sock = (p_sock) lua_getuserdata(L, o); + sock = (p_sock) lua_touserdata(L, numArg); if (sock->sock < 0) lua_error(L, "operation on closed socket"); return sock; @@ -1348,10 +1530,12 @@ static p_sock check_server(lua_State *L, int numArg) * Returns * pointer to socket, or doesn't return in case of error \*-------------------------------------------------------------------------*/ -static p_sock check_sock(lua_State *L, int numArg) +static p_sock check_sock(lua_State *L, int numArg, int client_tag, + int server_tag) { - lua_Object o = lua_getparam(L, numArg); - luaL_arg_check(L, (lua_tag(L, o) == get_tag(L, CLIENT_TAG)) || - (lua_tag(L, o) == get_tag(L, SERVER_TAG)), numArg, "socket expected"); - return lua_getuserdata(L, o); + p_sock sock; + luaL_arg_check(L, (lua_tag(L, numArg) == client_tag) || + (lua_tag(L, numArg) == server_tag), numArg, "socket expected"); + sock = lua_touserdata(L, numArg); + return sock; }