~aranha/aranha/mainline

82.2.2 by Daniel Silverstone
Add luasocket sources
1
/*=========================================================================*\
2
* TCP object 
3
* LuaSocket toolkit
4
*
5
* RCS ID: $Id: tcp.c,v 1.41 2005/10/07 04:40:59 diego Exp $
6
\*=========================================================================*/
7
#include <string.h> 
8
9
#include "lua.h"
10
#include "lauxlib.h"
11
12
#include "auxiliar.h"
13
#include "socket.h"
14
#include "inet.h"
15
#include "options.h"
16
#include "tcp.h"
17
18
/*=========================================================================*\
19
* Internal function prototypes
20
\*=========================================================================*/
21
static int global_create(lua_State *L);
22
static int meth_connect(lua_State *L);
23
static int meth_listen(lua_State *L);
24
static int meth_bind(lua_State *L);
25
static int meth_send(lua_State *L);
26
static int meth_getstats(lua_State *L);
27
static int meth_setstats(lua_State *L);
28
static int meth_getsockname(lua_State *L);
29
static int meth_getpeername(lua_State *L);
30
static int meth_shutdown(lua_State *L);
31
static int meth_receive(lua_State *L);
32
static int meth_accept(lua_State *L);
33
static int meth_close(lua_State *L);
34
static int meth_setoption(lua_State *L);
35
static int meth_settimeout(lua_State *L);
36
static int meth_getfd(lua_State *L);
37
static int meth_setfd(lua_State *L);
38
static int meth_dirty(lua_State *L);
39
40
/* tcp object methods */
41
static luaL_reg tcp[] = {
42
    {"__gc",        meth_close},
43
    {"__tostring",  auxiliar_tostring},
44
    {"accept",      meth_accept},
45
    {"bind",        meth_bind},
46
    {"close",       meth_close},
47
    {"connect",     meth_connect},
48
    {"dirty",       meth_dirty},
49
    {"getfd",       meth_getfd},
50
    {"getpeername", meth_getpeername},
51
    {"getsockname", meth_getsockname},
52
    {"getstats",    meth_getstats},
53
    {"setstats",    meth_setstats},
54
    {"listen",      meth_listen},
55
    {"receive",     meth_receive},
56
    {"send",        meth_send},
57
    {"setfd",       meth_setfd},
58
    {"setoption",   meth_setoption},
59
    {"setpeername", meth_connect},
60
    {"setsockname", meth_bind},
61
    {"settimeout",  meth_settimeout},
62
    {"shutdown",    meth_shutdown},
63
    {NULL,          NULL}
64
};
65
66
/* socket option handlers */
67
static t_opt opt[] = {
68
    {"keepalive",   opt_keepalive},
69
    {"reuseaddr",   opt_reuseaddr},
70
    {"tcp-nodelay", opt_tcp_nodelay},
71
    {"linger",      opt_linger},
72
    {NULL,          NULL}
73
};
74
75
/* functions in library namespace */
76
static luaL_reg func[] = {
77
    {"tcp", global_create},
78
    {NULL, NULL}
79
};
80
81
/*-------------------------------------------------------------------------*\
82
* Initializes module
83
\*-------------------------------------------------------------------------*/
84
int tcp_open(lua_State *L)
85
{
86
    /* create classes */
87
    auxiliar_newclass(L, "tcp{master}", tcp);
88
    auxiliar_newclass(L, "tcp{client}", tcp);
89
    auxiliar_newclass(L, "tcp{server}", tcp);
90
    /* create class groups */
91
    auxiliar_add2group(L, "tcp{master}", "tcp{any}");
92
    auxiliar_add2group(L, "tcp{client}", "tcp{any}");
93
    auxiliar_add2group(L, "tcp{server}", "tcp{any}");
94
    /* define library functions */
95
    luaL_openlib(L, NULL, func, 0); 
96
    return 0;
97
}
98
99
/*=========================================================================*\
100
* Lua methods
101
\*=========================================================================*/
102
/*-------------------------------------------------------------------------*\
103
* Just call buffered IO methods
104
\*-------------------------------------------------------------------------*/
105
static int meth_send(lua_State *L) {
106
    p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
107
    return buffer_meth_send(L, &tcp->buf);
108
}
109
110
static int meth_receive(lua_State *L) {
111
    p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
112
    return buffer_meth_receive(L, &tcp->buf);
113
}
114
115
static int meth_getstats(lua_State *L) {
116
    p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
117
    return buffer_meth_getstats(L, &tcp->buf);
118
}
119
120
static int meth_setstats(lua_State *L) {
121
    p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
122
    return buffer_meth_setstats(L, &tcp->buf);
123
}
124
125
/*-------------------------------------------------------------------------*\
126
* Just call option handler
127
\*-------------------------------------------------------------------------*/
128
static int meth_setoption(lua_State *L)
129
{
130
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
131
    return opt_meth_setoption(L, opt, &tcp->sock);
132
}
133
134
/*-------------------------------------------------------------------------*\
135
* Select support methods
136
\*-------------------------------------------------------------------------*/
137
static int meth_getfd(lua_State *L)
138
{
139
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
140
    lua_pushnumber(L, (int) tcp->sock);
141
    return 1;
142
}
143
144
/* this is very dangerous, but can be handy for those that are brave enough */
145
static int meth_setfd(lua_State *L)
146
{
147
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
148
    tcp->sock = (t_socket) luaL_checknumber(L, 2); 
149
    return 0;
150
}
151
152
static int meth_dirty(lua_State *L)
153
{
154
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
155
    lua_pushboolean(L, !buffer_isempty(&tcp->buf));
156
    return 1;
157
}
158
159
/*-------------------------------------------------------------------------*\
160
* Waits for and returns a client object attempting connection to the 
161
* server object 
162
\*-------------------------------------------------------------------------*/
163
static int meth_accept(lua_State *L)
164
{
165
    p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1);
