1 /*=========================================================================*\
2 * TCP object
3 * LuaSocket toolkit
4 \*=========================================================================*/
5 #include <string.h>
6 
7 #include "lua.h"
8 #include "lauxlib.h"
9 #include "compat.h"
10 
11 #include "auxiliar.h"
12 #include "socket.h"
13 #include "inet.h"
14 #include "options.h"
15 #include "tcp.h"
16 
17 /*=========================================================================*\
18 * Internal function prototypes
19 \*=========================================================================*/
20 static int global_create(lua_State *L);
21 static int global_create4(lua_State *L);
22 static int global_create6(lua_State *L);
23 static int global_connect(lua_State *L);
24 static int meth_connect(lua_State *L);
25 static int meth_listen(lua_State *L);
26 static int meth_getfamily(lua_State *L);
27 static int meth_bind(lua_State *L);
28 static int meth_send(lua_State *L);
29 static int meth_getstats(lua_State *L);
30 static int meth_setstats(lua_State *L);
31 static int meth_getsockname(lua_State *L);
32 static int meth_getpeername(lua_State *L);
33 static int meth_shutdown(lua_State *L);
34 static int meth_receive(lua_State *L);
35 static int meth_accept(lua_State *L);
36 static int meth_close(lua_State *L);
37 static int meth_getoption(lua_State *L);
38 static int meth_setoption(lua_State *L);
39 static int meth_gettimeout(lua_State *L);
40 static int meth_settimeout(lua_State *L);
41 static int meth_getfd(lua_State *L);
42 static int meth_setfd(lua_State *L);
43 static int meth_dirty(lua_State *L);
44 
45 /* tcp object methods */
46 static luaL_Reg tcp_methods[] = {
47     {"__gc",        meth_close},
48     {"__tostring",  auxiliar_tostring},
49     {"accept",      meth_accept},
50     {"bind",        meth_bind},
51     {"close",       meth_close},
52     {"connect",     meth_connect},
53     {"dirty",       meth_dirty},
54     {"getfamily",   meth_getfamily},
55     {"getfd",       meth_getfd},
56     {"getoption",   meth_getoption},
57     {"getpeername", meth_getpeername},
58     {"getsockname", meth_getsockname},
59     {"getstats",    meth_getstats},
60     {"setstats",    meth_setstats},
61     {"listen",      meth_listen},
62     {"receive",     meth_receive},
63     {"send",        meth_send},
64     {"setfd",       meth_setfd},
65     {"setoption",   meth_setoption},
66     {"setpeername", meth_connect},
67     {"setsockname", meth_bind},
68     {"settimeout",  meth_settimeout},
69     {"gettimeout",  meth_gettimeout},
70     {"shutdown",    meth_shutdown},
71     {NULL,          NULL}
72 };
73 
74 /* socket option handlers */
75 static t_opt optget[] = {
76     {"keepalive",   opt_get_keepalive},
77     {"reuseaddr",   opt_get_reuseaddr},
78     {"reuseport",   opt_get_reuseport},
79     {"tcp-nodelay", opt_get_tcp_nodelay},
80     {"linger",      opt_get_linger},
81     {"error",       opt_get_error},
82     {NULL,          NULL}
83 };
84 
85 static t_opt optset[] = {
86     {"keepalive",   opt_set_keepalive},
87     {"reuseaddr",   opt_set_reuseaddr},
88     {"reuseport",   opt_set_reuseport},
89     {"tcp-nodelay", opt_set_tcp_nodelay},
90     {"ipv6-v6only", opt_set_ip6_v6only},
91     {"linger",      opt_set_linger},
92     {NULL,          NULL}
93 };
94 
95 /* functions in library namespace */
96 static luaL_Reg func[] = {
97     {"tcp", global_create},
98     {"tcp4", global_create4},
99     {"tcp6", global_create6},
100     {"connect", global_connect},
101     {NULL, NULL}
102 };
103 
104 /*-------------------------------------------------------------------------*\
105 * Initializes module
106 \*-------------------------------------------------------------------------*/
tcp_open(lua_State * L)107 int tcp_open(lua_State *L)
108 {
109     /* create classes */
110     auxiliar_newclass(L, "tcp{master}", tcp_methods);
111     auxiliar_newclass(L, "tcp{client}", tcp_methods);
112     auxiliar_newclass(L, "tcp{server}", tcp_methods);
113     /* create class groups */
114     auxiliar_add2group(L, "tcp{master}", "tcp{any}");
115     auxiliar_add2group(L, "tcp{client}", "tcp{any}");
116     auxiliar_add2group(L, "tcp{server}", "tcp{any}");
117     /* define library functions */
118     luaL_setfuncs(L, func, 0);
119     return 0;
120 }
121 
122 /*=========================================================================*\
123 * Lua methods
124 \*=========================================================================*/
125 /*-------------------------------------------------------------------------*\
126 * Just call buffered IO methods
127 \*-------------------------------------------------------------------------*/
meth_send(lua_State * L)128 static int meth_send(lua_State *L) {
129     p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
130     return buffer_meth_send(L, &tcp->buf);
131 }
132 
meth_receive(lua_State * L)133 static int meth_receive(lua_State *L) {
134     p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
135     return buffer_meth_receive(L, &tcp->buf);
136 }
137 
meth_getstats(lua_State * L)138 static int meth_getstats(lua_State *L) {
139     p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
140     return buffer_meth_getstats(L, &tcp->buf);
141 }
142 
meth_setstats(lua_State * L)143 static int meth_setstats(lua_State *L) {
144     p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
145     return buffer_meth_setstats(L, &tcp->buf);
146 }
147 
148 /*-------------------------------------------------------------------------*\
149 * Just call option handler
150 \*-------------------------------------------------------------------------*/
meth_getoption(lua_State * L)151 static int meth_getoption(lua_State *L)
152 {
153     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
154     return opt_meth_getoption(L, optget, &tcp->sock);
155 }
156 
meth_setoption(lua_State * L)157 static int meth_setoption(lua_State *L)
158 {
159     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
160     return opt_meth_setoption(L, optset, &tcp->sock);
161 }
162 
163 /*-------------------------------------------------------------------------*\
164 * Select support methods
165 \*-------------------------------------------------------------------------*/
meth_getfd(lua_State * L)166 static int meth_getfd(lua_State *L)
167 {
168     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
169     lua_pushnumber(L, (int) tcp->sock);
170     return 1;
171 }
172 
173 /* this is very dangerous, but can be handy for those that are brave enough */
meth_setfd(lua_State * L)174 static int meth_setfd(lua_State *L)
175 {
176     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
177     tcp->sock = (t_socket) luaL_checknumber(L, 2);
178     return 0;
179 }
180 
meth_dirty(lua_State * L)181 static int meth_dirty(lua_State *L)
182 {
183     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
184     lua_pushboolean(L, !buffer_isempty(&tcp->buf));
185     return 1;
186 }
187 
188 /*-------------------------------------------------------------------------*\
189 * Waits for and returns a client object attempting connection to the
190 * server object
191 \*-------------------------------------------------------------------------*/
meth_accept(lua_State * L)192 static int meth_accept(lua_State *L)
193 {
194     p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1);
195     p_timeout tm = timeout_markstart(&server->tm);
196     t_socket sock;
197     const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm);
198     /* if successful, push client socket */
199     if (err == NULL) {
200         p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
201         auxiliar_setclass(L, "tcp{client}", -1);
202         /* initialize structure fields */
203         memset(clnt, 0, sizeof(t_tcp));
204         socket_setnonblocking(&sock);
205         clnt->sock = sock;
206         io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv,
207                 (p_error) socket_ioerror, &clnt->sock);
208         timeout_init(&clnt->tm, -1, -1);
209         buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
210         clnt->family = server->family;
211         return 1;
212     } else {
213         lua_pushnil(L);
214         lua_pushstring(L, err);
215         return 2;
216     }
217 }
218 
219 /*-------------------------------------------------------------------------*\
220 * Binds an object to an address
221 \*-------------------------------------------------------------------------*/
meth_bind(lua_State * L)222 static int meth_bind(lua_State *L) {
223     p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
224     const char *address =  luaL_checkstring(L, 2);
225     const char *port = luaL_checkstring(L, 3);
226     const char *err;
227     struct addrinfo bindhints;
228     memset(&bindhints, 0, sizeof(bindhints));
229     bindhints.ai_socktype = SOCK_STREAM;
230     bindhints.ai_family = tcp->family;
231     bindhints.ai_flags = AI_PASSIVE;
232     err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints);
233     if (err) {
234         lua_pushnil(L);
235         lua_pushstring(L, err);
236         return 2;
237     }
238     lua_pushnumber(L, 1);
239     return 1;
240 }
241 
242 /*-------------------------------------------------------------------------*\
243 * Turns a master tcp object into a client object.
244 \*-------------------------------------------------------------------------*/
meth_connect(lua_State * L)245 static int meth_connect(lua_State *L) {
246     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
247     const char *address =  luaL_checkstring(L, 2);
248     const char *port = luaL_checkstring(L, 3);
249     struct addrinfo connecthints;
250     const char *err;
251     memset(&connecthints, 0, sizeof(connecthints));
252     connecthints.ai_socktype = SOCK_STREAM;
253     /* make sure we try to connect only to the same family */
254     connecthints.ai_family = tcp->family;
255     timeout_markstart(&tcp->tm);
256     err = inet_tryconnect(&tcp->sock, &tcp->family, address, port,
257         &tcp->tm, &connecthints);
258     /* have to set the class even if it failed due to non-blocking connects */
259     auxiliar_setclass(L, "tcp{client}", 1);
260     if (err) {
261         lua_pushnil(L);
262         lua_pushstring(L, err);
263         return 2;
264     }
265     lua_pushnumber(L, 1);
266     return 1;
267 }
268 
269 /*-------------------------------------------------------------------------*\
270 * Closes socket used by object
271 \*-------------------------------------------------------------------------*/
meth_close(lua_State * L)272 static int meth_close(lua_State *L)
273 {
274     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
275     socket_destroy(&tcp->sock);
276     lua_pushnumber(L, 1);
277     return 1;
278 }
279 
280 /*-------------------------------------------------------------------------*\
281 * Returns family as string
282 \*-------------------------------------------------------------------------*/
meth_getfamily(lua_State * L)283 static int meth_getfamily(lua_State *L)
284 {
285     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
286     if (tcp->family == AF_INET6) {
287         lua_pushliteral(L, "inet6");
288         return 1;
289     } else if (tcp->family == AF_INET) {
290         lua_pushliteral(L, "inet4");
291         return 1;
292     } else {
293         lua_pushliteral(L, "inet4");
294         return 1;
295     }
296 }
297 
298 /*-------------------------------------------------------------------------*\
299 * Puts the sockt in listen mode
300 \*-------------------------------------------------------------------------*/
meth_listen(lua_State * L)301 static int meth_listen(lua_State *L)
302 {
303     p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
304     int backlog = (int) luaL_optnumber(L, 2, 32);
305     int err = socket_listen(&tcp->sock, backlog);
306     if (err != IO_DONE) {
307         lua_pushnil(L);
308         lua_pushstring(L, socket_strerror(err));
309         return 2;
310     }
311     /* turn master object into a server object */
312     auxiliar_setclass(L, "tcp{server}", 1);
313     lua_pushnumber(L, 1);
314     return 1;
315 }
316 
317 /*-------------------------------------------------------------------------*\
318 * Shuts the connection down partially
319 \*-------------------------------------------------------------------------*/
meth_shutdown(lua_State * L)320 static int meth_shutdown(lua_State *L)
321 {
322     /* SHUT_RD,  SHUT_WR,  SHUT_RDWR  have  the value 0, 1, 2, so we can use method index directly */
323     static const char* methods[] = { "receive", "send", "both", NULL };
324     p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
325     int how = luaL_checkoption(L, 2, "both", methods);
326     socket_shutdown(&tcp->sock, how);
327     lua_pushnumber(L, 1);
328     return 1;
329 }
330 
331 /*-------------------------------------------------------------------------*\
332 * Just call inet methods
333 \*-------------------------------------------------------------------------*/
meth_getpeername(lua_State * L)334 static int meth_getpeername(lua_State *L)
335 {
336     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
337     return inet_meth_getpeername(L, &tcp->sock, tcp->family);
338 }
339 
meth_getsockname(lua_State * L)340 static int meth_getsockname(lua_State *L)
341 {
342     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
343     return inet_meth_getsockname(L, &tcp->sock, tcp->family);
344 }
345 
346 /*-------------------------------------------------------------------------*\
347 * Just call tm methods
348 \*-------------------------------------------------------------------------*/
meth_settimeout(lua_State * L)349 static int meth_settimeout(lua_State *L)
350 {
351     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
352     return timeout_meth_settimeout(L, &tcp->tm);
353 }
354 
meth_gettimeout(lua_State * L)355 static int meth_gettimeout(lua_State *L)
356 {
357     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
358     return timeout_meth_gettimeout(L, &tcp->tm);
359 }
360 
361 /*=========================================================================*\
362 * Library functions
363 \*=========================================================================*/
364 /*-------------------------------------------------------------------------*\
365 * Creates a master tcp object
366 \*-------------------------------------------------------------------------*/
tcp_create(lua_State * L,int family)367 static int tcp_create(lua_State *L, int family) {
368     p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
369     memset(tcp, 0, sizeof(t_tcp));
370     /* set its type as master object */
371     auxiliar_setclass(L, "tcp{master}", -1);
372     /* if family is AF_UNSPEC, we leave the socket invalid and
373      * store AF_UNSPEC into family. This will allow it to later be
374      * replaced with an AF_INET6 or AF_INET socket upon first use. */
375     tcp->sock = SOCKET_INVALID;
376     tcp->family = family;
377     io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
378             (p_error) socket_ioerror, &tcp->sock);
379     timeout_init(&tcp->tm, -1, -1);
380     buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
381     if (family != AF_UNSPEC) {
382         const char *err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0);
383         if (err != NULL) {
384             lua_pushnil(L);
385             lua_pushstring(L, err);
386             return 2;
387         }
388         socket_setnonblocking(&tcp->sock);
389     }
390     return 1;
391 }
392 
global_create(lua_State * L)393 static int global_create(lua_State *L) {
394     return tcp_create(L, AF_UNSPEC);
395 }
396 
global_create4(lua_State * L)397 static int global_create4(lua_State *L) {
398     return tcp_create(L, AF_INET);
399 }
400 
global_create6(lua_State * L)401 static int global_create6(lua_State *L) {
402     return tcp_create(L, AF_INET6);
403 }
404 
global_connect(lua_State * L)405 static int global_connect(lua_State *L) {
406     const char *remoteaddr = luaL_checkstring(L, 1);
407     const char *remoteserv = luaL_checkstring(L, 2);
408     const char *localaddr  = luaL_optstring(L, 3, NULL);
409     const char *localserv  = luaL_optstring(L, 4, "0");
410     int family = inet_optfamily(L, 5, "unspec");
411     p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
412     struct addrinfo bindhints, connecthints;
413     const char *err = NULL;
414     /* initialize tcp structure */
415     memset(tcp, 0, sizeof(t_tcp));
416     io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
417             (p_error) socket_ioerror, &tcp->sock);
418     timeout_init(&tcp->tm, -1, -1);
419     buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
420     tcp->sock = SOCKET_INVALID;
421     tcp->family = AF_UNSPEC;
422     /* allow user to pick local address and port */
423     memset(&bindhints, 0, sizeof(bindhints));
424     bindhints.ai_socktype = SOCK_STREAM;
425     bindhints.ai_family = family;
426     bindhints.ai_flags = AI_PASSIVE;
427     if (localaddr) {
428         err = inet_trybind(&tcp->sock, &tcp->family, localaddr,
429             localserv, &bindhints);
430         if (err) {
431             lua_pushnil(L);
432             lua_pushstring(L, err);
433             return 2;
434         }
435     }
436     /* try to connect to remote address and port */
437     memset(&connecthints, 0, sizeof(connecthints));
438     connecthints.ai_socktype = SOCK_STREAM;
439     /* make sure we try to connect only to the same family */
440     connecthints.ai_family = tcp->family;
441     err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv,
442          &tcp->tm, &connecthints);
443     if (err) {
444         socket_destroy(&tcp->sock);
445         lua_pushnil(L);
446         lua_pushstring(L, err);
447         return 2;
448     }
449     auxiliar_setclass(L, "tcp{client}", -1);
450     return 1;
451 }
452