1
/*=========================================================================*\
2
* Input/Output interface for Lua programs
4
\*=========================================================================*/
10
/*=========================================================================*\
11
* Internal function prototypes
12
\*=========================================================================*/
13
static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b);
14
static int recvline(p_buffer buf, luaL_Buffer *b);
15
static int recvall(p_buffer buf, luaL_Buffer *b);
16
static int buffer_get(p_buffer buf, const char **data, size_t *count);
17
static void buffer_skip(p_buffer buf, size_t count);
18
static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent);
20
/* min and max macros */
22
#define MIN(x, y) ((x) < (y) ? x : y)
25
#define MAX(x, y) ((x) > (y) ? x : y)
28
/*=========================================================================*\
30
\*=========================================================================*/
31
/*-------------------------------------------------------------------------*\
33
\*-------------------------------------------------------------------------*/
34
int buffer_open(lua_State *L) {
39
/*-------------------------------------------------------------------------*\
40
* Initializes C structure
41
\*-------------------------------------------------------------------------*/
42
void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
43
buf->first = buf->last = 0;
46
buf->received = buf->sent = 0;
47
buf->birthday = timeout_gettime();
50
/*-------------------------------------------------------------------------*\
51
* object:getstats() interface
52
\*-------------------------------------------------------------------------*/
53
int buffer_meth_getstats(lua_State *L, p_buffer buf) {
54
lua_pushnumber(L, (lua_Number) buf->received);
55
lua_pushnumber(L, (lua_Number) buf->sent);
56
lua_pushnumber(L, timeout_gettime() - buf->birthday);
60
/*-------------------------------------------------------------------------*\
61
* object:setstats() interface
62
\*-------------------------------------------------------------------------*/
63
int buffer_meth_setstats(lua_State *L, p_buffer buf) {
64
buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received);
65
buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent);
66
if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4);
71
/*-------------------------------------------------------------------------*\
72
* object:send() interface
73
\*-------------------------------------------------------------------------*/
74
int buffer_meth_send(lua_State *L, p_buffer buf) {
75
int top = lua_gettop(L);
77
size_t size = 0, sent = 0;
78
const char *data = luaL_checklstring(L, 2, &size);
79
long start = (long) luaL_optnumber(L, 3, 1);
80
long end = (long) luaL_optnumber(L, 4, -1);
81
#ifdef LUASOCKET_DEBUG
82
p_timeout tm = timeout_markstart(buf->tm);
84
if (start < 0) start = (long) (size+start+1);
85
if (end < 0) end = (long) (size+end+1);
86
if (start < 1) start = (long) 1;
87
if (end > (long) size) end = (long) size;
88
if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent);
89
/* check if there was an error */
92
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
93
lua_pushnumber(L, (lua_Number) (sent+start-1));
95
lua_pushnumber(L, (lua_Number) (sent+start-1));
99
#ifdef LUASOCKET_DEBUG
100
/* push time elapsed during operation as the last return value */
101
lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
103
return lua_gettop(L) - top;
106
/*-------------------------------------------------------------------------*\
107
* object:receive() interface
108
\*-------------------------------------------------------------------------*/
109
int buffer_meth_receive(lua_State *L, p_buffer buf) {
110
int err = IO_DONE, top = lua_gettop(L);
113
const char *part = luaL_optlstring(L, 3, "", &size);
114
#ifdef LUASOCKET_DEBUG
115
p_timeout tm = timeout_markstart(buf->tm);
117
/* initialize buffer with optional extra prefix
118
* (useful for concatenating previous partial results) */
119
luaL_buffinit(L, &b);
120
luaL_addlstring(&b, part, size);
121
/* receive new patterns */
122
if (!lua_isnumber(L, 2)) {
123
const char *p= luaL_optstring(L, 2, "*l");
124
if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
125
else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
126
else luaL_argcheck(L, 0, 2, "invalid receive pattern");
127
/* get a fixed number of bytes (minus what was already partially
130
double n = lua_tonumber(L, 2);
131
size_t wanted = (size_t) n;
132
luaL_argcheck(L, n >= 0, 2, "invalid receive pattern");
133
if (size == 0 || wanted > size)
134
err = recvraw(buf, wanted-size, &b);
136
/* check if there was an error */
137
if (err != IO_DONE) {
138
/* we can't push anyting in the stack before pushing the
139
* contents of the buffer. this is the reason for the complication */
141
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
142
lua_pushvalue(L, -2);
150
#ifdef LUASOCKET_DEBUG
151
/* push time elapsed during operation as the last return value */
152
lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
154
return lua_gettop(L) - top;
157
/*-------------------------------------------------------------------------*\
158
* Determines if there is any data in the read buffer
159
\*-------------------------------------------------------------------------*/
160
int buffer_isempty(p_buffer buf) {
161
return buf->first >= buf->last;
164
/*=========================================================================*\
166
\*=========================================================================*/
167
/*-------------------------------------------------------------------------*\
168
* Sends a block of data (unbuffered)
169
\*-------------------------------------------------------------------------*/
170
#define STEPSIZE 8192
171
static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) {
173
p_timeout tm = buf->tm;
176
while (total < count && err == IO_DONE) {
178
size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE;
179
err = io->send(io->ctx, data+total, step, &done, tm);
187
/*-------------------------------------------------------------------------*\
188
* Reads a fixed number of bytes (buffered)
189
\*-------------------------------------------------------------------------*/
190
static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) {
193
while (err == IO_DONE) {
194
size_t count; const char *data;
195
err = buffer_get(buf, &data, &count);
196
count = MIN(count, wanted - total);
197
luaL_addlstring(b, data, count);
198
buffer_skip(buf, count);
200
if (total >= wanted) break;
205
/*-------------------------------------------------------------------------*\
206
* Reads everything until the connection is closed (buffered)
207
\*-------------------------------------------------------------------------*/
208
static int recvall(p_buffer buf, luaL_Buffer *b) {
211
while (err == IO_DONE) {
212
const char *data; size_t count;
213
err = buffer_get(buf, &data, &count);
215
luaL_addlstring(b, data, count);
216
buffer_skip(buf, count);
218
if (err == IO_CLOSED) {
219
if (total > 0) return IO_DONE;
220
else return IO_CLOSED;
224
/*-------------------------------------------------------------------------*\
225
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
226
* are not returned by the function and are discarded from the buffer
227
\*-------------------------------------------------------------------------*/
228
static int recvline(p_buffer buf, luaL_Buffer *b) {
230
while (err == IO_DONE) {
231
size_t count, pos; const char *data;
232
err = buffer_get(buf, &data, &count);
234
while (pos < count && data[pos] != '\n') {
235
/* we ignore all \r's */
236
if (data[pos] != '\r') luaL_addchar(b, data[pos]);
239
if (pos < count) { /* found '\n' */
240
buffer_skip(buf, pos+1); /* skip '\n' too */
241
break; /* we are done */
242
} else /* reached the end of the buffer */
243
buffer_skip(buf, pos);
248
/*-------------------------------------------------------------------------*\
249
* Skips a given number of bytes from read buffer. No data is read from the
251
\*-------------------------------------------------------------------------*/
252
static void buffer_skip(p_buffer buf, size_t count) {
253
buf->received += count;
255
if (buffer_isempty(buf))
256
buf->first = buf->last = 0;
259
/*-------------------------------------------------------------------------*\
260
* Return any data available in buffer, or get more data from transport layer
262
\*-------------------------------------------------------------------------*/
263
static int buffer_get(p_buffer buf, const char **data, size_t *count) {
266
p_timeout tm = buf->tm;
267
if (buffer_isempty(buf)) {
269
err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm);
273
*count = buf->last - buf->first;
274
*data = buf->data + buf->first;