2002-03-27 19:00:00 +01:00
|
|
|
/*=========================================================================*\
|
|
|
|
* Buffered input/output routines
|
2003-03-28 22:08:50 +01:00
|
|
|
*
|
|
|
|
* RCS ID: $Id$
|
2002-03-27 19:00:00 +01:00
|
|
|
\*=========================================================================*/
|
|
|
|
#include <lua.h>
|
|
|
|
#include <lauxlib.h>
|
|
|
|
|
2003-05-25 03:54:13 +02:00
|
|
|
#include "error.h"
|
|
|
|
#include "aux.h"
|
|
|
|
#include "buf.h"
|
2002-03-27 19:00:00 +01:00
|
|
|
|
|
|
|
/*=========================================================================*\
|
2003-05-25 03:54:13 +02:00
|
|
|
* Internal function prototypes
|
2002-03-27 19:00:00 +01:00
|
|
|
\*=========================================================================*/
|
|
|
|
static int recvraw(lua_State *L, p_buf buf, size_t wanted);
|
2003-05-25 03:54:13 +02:00
|
|
|
static int recvline(lua_State *L, p_buf buf);
|
2002-03-27 19:00:00 +01:00
|
|
|
static int recvall(lua_State *L, p_buf buf);
|
2003-05-25 03:54:13 +02:00
|
|
|
static int buf_get(p_buf buf, const char **data, size_t *count);
|
|
|
|
static void buf_skip(p_buf buf, size_t count);
|
|
|
|
static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent);
|
2002-03-27 19:00:00 +01:00
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* Exported functions
|
|
|
|
\*=========================================================================*/
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Initializes module
|
|
|
|
\*-------------------------------------------------------------------------*/
|
|
|
|
void buf_open(lua_State *L)
|
|
|
|
{
|
|
|
|
(void) L;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Initializes C structure
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2003-05-25 03:54:13 +02:00
|
|
|
void buf_init(p_buf buf, p_io io, p_tm tm)
|
2002-03-27 19:00:00 +01:00
|
|
|
{
|
2003-05-25 03:54:13 +02:00
|
|
|
buf->first = buf->last = 0;
|
|
|
|
buf->io = io;
|
|
|
|
buf->tm = tm;
|
2002-03-27 19:00:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Send data through buffered object
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2003-05-25 03:54:13 +02:00
|
|
|
int buf_meth_send(lua_State *L, p_buf buf)
|
2002-03-27 19:00:00 +01:00
|
|
|
{
|
|
|
|
int top = lua_gettop(L);
|
|
|
|
size_t total = 0;
|
2003-05-25 03:54:13 +02:00
|
|
|
int arg, err = IO_DONE;
|
|
|
|
p_tm tm = buf->tm;
|
|
|
|
tm_markstart(tm);
|
2002-03-27 19:00:00 +01:00
|
|
|
for (arg = 2; arg <= top; arg++) { /* first arg is socket object */
|
2003-05-25 03:54:13 +02:00
|
|
|
size_t sent, count;
|
|
|
|
const char *data = luaL_optlstring(L, arg, NULL, &count);
|
|
|
|
if (!data || err != IO_DONE) break;
|
|
|
|
err = sendraw(buf, data, count, &sent);
|
|
|
|
total += sent;
|
2002-03-27 19:00:00 +01:00
|
|
|
}
|
|
|
|
lua_pushnumber(L, total);
|
2003-05-25 03:54:13 +02:00
|
|
|
error_push(L, err);
|
2002-12-03 08:20:34 +01:00
|
|
|
#ifdef LUASOCKET_DEBUG
|
2002-03-27 19:00:00 +01:00
|
|
|
/* push time elapsed during operation as the last return value */
|
2003-05-25 03:54:13 +02:00
|
|
|
lua_pushnumber(L, (tm_gettime() - tm_getstart(tm))/1000.0);
|
2002-03-27 19:00:00 +01:00
|
|
|
#endif
|
|
|
|
return lua_gettop(L) - top;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Receive data from a buffered object
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2003-05-25 03:54:13 +02:00
|
|
|
int buf_meth_receive(lua_State *L, p_buf buf)
|
2002-03-27 19:00:00 +01:00
|
|
|
{
|
|
|
|
int top = lua_gettop(L);
|
2003-05-25 03:54:13 +02:00
|
|
|
int arg, err = IO_DONE;
|
|
|
|
p_tm tm = buf->tm;
|
|
|
|
tm_markstart(tm);
|
2002-03-27 19:00:00 +01:00
|
|
|
/* push default pattern if need be */
|
|
|
|
if (top < 2) {
|
|
|
|
lua_pushstring(L, "*l");
|
|
|
|
top++;
|
|
|
|
}
|
2003-05-25 03:54:13 +02:00
|
|
|
/* make sure we have enough stack space for all returns */
|
2003-03-21 00:11:25 +01:00
|
|
|
luaL_checkstack(L, top+LUA_MINSTACK, "too many arguments");
|
2002-03-27 19:00:00 +01:00
|
|
|
/* receive all patterns */
|
2003-05-25 03:54:13 +02:00
|
|
|
for (arg = 2; arg <= top && err == IO_DONE; arg++) {
|
2002-03-27 19:00:00 +01:00
|
|
|
if (!lua_isnumber(L, arg)) {
|
2003-05-25 03:54:13 +02:00
|
|
|
static const char *patternnames[] = {"*l", "*a", NULL};
|
|
|
|
const char *pattern = lua_isnil(L, arg) ?
|
|
|
|
"*l" : luaL_checkstring(L, arg);
|
2002-03-27 19:00:00 +01:00
|
|
|
/* get next pattern */
|
|
|
|
switch (luaL_findstring(pattern, patternnames)) {
|
2003-05-25 03:54:13 +02:00
|
|
|
case 0: /* line pattern */
|
|
|
|
err = recvline(L, buf); break;
|
|
|
|
case 1: /* until closed pattern */
|
|
|
|
err = recvall(L, buf);
|
|
|
|
if (err == IO_CLOSED) err = IO_DONE;
|
2002-03-27 19:00:00 +01:00
|
|
|
break;
|
|
|
|
default: /* else it is an error */
|
2003-03-21 00:11:25 +01:00
|
|
|
luaL_argcheck(L, 0, arg, "invalid receive pattern");
|
2002-03-27 19:00:00 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* raw pattern */
|
|
|
|
} else err = recvraw(L, buf, (size_t) lua_tonumber(L, arg));
|
|
|
|
}
|
|
|
|
/* push nil for each pattern after an error */
|
|
|
|
for ( ; arg <= top; arg++) lua_pushnil(L);
|
|
|
|
/* last return is an error code */
|
2003-05-25 03:54:13 +02:00
|
|
|
error_push(L, err);
|
2002-12-03 08:20:34 +01:00
|
|
|
#ifdef LUASOCKET_DEBUG
|
2002-03-27 19:00:00 +01:00
|
|
|
/* push time elapsed during operation as the last return value */
|
2003-05-25 03:54:13 +02:00
|
|
|
lua_pushnumber(L, (tm_gettime() - tm_getstart(tm))/1000.0);
|
2002-03-27 19:00:00 +01:00
|
|
|
#endif
|
|
|
|
return lua_gettop(L) - top;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Determines if there is any data in the read buffer
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2003-05-25 03:54:13 +02:00
|
|
|
int buf_isempty(p_buf buf)
|
2002-03-27 19:00:00 +01:00
|
|
|
{
|
2003-05-25 03:54:13 +02:00
|
|
|
return buf->first >= buf->last;
|
2002-03-27 19:00:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*=========================================================================*\
|
|
|
|
* Internal functions
|
|
|
|
\*=========================================================================*/
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Sends a raw block of data through a buffered object.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2003-05-25 03:54:13 +02:00
|
|
|
static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent)
|
2002-03-27 19:00:00 +01:00
|
|
|
{
|
2003-05-25 03:54:13 +02:00
|
|
|
p_io io = buf->io;
|
|
|
|
p_tm tm = buf->tm;
|
2002-03-27 19:00:00 +01:00
|
|
|
size_t total = 0;
|
2003-05-25 03:54:13 +02:00
|
|
|
int err = IO_DONE;
|
|
|
|
while (total < count && err == IO_DONE) {
|
2002-03-27 19:00:00 +01:00
|
|
|
size_t done;
|
2003-05-25 03:54:13 +02:00
|
|
|
err = io->send(io->ctx, data+total, count-total, &done, tm_get(tm));
|
2002-03-27 19:00:00 +01:00
|
|
|
total += done;
|
|
|
|
}
|
|
|
|
*sent = total;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Reads a raw block of data from a buffered object.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2003-05-25 03:54:13 +02:00
|
|
|
static
|
|
|
|
int recvraw(lua_State *L, p_buf buf, size_t wanted)
|
2002-03-27 19:00:00 +01:00
|
|
|
{
|
2003-05-25 03:54:13 +02:00
|
|
|
int err = IO_DONE;
|
2002-03-27 19:00:00 +01:00
|
|
|
size_t total = 0;
|
|
|
|
luaL_Buffer b;
|
|
|
|
luaL_buffinit(L, &b);
|
2003-05-25 03:54:13 +02:00
|
|
|
while (total < wanted && err == IO_DONE) {
|
|
|
|
size_t count; const char *data;
|
|
|
|
err = buf_get(buf, &data, &count);
|
|
|
|
count = MIN(count, wanted - total);
|
|
|
|
luaL_addlstring(&b, data, count);
|
|
|
|
buf_skip(buf, count);
|
|
|
|
total += count;
|
2002-03-27 19:00:00 +01:00
|
|
|
}
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Reads everything until the connection is closed
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2003-05-25 03:54:13 +02:00
|
|
|
static
|
|
|
|
int recvall(lua_State *L, p_buf buf)
|
2002-03-27 19:00:00 +01:00
|
|
|
{
|
2003-05-25 03:54:13 +02:00
|
|
|
int err = IO_DONE;
|
2002-03-27 19:00:00 +01:00
|
|
|
luaL_Buffer b;
|
|
|
|
luaL_buffinit(L, &b);
|
2003-05-25 03:54:13 +02:00
|
|
|
while (err == IO_DONE) {
|
|
|
|
const char *data; size_t count;
|
|
|
|
err = buf_get(buf, &data, &count);
|
|
|
|
luaL_addlstring(&b, data, count);
|
|
|
|
buf_skip(buf, count);
|
2002-03-27 19:00:00 +01:00
|
|
|
}
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
|
|
|
|
* are not returned by the function and are discarded from the buffer.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2003-05-25 03:54:13 +02:00
|
|
|
static
|
|
|
|
int recvline(lua_State *L, p_buf buf)
|
2002-03-27 19:00:00 +01:00
|
|
|
{
|
|
|
|
int err = 0;
|
|
|
|
luaL_Buffer b;
|
|
|
|
luaL_buffinit(L, &b);
|
2003-05-25 03:54:13 +02:00
|
|
|
while (err == IO_DONE) {
|
|
|
|
size_t count, pos; const char *data;
|
|
|
|
err = buf_get(buf, &data, &count);
|
2002-03-27 19:00:00 +01:00
|
|
|
pos = 0;
|
2003-05-25 03:54:13 +02:00
|
|
|
while (pos < count && data[pos] != '\n') {
|
2002-03-27 19:00:00 +01:00
|
|
|
/* we ignore all \r's */
|
|
|
|
if (data[pos] != '\r') luaL_putchar(&b, data[pos]);
|
|
|
|
pos++;
|
|
|
|
}
|
2003-05-25 03:54:13 +02:00
|
|
|
if (pos < count) { /* found '\n' */
|
|
|
|
buf_skip(buf, pos+1); /* skip '\n' too */
|
2002-03-27 19:00:00 +01:00
|
|
|
break; /* we are done */
|
|
|
|
} else /* reached the end of the buffer */
|
2003-05-25 03:54:13 +02:00
|
|
|
buf_skip(buf, pos);
|
2002-03-27 19:00:00 +01:00
|
|
|
}
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Skips a given number of bytes in read buffer
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2003-05-25 03:54:13 +02:00
|
|
|
static
|
|
|
|
void buf_skip(p_buf buf, size_t count)
|
2002-03-27 19:00:00 +01:00
|
|
|
{
|
2003-05-25 03:54:13 +02:00
|
|
|
buf->first += count;
|
|
|
|
if (buf_isempty(buf))
|
|
|
|
buf->first = buf->last = 0;
|
2002-03-27 19:00:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*\
|
|
|
|
* Return any data available in buffer, or get more data from transport layer
|
|
|
|
* if buffer is empty.
|
|
|
|
\*-------------------------------------------------------------------------*/
|
2003-05-25 03:54:13 +02:00
|
|
|
static
|
|
|
|
int buf_get(p_buf buf, const char **data, size_t *count)
|
2002-03-27 19:00:00 +01:00
|
|
|
{
|
2003-05-25 03:54:13 +02:00
|
|
|
int err = IO_DONE;
|
|
|
|
p_io io = buf->io;
|
|
|
|
p_tm tm = buf->tm;
|
|
|
|
if (buf_isempty(buf)) {
|
|
|
|
size_t got;
|
|
|
|
err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm_get(tm));
|
|
|
|
buf->first = 0;
|
|
|
|
buf->last = got;
|
2002-03-27 19:00:00 +01:00
|
|
|
}
|
2003-05-25 03:54:13 +02:00
|
|
|
*count = buf->last - buf->first;
|
|
|
|
*data = buf->data + buf->first;
|
2002-03-27 19:00:00 +01:00
|
|
|
return err;
|
|
|
|
}
|