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 \*-------------------------------------------------------------------------*/
tcp_open(lua_State * L)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 \*-------------------------------------------------------------------------*/
meth_send(lua_State * L)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 
meth_receive(lua_State * L)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 
meth_getstats(lua_State * L)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 
meth_setstats(lua_State * L)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 \*-------------------------------------------------------------------------*/
meth_setoption(lua_State * L)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 \*-------------------------------------------------------------------------*/
meth_getfd(lua_State * L)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 */
meth_setfd(lua_State * L)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 
meth_dirty(lua_State * L)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 \*-------------------------------------------------------------------------*/
meth_accept(lua_State * L)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 \*-------------------------------------------------------------------------*/
meth_bind(lua_State * L)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 \*-------------------------------------------------------------------------*/
meth_connect(lua_State * L)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 \*-------------------------------------------------------------------------*/
meth_close(lua_State * L)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 \*-------------------------------------------------------------------------*/
meth_listen(lua_State * L)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 \*-------------------------------------------------------------------------*/
meth_shutdown(lua_State * L)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 \*-------------------------------------------------------------------------*/
meth_getpeername(lua_State * L)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 
meth_getsockname(lua_State * L)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 \*-------------------------------------------------------------------------*/
meth_settimeout(lua_State * L)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 \*-------------------------------------------------------------------------*/
global_create(lua_State * L)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 }
340