~ubuntu-branches/ubuntu/trusty/lua-sec/trusty-proposed

« back to all changes in this revision

Viewing changes to src/luasocket/buffer.c

  • Committer: Package Import Robot
  • Author(s): Enrico Tassi
  • Date: 2012-06-25 20:44:04 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20120625204404-cpn3b3koh3x7qxvf
Tags: 0.4.1+git063e8a8-1
New upstream snaphost for luasocket 3.0 

Show diffs side-by-side

added added

removed removed

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