aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2002-03-27 18:00:00 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2002-03-27 18:00:00 +0000
commit8f05082f77a5bf612291de593f63e09e7fb3a5cb (patch)
treef1da6940e8d9b9f6cc129213d0c571da65e467c6 /src
parent3bd99ec59996653011f0eb40a0be4a523fe82897 (diff)
downloadluasocket-8f05082f77a5bf612291de593f63e09e7fb3a5cb.tar.gz
luasocket-8f05082f77a5bf612291de593f63e09e7fb3a5cb.tar.bz2
luasocket-8f05082f77a5bf612291de593f63e09e7fb3a5cb.zip
Initial revision
Diffstat (limited to 'src')
-rw-r--r--src/buffer.c338
-rw-r--r--src/buffer.h33
2 files changed, 371 insertions, 0 deletions
diff --git a/src/buffer.c b/src/buffer.c
new file mode 100644
index 0000000..a9a9782
--- /dev/null
+++ b/src/buffer.c
@@ -0,0 +1,338 @@
1/*=========================================================================*\
2* Buffered input/output routines
3* Lua methods:
4* send: unbuffered send using C base_send
5* receive: buffered read using C base_receive
6\*=========================================================================*/
7#include <lua.h>
8#include <lauxlib.h>
9
10#include "lsbuf.h"
11
12/*=========================================================================*\
13* Internal function prototypes.
14\*=========================================================================*/
15static int sendraw(lua_State *L, p_buf buf, cchar *data, size_t len,
16 size_t *done);
17static int recvraw(lua_State *L, p_buf buf, size_t wanted);
18static int recvdosline(lua_State *L, p_buf buf);
19static int recvunixline(lua_State *L, p_buf buf);
20static int recvall(lua_State *L, p_buf buf);
21
22static int buf_contents(lua_State *L, p_buf buf, cchar **data, size_t *len);
23static void buf_skip(lua_State *L, p_buf buf, size_t len);
24
25/*=========================================================================*\
26* Exported functions
27\*=========================================================================*/
28/*-------------------------------------------------------------------------*\
29* Initializes module
30\*-------------------------------------------------------------------------*/
31void buf_open(lua_State *L)
32{
33 (void) L;
34}
35
36/*-------------------------------------------------------------------------*\
37* Initializes C structure
38* Input
39* buf: buffer structure to initialize
40* base: socket object to associate with buffer structure
41\*-------------------------------------------------------------------------*/
42void buf_init(lua_State *L, p_buf buf, p_base base)
43{
44 (void) L;
45 buf->buf_first = buf->buf_last = 0;
46 buf->buf_base = base;
47}
48
49/*-------------------------------------------------------------------------*\
50* Send data through buffered object
51* Input
52* buf: buffer structure to be used
53* Lua Input: self, a_1 [, a_2, a_3 ... a_n]
54* self: socket object
55* a_i: strings to be sent.
56* Lua Returns
57* On success: nil, followed by the total number of bytes sent
58* On error: error message
59\*-------------------------------------------------------------------------*/
60int buf_send(lua_State *L, p_buf buf)
61{
62 int top = lua_gettop(L);
63 size_t total = 0;
64 int err = PRIV_DONE;
65 int arg;
66 p_base base = buf->buf_base;
67 tm_markstart(&base->base_tm);
68 for (arg = 2; arg <= top; arg++) { /* first arg is socket object */
69 size_t done, len;
70 cchar *data = luaL_opt_lstr(L, arg, NULL, &len);
71 if (!data || err != PRIV_DONE) break;
72 err = sendraw(L, buf, data, len, &done);
73 total += done;
74 }
75 priv_pusherror(L, err);
76 lua_pushnumber(L, total);
77#ifdef _DEBUG
78 /* push time elapsed during operation as the last return value */
79 lua_pushnumber(L, tm_getelapsed(&base->base_tm)/1000.0);
80#endif
81 return lua_gettop(L) - top;
82}
83
84/*-------------------------------------------------------------------------*\
85* Receive data from a buffered object
86* Input
87* buf: buffer structure to be used
88* Lua Input: self [pat_1, pat_2 ... pat_n]
89* self: socket object
90* pat_i: may be one of the following
91* "*l": reads a text line, defined as a string of caracters terminates
92* by a LF character, preceded or not by a CR character. This is
93* the default pattern
94* "*lu": reads a text line, terminanted by a CR character only. (Unix mode)
95* "*a": reads until connection closed
96* number: reads 'number' characters from the socket object
97* Lua Returns
98* On success: one string for each pattern
99* On error: all strings for which there was no error, followed by one
100* nil value for the remaining strings, followed by an error code
101\*-------------------------------------------------------------------------*/
102int buf_receive(lua_State *L, p_buf buf)
103{
104 int top = lua_gettop(L);
105 int arg, err = PRIV_DONE;
106 p_base base = buf->buf_base;
107 tm_markstart(&base->base_tm);
108 /* push default pattern if need be */
109 if (top < 2) {
110 lua_pushstring(L, "*l");
111 top++;
112 }
113 /* make sure we have enough stack space */
114 luaL_check_stack(L, top+LUA_MINSTACK, "too many arguments");
115 /* receive all patterns */
116 for (arg = 2; arg <= top && err == PRIV_DONE; arg++) {
117 if (!lua_isnumber(L, arg)) {
118 static cchar *patternnames[] = {"*l", "*lu", "*a", "*w", NULL};
119 cchar *pattern = luaL_opt_string(L, arg, NULL);
120 /* get next pattern */
121 switch (luaL_findstring(pattern, patternnames)) {
122 case 0: /* DOS line pattern */
123 err = recvdosline(L, buf); break;
124 case 1: /* Unix line pattern */
125 err = recvunixline(L, buf); break;
126 case 2: /* Until closed pattern */
127 err = recvall(L, buf); break;
128 case 3: /* Word pattern */
129 luaL_arg_check(L, 0, arg, "word patterns are deprecated");
130 break;
131 default: /* else it is an error */
132 luaL_arg_check(L, 0, arg, "invalid receive pattern");
133 break;
134 }
135 /* raw pattern */
136 } else err = recvraw(L, buf, (size_t) lua_tonumber(L, arg));
137 }
138 /* push nil for each pattern after an error */
139 for ( ; arg <= top; arg++) lua_pushnil(L);
140 /* last return is an error code */
141 priv_pusherror(L, err);
142#ifdef _DEBUG
143 /* push time elapsed during operation as the last return value */
144 lua_pushnumber(L, tm_getelapsed(&base->base_tm)/1000.0);
145#endif
146 return lua_gettop(L) - top;
147}
148
149/*-------------------------------------------------------------------------*\
150* Determines if there is any data in the read buffer
151* Input
152* buf: buffer structure to be used
153* Returns
154* 1 if empty, 0 if there is data
155\*-------------------------------------------------------------------------*/
156int buf_isempty(lua_State *L, p_buf buf)
157{
158 (void) L;
159 return buf->buf_first >= buf->buf_last;
160}
161
162/*=========================================================================*\
163* Internal functions
164\*=========================================================================*/
165/*-------------------------------------------------------------------------*\
166* Sends a raw block of data through a buffered object.
167* Input
168* buf: buffer structure to be used
169* data: data to be sent
170* len: number of bytes to send
171* Output
172* sent: number of bytes sent
173* Returns
174* operation error code.
175\*-------------------------------------------------------------------------*/
176static int sendraw(lua_State *L, p_buf buf, cchar *data, size_t len,
177 size_t *sent)
178{
179 p_base base = buf->buf_base;
180 size_t total = 0;
181 int err = PRIV_DONE;
182 while (total < len && err == PRIV_DONE) {
183 size_t done;
184 err = base->base_send(L, base, data + total, len - total, &done);
185 total += done;
186 }
187 *sent = total;
188 return err;
189}
190
191/*-------------------------------------------------------------------------*\
192* Reads a raw block of data from a buffered object.
193* Input
194* buf: buffer structure
195* wanted: number of bytes to be read
196* Returns
197* operation error code.
198\*-------------------------------------------------------------------------*/
199static int recvraw(lua_State *L, p_buf buf, size_t wanted)
200{
201 int err = PRIV_DONE;
202 size_t total = 0;
203 luaL_Buffer b;
204 luaL_buffinit(L, &b);
205 while (total < wanted && err == PRIV_DONE) {
206 size_t len; cchar *data;
207 err = buf_contents(L, buf, &data, &len);
208 len = MIN(len, wanted - total);
209 luaL_addlstring(&b, data, len);
210 buf_skip(L, buf, len);
211 total += len;
212 }
213 luaL_pushresult(&b);
214 return err;
215}
216
217/*-------------------------------------------------------------------------*\
218* Reads everything until the connection is closed
219* Input
220* buf: buffer structure
221* Result
222* operation error code.
223\*-------------------------------------------------------------------------*/
224static int recvall(lua_State *L, p_buf buf)
225{
226 int err = PRIV_DONE;
227 luaL_Buffer b;
228 luaL_buffinit(L, &b);
229 while (err == PRIV_DONE) {
230 cchar *data; size_t len;
231 err = buf_contents(L, buf, &data, &len);
232 luaL_addlstring(&b, data, len);
233 buf_skip(L, buf, len);
234 }
235 luaL_pushresult(&b);
236 return err;
237}
238
239/*-------------------------------------------------------------------------*\
240* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
241* are not returned by the function and are discarded from the buffer.
242* Input
243* buf: buffer structure
244* Result
245* operation error code. PRIV_DONE, PRIV_TIMEOUT or PRIV_CLOSED
246\*-------------------------------------------------------------------------*/
247static int recvdosline(lua_State *L, p_buf buf)
248{
249 int err = 0;
250 luaL_Buffer b;
251 luaL_buffinit(L, &b);
252 while (err == PRIV_DONE) {
253 size_t len, pos; cchar *data;
254 err = buf_contents(L, buf, &data, &len);
255 pos = 0;
256 while (pos < len && data[pos] != '\n') {
257 /* we ignore all \r's */
258 if (data[pos] != '\r') luaL_putchar(&b, data[pos]);
259 pos++;
260 }
261 if (pos < len) { /* found '\n' */
262 buf_skip(L, buf, pos+1); /* skip '\n' too */
263 break; /* we are done */
264 } else /* reached the end of the buffer */
265 buf_skip(L, buf, pos);
266 }
267 luaL_pushresult(&b);
268 return err;
269}
270
271/*-------------------------------------------------------------------------*\
272* Reads a line terminated by a LF character, which is not returned by
273* the function, and is skipped in the buffer.
274* Input
275* buf: buffer structure
276* Returns
277* operation error code. PRIV_DONE, PRIV_TIMEOUT or PRIV_CLOSED
278\*-------------------------------------------------------------------------*/
279static int recvunixline(lua_State *L, p_buf buf)
280{
281 int err = PRIV_DONE;
282 luaL_Buffer b;
283 luaL_buffinit(L, &b);
284 while (err == 0) {
285 size_t pos, len; cchar *data;
286 err = buf_contents(L, buf, &data, &len);
287 pos = 0;
288 while (pos < len && data[pos] != '\n') {
289 luaL_putchar(&b, data[pos]);
290 pos++;
291 }
292 if (pos < len) { /* found '\n' */
293 buf_skip(L, buf, pos+1); /* skip '\n' too */
294 break; /* we are done */
295 } else /* reached the end of the buffer */
296 buf_skip(L, buf, pos);
297 }
298 luaL_pushresult(&b);
299 return err;
300}
301
302/*-------------------------------------------------------------------------*\
303* Skips a given number of bytes in read buffer
304* Input
305* buf: buffer structure
306* len: number of bytes to skip
307\*-------------------------------------------------------------------------*/
308static void buf_skip(lua_State *L, p_buf buf, size_t len)
309{
310 buf->buf_first += len;
311 if (buf_isempty(L, buf)) buf->buf_first = buf->buf_last = 0;
312}
313
314/*-------------------------------------------------------------------------*\
315* Return any data available in buffer, or get more data from transport layer
316* if buffer is empty.
317* Input
318* buf: buffer structure
319* Output
320* data: pointer to buffer start
321* len: buffer buffer length
322* Returns
323* PRIV_DONE, PRIV_CLOSED, PRIV_TIMEOUT ...
324\*-------------------------------------------------------------------------*/
325static int buf_contents(lua_State *L, p_buf buf, cchar **data, size_t *len)
326{
327 int err = PRIV_DONE;
328 p_base base = buf->buf_base;
329 if (buf_isempty(L, buf)) {
330 size_t done;
331 err = base->base_receive(L, base, buf->buf_data, BUF_SIZE, &done);
332 buf->buf_first = 0;
333 buf->buf_last = done;
334 }
335 *len = buf->buf_last - buf->buf_first;
336 *data = buf->buf_data + buf->buf_first;
337 return err;
338}
diff --git a/src/buffer.h b/src/buffer.h
new file mode 100644
index 0000000..7463a67
--- /dev/null
+++ b/src/buffer.h
@@ -0,0 +1,33 @@
1/*=========================================================================*\
2* Buffered input/output routines
3* RCS ID: $Id$
4\*=========================================================================*/
5#ifndef BUF_H_
6#define BUF_H_
7
8#include <lua.h>
9#include "lsbase.h"
10
11/* buffer size in bytes */
12#define BUF_SIZE 8192
13
14/*-------------------------------------------------------------------------*\
15* Buffer control structure
16\*-------------------------------------------------------------------------*/
17typedef struct t_buf_tag {
18 size_t buf_first, buf_last;
19 uchar buf_data[BUF_SIZE];
20 p_base buf_base;
21} t_buf;
22typedef t_buf *p_buf;
23
24/*-------------------------------------------------------------------------*\
25* Exported functions
26\*-------------------------------------------------------------------------*/
27void buf_open(lua_State *L);
28void buf_init(lua_State *L, p_buf buf, p_base base);
29int buf_send(lua_State *L, p_buf buf);
30int buf_receive(lua_State *L, p_buf buf);
31int buf_isempty(lua_State *L, p_buf buf);
32
33#endif /* BUF_H_ */