1 /*=========================================================================*\
4 \*=========================================================================*/
16 /*=========================================================================*\
17 * Internal function prototypes
18 \*=========================================================================*/
19 static int global_create(lua_State
*L
);
20 static int global_create6(lua_State
*L
);
21 static int global_connect(lua_State
*L
);
22 static int meth_connect(lua_State
*L
);
23 static int meth_listen(lua_State
*L
);
24 static int meth_getfamily(lua_State
*L
);
25 static int meth_bind(lua_State
*L
);
26 static int meth_send(lua_State
*L
);
27 static int meth_getstats(lua_State
*L
);
28 static int meth_setstats(lua_State
*L
);
29 static int meth_getsockname(lua_State
*L
);
30 static int meth_getpeername(lua_State
*L
);
31 static int meth_shutdown(lua_State
*L
);
32 static int meth_receive(lua_State
*L
);
33 static int meth_accept(lua_State
*L
);
34 static int meth_close(lua_State
*L
);
35 static int meth_getoption(lua_State
*L
);
36 static int meth_setoption(lua_State
*L
);
37 static int meth_settimeout(lua_State
*L
);
38 static int meth_getfd(lua_State
*L
);
39 static int meth_setfd(lua_State
*L
);
40 static int meth_dirty(lua_State
*L
);
42 /* tcp object methods */
43 static luaL_Reg tcp_methods
[] = {
45 {"__tostring", auxiliar_tostring
},
46 {"accept", meth_accept
},
48 {"close", meth_close
},
49 {"connect", meth_connect
},
50 {"dirty", meth_dirty
},
51 {"getfamily", meth_getfamily
},
52 {"getfd", meth_getfd
},
53 {"getoption", meth_getoption
},
54 {"getpeername", meth_getpeername
},
55 {"getsockname", meth_getsockname
},
56 {"getstats", meth_getstats
},
57 {"setstats", meth_setstats
},
58 {"listen", meth_listen
},
59 {"receive", meth_receive
},
61 {"setfd", meth_setfd
},
62 {"setoption", meth_setoption
},
63 {"setpeername", meth_connect
},
64 {"setsockname", meth_bind
},
65 {"settimeout", meth_settimeout
},
66 {"shutdown", meth_shutdown
},
70 /* socket option handlers */
71 static t_opt optget
[] = {
72 {"keepalive", opt_get_keepalive
},
73 {"reuseaddr", opt_get_reuseaddr
},
74 {"tcp-nodelay", opt_get_tcp_nodelay
},
75 {"linger", opt_get_linger
},
79 static t_opt optset
[] = {
80 {"keepalive", opt_set_keepalive
},
81 {"reuseaddr", opt_set_reuseaddr
},
82 {"tcp-nodelay", opt_set_tcp_nodelay
},
83 {"ipv6-v6only", opt_set_ip6_v6only
},
84 {"linger", opt_set_linger
},
88 /* functions in library namespace */
89 static luaL_Reg func
[] = {
90 {"tcp", global_create
},
91 {"tcp6", global_create6
},
92 {"connect", global_connect
},
96 /*-------------------------------------------------------------------------*\
98 \*-------------------------------------------------------------------------*/
99 int tcp_open(lua_State
*L
)
102 auxiliar_newclass(L
, "tcp.master", tcp_methods
);
103 auxiliar_newclass(L
, "tcp.client", tcp_methods
);
104 auxiliar_newclass(L
, "tcp.server", tcp_methods
);
105 /* create class groups */
106 auxiliar_add2group(L
, "tcp.master", "tcp{any}");
107 auxiliar_add2group(L
, "tcp.client", "tcp{any}");
108 auxiliar_add2group(L
, "tcp.server", "tcp{any}");
109 /* define library functions */
110 luaL_openlib(L
, NULL
, func
, 0);
114 /*=========================================================================*\
116 \*=========================================================================*/
117 /*-------------------------------------------------------------------------*\
118 * Just call buffered IO methods
119 \*-------------------------------------------------------------------------*/
120 static int meth_send(lua_State
*L
) {
121 p_tcp tcp
= (p_tcp
) auxiliar_checkclass(L
, "tcp.client", 1);
122 return buffer_meth_send(L
, &tcp
->buf
);
125 static int meth_receive(lua_State
*L
) {
126 p_tcp tcp
= (p_tcp
) auxiliar_checkclass(L
, "tcp.client", 1);
127 return buffer_meth_receive(L
, &tcp
->buf
);
130 static int meth_getstats(lua_State
*L
) {
131 p_tcp tcp
= (p_tcp
) auxiliar_checkclass(L
, "tcp.client", 1);
132 return buffer_meth_getstats(L
, &tcp
->buf
);
135 static int meth_setstats(lua_State
*L
) {
136 p_tcp tcp
= (p_tcp
) auxiliar_checkclass(L
, "tcp.client", 1);
137 return buffer_meth_setstats(L
, &tcp
->buf
);
140 /*-------------------------------------------------------------------------*\
141 * Just call option handler
142 \*-------------------------------------------------------------------------*/
143 static int meth_getoption(lua_State
*L
)
145 p_tcp tcp
= (p_tcp
) auxiliar_checkgroup(L
, "tcp{any}", 1);
146 return opt_meth_getoption(L
, optget
, &tcp
->sock
);
149 static int meth_setoption(lua_State
*L
)
151 p_tcp tcp
= (p_tcp
) auxiliar_checkgroup(L
, "tcp{any}", 1);
152 return opt_meth_setoption(L
, optset
, &tcp
->sock
);
155 /*-------------------------------------------------------------------------*\
156 * Select support methods
157 \*-------------------------------------------------------------------------*/
158 static int meth_getfd(lua_State
*L
)
160 p_tcp tcp
= (p_tcp
) auxiliar_checkgroup(L
, "tcp{any}", 1);
161 lua_pushnumber(L
, (int) tcp
->sock
);
165 /* this is very dangerous, but can be handy for those that are brave enough */
166 static int meth_setfd(lua_State
*L
)
168 p_tcp tcp
= (p_tcp
) auxiliar_checkgroup(L
, "tcp{any}", 1);
169 tcp
->sock
= (t_socket
) luaL_checknumber(L
, 2);
173 static int meth_dirty(lua_State
*L
)
175 p_tcp tcp
= (p_tcp
) auxiliar_checkgroup(L
, "tcp{any}", 1);
176 lua_pushboolean(L
, !buffer_isempty(&tcp
->buf
));
180 /*-------------------------------------------------------------------------*\
181 * Waits for and returns a client object attempting connection to the
183 \*-------------------------------------------------------------------------*/
184 static int meth_accept(lua_State
*L
)
186 p_tcp server
= (p_tcp
) auxiliar_checkclass(L
, "tcp.server", 1);
187 p_timeout tm
= timeout_markstart(&server
->tm
);
189 const char *err
= inet_tryaccept(&server
->sock
, server
->family
, &sock
, tm
);
190 /* if successful, push client socket */
192 p_tcp clnt
= (p_tcp
) lua_newuserdata(L
, sizeof(t_tcp
));
193 auxiliar_setclass(L
, "tcp.client", -1);
194 /* initialize structure fields */
195 memset(clnt
, 0, sizeof(t_tcp
));
196 socket_setnonblocking(&sock
);
198 io_init(&clnt
->io
, (p_send
) socket_send
, (p_recv
) socket_recv
,
199 (p_error
) socket_ioerror
, &clnt
->sock
);
200 timeout_init(&clnt
->tm
, -1, -1);
201 buffer_init(&clnt
->buf
, &clnt
->io
, &clnt
->tm
);
202 clnt
->family
= server
->family
;
206 lua_pushstring(L
, err
);
211 /*-------------------------------------------------------------------------*\
212 * Binds an object to an address
213 \*-------------------------------------------------------------------------*/
214 static int meth_bind(lua_State
*L
)
216 p_tcp tcp
= (p_tcp
) auxiliar_checkclass(L
, "tcp.master", 1);
217 const char *address
= luaL_checkstring(L
, 2);
218 const char *port
= luaL_checkstring(L
, 3);
220 struct addrinfo bindhints
;
221 memset(&bindhints
, 0, sizeof(bindhints
));
222 bindhints
.ai_socktype
= SOCK_STREAM
;
223 bindhints
.ai_family
= tcp
->family
;
224 bindhints
.ai_flags
= AI_PASSIVE
;
225 address
= strcmp(address
, "*")? address
: NULL
;
226 err
= inet_trybind(&tcp
->sock
, address
, port
, &bindhints
);
229 lua_pushstring(L
, err
);
232 lua_pushnumber(L
, 1);
236 /*-------------------------------------------------------------------------*\
237 * Turns a master tcp object into a client object.
238 \*-------------------------------------------------------------------------*/
239 static int meth_connect(lua_State
*L
)
241 p_tcp tcp
= (p_tcp
) auxiliar_checkgroup(L
, "tcp{any}", 1);
242 const char *address
= luaL_checkstring(L
, 2);
243 const char *port
= luaL_checkstring(L
, 3);
244 struct addrinfo connecthints
;
246 memset(&connecthints
, 0, sizeof(connecthints
));
247 connecthints
.ai_socktype
= SOCK_STREAM
;
248 /* make sure we try to connect only to the same family */
249 connecthints
.ai_family
= tcp
->family
;
250 timeout_markstart(&tcp
->tm
);
251 err
= inet_tryconnect(&tcp
->sock
, address
, port
, &tcp
->tm
, &connecthints
);
252 /* have to set the class even if it failed due to non-blocking connects */
253 auxiliar_setclass(L
, "tcp.client", 1);
256 lua_pushstring(L
, err
);
259 lua_pushnumber(L
, 1);
263 /*-------------------------------------------------------------------------*\
264 * Closes socket used by object
265 \*-------------------------------------------------------------------------*/
266 static int meth_close(lua_State
*L
)
268 p_tcp tcp
= (p_tcp
) auxiliar_checkgroup(L
, "tcp{any}", 1);
269 socket_destroy(&tcp
->sock
);
270 lua_pushnumber(L
, 1);
274 /*-------------------------------------------------------------------------*\
275 * Returns family as string
276 \*-------------------------------------------------------------------------*/
277 static int meth_getfamily(lua_State
*L
)
279 p_tcp tcp
= (p_tcp
) auxiliar_checkgroup(L
, "tcp{any}", 1);
280 if (tcp
->family
== PF_INET6
) {
281 lua_pushliteral(L
, "inet6");
284 lua_pushliteral(L
, "inet4");
289 /*-------------------------------------------------------------------------*\
290 * Puts the sockt in listen mode
291 \*-------------------------------------------------------------------------*/
292 static int meth_listen(lua_State
*L
)
294 p_tcp tcp
= (p_tcp
) auxiliar_checkclass(L
, "tcp.master", 1);
295 int backlog
= (int) luaL_optnumber(L
, 2, 32);
296 int err
= socket_listen(&tcp
->sock
, backlog
);
297 if (err
!= IO_DONE
) {
299 lua_pushstring(L
, socket_strerror(err
));
302 /* turn master object into a server object */
303 auxiliar_setclass(L
, "tcp.server", 1);
304 lua_pushnumber(L
, 1);
308 /*-------------------------------------------------------------------------*\
309 * Shuts the connection down partially
310 \*-------------------------------------------------------------------------*/
311 static int meth_shutdown(lua_State
*L
)
313 /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
314 static const char* methods
[] = { "receive", "send", "both", NULL
};
315 p_tcp tcp
= (p_tcp
) auxiliar_checkclass(L
, "tcp.client", 1);
316 int how
= luaL_checkoption(L
, 2, "both", methods
);
317 socket_shutdown(&tcp
->sock
, how
);
318 lua_pushnumber(L
, 1);
322 /*-------------------------------------------------------------------------*\
323 * Just call inet methods
324 \*-------------------------------------------------------------------------*/
325 static int meth_getpeername(lua_State
*L
)
327 p_tcp tcp
= (p_tcp
) auxiliar_checkgroup(L
, "tcp{any}", 1);
328 return inet_meth_getpeername(L
, &tcp
->sock
, tcp
->family
);
331 static int meth_getsockname(lua_State
*L
)
333 p_tcp tcp
= (p_tcp
) auxiliar_checkgroup(L
, "tcp{any}", 1);
334 return inet_meth_getsockname(L
, &tcp
->sock
, tcp
->family
);
337 /*-------------------------------------------------------------------------*\
338 * Just call tm methods
339 \*-------------------------------------------------------------------------*/
340 static int meth_settimeout(lua_State
*L
)
342 p_tcp tcp
= (p_tcp
) auxiliar_checkgroup(L
, "tcp{any}", 1);
343 return timeout_meth_settimeout(L
, &tcp
->tm
);
346 /*=========================================================================*\
348 \*=========================================================================*/
349 /*-------------------------------------------------------------------------*\
350 * Creates a master tcp object
351 \*-------------------------------------------------------------------------*/
352 static int tcp_create(lua_State
*L
, int family
) {
354 const char *err
= inet_trycreate(&sock
, family
, SOCK_STREAM
);
355 /* try to allocate a system socket */
357 /* allocate tcp object */
358 p_tcp tcp
= (p_tcp
) lua_newuserdata(L
, sizeof(t_tcp
));
359 memset(tcp
, 0, sizeof(t_tcp
));
360 /* set its type as master object */
361 auxiliar_setclass(L
, "tcp.master", -1);
362 /* initialize remaining structure fields */
363 socket_setnonblocking(&sock
);
364 if (family
== PF_INET6
) {
366 setsockopt(sock
, IPPROTO_IPV6
, IPV6_V6ONLY
,
367 (void *)&yes
, sizeof(yes
));
370 io_init(&tcp
->io
, (p_send
) socket_send
, (p_recv
) socket_recv
,
371 (p_error
) socket_ioerror
, &tcp
->sock
);
372 timeout_init(&tcp
->tm
, -1, -1);
373 buffer_init(&tcp
->buf
, &tcp
->io
, &tcp
->tm
);
374 tcp
->family
= family
;
378 lua_pushstring(L
, err
);
383 static int global_create(lua_State
*L
) {
384 return tcp_create(L
, AF_INET
);
387 static int global_create6(lua_State
*L
) {
388 return tcp_create(L
, AF_INET6
);
391 static const char *tryconnect6(const char *remoteaddr
, const char *remoteserv
,
392 struct addrinfo
*connecthints
, p_tcp tcp
) {
393 struct addrinfo
*iterator
= NULL
, *resolved
= NULL
;
394 const char *err
= NULL
;
396 err
= socket_gaistrerror(getaddrinfo(remoteaddr
, remoteserv
,
397 connecthints
, &resolved
));
399 if (resolved
) freeaddrinfo(resolved
);
402 /* iterate over all returned addresses trying to connect */
403 for (iterator
= resolved
; iterator
; iterator
= iterator
->ai_next
) {
404 p_timeout tm
= timeout_markstart(&tcp
->tm
);
405 /* create new socket if one wasn't created by the bind stage */
406 if (tcp
->sock
== SOCKET_INVALID
) {
407 err
= socket_strerror(socket_create(&tcp
->sock
,
408 iterator
->ai_family
, iterator
->ai_socktype
,
409 iterator
->ai_protocol
));
411 freeaddrinfo(resolved
);
414 tcp
->family
= iterator
->ai_family
;
415 /* all sockets initially non-blocking */
416 socket_setnonblocking(&tcp
->sock
);
418 /* finally try connecting to remote address */
419 err
= socket_strerror(socket_connect(&tcp
->sock
,
420 (SA
*) iterator
->ai_addr
,
421 (socklen_t
) iterator
->ai_addrlen
, tm
));
422 /* if success, break out of loop */
423 if (err
== NULL
) break;
426 freeaddrinfo(resolved
);
427 /* here, if err is set, we failed */
431 static int global_connect(lua_State
*L
) {
432 const char *remoteaddr
= luaL_checkstring(L
, 1);
433 const char *remoteserv
= luaL_checkstring(L
, 2);
434 const char *localaddr
= luaL_optstring(L
, 3, NULL
);
435 const char *localserv
= luaL_optstring(L
, 4, "0");
436 int family
= inet_optfamily(L
, 5, "unspec");
437 p_tcp tcp
= (p_tcp
) lua_newuserdata(L
, sizeof(t_tcp
));
438 struct addrinfo bindhints
, connecthints
;
439 const char *err
= NULL
;
440 /* initialize tcp structure */
441 memset(tcp
, 0, sizeof(t_tcp
));
442 io_init(&tcp
->io
, (p_send
) socket_send
, (p_recv
) socket_recv
,
443 (p_error
) socket_ioerror
, &tcp
->sock
);
444 timeout_init(&tcp
->tm
, -1, -1);
445 buffer_init(&tcp
->buf
, &tcp
->io
, &tcp
->tm
);
446 tcp
->sock
= SOCKET_INVALID
;
447 /* allow user to pick local address and port */
448 memset(&bindhints
, 0, sizeof(bindhints
));
449 bindhints
.ai_socktype
= SOCK_STREAM
;
450 bindhints
.ai_family
= family
;
451 bindhints
.ai_flags
= AI_PASSIVE
;
453 err
= inet_trybind(&tcp
->sock
, localaddr
, localserv
, &bindhints
);
456 lua_pushstring(L
, err
);
459 tcp
->family
= bindhints
.ai_family
;
461 /* try to connect to remote address and port */
462 memset(&connecthints
, 0, sizeof(connecthints
));
463 connecthints
.ai_socktype
= SOCK_STREAM
;
464 /* make sure we try to connect only to the same family */
465 connecthints
.ai_family
= bindhints
.ai_family
;
466 err
= tryconnect6(remoteaddr
, remoteserv
, &connecthints
, tcp
);
468 socket_destroy(&tcp
->sock
);
470 lua_pushstring(L
, err
);
473 auxiliar_setclass(L
, "tcp.client", -1);