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