diff options
Diffstat (limited to 'src/tcp.c')
-rw-r--r-- | src/tcp.c | 111 |
1 files changed, 19 insertions, 92 deletions
@@ -19,8 +19,8 @@ | |||
19 | * Internal function prototypes | 19 | * Internal function prototypes |
20 | \*=========================================================================*/ | 20 | \*=========================================================================*/ |
21 | static int global_create(lua_State *L); | 21 | static int global_create(lua_State *L); |
22 | static int global_create6(lua_State *L); | ||
22 | static int global_connect6(lua_State *L); | 23 | static int global_connect6(lua_State *L); |
23 | static int global_bind6(lua_State *L); | ||
24 | static int meth_connect(lua_State *L); | 24 | static int meth_connect(lua_State *L); |
25 | static int meth_listen(lua_State *L); | 25 | static int meth_listen(lua_State *L); |
26 | static int meth_bind(lua_State *L); | 26 | static int meth_bind(lua_State *L); |
@@ -77,8 +77,8 @@ static t_opt optset[] = { | |||
77 | /* functions in library namespace */ | 77 | /* functions in library namespace */ |
78 | static luaL_reg func[] = { | 78 | static luaL_reg func[] = { |
79 | {"tcp", global_create}, | 79 | {"tcp", global_create}, |
80 | {"tcp6", global_create6}, | ||
80 | {"connect6", global_connect6}, | 81 | {"connect6", global_connect6}, |
81 | {"bind6", global_bind6}, | ||
82 | {NULL, NULL} | 82 | {NULL, NULL} |
83 | }; | 83 | }; |
84 | 84 | ||
@@ -196,8 +196,14 @@ static int meth_bind(lua_State *L) | |||
196 | { | 196 | { |
197 | p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); | 197 | p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); |
198 | const char *address = luaL_checkstring(L, 2); | 198 | const char *address = luaL_checkstring(L, 2); |
199 | unsigned short port = (unsigned short) luaL_checknumber(L, 3); | 199 | const char *port = luaL_checkstring(L, 3); |
200 | const char *err = inet_trybind(&tcp->sock, address, port); | 200 | const char *err; |
201 | struct addrinfo bindhints; | ||
202 | memset(&bindhints, 0, sizeof(bindhints)); | ||
203 | bindhints.ai_socktype = SOCK_STREAM; | ||
204 | bindhints.ai_family = tcp->domain; | ||
205 | bindhints.ai_flags = AI_PASSIVE; | ||
206 | err = inet_trybind(&tcp->sock, address, port, &bindhints); | ||
201 | if (err) { | 207 | if (err) { |
202 | lua_pushnil(L); | 208 | lua_pushnil(L); |
203 | lua_pushstring(L, err); | 209 | lua_pushstring(L, err); |
@@ -317,11 +323,11 @@ static int meth_settimeout(lua_State *L) | |||
317 | /*-------------------------------------------------------------------------*\ | 323 | /*-------------------------------------------------------------------------*\ |
318 | * Creates a master tcp object | 324 | * Creates a master tcp object |
319 | \*-------------------------------------------------------------------------*/ | 325 | \*-------------------------------------------------------------------------*/ |
320 | static int global_create(lua_State *L) { | 326 | static int tcp_create(lua_State *L, int domain) { |
321 | t_socket sock; | 327 | t_socket sock; |
322 | const char *err = inet_trycreate(&sock, SOCK_STREAM); | 328 | const char *err = inet_trycreate(&sock, domain, SOCK_STREAM); |
323 | /* try to allocate a system socket */ | 329 | /* try to allocate a system socket */ |
324 | if (!err) { | 330 | if (!err) { |
325 | /* allocate tcp object */ | 331 | /* allocate tcp object */ |
326 | p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); | 332 | p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); |
327 | /* set its type as master object */ | 333 | /* set its type as master object */ |
@@ -333,6 +339,7 @@ static int global_create(lua_State *L) { | |||
333 | (p_error) socket_ioerror, &tcp->sock); | 339 | (p_error) socket_ioerror, &tcp->sock); |
334 | timeout_init(&tcp->tm, -1, -1); | 340 | timeout_init(&tcp->tm, -1, -1); |
335 | buffer_init(&tcp->buf, &tcp->io, &tcp->tm); | 341 | buffer_init(&tcp->buf, &tcp->io, &tcp->tm); |
342 | tcp->domain = domain; | ||
336 | return 1; | 343 | return 1; |
337 | } else { | 344 | } else { |
338 | lua_pushnil(L); | 345 | lua_pushnil(L); |
@@ -341,92 +348,12 @@ static int global_create(lua_State *L) { | |||
341 | } | 348 | } |
342 | } | 349 | } |
343 | 350 | ||
344 | static const char *trybind6(const char *localaddr, const char *localserv, | 351 | static int global_create(lua_State *L) { |
345 | struct addrinfo *bindhints, p_tcp tcp) { | 352 | return tcp_create(L, AF_INET); |
346 | struct addrinfo *iterator = NULL, *resolved = NULL; | ||
347 | const char *err = NULL; | ||
348 | /* translate luasocket special values to C */ | ||
349 | if (strcmp(localaddr, "*") == 0) localaddr = NULL; | ||
350 | if (!localserv) localserv = "0"; | ||
351 | /* try resolving */ | ||
352 | err = socket_gaistrerror(getaddrinfo(localaddr, localserv, | ||
353 | bindhints, &resolved)); | ||
354 | if (err) { | ||
355 | if (resolved) freeaddrinfo(resolved); | ||
356 | return err; | ||
357 | } | ||
358 | /* iterate over resolved addresses until one is good */ | ||
359 | for (iterator = resolved; iterator; iterator = iterator->ai_next) { | ||
360 | /* create a new socket each time because parameters | ||
361 | * may have changed */ | ||
362 | err = socket_strerror(socket_create(&tcp->sock, | ||
363 | iterator->ai_family, iterator->ai_socktype, | ||
364 | iterator->ai_protocol)); | ||
365 | /* if failed to create socket, bail out */ | ||
366 | if (err != NULL) { | ||
367 | freeaddrinfo(resolved); | ||
368 | return err; | ||
369 | } | ||
370 | /* all sockets are set as non-blocking initially */ | ||
371 | socket_setnonblocking(&tcp->sock); | ||
372 | /* try binding to local address */ | ||
373 | err = socket_strerror(socket_bind(&tcp->sock, | ||
374 | (SA *) iterator->ai_addr, | ||
375 | iterator->ai_addrlen)); | ||
376 | /* if faiiled, we try the next one */ | ||
377 | if (err != NULL) socket_destroy(&tcp->sock); | ||
378 | /* if success, we abort loop */ | ||
379 | else break; | ||
380 | } | ||
381 | /* at this point, if err is not set, se succeeded */ | ||
382 | if (err == NULL) { | ||
383 | /* save family of chosen local address */ | ||
384 | bindhints->ai_family = iterator->ai_family; | ||
385 | } | ||
386 | /* cleanup and return error */ | ||
387 | freeaddrinfo(resolved); | ||
388 | return err; | ||
389 | } | 353 | } |
390 | 354 | ||
391 | static int global_bind6(lua_State *L) { | 355 | static int global_create6(lua_State *L) { |
392 | const char *localaddr = luaL_checkstring(L, 1); | 356 | return tcp_create(L, AF_INET6); |
393 | const char *localserv = luaL_checkstring(L, 2); | ||
394 | int backlog = luaL_checkint(L, 3); | ||
395 | p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); | ||
396 | struct addrinfo bindhints; | ||
397 | const char *err = NULL; | ||
398 | /* initialize tcp structure */ | ||
399 | io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, | ||
400 | (p_error) socket_ioerror, &tcp->sock); | ||
401 | timeout_init(&tcp->tm, -1, -1); | ||
402 | buffer_init(&tcp->buf, &tcp->io, &tcp->tm); | ||
403 | tcp->sock = SOCKET_INVALID; | ||
404 | /* try binding to local address */ | ||
405 | memset(&bindhints, 0, sizeof(bindhints)); | ||
406 | bindhints.ai_socktype = SOCK_STREAM; | ||
407 | bindhints.ai_family = PF_UNSPEC; | ||
408 | bindhints.ai_flags = AI_PASSIVE; | ||
409 | err = trybind6(localaddr, localserv, &bindhints, tcp); | ||
410 | if (err == NULL) { | ||
411 | /* all server sockets initially with reuseaddr set */ | ||
412 | int val = 1; | ||
413 | setsockopt(tcp->sock, SOL_SOCKET, SO_REUSEADDR, | ||
414 | (char *) &val, sizeof(val)); | ||
415 | /* set the backlog and listen */ | ||
416 | err = socket_strerror(socket_listen(&tcp->sock, backlog)); | ||
417 | if (err) { | ||
418 | socket_destroy(&tcp->sock); | ||
419 | lua_pushnil(L); | ||
420 | lua_pushstring(L, err); | ||
421 | return 2; | ||
422 | } | ||
423 | auxiliar_setclass(L, "tcp{server}", -1); | ||
424 | return 1; | ||
425 | } else { | ||
426 | lua_pushnil(L); | ||
427 | lua_pushstring(L, err); | ||
428 | return 2; | ||
429 | } | ||
430 | } | 357 | } |
431 | 358 | ||
432 | static const char *tryconnect6(const char *remoteaddr, const char *remoteserv, | 359 | static const char *tryconnect6(const char *remoteaddr, const char *remoteserv, |
@@ -488,7 +415,7 @@ static int global_connect6(lua_State *L) { | |||
488 | bindhints.ai_family = PF_UNSPEC; | 415 | bindhints.ai_family = PF_UNSPEC; |
489 | bindhints.ai_flags = AI_PASSIVE; | 416 | bindhints.ai_flags = AI_PASSIVE; |
490 | if (localaddr) { | 417 | if (localaddr) { |
491 | err = trybind6(localaddr, localserv, &bindhints, tcp); | 418 | err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints); |
492 | if (err) { | 419 | if (err) { |
493 | lua_pushnil(L); | 420 | lua_pushnil(L); |
494 | lua_pushstring(L, err); | 421 | lua_pushstring(L, err); |