mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-12-26 12:28:21 +01:00
All input from sockets is now buffered. This has drastically
improved line I/O. The code is much simpler now, too. All timeout management has been rewritten.
This commit is contained in:
parent
17c4d1c305
commit
41643c2643
602
src/luasocket.c
602
src/luasocket.c
@ -6,9 +6,7 @@
|
|||||||
* Module: LUASOCKET.C
|
* Module: LUASOCKET.C
|
||||||
*
|
*
|
||||||
* This module is part of an effort to make the most important features
|
* This module is part of an effort to make the most important features
|
||||||
* of the TCP/IP protocol available for Lua scripts.
|
* of the TCP/IP protocol available to Lua scripts.
|
||||||
* The main intent of the project was the distribution with the CGILua
|
|
||||||
* toolkit, in which is is used to implement the SMTP client functions.
|
|
||||||
* The Lua interface to TCP/IP follows the BSD TCP/IP API closely,
|
* The Lua interface to TCP/IP follows the BSD TCP/IP API closely,
|
||||||
* trying to simplify all tasks involved in setting up a client connection
|
* trying to simplify all tasks involved in setting up a client connection
|
||||||
* and simple server connections.
|
* and simple server connections.
|
||||||
@ -21,16 +19,15 @@
|
|||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Common include files
|
* Common include files
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include <lua.h>
|
|
||||||
#include <lauxlib.h>
|
#include <lauxlib.h>
|
||||||
|
#include <lua.h>
|
||||||
#include <lualib.h>
|
#include <lualib.h>
|
||||||
|
|
||||||
#include "luasocket.h"
|
#include "luasocket.h"
|
||||||
@ -41,11 +38,11 @@
|
|||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <winbase.h>
|
#include <winbase.h>
|
||||||
|
#else
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* BSD include files
|
* BSD include files
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#else
|
|
||||||
/* close function */
|
/* close function */
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
/* fnctnl function and associated constants */
|
/* fnctnl function and associated constants */
|
||||||
@ -100,6 +97,12 @@
|
|||||||
#define NET_TIMEOUT 0 /* operation timed out */
|
#define NET_TIMEOUT 0 /* operation timed out */
|
||||||
#define NET_CLOSED 1 /* the connection has been closed */
|
#define NET_CLOSED 1 /* the connection has been closed */
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Time out mode to be checked
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
#define TM_RECEIVE 1
|
||||||
|
#define TM_SEND 2
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* As far as a Lua script is concerned, there are two kind of objects
|
* As far as a Lua script is concerned, there are two kind of objects
|
||||||
* representing a socket. A client socket is an object created by the
|
* representing a socket. A client socket is an object created by the
|
||||||
@ -107,7 +110,7 @@
|
|||||||
* and close. A server socket is an object created by the function bind,
|
* and close. A server socket is an object created by the function bind,
|
||||||
* and implementing the methods listen, accept and close. Lua tag values
|
* and implementing the methods listen, accept and close. Lua tag values
|
||||||
* for these objects are created in the lua_socketlibopen function, and
|
* for these objects are created in the lua_socketlibopen function, and
|
||||||
* passed as closure values (first argumnents to every library function,
|
* passed as closure values (last argumnents to every library function)
|
||||||
# because we can't have any global variables.
|
# because we can't have any global variables.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
#define CLIENT_TAG -2
|
#define CLIENT_TAG -2
|
||||||
@ -115,27 +118,30 @@
|
|||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Both socket types are stored in the same structure to simplify
|
* Both socket types are stored in the same structure to simplify
|
||||||
* implementation. The tag value used is different, though. The timeout
|
* implementation. The tag value used is different, though.
|
||||||
* fields are not used for the server socket object.
|
* The timeout and buffer parameters are not used by server sockets.
|
||||||
* There are two timeout values. The block timeout specifies the maximum
|
|
||||||
* 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 luasocket IO operation to complete.
|
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
typedef struct t_sock {
|
typedef struct t_sock {
|
||||||
SOCKET sock; /* operating system socket object */
|
/* operating system socket object */
|
||||||
int b; /* block timeout in ms */
|
SOCKET sock;
|
||||||
int r; /* return timeout in ms */
|
/* start time of the current operation */
|
||||||
int blocking; /* is this socket in blocking mode? */
|
int tm_start;
|
||||||
|
#ifdef _DEBUG
|
||||||
|
/* end time of current operation, for debug purposes */
|
||||||
|
int tm_end;
|
||||||
|
#endif
|
||||||
|
/* return and blocking timeout values (-1 if no limit) */
|
||||||
|
int tm_return, tm_block;
|
||||||
|
/* buffered I/O storage */
|
||||||
|
unsigned char bf_buffer[LUASOCKET_BUFFERSIZE];
|
||||||
|
/* first and last red bytes not yet passed to application */
|
||||||
|
int bf_first, bf_last;
|
||||||
} t_sock;
|
} t_sock;
|
||||||
typedef t_sock *p_sock;
|
typedef t_sock *p_sock;
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Macros and internal declarations
|
* Macros and internal declarations
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
/* return time since marked start in ms */
|
|
||||||
#define time_since(start) (get_time()-start)
|
|
||||||
|
|
||||||
/* min and max macros */
|
/* min and max macros */
|
||||||
#ifndef min
|
#ifndef min
|
||||||
#define min(x, y) ((x) < (y) ? x : y)
|
#define min(x, y) ((x) < (y) ? x : y)
|
||||||
@ -157,6 +163,24 @@ static int net_receive(lua_State *L);
|
|||||||
static int net_timeout(lua_State *L);
|
static int net_timeout(lua_State *L);
|
||||||
static int net_close(lua_State *L);
|
static int net_close(lua_State *L);
|
||||||
|
|
||||||
|
/* buffered I/O management */
|
||||||
|
static const unsigned char *bf_receive(p_sock sock, int *length);
|
||||||
|
static void bf_skip(p_sock sock, int length);
|
||||||
|
static int bf_isempty(p_sock sock);
|
||||||
|
|
||||||
|
/* timeout management */
|
||||||
|
static int tm_timedout(p_sock sock, int mode);
|
||||||
|
static int tm_gettimeleft(p_sock sock);
|
||||||
|
static int tm_gettime(void);
|
||||||
|
static void tm_markstart(p_sock sock);
|
||||||
|
|
||||||
|
/* I/O */
|
||||||
|
static int send_raw(p_sock sock, const char *data, int wanted, int *err);
|
||||||
|
static int receive_raw(lua_State *L, p_sock sock, int wanted);
|
||||||
|
static int receive_dosline(lua_State *L, p_sock sock);
|
||||||
|
static int receive_unixline(lua_State *L, p_sock sock);
|
||||||
|
static int receive_all(lua_State *L, p_sock sock);
|
||||||
|
|
||||||
/* fallbacks */
|
/* fallbacks */
|
||||||
static int server_gettable(lua_State *L);
|
static int server_gettable(lua_State *L);
|
||||||
static int client_gettable(lua_State *L);
|
static int client_gettable(lua_State *L);
|
||||||
@ -170,7 +194,7 @@ static p_sock check_sock(lua_State *L, int numArg, int server_tag,
|
|||||||
static void pop_tags(lua_State *L, int *client_tag, int *server_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);
|
static void push_tags(lua_State *L, int client_tag, int server_tag);
|
||||||
|
|
||||||
/* result handling routines */
|
/* error code translations functions */
|
||||||
static char *host_strerror(void);
|
static char *host_strerror(void);
|
||||||
static char *bind_strerror(void);
|
static char *bind_strerror(void);
|
||||||
static char *sock_strerror(void);
|
static char *sock_strerror(void);
|
||||||
@ -181,7 +205,6 @@ 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);
|
static void push_server(lua_State *L, p_sock sock, int server_tag);
|
||||||
|
|
||||||
/* plataform specific functions */
|
/* plataform specific functions */
|
||||||
static int get_time(void);
|
|
||||||
static void set_blocking(p_sock sock);
|
static void set_blocking(p_sock sock);
|
||||||
static void set_nonblocking(p_sock sock);
|
static void set_nonblocking(p_sock sock);
|
||||||
|
|
||||||
@ -190,19 +213,6 @@ static p_sock create_sock(void);
|
|||||||
static p_sock create_tcpsock(void);
|
static p_sock create_tcpsock(void);
|
||||||
static int fill_sockaddr(struct sockaddr_in *server, const char *hostname,
|
static int fill_sockaddr(struct sockaddr_in *server, const char *hostname,
|
||||||
unsigned short port);
|
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
|
* Test support functions
|
||||||
@ -214,7 +224,7 @@ static void receive_all(lua_State *L, p_sock sock, int start,
|
|||||||
static int net_time(lua_State *L);
|
static int 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);
|
lua_pushnumber(L, tm_gettime()/1000.0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,6 +289,7 @@ static int net_connect(lua_State *L)
|
|||||||
lua_pushstring(L, connect_strerror());
|
lua_pushstring(L, connect_strerror());
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
set_nonblocking(sock);
|
||||||
push_client(L, sock, client_tag);
|
push_client(L, sock, client_tag);
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
return 2;
|
return 2;
|
||||||
@ -341,6 +352,7 @@ static int net_accept(lua_State *L)
|
|||||||
return 2;
|
return 2;
|
||||||
} else {
|
} else {
|
||||||
client->sock = client_sock;
|
client->sock = client_sock;
|
||||||
|
set_nonblocking(client);
|
||||||
push_client(L, client, client_tag);
|
push_client(L, client, client_tag);
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
return 2;
|
return 2;
|
||||||
@ -431,10 +443,10 @@ static int net_timeout(lua_State *L)
|
|||||||
mode = luaL_opt_string(L, 3, "b");
|
mode = luaL_opt_string(L, 3, "b");
|
||||||
switch (*mode) {
|
switch (*mode) {
|
||||||
case 'b':
|
case 'b':
|
||||||
sock->b = ms;
|
sock->tm_block = ms;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
sock->r = ms;
|
sock->tm_return = ms;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
luaL_arg_check(L, 0, 3, "invalid timeout mode");
|
luaL_arg_check(L, 0, 3, "invalid timeout mode");
|
||||||
@ -459,35 +471,26 @@ static int net_send(lua_State *L)
|
|||||||
{
|
{
|
||||||
p_sock sock;
|
p_sock sock;
|
||||||
const char *data;
|
const char *data;
|
||||||
size_t size;
|
int wanted;
|
||||||
int start = get_time();
|
|
||||||
long total = 0;
|
long total = 0;
|
||||||
int arg;
|
int arg;
|
||||||
int err = NET_DONE;
|
int err = NET_DONE;
|
||||||
int end;
|
|
||||||
int top;
|
int top;
|
||||||
int client_tag, server_tag;
|
int client_tag, server_tag;
|
||||||
pop_tags(L, &client_tag, &server_tag);
|
pop_tags(L, &client_tag, &server_tag);
|
||||||
top = lua_gettop(L);
|
top = lua_gettop(L);
|
||||||
sock = check_client(L, 1, client_tag);
|
sock = check_client(L, 1, client_tag);
|
||||||
#ifdef _DEBUG_BLOCK
|
tm_markstart(sock);
|
||||||
printf("luasocket: send start\n");
|
|
||||||
#endif
|
|
||||||
for (arg = 2; arg <= top; arg++) {
|
for (arg = 2; arg <= top; arg++) {
|
||||||
data = luaL_opt_lstr(L, arg, NULL, &size);
|
data = luaL_opt_lstr(L, arg, NULL, &wanted);
|
||||||
if (!data || err != NET_DONE)
|
if (!data || err != NET_DONE) break;
|
||||||
break;
|
total += send_raw(sock, data, wanted, &err);
|
||||||
total += send_raw(sock, data, size, start, &err, &end);
|
|
||||||
}
|
}
|
||||||
push_error(L, err);
|
push_error(L, err);
|
||||||
lua_pushnumber(L, (double) total);
|
lua_pushnumber(L, (double) total);
|
||||||
#ifdef _DEBUG_BLOCK
|
|
||||||
printf("luasocket: send end\n");
|
|
||||||
#endif
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
/* pass the time elapsed during function execution to Lua, so that
|
/* push time elapsed during operation as the last return value */
|
||||||
** the test script can make sure we respected the timeouts */
|
lua_pushnumber(L, (sock->tm_end - sock->tm_start)/1000.0);
|
||||||
lua_pushnumber(L, (end-start)/1000.0);
|
|
||||||
#endif
|
#endif
|
||||||
return lua_gettop(L) - top;
|
return lua_gettop(L) - top;
|
||||||
}
|
}
|
||||||
@ -501,33 +504,31 @@ lua_pushnumber(L, (end-start)/1000.0);
|
|||||||
* by a LF character, preceded or not by a CR character. This is
|
* by a LF character, preceded or not by a CR character. This is
|
||||||
* the default pattern
|
* the default pattern
|
||||||
* "*lu": reads a text line, terminanted by a CR character only. (Unix mode)
|
* "*lu": reads a text line, terminanted by a CR character only. (Unix mode)
|
||||||
|
* "*a": reads until connection closed
|
||||||
* number: reads 'number' characters from the socket
|
* number: reads 'number' characters from the socket
|
||||||
* Returns
|
* Returns
|
||||||
* On success: one string for each pattern
|
* On success: one string for each pattern
|
||||||
* On error: all strings for which there was no error, followed by one
|
* On error: all strings for which there was no error, followed by one
|
||||||
* nil value for each failed string, followed by an error code
|
* nil value for the remaining strings, followed by an error code
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int net_receive(lua_State *L)
|
static int net_receive(lua_State *L)
|
||||||
{
|
{
|
||||||
static const char *const modenames[] = {"*l", "*lu", "*a", NULL};
|
static const char *const modenames[] = {"*l", "*lu", "*a", NULL};
|
||||||
int err = NET_DONE, arg = 2;
|
int err = NET_DONE, arg = 2;
|
||||||
int start = get_time();
|
const char *mode;
|
||||||
int end;
|
|
||||||
int client_tag, server_tag;
|
int client_tag, server_tag;
|
||||||
int top;
|
int top;
|
||||||
p_sock sock;
|
p_sock sock;
|
||||||
const char *mode;
|
|
||||||
pop_tags(L, &client_tag, &server_tag);
|
pop_tags(L, &client_tag, &server_tag);
|
||||||
sock = check_client(L, 1, client_tag);
|
sock = check_client(L, 1, client_tag);
|
||||||
#ifdef _DEBUG_BLOCK
|
tm_markstart(sock);
|
||||||
printf("luasocket: receive start\n");
|
|
||||||
#endif
|
|
||||||
/* push default pattern */
|
/* push default pattern */
|
||||||
top = lua_gettop(L);
|
top = lua_gettop(L);
|
||||||
if (top < 2) {
|
if (top < 2) {
|
||||||
lua_pushstring(L, "*l");
|
lua_pushstring(L, "*l");
|
||||||
top++;
|
top++;
|
||||||
}
|
}
|
||||||
|
/* receive all patterns */
|
||||||
for (arg = 2; arg <= top; arg++) {
|
for (arg = 2; arg <= top; arg++) {
|
||||||
/* if one pattern failed, we just skip all other patterns */
|
/* if one pattern failed, we just skip all other patterns */
|
||||||
if (err != NET_DONE) {
|
if (err != NET_DONE) {
|
||||||
@ -536,24 +537,24 @@ printf("luasocket: receive start\n");
|
|||||||
}
|
}
|
||||||
if (lua_isnumber(L, arg)) {
|
if (lua_isnumber(L, arg)) {
|
||||||
long size = (long) lua_tonumber(L, arg);
|
long size = (long) lua_tonumber(L, arg);
|
||||||
receive_raw(L, sock, size, start, &err, &end);
|
err = receive_raw(L, sock, size);
|
||||||
} else {
|
} else {
|
||||||
mode = luaL_opt_string(L, arg, NULL);
|
mode = luaL_opt_string(L, arg, NULL);
|
||||||
/* get next pattern */
|
/* get next pattern */
|
||||||
switch (luaL_findstring(mode, modenames)) {
|
switch (luaL_findstring(mode, modenames)) {
|
||||||
/* DOS line mode */
|
/* DOS line mode */
|
||||||
case 0:
|
case 0:
|
||||||
receive_dosline(L, sock, start, &err, &end);
|
err = receive_dosline(L, sock);
|
||||||
break;
|
break;
|
||||||
/* Unix line mode */
|
/* Unix line mode */
|
||||||
case 1:
|
case 1:
|
||||||
receive_unixline(L, sock, start, &err, &end);
|
err = receive_unixline(L, sock);
|
||||||
break;
|
break;
|
||||||
/* 'Til closed mode */
|
/* until closed mode */
|
||||||
case 2:
|
case 2:
|
||||||
receive_all(L, sock, start, &err, &end);
|
err = receive_all(L, sock);
|
||||||
break;
|
break;
|
||||||
/* else it must be a number, raw mode */
|
/* else it is an error */
|
||||||
default:
|
default:
|
||||||
luaL_arg_check(L, 0, arg, "invalid receive pattern");
|
luaL_arg_check(L, 0, arg, "invalid receive pattern");
|
||||||
break;
|
break;
|
||||||
@ -562,13 +563,9 @@ printf("luasocket: receive start\n");
|
|||||||
}
|
}
|
||||||
/* last return is an error code */
|
/* last return is an error code */
|
||||||
push_error(L, err);
|
push_error(L, err);
|
||||||
#ifdef _DEBUG_BLOCK
|
|
||||||
printf("luasocket: receive end\n");
|
|
||||||
#endif
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
/* pass the time elapsed during function execution to Lua, so that
|
/* push time elapsed during operation as the last return value */
|
||||||
** the test script can make sure we respected the timeouts */
|
lua_pushnumber(L, (sock->tm_end - sock->tm_start)/1000.0);
|
||||||
lua_pushnumber(L, (end-start)/1000.0);
|
|
||||||
#endif
|
#endif
|
||||||
return lua_gettop(L) - top;
|
return lua_gettop(L) - top;
|
||||||
}
|
}
|
||||||
@ -598,8 +595,8 @@ static int net_close(lua_State *L)
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int client_gettable(lua_State *L)
|
static int client_gettable(lua_State *L)
|
||||||
{
|
{
|
||||||
static const char *const net_api[] = {"receive","send","timeout","close",
|
static const char *const net_api[] =
|
||||||
"connect", NULL};
|
{"receive","send","timeout","close", "connect", NULL};
|
||||||
const char *idx = luaL_check_string(L, 2);
|
const char *idx = luaL_check_string(L, 2);
|
||||||
int server_tag, client_tag;
|
int server_tag, client_tag;
|
||||||
pop_tags(L, &client_tag, &server_tag);
|
pop_tags(L, &client_tag, &server_tag);
|
||||||
@ -700,12 +697,11 @@ static void handle_sigpipe(void)
|
|||||||
static p_sock create_sock(void)
|
static p_sock create_sock(void)
|
||||||
{
|
{
|
||||||
p_sock sock = (p_sock) malloc(sizeof(t_sock));
|
p_sock sock = (p_sock) malloc(sizeof(t_sock));
|
||||||
if (!sock)
|
if (!sock) return NULL;
|
||||||
return NULL;
|
|
||||||
sock->sock = -1;
|
sock->sock = -1;
|
||||||
sock->r = -1;
|
sock->tm_block = -1;
|
||||||
sock->b = -1;
|
sock->tm_return = -1;
|
||||||
sock->blocking = 1;
|
sock->bf_first = sock->bf_last = 0;
|
||||||
return sock;
|
return sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -777,63 +773,27 @@ static int fill_sockaddr(struct sockaddr_in *address, const char *hostname,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Determine the time limit to be passed to the select function, given
|
* Determines how much time we have left for the current io operation
|
||||||
* the time elapsed since the beginning of the operation.
|
* an IO write operation.
|
||||||
* Input
|
* Input
|
||||||
* sock: socket structure being used in operation
|
* sock: socket structure being used in operation
|
||||||
* elapsed: time elapsed since operation started
|
|
||||||
* Returns
|
* Returns
|
||||||
* time limit before function return in ms or -1 in case there is no
|
* the number of ms left or -1 if there is no time limit
|
||||||
* time limit
|
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int get_timeout(p_sock sock, int elapsed)
|
static int tm_gettimeleft(p_sock sock)
|
||||||
{
|
{
|
||||||
/* no timeout */
|
/* no timeout */
|
||||||
if (sock->b < 0 && sock->r < 0)
|
if (sock->tm_block < 0 && sock->tm_return < 0)
|
||||||
return -1;
|
return -1;
|
||||||
/* there is no block timeout, we use the return timeout */
|
/* there is no block timeout, we use the return timeout */
|
||||||
if (sock->b < 0)
|
else if (sock->tm_block < 0)
|
||||||
return max(0, sock->r - elapsed);
|
return max(sock->tm_return - tm_gettime() + sock->tm_start, 0);
|
||||||
/* there is no return timeout, we use the block timeout */
|
/* there is no return timeout, we use the block timeout */
|
||||||
else if (sock->r < 0)
|
else if (sock->tm_return < 0)
|
||||||
return sock->b;
|
return sock->tm_block;
|
||||||
/* both timeouts are specified */
|
/* both timeouts are specified */
|
||||||
else
|
else return min(sock->tm_block,
|
||||||
return min(sock->b, max(0, sock->r - elapsed));
|
max(sock->tm_return - tm_gettime() + sock->tm_start, 0));
|
||||||
}
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
|
||||||
* Determines if we have a timeout condition or if we can proceed with
|
|
||||||
* an IO read operation.
|
|
||||||
* Input
|
|
||||||
* sock: socket structure being used in operation
|
|
||||||
* elapsed: time elapsed since operation started
|
|
||||||
* Returns
|
|
||||||
* 1 if we can proceed, 0 if a timeou has occured
|
|
||||||
\*-------------------------------------------------------------------------*/
|
|
||||||
static int read_or_timeout(p_sock sock, int elapsed)
|
|
||||||
{
|
|
||||||
fd_set set; /* file descriptor set */
|
|
||||||
struct timeval to; /* timeout structure */
|
|
||||||
int ms = get_timeout(sock, elapsed);
|
|
||||||
int err;
|
|
||||||
/* got timeout */
|
|
||||||
if (ms == 0)
|
|
||||||
return 0;
|
|
||||||
FD_ZERO(&set);
|
|
||||||
FD_SET(sock->sock, &set);
|
|
||||||
/* we have a limit on the time we can wait */
|
|
||||||
if (ms > 0) {
|
|
||||||
to.tv_sec = ms / 1000;
|
|
||||||
to.tv_usec = (ms % 1000) * 1000;
|
|
||||||
err = select(sock->sock+1, &set, NULL, NULL, &to);
|
|
||||||
set_nonblocking(sock);
|
|
||||||
/* we can wait forever */
|
|
||||||
} else {
|
|
||||||
err = select(sock->sock+1, &set, NULL, NULL, NULL);
|
|
||||||
set_blocking(sock);
|
|
||||||
}
|
|
||||||
return (err > 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@ -841,33 +801,110 @@ static int read_or_timeout(p_sock sock, int elapsed)
|
|||||||
* an IO write operation.
|
* an IO write operation.
|
||||||
* Input
|
* Input
|
||||||
* sock: socket structure being used in operation
|
* sock: socket structure being used in operation
|
||||||
* elapsed: time elapsed since operation started
|
* mode: TM_RECEIVE or TM_SEND
|
||||||
* Returns
|
* Returns
|
||||||
* 1 if we can proceed, 0 if a timeou has occured
|
* 1 if we can proceed, 0 if a timeout has occured
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int write_or_timeout(p_sock sock, int elapsed)
|
static int tm_timedout(p_sock sock, int mode)
|
||||||
{
|
{
|
||||||
fd_set set; /* file descriptor set */
|
fd_set fds;
|
||||||
struct timeval to; /* timeout structure */
|
int ret, delta;
|
||||||
int ms = get_timeout(sock, elapsed);
|
fd_set *preadfds = NULL, *pwritefds = NULL;
|
||||||
int err;
|
struct timeval tm;
|
||||||
/* got timeout */
|
struct timeval *ptm = NULL;
|
||||||
if (ms == 0)
|
/* find out how much time we have left, in ms */
|
||||||
return 0;
|
int ms = tm_gettimeleft(sock);
|
||||||
FD_ZERO(&set);
|
/* fill file descriptor set */
|
||||||
FD_SET(sock->sock, &set);
|
FD_ZERO(&fds); FD_SET(sock->sock, &fds);
|
||||||
/* we have a limit on the time we can wait */
|
/* fill timeval structure */
|
||||||
if (ms > 0) {
|
tm.tv_sec = ms / 1000;
|
||||||
to.tv_sec = ms / 1000;
|
tm.tv_usec = (ms % 1000) * 1000;
|
||||||
to.tv_usec = (ms % 1000) * 1000;
|
/* define function parameters */
|
||||||
err = select(sock->sock+1, NULL, &set, NULL, &to);
|
if (ms > 0) ptm = &tm; /* ptm == NULL when we don't have timeout */
|
||||||
set_nonblocking(sock);
|
if (mode == TM_RECEIVE) preadfds = &fds;
|
||||||
/* we can wait forever */
|
else pwritefds = &fds;
|
||||||
} else {
|
delta = tm_gettime();
|
||||||
err = select(sock->sock+1, NULL, &set, NULL, NULL);
|
/* see if we can read or write or if we timedout */
|
||||||
set_blocking(sock);
|
ret = select(sock->sock+1, preadfds, pwritefds, NULL, ptm);
|
||||||
|
#ifdef _DEBUG
|
||||||
|
/* store end time for this operation before calling select */
|
||||||
|
sock->tm_end = tm_gettime();
|
||||||
|
#endif
|
||||||
|
return ret <= 0;
|
||||||
}
|
}
|
||||||
return (err > 0);
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Marks the operation start time in sock structure
|
||||||
|
* Input
|
||||||
|
* sock: socket structure being used in operation
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static void tm_markstart(p_sock sock)
|
||||||
|
{
|
||||||
|
sock->tm_start = tm_gettime();
|
||||||
|
#ifdef _DEBUG
|
||||||
|
sock->tm_end = sock->tm_start;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Determines of there is any data in the read buffer
|
||||||
|
* Input
|
||||||
|
* sock: socket structure being used in operation
|
||||||
|
* Returns
|
||||||
|
* 1 if empty, 0 if there is data
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int bf_isempty(p_sock sock)
|
||||||
|
{
|
||||||
|
return sock->bf_first >= sock->bf_last;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Skip a given number of bytes in read buffer
|
||||||
|
* Input
|
||||||
|
* sock: socket structure being used in operation
|
||||||
|
* length: number of bytes to skip
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static void bf_skip(p_sock sock, int length)
|
||||||
|
{
|
||||||
|
sock->bf_first += length;
|
||||||
|
if (bf_isempty(sock)) sock->bf_first = sock->bf_last = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Return any data avilable in buffer, or get more data from transport layer
|
||||||
|
* if there is none.
|
||||||
|
* Input
|
||||||
|
* sock: socket structure being used in operation
|
||||||
|
* Output
|
||||||
|
* length: number of bytes available in buffer
|
||||||
|
* Returns
|
||||||
|
* pointer to start of data
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static const unsigned char *bf_receive(p_sock sock, int *length)
|
||||||
|
{
|
||||||
|
if (bf_isempty(sock)) {
|
||||||
|
int got = recv(sock->sock, sock->bf_buffer, LUASOCKET_BUFFERSIZE, 0);
|
||||||
|
sock->bf_first = 0;
|
||||||
|
if (got >= 0) sock->bf_last = got;
|
||||||
|
else sock->bf_last = 0;
|
||||||
|
}
|
||||||
|
*length = sock->bf_last - sock->bf_first;
|
||||||
|
return sock->bf_buffer + sock->bf_first;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Gets time in ms, relative to system startup.
|
||||||
|
* Returns
|
||||||
|
* time in ms.
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int tm_gettime(void)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return GetTickCount();
|
||||||
|
#else
|
||||||
|
struct tms t;
|
||||||
|
return (times(&t)*1000)/CLK_TCK;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@ -877,49 +914,24 @@ static int write_or_timeout(p_sock sock, int elapsed)
|
|||||||
* sock: socket structure being used in operation
|
* sock: socket structure being used in operation
|
||||||
* data: buffer to be sent
|
* data: buffer to be sent
|
||||||
* wanted: number of bytes in buffer
|
* wanted: number of bytes in buffer
|
||||||
* start: time the operation started, in ms
|
|
||||||
* Output
|
* Output
|
||||||
* err: operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED
|
* err: operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED
|
||||||
* Returns
|
* Returns
|
||||||
* Number of bytes written
|
* Number of bytes written
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int send_raw(p_sock sock, const char *data, int wanted,
|
static int send_raw(p_sock sock, const char *data, int wanted, int *err)
|
||||||
int start, int *err, int *end)
|
|
||||||
{
|
{
|
||||||
int put = 0, total = 0;
|
int put = 0, total = 0;
|
||||||
*end = start;
|
|
||||||
while (wanted > 0) {
|
while (wanted > 0) {
|
||||||
if(!write_or_timeout(sock, time_since(start))) {
|
if (tm_timedout(sock, TM_SEND)) {
|
||||||
#ifdef _DEBUG
|
|
||||||
*end = get_time();
|
|
||||||
#endif
|
|
||||||
*err = NET_TIMEOUT;
|
*err = NET_TIMEOUT;
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
#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 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();
|
|
||||||
#endif
|
|
||||||
put = send(sock->sock, data, wanted, 0);
|
put = send(sock->sock, data, wanted, 0);
|
||||||
if (put <= 0) {
|
if (put <= 0) {
|
||||||
#ifdef WIN32
|
|
||||||
/* on WinSock, a select over a socket on which there is a
|
|
||||||
** non-blocking operation pending returns immediately, even
|
|
||||||
** if the call would block. therefore, we have to do a busy
|
|
||||||
** wait here. */
|
|
||||||
if (WSAGetLastError() == WSAEWOULDBLOCK)
|
|
||||||
continue;
|
|
||||||
#endif
|
|
||||||
*err = NET_CLOSED;
|
*err = NET_CLOSED;
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
#ifdef _DEBUG_BLOCK
|
|
||||||
printf("luasocket: sent %d, wanted %d, %dms elapsed\n", put, wanted, time_since(start));
|
|
||||||
#endif
|
|
||||||
wanted -= put;
|
wanted -= put;
|
||||||
data += put;
|
data += put;
|
||||||
total += put;
|
total += put;
|
||||||
@ -934,180 +946,146 @@ printf("luasocket: sent %d, wanted %d, %dms elapsed\n", put, wanted, time_since(
|
|||||||
* Input
|
* Input
|
||||||
* sock: socket structure being used in operation
|
* sock: socket structure being used in operation
|
||||||
* wanted: number of bytes to be read
|
* wanted: number of bytes to be read
|
||||||
* start: time the operation started, in ms
|
|
||||||
* Output
|
|
||||||
* err: operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED
|
|
||||||
* Returns
|
* Returns
|
||||||
* Number of bytes read
|
* operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
#define MIN(x,y) ((x)<(y)?(x):(y))
|
static int receive_raw(lua_State *L, p_sock sock, int wanted)
|
||||||
static void receive_raw(lua_State *L, p_sock sock, int wanted, int start,
|
|
||||||
int *err, int *end)
|
|
||||||
{
|
{
|
||||||
int got = 0;
|
int got = 0;
|
||||||
char *buffer = NULL;
|
const unsigned char *buffer = NULL;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
*end = start;
|
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
while (wanted > 0) {
|
while (wanted > 0) {
|
||||||
if(!read_or_timeout(sock, time_since(start))) {
|
if (bf_isempty(sock) && tm_timedout(sock, TM_RECEIVE)) {
|
||||||
#ifdef _DEBUG
|
|
||||||
*end = get_time();
|
|
||||||
#endif
|
|
||||||
*err = NET_TIMEOUT;
|
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
return;
|
return NET_TIMEOUT;
|
||||||
}
|
}
|
||||||
#ifdef _DEBUG
|
buffer = bf_receive(sock, &got);
|
||||||
*end = get_time();
|
|
||||||
#endif
|
|
||||||
buffer = luaL_prepbuffer(&b);
|
|
||||||
got = recv(sock->sock, buffer, MIN(wanted, LUAL_BUFFERSIZE), 0);
|
|
||||||
#ifdef _DEBUG_BLOCK
|
|
||||||
printf("luasocket: wanted %d, got %d, %dms elapsed\n", wanted, got, time_since(start));
|
|
||||||
#endif
|
|
||||||
if (got <= 0) {
|
if (got <= 0) {
|
||||||
*err = NET_CLOSED;
|
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
return;
|
return NET_CLOSED;
|
||||||
}
|
}
|
||||||
|
got = min(got, wanted);
|
||||||
|
luaL_addlstring(&b, buffer, got);
|
||||||
|
bf_skip(sock, got);
|
||||||
wanted -= got;
|
wanted -= got;
|
||||||
luaL_addsize(&b, got);
|
|
||||||
}
|
}
|
||||||
*err = NET_DONE;
|
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
|
return NET_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Reads everything until the connection is closed
|
* Reads everything until the connection is closed
|
||||||
* Input
|
* Input
|
||||||
* sock: socket structure being used in operation
|
* 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
|
* Result
|
||||||
* a string is pushed into the Lua stack with the line just read
|
* operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static void receive_all(lua_State *L, p_sock sock, int start,
|
static int receive_all(lua_State *L, p_sock sock)
|
||||||
int *err, int *end)
|
|
||||||
{
|
{
|
||||||
int got;
|
int got = 0;
|
||||||
char *buffer;
|
const unsigned char *buffer = NULL;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
*end = start;
|
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
buffer = luaL_prepbuffer(&b);
|
if (bf_isempty(sock) && tm_timedout(sock, TM_RECEIVE)) {
|
||||||
if (read_or_timeout(sock, time_since(start))) {
|
buffer = bf_receive(sock, &got);
|
||||||
#ifdef _DEBUG
|
|
||||||
*end = get_time();
|
|
||||||
#endif
|
|
||||||
got = recv(sock->sock, buffer, LUAL_BUFFERSIZE, 0);
|
|
||||||
if (got <= 0) {
|
if (got <= 0) {
|
||||||
*err = NET_DONE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
luaL_addsize(&b, got);
|
|
||||||
} else {
|
|
||||||
*err = NET_TIMEOUT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
|
return NET_DONE;
|
||||||
|
}
|
||||||
|
luaL_addlstring(&b, buffer, got);
|
||||||
|
} else {
|
||||||
|
luaL_pushresult(&b);
|
||||||
|
return NET_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
|
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
|
||||||
* are not returned by the function. All operations are non-blocking and the
|
* are not returned by the function and are discarded from the stream. All
|
||||||
* function respects the timeout values in sock.
|
* operations are non-blocking and the function respects the timeout
|
||||||
|
* values in sock.
|
||||||
* Input
|
* Input
|
||||||
* sock: socket structure being used in operation
|
* sock: socket structure being used in operation
|
||||||
* wanted: number of bytes in buffer
|
|
||||||
* 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
|
|
||||||
* Result
|
* Result
|
||||||
* a string is pushed into the Lua stack with the line just read
|
* operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static void receive_dosline(lua_State *L, p_sock sock, int start,
|
static int receive_dosline(lua_State *L, p_sock sock)
|
||||||
int *err, int *end)
|
|
||||||
{
|
{
|
||||||
char c = ' ';
|
int got = 0;
|
||||||
long got = 0;
|
const unsigned char *buffer = NULL;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
*end = start;
|
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
if (read_or_timeout(sock, time_since(start))) {
|
if (bf_isempty(sock) && tm_timedout(sock, TM_RECEIVE)) {
|
||||||
#ifdef _DEBUG
|
|
||||||
*end = get_time();
|
|
||||||
#endif
|
|
||||||
got = recv(sock->sock, &c, 1, 0);
|
|
||||||
if (got <= 0) {
|
|
||||||
*err = NET_CLOSED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (c != '\n') {
|
|
||||||
if (c != '\r') luaL_putchar(&b, c);
|
|
||||||
} else {
|
|
||||||
*err = NET_DONE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*err = NET_TIMEOUT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
|
return NET_TIMEOUT;
|
||||||
|
}
|
||||||
|
buffer = bf_receive(sock, &got);
|
||||||
|
if (got > 0) {
|
||||||
|
int len = 0, end = 1;
|
||||||
|
while (len < got) {
|
||||||
|
if (buffer[len] == '\n') { /* found eol */
|
||||||
|
if (len > 0 && buffer[len-1] == '\r') {
|
||||||
|
end++; len--;
|
||||||
|
}
|
||||||
|
luaL_addlstring(&b, buffer, len);
|
||||||
|
bf_skip(sock, len + end); /* skip '\r\n' in stream */
|
||||||
|
luaL_pushresult(&b);
|
||||||
|
return NET_DONE;
|
||||||
|
}
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
luaL_addlstring(&b, buffer, got);
|
||||||
|
bf_skip(sock, got);
|
||||||
|
} else {
|
||||||
|
luaL_pushresult(&b);
|
||||||
|
return NET_CLOSED;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Reads a line terminated by a LF character, which is not returned by
|
* Reads a line terminated by a LF character, which is not returned by
|
||||||
* the function. All operations are non-blocking and the function respects
|
* the function, and is skipped in the stream. All operations are
|
||||||
* the timeout values in sock.
|
* non-blocking and the function respects the timeout values in sock.
|
||||||
* Input
|
* Input
|
||||||
* sock: socket structure being used in operation
|
* sock: socket structure being used in operation
|
||||||
* wanted: number of bytes in buffer
|
|
||||||
* 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
|
* Returns
|
||||||
* Number of bytes read
|
* operation error code. NET_DONE, NET_TIMEOUT or NET_CLOSED
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static void receive_unixline(lua_State *L, p_sock sock, int start,
|
static int receive_unixline(lua_State *L, p_sock sock)
|
||||||
int *err, int *end)
|
|
||||||
{
|
{
|
||||||
char c = ' ';
|
int got = 0;
|
||||||
long got = 0;
|
const unsigned char *buffer = NULL;
|
||||||
long size = 0;
|
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
*end = start;
|
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
if (read_or_timeout(sock, time_since(start))) {
|
if (bf_isempty(sock) && tm_timedout(sock, TM_RECEIVE)) {
|
||||||
#ifdef _DEBUG
|
|
||||||
*end = get_time();
|
|
||||||
#endif
|
|
||||||
got = recv(sock->sock, &c, 1, 0);
|
|
||||||
if (got <= 0) {
|
|
||||||
*err = NET_CLOSED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (c != '\n') {
|
|
||||||
luaL_putchar(&b, c);
|
|
||||||
size++;
|
|
||||||
} else {
|
|
||||||
*err = NET_DONE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*err = NET_TIMEOUT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
|
return NET_TIMEOUT;
|
||||||
|
}
|
||||||
|
buffer = bf_receive(sock, &got);
|
||||||
|
if (got > 0) {
|
||||||
|
int len = 0;
|
||||||
|
while (len < got) {
|
||||||
|
if (buffer[len] == '\n') { /* found eol */
|
||||||
|
luaL_addlstring(&b, buffer, len);
|
||||||
|
bf_skip(sock, len + 1); /* skip '\n' in stream */
|
||||||
|
luaL_pushresult(&b);
|
||||||
|
return NET_DONE;
|
||||||
|
}
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
luaL_addlstring(&b, buffer, got);
|
||||||
|
bf_skip(sock, got);
|
||||||
|
} else {
|
||||||
|
luaL_pushresult(&b);
|
||||||
|
return NET_CLOSED;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@ -1204,15 +1182,6 @@ static int wsock_open(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
|
||||||
* Gets time in ms, relative to system startup.
|
|
||||||
* Returns
|
|
||||||
* time in ms.
|
|
||||||
\*-------------------------------------------------------------------------*/
|
|
||||||
static int get_time(void)
|
|
||||||
{
|
|
||||||
return GetTickCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Put socket into blocking mode.
|
* Put socket into blocking mode.
|
||||||
@ -1303,28 +1272,14 @@ static char *connect_strerror(void)
|
|||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* BSD specific functions.
|
* BSD specific functions.
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
/*-------------------------------------------------------------------------*\
|
|
||||||
* Gets time in ms, relative to system startup.
|
|
||||||
* Returns
|
|
||||||
* time in ms.
|
|
||||||
\*-------------------------------------------------------------------------*/
|
|
||||||
static int get_time(void)
|
|
||||||
{
|
|
||||||
struct tms t;
|
|
||||||
return (times(&t)*1000)/CLK_TCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Put socket into blocking mode.
|
* Put socket into blocking mode.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static void set_blocking(p_sock sock)
|
static void set_blocking(p_sock sock)
|
||||||
{
|
{
|
||||||
if (!sock->blocking) {
|
|
||||||
int flags = fcntl(sock->sock, F_GETFL, 0);
|
int flags = fcntl(sock->sock, F_GETFL, 0);
|
||||||
flags &= (~(O_NONBLOCK));
|
flags &= (~(O_NONBLOCK));
|
||||||
fcntl(sock->sock, F_SETFL, flags);
|
fcntl(sock->sock, F_SETFL, flags);
|
||||||
sock->blocking = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@ -1332,12 +1287,9 @@ static void set_blocking(p_sock sock)
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static void set_nonblocking(p_sock sock)
|
static void set_nonblocking(p_sock sock)
|
||||||
{
|
{
|
||||||
if (sock->blocking) {
|
|
||||||
int flags = fcntl(sock->sock, F_GETFL, 0);
|
int flags = fcntl(sock->sock, F_GETFL, 0);
|
||||||
flags |= O_NONBLOCK;
|
flags |= O_NONBLOCK;
|
||||||
fcntl(sock->sock, F_SETFL, flags);
|
fcntl(sock->sock, F_SETFL, flags);
|
||||||
sock->blocking = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
|
Loading…
Reference in New Issue
Block a user