luasocket/src/buffer.c

263 lines
9.5 KiB
C
Raw Normal View History

2002-03-27 19:00:00 +01:00
/*=========================================================================*\
* Input/Output interface for Lua programs
* LuaSocket toolkit
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>
#include "buffer.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(p_buf buf, size_t wanted, luaL_Buffer *b);
static int recvline(p_buf buf, luaL_Buffer *b);
static int recvall(p_buf buf, luaL_Buffer *b);
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
/* min and max macros */
#ifndef MIN
#define MIN(x, y) ((x) < (y) ? x : y)
#endif
#ifndef MAX
#define MAX(x, y) ((x) > (y) ? x : y)
#endif
2002-03-27 19:00:00 +01:00
/*=========================================================================*\
* Exported functions
\*=========================================================================*/
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
2004-07-01 05:32:09 +02:00
int buf_open(lua_State *L) {
2002-03-27 19:00:00 +01:00
(void) L;
return 0;
2002-03-27 19:00:00 +01:00
}
/*-------------------------------------------------------------------------*\
* Initializes C structure
\*-------------------------------------------------------------------------*/
2004-07-01 05:32:09 +02:00
void buf_init(p_buf buf, p_io io, p_tm tm) {
2003-05-25 03:54:13 +02:00
buf->first = buf->last = 0;
buf->io = io;
buf->tm = tm;
2004-07-01 08:09:29 +02:00
buf->received = buf->sent = 0;
buf->birthday = tm_gettime();
}
/*-------------------------------------------------------------------------*\
* object:getstats() interface
\*-------------------------------------------------------------------------*/
int buf_meth_getstats(lua_State *L, p_buf buf) {
lua_pushnumber(L, buf->received);
lua_pushnumber(L, buf->sent);
lua_pushnumber(L, tm_gettime() - buf->birthday);
return 3;
2002-03-27 19:00:00 +01:00
}
2004-07-26 06:03:55 +02:00
/*-------------------------------------------------------------------------*\
* object:setstats() interface
\*-------------------------------------------------------------------------*/
int buf_meth_setstats(lua_State *L, p_buf buf) {
buf->received = (long) luaL_optnumber(L, 2, buf->received);
buf->sent = (long) luaL_optnumber(L, 3, buf->sent);
if (lua_isnumber(L, 4)) buf->birthday = tm_gettime() - lua_tonumber(L, 4);
lua_pushnumber(L, 1);
return 1;
}
2002-03-27 19:00:00 +01:00
/*-------------------------------------------------------------------------*\
* object:send() interface
2002-03-27 19:00:00 +01:00
\*-------------------------------------------------------------------------*/
2004-07-01 05:32:09 +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);
2004-07-01 05:32:09 +02:00
p_tm tm = tm_markstart(buf->tm);
2004-07-19 00:56:14 +02:00
int err = IO_DONE;
size_t size, sent;
const char *data = luaL_checklstring(L, 2, &size);
2004-07-26 06:03:55 +02:00
long start = (long) luaL_optnumber(L, 3, 1);
long end = (long) luaL_optnumber(L, 4, -1);
if (start < 0) start = (long) (size+start+1);
if (end < 0) end = (long) (size+end+1);
if (start < 1) start = (long) 1;
if (end > (long) size) end = (long) size;
2004-07-19 00:56:14 +02:00
if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent);
/* check if there was an error */
if (err != IO_DONE) {
lua_pushnil(L);
2004-07-15 08:11:53 +02:00
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
2005-01-27 22:30:01 +01:00
lua_pushnumber(L, sent+start-1);
} else {
2005-01-27 22:30:01 +01:00
lua_pushnumber(L, sent+start-1);
lua_pushnil(L);
lua_pushnil(L);
}
#ifdef LUASOCKET_DEBUG
2002-03-27 19:00:00 +01:00
/* push time elapsed during operation as the last return value */
2004-07-01 05:32:09 +02:00
lua_pushnumber(L, tm_gettime() - tm_getstart(tm));
2002-03-27 19:00:00 +01:00
#endif
return lua_gettop(L) - top;
}
/*-------------------------------------------------------------------------*\
* object:receive() interface
2002-03-27 19:00:00 +01:00
\*-------------------------------------------------------------------------*/
2004-07-01 05:32:09 +02:00
int buf_meth_receive(lua_State *L, p_buf buf) {
int err = IO_DONE, top = lua_gettop(L);
2004-07-01 05:32:09 +02:00
p_tm tm = tm_markstart(buf->tm);
luaL_Buffer b;
2004-07-15 08:11:53 +02:00
size_t size;
const char *part = luaL_optlstring(L, 3, "", &size);
/* initialize buffer with optional extra prefix
* (useful for concatenating previous partial results) */
luaL_buffinit(L, &b);
2004-07-15 08:11:53 +02:00
luaL_addlstring(&b, part, size);
/* receive new patterns */
if (!lua_isnumber(L, 2)) {
2004-07-15 08:11:53 +02:00
const char *p= luaL_optstring(L, 2, "*l");
if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
else luaL_argcheck(L, 0, 2, "invalid receive pattern");
/* get a fixed number of bytes */
2005-02-08 11:01:01 +01:00
} else err = recvraw(buf, (size_t) lua_tonumber(L, 2)-size, &b);
/* check if there was an error */
if (err != IO_DONE) {
2004-07-15 08:11:53 +02:00
/* we can't push anyting in the stack before pushing the
* contents of the buffer. this is the reason for the complication */
luaL_pushresult(&b);
2004-07-15 08:11:53 +02:00
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
lua_pushvalue(L, -2);
lua_pushnil(L);
lua_replace(L, -4);
} else {
luaL_pushresult(&b);
lua_pushnil(L);
lua_pushnil(L);
2002-03-27 19:00:00 +01:00
}
#ifdef LUASOCKET_DEBUG
2002-03-27 19:00:00 +01:00
/* push time elapsed during operation as the last return value */
2004-07-01 05:32:09 +02:00
lua_pushnumber(L, tm_gettime() - tm_getstart(tm));
2002-03-27 19:00:00 +01:00
#endif
return lua_gettop(L) - top;
}
/*-------------------------------------------------------------------------*\
* Determines if there is any data in the read buffer
\*-------------------------------------------------------------------------*/
2004-07-01 05:32:09 +02:00
int buf_isempty(p_buf buf) {
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 block of data (unbuffered)
2002-03-27 19:00:00 +01:00
\*-------------------------------------------------------------------------*/
2004-11-27 08:58:04 +01:00
#define STEPSIZE 8192
2004-07-01 05:32:09 +02:00
static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent) {
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;
2004-07-01 05:32:09 +02:00
while (total < count && err == IO_DONE) {
2002-03-27 19:00:00 +01:00
size_t done;
2004-11-27 08:58:04 +01:00
size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE;
err = io->send(io->ctx, data+total, step, &done, tm);
2002-03-27 19:00:00 +01:00
total += done;
}
*sent = total;
2004-07-01 08:09:29 +02:00
buf->sent += total;
2002-03-27 19:00:00 +01:00
return err;
}
/*-------------------------------------------------------------------------*\
* Reads a fixed number of bytes (buffered)
2002-03-27 19:00:00 +01:00
\*-------------------------------------------------------------------------*/
2004-07-01 05:32:09 +02:00
static int recvraw(p_buf buf, size_t wanted, luaL_Buffer *b) {
int err = IO_DONE;
2002-03-27 19:00:00 +01:00
size_t total = 0;
2004-07-01 05:32:09 +02:00
while (total < wanted && err == IO_DONE) {
2003-05-25 03:54:13 +02:00
size_t count; const char *data;
err = buf_get(buf, &data, &count);
count = MIN(count, wanted - total);
luaL_addlstring(b, data, count);
2003-05-25 03:54:13 +02:00
buf_skip(buf, count);
total += count;
2002-03-27 19:00:00 +01:00
}
return err;
}
/*-------------------------------------------------------------------------*\
* Reads everything until the connection is closed (buffered)
2002-03-27 19:00:00 +01:00
\*-------------------------------------------------------------------------*/
2004-07-01 05:32:09 +02:00
static int recvall(p_buf buf, luaL_Buffer *b) {
2003-05-25 03:54:13 +02:00
int err = IO_DONE;
2004-07-01 05:32:09 +02:00
while (err == IO_DONE) {
2003-05-25 03:54:13 +02:00
const char *data; size_t count;
err = buf_get(buf, &data, &count);
luaL_addlstring(b, data, count);
2003-05-25 03:54:13 +02:00
buf_skip(buf, count);
2002-03-27 19:00:00 +01:00
}
if (err == IO_CLOSED) return IO_DONE;
else return err;
2002-03-27 19:00:00 +01:00
}
/*-------------------------------------------------------------------------*\
* 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
2002-03-27 19:00:00 +01:00
\*-------------------------------------------------------------------------*/
2004-07-01 05:32:09 +02:00
static int recvline(p_buf buf, luaL_Buffer *b) {
int err = IO_DONE;
2004-07-01 05:32:09 +02:00
while (err == IO_DONE) {
2003-05-25 03:54:13 +02:00
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]);
2002-03-27 19:00:00 +01:00
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
}
return err;
}
/*-------------------------------------------------------------------------*\
* Skips a given number of bytes from read buffer. No data is read from the
* transport layer
2002-03-27 19:00:00 +01:00
\*-------------------------------------------------------------------------*/
2004-07-01 05:32:09 +02:00
static void buf_skip(p_buf buf, size_t count) {
2004-07-01 08:09:29 +02:00
buf->received += count;
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
2002-03-27 19:00:00 +01:00
\*-------------------------------------------------------------------------*/
2004-07-01 05:32:09 +02:00
static int buf_get(p_buf buf, const char **data, size_t *count) {
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;
2004-07-01 05:32:09 +02:00
err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm);
2003-05-25 03:54:13 +02:00
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;
}