166
    p_timeout tm = timeout_markstart(&server->tm);
167
    t_socket sock;
168
    int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
169
    /* if successful, push client socket */
170
    if (err == IO_DONE) {
171
        p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
172
        auxiliar_setclass(L, "tcp{client}", -1);
173
        /* initialize structure fields */
174
        socket_setnonblocking(&sock);
175
        clnt->sock = sock;
176
        io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv, 
177
                (p_error) socket_ioerror, &clnt->sock);
178
        timeout_init(&clnt->tm, -1, -1);
179
        buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
180
        return 1;
181
    } else {
182
        lua_pushnil(L); 
183
        lua_pushstring(L, socket_strerror(err));
184
        return 2;
185
    }
186
}
187
188
/*-------------------------------------------------------------------------*\
189
* Binds an object to an address 
190
\*-------------------------------------------------------------------------*/
191
static int meth_bind(lua_State *L)
192
{
193
    p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
194
    const char *address =  luaL_checkstring(L, 2);
195
    unsigned short port = (unsigned short) luaL_checknumber(L, 3);
196
    const char *err = inet_trybind(&tcp->sock, address, port);
197
    if (err) {
198
        lua_pushnil(L);
199
        lua_pushstring(L, err);
200
        return 2;
201
    }
202
    lua_pushnumber(L, 1);
203
    return 1;
204
}
205
206
/*-------------------------------------------------------------------------*\
207
* Turns a master tcp object into a client object.
208
\*-------------------------------------------------------------------------*/
209
static int meth_connect(lua_State *L)
210
{
211
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
212
    const char *address =  luaL_checkstring(L, 2);
213
    unsigned short port = (unsigned short) luaL_checknumber(L, 3);
214
    p_timeout tm = timeout_markstart(&tcp->tm);
215
    const char *err = inet_tryconnect(&tcp->sock, address, port, tm);
216
    /* have to set the class even if it failed due to non-blocking connects */
217
    auxiliar_setclass(L, "tcp{client}", 1);
218
    if (err) {
219
        lua_pushnil(L);
220
        lua_pushstring(L, err);
221
        return 2;
222
    }
223
    /* turn master object into a client object */
224
    lua_pushnumber(L, 1);
225
    return 1;
226
}
227
228
/*-------------------------------------------------------------------------*\
229
* Closes socket used by object 
230
\*-------------------------------------------------------------------------*/
231
static int meth_close(lua_State *L)
232
{
233
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
234
    socket_destroy(&tcp->sock);
235
    lua_pushnumber(L, 1);
236
    return 1;
237
}
238
239
/*-------------------------------------------------------------------------*\
240
* Puts the sockt in listen mode
241
\*-------------------------------------------------------------------------*/
242
static int meth_listen(lua_State *L)
243
{
244
    p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
245
    int backlog = (int) luaL_optnumber(L, 2, 32);
246
    int err = socket_listen(&tcp->sock, backlog);
247
    if (err != IO_DONE) {
248
        lua_pushnil(L);
249
        lua_pushstring(L, socket_strerror(err));
250
        return 2;
251
    }
252
    /* turn master object into a server object */
253
    auxiliar_setclass(L, "tcp{server}", 1);
254
    lua_pushnumber(L, 1);
255
    return 1;
256
}
257
258
/*-------------------------------------------------------------------------*\
259
* Shuts the connection down partially
260
\*-------------------------------------------------------------------------*/
261
static int meth_shutdown(lua_State *L)
262
{
263
    p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
264
    const char *how = luaL_optstring(L, 2, "both");
265
    switch (how[0]) {
266
        case 'b':
267
            if (strcmp(how, "both")) goto error;
268
            socket_shutdown(&tcp->sock, 2);
269
            break;
270
        case 's':
271
            if (strcmp(how, "send")) goto error;
272
            socket_shutdown(&tcp->sock, 1);
273
            break;
274
        case 'r':
275
            if (strcmp(how, "receive")) goto error;
276
            socket_shutdown(&tcp->sock, 0);
277
            break;
278
    }
279
    lua_pushnumber(L, 1);
280
    return 1;
281
error:
282
    luaL_argerror(L, 2, "invalid shutdown method");
283
    return 0;
284
}
285
286
/*-------------------------------------------------------------------------*\
287
* Just call inet methods
288
\*-------------------------------------------------------------------------*/
289
static int meth_getpeername(lua_State *L)
290
{
291
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
292
    return inet_meth_getpeername(L, &tcp->sock);
293
}
294
295
static int meth_getsockname(lua_State *L)
296
{
297
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
298
    return inet_meth_getsockname(L, &tcp->sock);
299
}
300
301
/*-------------------------------------------------------------------------*\
302
* Just call tm methods
303
\*-------------------------------------------------------------------------*/
304
static int meth_settimeout(lua_State *L)
305
{
306
    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
307
    return timeout_meth_settimeout(L, &tcp->tm);
308
}
309
310
/*=========================================================================*\
311
* Library functions
312
\*=========================================================================*/
313
/*-------------------------------------------------------------------------*\
314
* Creates a master tcp object 
315
\*-------------------------------------------------------------------------*/
316
static int global_create(lua_State *L)
317
{
318
    t_socket sock;
319
    const char *err = inet_trycreate(&sock, SOCK_STREAM);
320
    /* try to allocate a system socket */
321
    if (!err) { 
322
        /* allocate tcp object */
323
        p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
324
        /* set its type as master object */
325
        auxiliar_setclass(L, "tcp{master}", -1);
326
        /* initialize remaining structure fields */
327
        socket_setnonblocking(&sock);
328
        tcp->sock = sock;
329
        io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, 
330
                (p_error) socket_ioerror, &tcp->sock);
331
        timeout_init(&tcp->tm, -1, -1);
332
        buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
333
        return 1;
334
    } else {
335
        lua_pushnil(L);
336
        lua_pushstring(L, err);
337
        return 2;
338
    }
339
}