comparison src/tcp.c @ 0:4b915342e2a8

LuaSocket 2.0.2 + CMake build description.
author Eric Wing <ewing . public |-at-| gmail . com>
date Tue, 26 Aug 2008 18:40:01 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4b915342e2a8
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 }