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