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