1
/*=========================================================================*\
5
* RCS ID: $Id: tcp.c,v 1.41 2005/10/07 04:40:59 diego Exp $
6
\*=========================================================================*/
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);
40
/* tcp object methods */
41
static luaL_reg tcp[] = {
43
{"__tostring", auxiliar_tostring},
44
{"accept", meth_accept},
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},
57
{"setfd", meth_setfd},
58
{"setoption", meth_setoption},
59
{"setpeername", meth_connect},
60
{"setsockname", meth_bind},
61
{"settimeout", meth_settimeout},
62
{"shutdown", meth_shutdown},
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},
75
/* functions in library namespace */
76
static luaL_reg func[] = {
77
{"tcp", global_create},
81
/*-------------------------------------------------------------------------*\
83
\*-------------------------------------------------------------------------*/
84
int tcp_open(lua_State *L)
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);
99
/*=========================================================================*\
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);
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);
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);
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);
125
/*-------------------------------------------------------------------------*\
126
* Just call option handler
127
\*-------------------------------------------------------------------------*/
128
static int meth_setoption(lua_State *L)
130
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
131
return opt_meth_setoption(L, opt, &tcp->sock);
134
/*-------------------------------------------------------------------------*\
135
* Select support methods
136
\*-------------------------------------------------------------------------*/
137
static int meth_getfd(lua_State *L)
139
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
140
lua_pushnumber(L, (int) tcp->sock);
144
/* this is very dangerous, but can be handy for those that are brave enough */
145
static int meth_setfd(lua_State *L)
147
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
148
tcp->sock = (t_socket) luaL_checknumber(L, 2);
152
static int meth_dirty(lua_State *L)
154
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
155
lua_pushboolean(L, !buffer_isempty(&tcp->buf));
159
/*-------------------------------------------------------------------------*\
160
* Waits for and returns a client object attempting connection to the
162
\*-------------------------------------------------------------------------*/
163
static int meth_accept(lua_State *L)
165
p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1);
166
p_timeout tm = timeout_markstart(&server->tm);
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);
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);
183
lua_pushstring(L, socket_strerror(err));
188
/*-------------------------------------------------------------------------*\
189
* Binds an object to an address
190
\*-------------------------------------------------------------------------*/
191
static int meth_bind(lua_State *L)
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);
199
lua_pushstring(L, err);
202
lua_pushnumber(L, 1);
206
/*-------------------------------------------------------------------------*\
207
* Turns a master tcp object into a client object.
208
\*-------------------------------------------------------------------------*/
209
static int meth_connect(lua_State *L)
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);
220
lua_pushstring(L, err);
223
/* turn master object into a client object */
224
lua_pushnumber(L, 1);
228
/*-------------------------------------------------------------------------*\
229
* Closes socket used by object
230
\*-------------------------------------------------------------------------*/
231
static int meth_close(lua_State *L)
233
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
234
socket_destroy(&tcp->sock);
235
lua_pushnumber(L, 1);
239
/*-------------------------------------------------------------------------*\
240
* Puts the sockt in listen mode
241
\*-------------------------------------------------------------------------*/
242
static int meth_listen(lua_State *L)
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) {
249
lua_pushstring(L, socket_strerror(err));
252
/* turn master object into a server object */
253
auxiliar_setclass(L, "tcp{server}", 1);
254
lua_pushnumber(L, 1);
258
/*-------------------------------------------------------------------------*\
259
* Shuts the connection down partially
260
\*-------------------------------------------------------------------------*/
261
static int meth_shutdown(lua_State *L)
263
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
264
const char *how = luaL_optstring(L, 2, "both");
267
if (strcmp(how, "both")) goto error;
268
socket_shutdown(&tcp->sock, 2);
271
if (strcmp(how, "send")) goto error;
272
socket_shutdown(&tcp->sock, 1);
275
if (strcmp(how, "receive")) goto error;
276
socket_shutdown(&tcp->sock, 0);
279
lua_pushnumber(L, 1);
282
luaL_argerror(L, 2, "invalid shutdown method");
286
/*-------------------------------------------------------------------------*\
287
* Just call inet methods
288
\*-------------------------------------------------------------------------*/
289
static int meth_getpeername(lua_State *L)
291
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
292
return inet_meth_getpeername(L, &tcp->sock);
295
static int meth_getsockname(lua_State *L)
297
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
298
return inet_meth_getsockname(L, &tcp->sock);
301
/*-------------------------------------------------------------------------*\
302
* Just call tm methods
303
\*-------------------------------------------------------------------------*/
304
static int meth_settimeout(lua_State *L)
306
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
307
return timeout_meth_settimeout(L, &tcp->tm);
310
/*=========================================================================*\
312
\*=========================================================================*/
313
/*-------------------------------------------------------------------------*\
314
* Creates a master tcp object
315
\*-------------------------------------------------------------------------*/
316
static int global_create(lua_State *L)
319
const char *err = inet_trycreate(&sock, SOCK_STREAM);
320
/* try to allocate a system socket */
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);
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);
336
lua_pushstring(L, err);