Mercurial > luasocket
comparison src/buffer.c @ 0:4b915342e2a8
LuaSocket 2.0.2 + CMake build description.
author | Eric Wing <ewing . public |-at-| gmail . com> |
---|---|
date | Tue, 26 Aug 2008 18:40:01 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4b915342e2a8 |
---|---|
1 /*=========================================================================*\ | |
2 * Input/Output interface for Lua programs | |
3 * LuaSocket toolkit | |
4 * | |
5 * RCS ID: $Id: buffer.c,v 1.28 2007/06/11 23:44:54 diego Exp $ | |
6 \*=========================================================================*/ | |
7 #include "lua.h" | |
8 #include "lauxlib.h" | |
9 | |
10 #include "buffer.h" | |
11 | |
12 /*=========================================================================*\ | |
13 * Internal function prototypes | |
14 \*=========================================================================*/ | |
15 static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b); | |
16 static int recvline(p_buffer buf, luaL_Buffer *b); | |
17 static int recvall(p_buffer buf, luaL_Buffer *b); | |
18 static int buffer_get(p_buffer buf, const char **data, size_t *count); | |
19 static void buffer_skip(p_buffer buf, size_t count); | |
20 static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent); | |
21 | |
22 /* min and max macros */ | |
23 #ifndef MIN | |
24 #define MIN(x, y) ((x) < (y) ? x : y) | |
25 #endif | |
26 #ifndef MAX | |
27 #define MAX(x, y) ((x) > (y) ? x : y) | |
28 #endif | |
29 | |
30 /*=========================================================================*\ | |
31 * Exported functions | |
32 \*=========================================================================*/ | |
33 /*-------------------------------------------------------------------------*\ | |
34 * Initializes module | |
35 \*-------------------------------------------------------------------------*/ | |
36 int buffer_open(lua_State *L) { | |
37 (void) L; | |
38 return 0; | |
39 } | |
40 | |
41 /*-------------------------------------------------------------------------*\ | |
42 * Initializes C structure | |
43 \*-------------------------------------------------------------------------*/ | |
44 void buffer_init(p_buffer buf, p_io io, p_timeout tm) { | |
45 buf->first = buf->last = 0; | |
46 buf->io = io; | |
47 buf->tm = tm; | |
48 buf->received = buf->sent = 0; | |
49 buf->birthday = timeout_gettime(); | |
50 } | |
51 | |
52 /*-------------------------------------------------------------------------*\ | |
53 * object:getstats() interface | |
54 \*-------------------------------------------------------------------------*/ | |
55 int buffer_meth_getstats(lua_State *L, p_buffer buf) { | |
56 lua_pushnumber(L, buf->received); | |
57 lua_pushnumber(L, buf->sent); | |
58 lua_pushnumber(L, timeout_gettime() - buf->birthday); | |
59 return 3; | |
60 } | |
61 | |
62 /*-------------------------------------------------------------------------*\ | |
63 * object:setstats() interface | |
64 \*-------------------------------------------------------------------------*/ | |
65 int buffer_meth_setstats(lua_State *L, p_buffer buf) { | |
66 buf->received = (long) luaL_optnumber(L, 2, buf->received); | |
67 buf->sent = (long) luaL_optnumber(L, 3, buf->sent); | |
68 if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4); | |
69 lua_pushnumber(L, 1); | |
70 return 1; | |
71 } | |
72 | |
73 /*-------------------------------------------------------------------------*\ | |
74 * object:send() interface | |
75 \*-------------------------------------------------------------------------*/ | |
76 int buffer_meth_send(lua_State *L, p_buffer buf) { | |
77 int top = lua_gettop(L); | |
78 int err = IO_DONE; | |
79 size_t size = 0, sent = 0; | |
80 const char *data = luaL_checklstring(L, 2, &size); | |
81 long start = (long) luaL_optnumber(L, 3, 1); | |
82 long end = (long) luaL_optnumber(L, 4, -1); | |
83 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 */ | |
90 if (err != IO_DONE) { | |
91 lua_pushnil(L); | |
92 lua_pushstring(L, buf->io->error(buf->io->ctx, err)); | |
93 lua_pushnumber(L, sent+start-1); | |
94 } else { | |
95 lua_pushnumber(L, sent+start-1); | |
96 lua_pushnil(L); | |
97 lua_pushnil(L); | |
98 } | |
99 #ifdef LUASOCKET_DEBUG | |
100 /* push time elapsed during operation as the last return value */ | |
101 lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm)); | |
102 #endif | |
103 return lua_gettop(L) - top; | |
104 } | |
105 | |
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); | |
111 luaL_Buffer b; | |
112 size_t size; | |
113 const char *part = luaL_optlstring(L, 3, "", &size); | |
114 p_timeout tm = timeout_markstart(buf->tm); | |
115 /* initialize buffer with optional extra prefix | |
116 * (useful for concatenating previous partial results) */ | |
117 luaL_buffinit(L, &b); | |
118 luaL_addlstring(&b, part, size); | |
119 /* receive new patterns */ | |
120 if (!lua_isnumber(L, 2)) { | |
121 const char *p= luaL_optstring(L, 2, "*l"); | |
122 if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b); | |
123 else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); | |
124 else luaL_argcheck(L, 0, 2, "invalid receive pattern"); | |
125 /* get a fixed number of bytes (minus what was already partially | |
126 * received) */ | |
127 } else err = recvraw(buf, (size_t) lua_tonumber(L, 2)-size, &b); | |
128 /* check if there was an error */ | |
129 if (err != IO_DONE) { | |
130 /* we can't push anyting in the stack before pushing the | |
131 * contents of the buffer. this is the reason for the complication */ | |
132 luaL_pushresult(&b); | |
133 lua_pushstring(L, buf->io->error(buf->io->ctx, err)); | |
134 lua_pushvalue(L, -2); | |
135 lua_pushnil(L); | |
136 lua_replace(L, -4); | |
137 } else { | |
138 luaL_pushresult(&b); | |
139 lua_pushnil(L); | |
140 lua_pushnil(L); | |
141 } | |
142 #ifdef LUASOCKET_DEBUG | |
143 /* push time elapsed during operation as the last return value */ | |
144 lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm)); | |
145 #endif | |
146 return lua_gettop(L) - top; | |
147 } | |
148 | |
149 /*-------------------------------------------------------------------------*\ | |
150 * Determines if there is any data in the read buffer | |
151 \*-------------------------------------------------------------------------*/ | |
152 int buffer_isempty(p_buffer buf) { | |
153 return buf->first >= buf->last; | |
154 } | |
155 | |
156 /*=========================================================================*\ | |
157 * Internal functions | |
158 \*=========================================================================*/ | |
159 /*-------------------------------------------------------------------------*\ | |
160 * Sends a block of data (unbuffered) | |
161 \*-------------------------------------------------------------------------*/ | |
162 #define STEPSIZE 8192 | |
163 static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) { | |
164 p_io io = buf->io; | |
165 p_timeout tm = buf->tm; | |
166 size_t total = 0; | |
167 int err = IO_DONE; | |
168 while (total < count && err == IO_DONE) { | |
169 size_t done; | |
170 size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE; | |
171 err = io->send(io->ctx, data+total, step, &done, tm); | |
172 total += done; | |
173 } | |
174 *sent = total; | |
175 buf->sent += total; | |
176 return err; | |
177 } | |
178 | |
179 /*-------------------------------------------------------------------------*\ | |
180 * Reads a fixed number of bytes (buffered) | |
181 \*-------------------------------------------------------------------------*/ | |
182 static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) { | |
183 int err = IO_DONE; | |
184 size_t total = 0; | |
185 while (err == IO_DONE) { | |
186 size_t count; const char *data; | |
187 err = buffer_get(buf, &data, &count); | |
188 count = MIN(count, wanted - total); | |
189 luaL_addlstring(b, data, count); | |
190 buffer_skip(buf, count); | |
191 total += count; | |
192 if (total >= wanted) break; | |
193 } | |
194 return err; | |
195 } | |
196 | |
197 /*-------------------------------------------------------------------------*\ | |
198 * Reads everything until the connection is closed (buffered) | |
199 \*-------------------------------------------------------------------------*/ | |
200 static int recvall(p_buffer buf, luaL_Buffer *b) { | |
201 int err = IO_DONE; | |
202 size_t total = 0; | |
203 while (err == IO_DONE) { | |
204 const char *data; size_t count; | |
205 err = buffer_get(buf, &data, &count); | |
206 total += count; | |
207 luaL_addlstring(b, data, count); | |
208 buffer_skip(buf, count); | |
209 } | |
210 if (err == IO_CLOSED) { | |
211 if (total > 0) return IO_DONE; | |
212 else return IO_CLOSED; | |
213 } else return err; | |
214 } | |
215 | |
216 /*-------------------------------------------------------------------------*\ | |
217 * Reads a line terminated by a CR LF pair or just by a LF. The CR and LF | |
218 * are not returned by the function and are discarded from the buffer | |
219 \*-------------------------------------------------------------------------*/ | |
220 static int recvline(p_buffer buf, luaL_Buffer *b) { | |
221 int err = IO_DONE; | |
222 while (err == IO_DONE) { | |
223 size_t count, pos; const char *data; | |
224 err = buffer_get(buf, &data, &count); | |
225 pos = 0; | |
226 while (pos < count && data[pos] != '\n') { | |
227 /* we ignore all \r's */ | |
228 if (data[pos] != '\r') luaL_putchar(b, data[pos]); | |
229 pos++; | |
230 } | |
231 if (pos < count) { /* found '\n' */ | |
232 buffer_skip(buf, pos+1); /* skip '\n' too */ | |
233 break; /* we are done */ | |
234 } else /* reached the end of the buffer */ | |
235 buffer_skip(buf, pos); | |
236 } | |
237 return err; | |
238 } | |
239 | |
240 /*-------------------------------------------------------------------------*\ | |
241 * Skips a given number of bytes from read buffer. No data is read from the | |
242 * transport layer | |
243 \*-------------------------------------------------------------------------*/ | |
244 static void buffer_skip(p_buffer buf, size_t count) { | |
245 buf->received += count; | |
246 buf->first += count; | |
247 if (buffer_isempty(buf)) | |
248 buf->first = buf->last = 0; | |
249 } | |
250 | |
251 /*-------------------------------------------------------------------------*\ | |
252 * Return any data available in buffer, or get more data from transport layer | |
253 * if buffer is empty | |
254 \*-------------------------------------------------------------------------*/ | |
255 static int buffer_get(p_buffer buf, const char **data, size_t *count) { | |
256 int err = IO_DONE; | |
257 p_io io = buf->io; | |
258 p_timeout tm = buf->tm; | |
259 if (buffer_isempty(buf)) { | |
260 size_t got; | |
261 err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm); | |
262 buf->first = 0; | |
263 buf->last = got; | |
264 } | |
265 *count = buf->last - buf->first; | |
266 *data = buf->data + buf->first; | |
267 return err; | |
268 } |