From a71a09f67ceb1bdadde86981da76d4f42dffab81 Mon Sep 17 00:00:00 2001 From: Danyil Bohdan Date: Sat, 26 Jul 2014 10:50:17 +0300 Subject: aio: optional argument addrvar for accept. --- examples/tcp.server | 3 ++- jim-aio.c | 28 ++++++++++++++++++++++++++-- jim_tcl.txt | 8 +++++--- tests/event.test | 35 ++++++++++++++++++++++++++++++++++- 4 files changed, 67 insertions(+), 7 deletions(-) diff --git a/examples/tcp.server b/examples/tcp.server index 1240f2b..a86cd63 100644 --- a/examples/tcp.server +++ b/examples/tcp.server @@ -6,7 +6,8 @@ set s [socket stream.server 20000] $s readable { # Clean up children os.wait -nohang 0 - set sock [$s accept] + set sock [$s accept addr] + puts "Client address: $addr" # Make this server forking so we can accept multiple # simultaneous connections diff --git a/jim-aio.c b/jim-aio.c index 70fc1e3..37e1ea7 100644 --- a/jim-aio.c +++ b/jim-aio.c @@ -623,6 +623,30 @@ static int aio_cmd_accept(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_ERR; } + if (argc > 0) { + /* INET6_ADDRSTRLEN is 46. Add some for [] and port */ + char addrbuf[60]; + +#if IPV6 + if (sa.sa.sa_family == PF_INET6) { + addrbuf[0] = '['; + /* Allow 9 for []:65535\0 */ + inet_ntop(sa.sa.sa_family, &sa.sin6.sin6_addr, addrbuf + 1, sizeof(addrbuf) - 9); + snprintf(addrbuf + strlen(addrbuf), 8, "]:%d", ntohs(sa.sin.sin_port)); + } + else +#endif + if (sa.sa.sa_family == PF_INET) { + /* Allow 7 for :65535\0 */ + inet_ntop(sa.sa.sa_family, &sa.sin.sin_addr, addrbuf, sizeof(addrbuf) - 7); + snprintf(addrbuf + strlen(addrbuf), 7, ":%d", ntohs(sa.sin.sin_port)); + } + + if (Jim_SetVariable(interp, argv[0], Jim_NewStringObj(interp, addrbuf, -1)) != JIM_OK) { + return JIM_ERR; + } + } + /* Create the file command */ return JimMakeChannel(interp, NULL, sock, Jim_NewStringObj(interp, "accept", -1), "aio.sockstream%ld", af->addr_family, "r+"); @@ -916,10 +940,10 @@ static const jim_subcmd_type aio_command_table[] = { /* Description: Send 'str' to the given address (dgram only) */ }, { "accept", - NULL, + "?addrvar?", aio_cmd_accept, 0, - 0, + 1, /* Description: Server socket only: Accept a connection and return stream */ }, { "listen", diff --git a/jim_tcl.txt b/jim_tcl.txt index 255d12b..d6172b9 100644 --- a/jim_tcl.txt +++ b/jim_tcl.txt @@ -4431,14 +4431,16 @@ See `open` and `socket` for commands which return an I/O handle. aio ~~~ -+$handle *accept*+:: - Server socket only: Accept a connection and return stream ++$handle *accept* ?addrvar?+:: + Server socket only: Accept a connection and return stream. + If +'addrvar'+ is specified, the address of the connected client is stored + in the named variable in the form 'addr:port'. See `socket` for details. +$handle *buffering none|line|full*+:: Sets the buffering mode of the stream. +$handle *close* ?r(ead)|w(rite)?+:: - Closes the stream. + Closes the stream. The two-argument form is a "half-close" on a socket. See the +shutdown(2)+ man page. +$handle *copyto* 'tofd ?size?'+:: diff --git a/tests/event.test b/tests/event.test index 856e0cc..096f21b 100644 --- a/tests/event.test +++ b/tests/event.test @@ -15,6 +15,8 @@ needs cmd after eventloop testConstraint socket [expr {[info commands socket] ne ""}] testConstraint exec [expr {[info commands exec] ne ""}] testConstraint signal [expr {[info commands signal] ne ""}] +catch {[socket -ipv6 stream ::1:5000]} ipv6res +testConstraint ipv6 [expr {$ipv6res ne "ipv6 not supported"}] test event-5.1 {Tcl_BackgroundError, HandleBgErrors procedures} jim { catch {rename bgerror {}} @@ -152,7 +154,6 @@ test event-11.6 {Tcl_VwaitCmd procedure: round robin scheduling, same source} {s list $x $y $z } {3 3 done} - test event-12.1 {Tcl_UpdateCmd procedure} { list [catch {update a b} msg] $msg } {1 {wrong # args: should be "update ?idletasks?"}} @@ -200,4 +201,36 @@ test event-13.1 "vwait/signal" signal { } msg] $msg } {5 SIGALRM} + +test event-14.1 {socket stream.server client address} {jim socket} { + set s1 [socket stream.server 5001] + after 200 + set s2 [socket stream 127.0.0.1:5001] + set addr {} + $s1 readable { + $s1 accept addr + } + vwait addr + $s1 close + $s2 close + # Return client address without the port. + list [lindex [split $addr :] 0] +} {127.0.0.1} + +test event-14.2 {IPv6 socket stream.server client address} {jim socket ipv6} { + set s1 [socket -ipv6 stream.server ::1:5001] + after 200 + set s2 [socket -ipv6 stream ::1:5001] + set addr6 {} + $s1 readable { + $s1 accept addr6 + } + vwait addr6 + $s1 close + $s2 close + # Return client IPv6 address without the port. + list [join [lrange [split $addr6 :] 0 end-1] :] +} {{[::1]}} + + testreport -- cgit v1.1