diff options
-rw-r--r-- | doc/tcp.html | 6 | ||||
-rw-r--r-- | doc/udp.html | 6 | ||||
-rw-r--r-- | src/inet.c | 17 | ||||
-rw-r--r-- | src/inet.h | 2 | ||||
-rw-r--r-- | src/tcp.c | 52 | ||||
-rw-r--r-- | src/udp.c | 52 | ||||
-rw-r--r-- | test/testclnt.lua | 19 |
7 files changed, 78 insertions, 76 deletions
diff --git a/doc/tcp.html b/doc/tcp.html index 6fc9900..fb627a1 100644 --- a/doc/tcp.html +++ b/doc/tcp.html | |||
@@ -65,6 +65,12 @@ href=#bind><tt>connect</tt></a>, depending on the address | |||
65 | family obtained from the resolver. | 65 | family obtained from the resolver. |
66 | </p> | 66 | </p> |
67 | 67 | ||
68 | <p class=note> | ||
69 | Note: Before the choice between IPv4 and IPv6 happens, | ||
70 | the internal socket object is invalid and therefore <a | ||
71 | href=#setoption><tt>setoption</tt></a> will fail. | ||
72 | </p> | ||
73 | |||
68 | <!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | 74 | <!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> |
69 | 75 | ||
70 | <p class=name id="socket.tcp4"> | 76 | <p class=name id="socket.tcp4"> |
diff --git a/doc/udp.html b/doc/udp.html index e313af4..a300f2f 100644 --- a/doc/udp.html +++ b/doc/udp.html | |||
@@ -76,6 +76,12 @@ href=#setsockname><tt>sockname</tt></a>, depending on the address | |||
76 | family obtained from the resolver. | 76 | family obtained from the resolver. |
77 | </p> | 77 | </p> |
78 | 78 | ||
79 | <p class=note> | ||
80 | Note: Before the choice between IPv4 and IPv6 happens, | ||
81 | the internal socket object is invalid and therefore <a | ||
82 | href=#setoption><tt>setoption</tt></a> will fail. | ||
83 | </p> | ||
84 | |||
79 | <!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | 85 | <!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> |
80 | 86 | ||
81 | <p class="name" id="socket.udp"> | 87 | <p class="name" id="socket.udp"> |
@@ -352,8 +352,13 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp) | |||
352 | /*-------------------------------------------------------------------------*\ | 352 | /*-------------------------------------------------------------------------*\ |
353 | * Tries to create a new inet socket | 353 | * Tries to create a new inet socket |
354 | \*-------------------------------------------------------------------------*/ | 354 | \*-------------------------------------------------------------------------*/ |
355 | const char *inet_trycreate(p_socket ps, int family, int type) { | 355 | const char *inet_trycreate(p_socket ps, int family, int type, int protocol) { |
356 | return socket_strerror(socket_create(ps, family, type, 0)); | 356 | const char *err = socket_strerror(socket_create(ps, family, type, protocol)); |
357 | if (err == NULL && family == AF_INET6) { | ||
358 | int yes = 1; | ||
359 | setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes)); | ||
360 | } | ||
361 | return err; | ||
357 | } | 362 | } |
358 | 363 | ||
359 | /*-------------------------------------------------------------------------*\ | 364 | /*-------------------------------------------------------------------------*\ |
@@ -408,8 +413,8 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address, | |||
408 | * not enter this branch. */ | 413 | * not enter this branch. */ |
409 | if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { | 414 | if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { |
410 | socket_destroy(ps); | 415 | socket_destroy(ps); |
411 | err = socket_strerror(socket_create(ps, iterator->ai_family, | 416 | err = inet_trycreate(ps, iterator->ai_family, |
412 | iterator->ai_socktype, iterator->ai_protocol)); | 417 | iterator->ai_socktype, iterator->ai_protocol); |
413 | if (err) continue; | 418 | if (err) continue; |
414 | current_family = iterator->ai_family; | 419 | current_family = iterator->ai_family; |
415 | /* set non-blocking before connect */ | 420 | /* set non-blocking before connect */ |
@@ -466,8 +471,8 @@ const char *inet_trybind(p_socket ps, int *family, const char *address, | |||
466 | for (iterator = resolved; iterator; iterator = iterator->ai_next) { | 471 | for (iterator = resolved; iterator; iterator = iterator->ai_next) { |
467 | if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { | 472 | if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { |
468 | socket_destroy(ps); | 473 | socket_destroy(ps); |
469 | err = socket_strerror(socket_create(ps, iterator->ai_family, | 474 | err = inet_trycreate(ps, iterator->ai_family, |
470 | iterator->ai_socktype, iterator->ai_protocol)); | 475 | iterator->ai_socktype, iterator->ai_protocol); |
471 | if (err) continue; | 476 | if (err) continue; |
472 | current_family = iterator->ai_family; | 477 | current_family = iterator->ai_family; |
473 | } | 478 | } |
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | int inet_open(lua_State *L); | 25 | int inet_open(lua_State *L); |
26 | 26 | ||
27 | const char *inet_trycreate(p_socket ps, int family, int type); | 27 | const char *inet_trycreate(p_socket ps, int family, int type, int protocol); |
28 | const char *inet_tryconnect(p_socket ps, int *family, const char *address, | 28 | const char *inet_tryconnect(p_socket ps, int *family, const char *address, |
29 | const char *serv, p_timeout tm, struct addrinfo *connecthints); | 29 | const char *serv, p_timeout tm, struct addrinfo *connecthints); |
30 | const char *inet_trybind(p_socket ps, int *family, const char *address, | 30 | const char *inet_trybind(p_socket ps, int *family, const char *address, |
@@ -355,39 +355,29 @@ static int meth_settimeout(lua_State *L) | |||
355 | * Creates a master tcp object | 355 | * Creates a master tcp object |
356 | \*-------------------------------------------------------------------------*/ | 356 | \*-------------------------------------------------------------------------*/ |
357 | static int tcp_create(lua_State *L, int family) { | 357 | static int tcp_create(lua_State *L, int family) { |
358 | t_socket sock; | 358 | p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); |
359 | /* if family is AF_UNSPEC, we create an AF_INET socket | 359 | memset(tcp, 0, sizeof(t_tcp)); |
360 | * but store AF_UNSPEC into tcp-family. This will allow it | 360 | /* set its type as master object */ |
361 | * later be replaced with an AF_INET6 socket if | 361 | auxiliar_setclass(L, "tcp{master}", -1); |
362 | * trybind or tryconnect prefer it instead. */ | 362 | /* if family is AF_UNSPEC, we leave the socket invalid and |
363 | const char *err = inet_trycreate(&sock, family == AF_UNSPEC? | 363 | * store AF_UNSPEC into family. This will allow it to later be |
364 | AF_INET: family, SOCK_STREAM); | 364 | * replaced with an AF_INET6 or AF_INET socket upon first use. */ |
365 | /* try to allocate a system socket */ | 365 | tcp->sock = SOCKET_INVALID; |
366 | if (!err) { | 366 | tcp->family = family; |
367 | /* allocate tcp object */ | 367 | io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, |
368 | p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); | 368 | (p_error) socket_ioerror, &tcp->sock); |
369 | memset(tcp, 0, sizeof(t_tcp)); | 369 | timeout_init(&tcp->tm, -1, -1); |
370 | /* set its type as master object */ | 370 | buffer_init(&tcp->buf, &tcp->io, &tcp->tm); |
371 | auxiliar_setclass(L, "tcp{master}", -1); | 371 | if (family != AF_UNSPEC) { |
372 | /* initialize remaining structure fields */ | 372 | const char *err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0); |
373 | socket_setnonblocking(&sock); | 373 | if (err != NULL) { |
374 | if (family == AF_INET6) { | 374 | lua_pushnil(L); |
375 | int yes = 1; | 375 | lua_pushstring(L, err); |
376 | setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, | 376 | return 2; |
377 | (void *)&yes, sizeof(yes)); | ||
378 | } | 377 | } |
379 | tcp->sock = sock; | 378 | socket_setnonblocking(&tcp->sock); |
380 | io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, | ||
381 | (p_error) socket_ioerror, &tcp->sock); | ||
382 | timeout_init(&tcp->tm, -1, -1); | ||
383 | buffer_init(&tcp->buf, &tcp->io, &tcp->tm); | ||
384 | tcp->family = family; | ||
385 | return 1; | ||
386 | } else { | ||
387 | lua_pushnil(L); | ||
388 | lua_pushstring(L, err); | ||
389 | return 2; | ||
390 | } | 379 | } |
380 | return 1; | ||
391 | } | 381 | } |
392 | 382 | ||
393 | static int global_create(lua_State *L) { | 383 | static int global_create(lua_State *L) { |
@@ -185,7 +185,7 @@ static int meth_sendto(lua_State *L) { | |||
185 | return 2; | 185 | return 2; |
186 | } | 186 | } |
187 | timeout_markstart(tm); | 187 | timeout_markstart(tm); |
188 | err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, | 188 | err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, |
189 | (socklen_t) ai->ai_addrlen, tm); | 189 | (socklen_t) ai->ai_addrlen, tm); |
190 | freeaddrinfo(ai); | 190 | freeaddrinfo(ai); |
191 | if (err != IO_DONE) { | 191 | if (err != IO_DONE) { |
@@ -237,7 +237,7 @@ static int meth_receivefrom(lua_State *L) | |||
237 | char portstr[6]; | 237 | char portstr[6]; |
238 | timeout_markstart(tm); | 238 | timeout_markstart(tm); |
239 | count = MIN(count, sizeof(buffer)); | 239 | count = MIN(count, sizeof(buffer)); |
240 | err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, | 240 | err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, |
241 | &addr_len, tm); | 241 | &addr_len, tm); |
242 | /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ | 242 | /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ |
243 | if (err == IO_CLOSED) | 243 | if (err == IO_CLOSED) |
@@ -247,7 +247,7 @@ static int meth_receivefrom(lua_State *L) | |||
247 | lua_pushstring(L, udp_strerror(err)); | 247 | lua_pushstring(L, udp_strerror(err)); |
248 | return 2; | 248 | return 2; |
249 | } | 249 | } |
250 | err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, | 250 | err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, |
251 | INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV); | 251 | INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV); |
252 | if (err) { | 252 | if (err) { |
253 | lua_pushnil(L); | 253 | lua_pushnil(L); |
@@ -351,7 +351,7 @@ static int meth_setpeername(lua_State *L) { | |||
351 | /* make sure we try to connect only to the same family */ | 351 | /* make sure we try to connect only to the same family */ |
352 | connecthints.ai_family = udp->family; | 352 | connecthints.ai_family = udp->family; |
353 | if (connecting) { | 353 | if (connecting) { |
354 | err = inet_tryconnect(&udp->sock, &udp->family, address, | 354 | err = inet_tryconnect(&udp->sock, &udp->family, address, |
355 | port, tm, &connecthints); | 355 | port, tm, &connecthints); |
356 | if (err) { | 356 | if (err) { |
357 | lua_pushnil(L); | 357 | lua_pushnil(L); |
@@ -365,7 +365,6 @@ static int meth_setpeername(lua_State *L) { | |||
365 | inet_trydisconnect(&udp->sock, udp->family, tm); | 365 | inet_trydisconnect(&udp->sock, udp->family, tm); |
366 | auxiliar_setclass(L, "udp{unconnected}", 1); | 366 | auxiliar_setclass(L, "udp{unconnected}", 1); |
367 | } | 367 | } |
368 | /* change class to connected or unconnected depending on address */ | ||
369 | lua_pushnumber(L, 1); | 368 | lua_pushnumber(L, 1); |
370 | return 1; | 369 | return 1; |
371 | } | 370 | } |
@@ -410,34 +409,25 @@ static int meth_setsockname(lua_State *L) { | |||
410 | * Creates a master udp object | 409 | * Creates a master udp object |
411 | \*-------------------------------------------------------------------------*/ | 410 | \*-------------------------------------------------------------------------*/ |
412 | static int udp_create(lua_State *L, int family) { | 411 | static int udp_create(lua_State *L, int family) { |
413 | t_socket sock; | 412 | /* allocate udp object */ |
414 | /* if family is AF_UNSPEC, we create an AF_INET socket | 413 | p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); |
415 | * but store AF_UNSPEC into tcp-family. This will allow it | 414 | auxiliar_setclass(L, "udp{unconnected}", -1); |
416 | * later be replaced with an AF_INET6 socket if | 415 | /* if family is AF_UNSPEC, we leave the socket invalid and |
417 | * trybind or tryconnect prefer it instead. */ | 416 | * store AF_UNSPEC into family. This will allow it to later be |
418 | const char *err = inet_trycreate(&sock, family == AF_UNSPEC? | 417 | * replaced with an AF_INET6 or AF_INET socket upon first use. */ |
419 | AF_INET: family, SOCK_DGRAM); | 418 | udp->sock = SOCKET_INVALID; |
420 | /* try to allocate a system socket */ | 419 | timeout_init(&udp->tm, -1, -1); |
421 | if (!err) { | 420 | udp->family = family; |
422 | /* allocate udp object */ | 421 | if (family != AF_UNSPEC) { |
423 | p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); | 422 | const char *err = inet_trycreate(&udp->sock, family, SOCK_DGRAM, 0); |
424 | auxiliar_setclass(L, "udp{unconnected}", -1); | 423 | if (err != NULL) { |
425 | /* initialize remaining structure fields */ | 424 | lua_pushnil(L); |
426 | socket_setnonblocking(&sock); | 425 | lua_pushstring(L, err); |
427 | if (family == AF_INET6) { | 426 | return 2; |
428 | int yes = 1; | ||
429 | setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, | ||
430 | (void *)&yes, sizeof(yes)); | ||
431 | } | 427 | } |
432 | udp->sock = sock; | 428 | socket_setnonblocking(&udp->sock); |
433 | timeout_init(&udp->tm, -1, -1); | ||
434 | udp->family = family; | ||
435 | return 1; | ||
436 | } else { | ||
437 | lua_pushnil(L); | ||
438 | lua_pushstring(L, err); | ||
439 | return 2; | ||
440 | } | 429 | } |
430 | return 1; | ||
441 | } | 431 | } |
442 | 432 | ||
443 | static int global_create(lua_State *L) { | 433 | static int global_create(lua_State *L) { |
diff --git a/test/testclnt.lua b/test/testclnt.lua index abf9608..ee1201f 100644 --- a/test/testclnt.lua +++ b/test/testclnt.lua | |||
@@ -304,15 +304,20 @@ function isclosed(c) | |||
304 | end | 304 | end |
305 | 305 | ||
306 | function active_close() | 306 | function active_close() |
307 | reconnect() | 307 | local tcp = socket.tcp4() |
308 | if isclosed(data) then fail("should not be closed") end | 308 | if isclosed(tcp) then fail("should not be closed") end |
309 | data:close() | 309 | tcp:close() |
310 | if not isclosed(data) then fail("should be closed") end | 310 | if not isclosed(tcp) then fail("should be closed") end |
311 | data = nil | 311 | tcp = socket.tcp() |
312 | local udp = socket.udp() | 312 | if not isclosed(tcp) then fail("should be closed") end |
313 | tcp = nil | ||
314 | local udp = socket.udp4() | ||
313 | if isclosed(udp) then fail("should not be closed") end | 315 | if isclosed(udp) then fail("should not be closed") end |
314 | udp:close() | 316 | udp:close() |
315 | if not isclosed(udp) then fail("should be closed") end | 317 | if not isclosed(udp) then fail("should be closed") end |
318 | udp = socket.udp() | ||
319 | if not isclosed(udp) then fail("should be closed") end | ||
320 | udp = nil | ||
316 | pass("ok") | 321 | pass("ok") |
317 | end | 322 | end |
318 | 323 | ||
@@ -368,7 +373,7 @@ function test_selectbugs() | |||
368 | pass("invalid input: ok") | 373 | pass("invalid input: ok") |
369 | local toomany = {} | 374 | local toomany = {} |
370 | for i = 1, socket._SETSIZE+1 do | 375 | for i = 1, socket._SETSIZE+1 do |
371 | toomany[#toomany+1] = socket.udp() | 376 | toomany[#toomany+1] = socket.udp4() |
372 | end | 377 | end |
373 | if #toomany > socket._SETSIZE then | 378 | if #toomany > socket._SETSIZE then |
374 | local e = pcall(socket.select, toomany, nil, 0.1) | 379 | local e = pcall(socket.select, toomany, nil, 0.1) |