diff options
| -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_ */ | ||
