diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2002-03-27 18:00:00 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2002-03-27 18:00:00 +0000 |
commit | 8f05082f77a5bf612291de593f63e09e7fb3a5cb (patch) | |
tree | f1da6940e8d9b9f6cc129213d0c571da65e467c6 /src | |
parent | 3bd99ec59996653011f0eb40a0be4a523fe82897 (diff) | |
download | luasocket-8f05082f77a5bf612291de593f63e09e7fb3a5cb.tar.gz luasocket-8f05082f77a5bf612291de593f63e09e7fb3a5cb.tar.bz2 luasocket-8f05082f77a5bf612291de593f63e09e7fb3a5cb.zip |
Initial revision
Diffstat (limited to 'src')
-rw-r--r-- | src/buffer.c | 338 | ||||
-rw-r--r-- | src/buffer.h | 33 |
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 | \*=========================================================================*/ | ||
15 | static int sendraw(lua_State *L, p_buf buf, cchar *data, size_t len, | ||
16 | size_t *done); | ||
17 | static int recvraw(lua_State *L, p_buf buf, size_t wanted); | ||
18 | static int recvdosline(lua_State *L, p_buf buf); | ||
19 | static int recvunixline(lua_State *L, p_buf buf); | ||
20 | static int recvall(lua_State *L, p_buf buf); | ||
21 | |||
22 | static int buf_contents(lua_State *L, p_buf buf, cchar **data, size_t *len); | ||
23 | static void buf_skip(lua_State *L, p_buf buf, size_t len); | ||
24 | |||
25 | /*=========================================================================*\ | ||
26 | * Exported functions | ||
27 | \*=========================================================================*/ | ||
28 | /*-------------------------------------------------------------------------*\ | ||
29 | * Initializes module | ||
30 | \*-------------------------------------------------------------------------*/ | ||
31 | void 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 | \*-------------------------------------------------------------------------*/ | ||
42 | void 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 | \*-------------------------------------------------------------------------*/ | ||
60 | int 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 | \*-------------------------------------------------------------------------*/ | ||
102 | int 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 | \*-------------------------------------------------------------------------*/ | ||
156 | int 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 | \*-------------------------------------------------------------------------*/ | ||
176 | static 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 | \*-------------------------------------------------------------------------*/ | ||
199 | static 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 | \*-------------------------------------------------------------------------*/ | ||
224 | static 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 | \*-------------------------------------------------------------------------*/ | ||
247 | static 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 | \*-------------------------------------------------------------------------*/ | ||
279 | static 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 | \*-------------------------------------------------------------------------*/ | ||
308 | static 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 | \*-------------------------------------------------------------------------*/ | ||
325 | static 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 | \*-------------------------------------------------------------------------*/ | ||
17 | typedef 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; | ||
22 | typedef t_buf *p_buf; | ||
23 | |||
24 | /*-------------------------------------------------------------------------*\ | ||
25 | * Exported functions | ||
26 | \*-------------------------------------------------------------------------*/ | ||
27 | void buf_open(lua_State *L); | ||
28 | void buf_init(lua_State *L, p_buf buf, p_base base); | ||
29 | int buf_send(lua_State *L, p_buf buf); | ||
30 | int buf_receive(lua_State *L, p_buf buf); | ||
31 | int buf_isempty(lua_State *L, p_buf buf); | ||
32 | |||
33 | #endif /* BUF_H_ */ | ||