beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luasocket / src / tcp.c
blobe73340314789e950316195cafe63c27a730f47b4
1 /*=========================================================================*\
2 * TCP object
3 * LuaSocket toolkit
4 \*=========================================================================*/
5 #include <string.h>
7 #include "lua.h"
8 #include "lauxlib.h"
10 #include "auxiliar.h"
11 #include "socket.h"
12 #include "inet.h"
13 #include "options.h"
14 #include "tcp.h"
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[] = {
44 {"__gc", meth_close},
45 {"__tostring", auxiliar_tostring},
46 {"accept", meth_accept},
47 {"bind", meth_bind},
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},
60 {"send", meth_send},
61 {"setfd", meth_setfd},
62 {"setoption", meth_setoption},
63 {"setpeername", meth_connect},
64 {"setsockname", meth_bind},
65 {"settimeout", meth_settimeout},
66 {"shutdown", meth_shutdown},
67 {NULL, NULL}
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},
76 {NULL, NULL}
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},
85 {NULL, NULL}
88 /* functions in library namespace */
89 static luaL_Reg func[] = {
90 {"tcp", global_create},
91 {"tcp6", global_create6},
92 {"connect", global_connect},
93 {NULL, NULL}
96 /*-------------------------------------------------------------------------*\
97 * Initializes module
98 \*-------------------------------------------------------------------------*/
99 int tcp_open(lua_State *L)
101 /* create classes */
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);
111 return 0;
114 /*=========================================================================*\
115 * Lua methods
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);
162 return 1;
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);
170 return 0;
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));
177 return 1;
180 /*-------------------------------------------------------------------------*\
181 * Waits for and returns a client object attempting connection to the
182 * server object
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);
188 t_socket sock;
189 const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm);
190 /* if successful, push client socket */
191 if (err == NULL) {
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);
197 clnt->sock = 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;
203 return 1;
204 } else {
205 lua_pushnil(L);
206 lua_pushstring(L, err);
207 return 2;
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);
219 const char *err;
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);
227 if (err) {
228 lua_pushnil(L);
229 lua_pushstring(L, err);
230 return 2;
232 lua_pushnumber(L, 1);
233 return 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;
245 const char *err;
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);
254 if (err) {
255 lua_pushnil(L);
256 lua_pushstring(L, err);
257 return 2;
259 lua_pushnumber(L, 1);
260 return 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);
271 return 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");
282 return 1;
283 } else {
284 lua_pushliteral(L, "inet4");
285 return 1;
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) {
298 lua_pushnil(L);
299 lua_pushstring(L, socket_strerror(err));
300 return 2;
302 /* turn master object into a server object */
303 auxiliar_setclass(L, "tcp.server", 1);
304 lua_pushnumber(L, 1);
305 return 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);
319 return 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 /*=========================================================================*\
347 * Library functions
348 \*=========================================================================*/
349 /*-------------------------------------------------------------------------*\
350 * Creates a master tcp object
351 \*-------------------------------------------------------------------------*/
352 static int tcp_create(lua_State *L, int family) {
353 t_socket sock;
354 const char *err = inet_trycreate(&sock, family, SOCK_STREAM);
355 /* try to allocate a system socket */
356 if (!err) {
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) {
365 int yes = 1;
366 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
367 (void *)&yes, sizeof(yes));
369 tcp->sock = sock;
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;
375 return 1;
376 } else {
377 lua_pushnil(L);
378 lua_pushstring(L, err);
379 return 2;
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;
395 /* try resolving */
396 err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv,
397 connecthints, &resolved));
398 if (err != NULL) {
399 if (resolved) freeaddrinfo(resolved);
400 return err;
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));
410 if (err != NULL) {
411 freeaddrinfo(resolved);
412 return err;
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 */
428 return err;
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;
452 if (localaddr) {
453 err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints);
454 if (err) {
455 lua_pushnil(L);
456 lua_pushstring(L, err);
457 return 2;
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);
467 if (err) {
468 socket_destroy(&tcp->sock);
469 lua_pushnil(L);
470 lua_pushstring(L, err);
471 return 2;
473 auxiliar_setclass(L, "tcp.client", -1);
474 return 1;