diff options
Diffstat (limited to 'src/tcp.c')
-rw-r--r-- | src/tcp.c | 123 |
1 files changed, 39 insertions, 84 deletions
@@ -18,6 +18,7 @@ | |||
18 | * Internal function prototypes | 18 | * Internal function prototypes |
19 | \*=========================================================================*/ | 19 | \*=========================================================================*/ |
20 | static int global_create(lua_State *L); | 20 | static int global_create(lua_State *L); |
21 | static int global_create4(lua_State *L); | ||
21 | static int global_create6(lua_State *L); | 22 | static int global_create6(lua_State *L); |
22 | static int global_connect(lua_State *L); | 23 | static int global_connect(lua_State *L); |
23 | static int meth_connect(lua_State *L); | 24 | static int meth_connect(lua_State *L); |
@@ -90,6 +91,7 @@ static t_opt optset[] = { | |||
90 | /* functions in library namespace */ | 91 | /* functions in library namespace */ |
91 | static luaL_Reg func[] = { | 92 | static luaL_Reg func[] = { |
92 | {"tcp", global_create}, | 93 | {"tcp", global_create}, |
94 | {"tcp4", global_create4}, | ||
93 | {"tcp6", global_create6}, | 95 | {"tcp6", global_create6}, |
94 | {"connect", global_connect}, | 96 | {"connect", global_connect}, |
95 | {NULL, NULL} | 97 | {NULL, NULL} |
@@ -213,8 +215,7 @@ static int meth_accept(lua_State *L) | |||
213 | /*-------------------------------------------------------------------------*\ | 215 | /*-------------------------------------------------------------------------*\ |
214 | * Binds an object to an address | 216 | * Binds an object to an address |
215 | \*-------------------------------------------------------------------------*/ | 217 | \*-------------------------------------------------------------------------*/ |
216 | static int meth_bind(lua_State *L) | 218 | static int meth_bind(lua_State *L) { |
217 | { | ||
218 | p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); | 219 | p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); |
219 | const char *address = luaL_checkstring(L, 2); | 220 | const char *address = luaL_checkstring(L, 2); |
220 | const char *port = luaL_checkstring(L, 3); | 221 | const char *port = luaL_checkstring(L, 3); |
@@ -224,7 +225,7 @@ static int meth_bind(lua_State *L) | |||
224 | bindhints.ai_socktype = SOCK_STREAM; | 225 | bindhints.ai_socktype = SOCK_STREAM; |
225 | bindhints.ai_family = tcp->family; | 226 | bindhints.ai_family = tcp->family; |
226 | bindhints.ai_flags = AI_PASSIVE; | 227 | bindhints.ai_flags = AI_PASSIVE; |
227 | err = inet_trybind(&tcp->sock, address, port, &bindhints); | 228 | err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints); |
228 | if (err) { | 229 | if (err) { |
229 | lua_pushnil(L); | 230 | lua_pushnil(L); |
230 | lua_pushstring(L, err); | 231 | lua_pushstring(L, err); |
@@ -237,8 +238,7 @@ static int meth_bind(lua_State *L) | |||
237 | /*-------------------------------------------------------------------------*\ | 238 | /*-------------------------------------------------------------------------*\ |
238 | * Turns a master tcp object into a client object. | 239 | * Turns a master tcp object into a client object. |
239 | \*-------------------------------------------------------------------------*/ | 240 | \*-------------------------------------------------------------------------*/ |
240 | static int meth_connect(lua_State *L) | 241 | static int meth_connect(lua_State *L) { |
241 | { | ||
242 | p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); | 242 | p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); |
243 | const char *address = luaL_checkstring(L, 2); | 243 | const char *address = luaL_checkstring(L, 2); |
244 | const char *port = luaL_checkstring(L, 3); | 244 | const char *port = luaL_checkstring(L, 3); |
@@ -249,7 +249,7 @@ static int meth_connect(lua_State *L) | |||
249 | /* make sure we try to connect only to the same family */ | 249 | /* make sure we try to connect only to the same family */ |
250 | connecthints.ai_family = tcp->family; | 250 | connecthints.ai_family = tcp->family; |
251 | timeout_markstart(&tcp->tm); | 251 | timeout_markstart(&tcp->tm); |
252 | err = inet_tryconnect(&tcp->sock, &tcp->family, address, port, | 252 | err = inet_tryconnect(&tcp->sock, &tcp->family, address, port, |
253 | &tcp->tm, &connecthints); | 253 | &tcp->tm, &connecthints); |
254 | /* have to set the class even if it failed due to non-blocking connects */ | 254 | /* have to set the class even if it failed due to non-blocking connects */ |
255 | auxiliar_setclass(L, "tcp{client}", 1); | 255 | auxiliar_setclass(L, "tcp{client}", 1); |
@@ -279,9 +279,12 @@ static int meth_close(lua_State *L) | |||
279 | static int meth_getfamily(lua_State *L) | 279 | static int meth_getfamily(lua_State *L) |
280 | { | 280 | { |
281 | p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); | 281 | p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); |
282 | if (tcp->family == PF_INET6) { | 282 | if (tcp->family == AF_INET6) { |
283 | lua_pushliteral(L, "inet6"); | 283 | lua_pushliteral(L, "inet6"); |
284 | return 1; | 284 | return 1; |
285 | } else if (tcp->family == AF_INET) { | ||
286 | lua_pushliteral(L, "inet4"); | ||
287 | return 1; | ||
285 | } else { | 288 | } else { |
286 | lua_pushliteral(L, "inet4"); | 289 | lua_pushliteral(L, "inet4"); |
287 | return 1; | 290 | return 1; |
@@ -352,37 +355,36 @@ static int meth_settimeout(lua_State *L) | |||
352 | * Creates a master tcp object | 355 | * Creates a master tcp object |
353 | \*-------------------------------------------------------------------------*/ | 356 | \*-------------------------------------------------------------------------*/ |
354 | static int tcp_create(lua_State *L, int family) { | 357 | static int tcp_create(lua_State *L, int family) { |
355 | t_socket sock; | 358 | p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); |
356 | const char *err = inet_trycreate(&sock, family, SOCK_STREAM); | 359 | memset(tcp, 0, sizeof(t_tcp)); |
357 | /* try to allocate a system socket */ | 360 | /* set its type as master object */ |
358 | if (!err) { | 361 | auxiliar_setclass(L, "tcp{master}", -1); |
359 | /* allocate tcp object */ | 362 | /* if family is AF_UNSPEC, we leave the socket invalid and |
360 | p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); | 363 | * store AF_UNSPEC into family. This will allow it to later be |
361 | memset(tcp, 0, sizeof(t_tcp)); | 364 | * replaced with an AF_INET6 or AF_INET socket upon first use. */ |
362 | /* set its type as master object */ | 365 | tcp->sock = SOCKET_INVALID; |
363 | auxiliar_setclass(L, "tcp{master}", -1); | 366 | tcp->family = family; |
364 | /* initialize remaining structure fields */ | 367 | io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, |
365 | socket_setnonblocking(&sock); | 368 | (p_error) socket_ioerror, &tcp->sock); |
366 | if (family == PF_INET6) { | 369 | timeout_init(&tcp->tm, -1, -1); |
367 | int yes = 1; | 370 | buffer_init(&tcp->buf, &tcp->io, &tcp->tm); |
368 | setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, | 371 | if (family != AF_UNSPEC) { |
369 | (void *)&yes, sizeof(yes)); | 372 | const char *err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0); |
373 | if (err != NULL) { | ||
374 | lua_pushnil(L); | ||
375 | lua_pushstring(L, err); | ||
376 | return 2; | ||
370 | } | 377 | } |
371 | tcp->sock = sock; | 378 | socket_setnonblocking(&tcp->sock); |
372 | io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, | ||
373 | (p_error) socket_ioerror, &tcp->sock); | ||
374 | timeout_init(&tcp->tm, -1, -1); | ||
375 | buffer_init(&tcp->buf, &tcp->io, &tcp->tm); | ||
376 | tcp->family = family; | ||
377 | return 1; | ||
378 | } else { | ||
379 | lua_pushnil(L); | ||
380 | lua_pushstring(L, err); | ||
381 | return 2; | ||
382 | } | 379 | } |
380 | return 1; | ||
383 | } | 381 | } |
384 | 382 | ||
385 | static int global_create(lua_State *L) { | 383 | static int global_create(lua_State *L) { |
384 | return tcp_create(L, AF_UNSPEC); | ||
385 | } | ||
386 | |||
387 | static int global_create4(lua_State *L) { | ||
386 | return tcp_create(L, AF_INET); | 388 | return tcp_create(L, AF_INET); |
387 | } | 389 | } |
388 | 390 | ||
@@ -390,53 +392,6 @@ static int global_create6(lua_State *L) { | |||
390 | return tcp_create(L, AF_INET6); | 392 | return tcp_create(L, AF_INET6); |
391 | } | 393 | } |
392 | 394 | ||
393 | #if 0 | ||
394 | static const char *tryconnect6(const char *remoteaddr, const char *remoteserv, | ||
395 | struct addrinfo *connecthints, p_tcp tcp) { | ||
396 | struct addrinfo *iterator = NULL, *resolved = NULL; | ||
397 | const char *err = NULL; | ||
398 | /* try resolving */ | ||
399 | err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv, | ||
400 | connecthints, &resolved)); | ||
401 | if (err != NULL) { | ||
402 | if (resolved) freeaddrinfo(resolved); | ||
403 | return err; | ||
404 | } | ||
405 | /* iterate over all returned addresses trying to connect */ | ||
406 | for (iterator = resolved; iterator; iterator = iterator->ai_next) { | ||
407 | p_timeout tm = timeout_markstart(&tcp->tm); | ||
408 | /* create new socket if necessary. if there was no | ||
409 | * bind, we need to create one for every new family | ||
410 | * that shows up while iterating. if there was a | ||
411 | * bind, all families will be the same and we will | ||
412 | * not enter this branch. */ | ||
413 | if (tcp->family != iterator->ai_family) { | ||
414 | socket_destroy(&tcp->sock); | ||
415 | err = socket_strerror(socket_create(&tcp->sock, | ||
416 | iterator->ai_family, iterator->ai_socktype, | ||
417 | iterator->ai_protocol)); | ||
418 | if (err != NULL) { | ||
419 | freeaddrinfo(resolved); | ||
420 | return err; | ||
421 | } | ||
422 | tcp->family = iterator->ai_family; | ||
423 | /* all sockets initially non-blocking */ | ||
424 | socket_setnonblocking(&tcp->sock); | ||
425 | } | ||
426 | /* finally try connecting to remote address */ | ||
427 | err = socket_strerror(socket_connect(&tcp->sock, | ||
428 | (SA *) iterator->ai_addr, | ||
429 | (socklen_t) iterator->ai_addrlen, tm)); | ||
430 | /* if success, break out of loop */ | ||
431 | if (err == NULL) break; | ||
432 | } | ||
433 | |||
434 | freeaddrinfo(resolved); | ||
435 | /* here, if err is set, we failed */ | ||
436 | return err; | ||
437 | } | ||
438 | #endif | ||
439 | |||
440 | static int global_connect(lua_State *L) { | 395 | static int global_connect(lua_State *L) { |
441 | const char *remoteaddr = luaL_checkstring(L, 1); | 396 | const char *remoteaddr = luaL_checkstring(L, 1); |
442 | const char *remoteserv = luaL_checkstring(L, 2); | 397 | const char *remoteserv = luaL_checkstring(L, 2); |
@@ -453,26 +408,26 @@ static int global_connect(lua_State *L) { | |||
453 | timeout_init(&tcp->tm, -1, -1); | 408 | timeout_init(&tcp->tm, -1, -1); |
454 | buffer_init(&tcp->buf, &tcp->io, &tcp->tm); | 409 | buffer_init(&tcp->buf, &tcp->io, &tcp->tm); |
455 | tcp->sock = SOCKET_INVALID; | 410 | tcp->sock = SOCKET_INVALID; |
456 | tcp->family = PF_UNSPEC; | 411 | tcp->family = AF_UNSPEC; |
457 | /* allow user to pick local address and port */ | 412 | /* allow user to pick local address and port */ |
458 | memset(&bindhints, 0, sizeof(bindhints)); | 413 | memset(&bindhints, 0, sizeof(bindhints)); |
459 | bindhints.ai_socktype = SOCK_STREAM; | 414 | bindhints.ai_socktype = SOCK_STREAM; |
460 | bindhints.ai_family = family; | 415 | bindhints.ai_family = family; |
461 | bindhints.ai_flags = AI_PASSIVE; | 416 | bindhints.ai_flags = AI_PASSIVE; |
462 | if (localaddr) { | 417 | if (localaddr) { |
463 | err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints); | 418 | err = inet_trybind(&tcp->sock, &tcp->family, localaddr, |
419 | localserv, &bindhints); | ||
464 | if (err) { | 420 | if (err) { |
465 | lua_pushnil(L); | 421 | lua_pushnil(L); |
466 | lua_pushstring(L, err); | 422 | lua_pushstring(L, err); |
467 | return 2; | 423 | return 2; |
468 | } | 424 | } |
469 | tcp->family = bindhints.ai_family; | ||
470 | } | 425 | } |
471 | /* try to connect to remote address and port */ | 426 | /* try to connect to remote address and port */ |
472 | memset(&connecthints, 0, sizeof(connecthints)); | 427 | memset(&connecthints, 0, sizeof(connecthints)); |
473 | connecthints.ai_socktype = SOCK_STREAM; | 428 | connecthints.ai_socktype = SOCK_STREAM; |
474 | /* make sure we try to connect only to the same family */ | 429 | /* make sure we try to connect only to the same family */ |
475 | connecthints.ai_family = bindhints.ai_family; | 430 | connecthints.ai_family = tcp->family; |
476 | err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv, | 431 | err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv, |
477 | &tcp->tm, &connecthints); | 432 | &tcp->tm, &connecthints); |
478 | if (err) { | 433 | if (err) { |