summaryrefslogtreecommitdiffstats
path: root/tcl8.6/tests/socket.test
diff options
context:
space:
mode:
Diffstat (limited to 'tcl8.6/tests/socket.test')
-rw-r--r--tcl8.6/tests/socket.test2413
1 files changed, 2413 insertions, 0 deletions
diff --git a/tcl8.6/tests/socket.test b/tcl8.6/tests/socket.test
new file mode 100644
index 0000000..d43c41c
--- /dev/null
+++ b/tcl8.6/tests/socket.test
@@ -0,0 +1,2413 @@
+# Commands tested in this file: socket.
+#
+# This file contains a collection of tests for one or more of the Tcl built-in
+# commands. Sourcing this file into Tcl runs the tests and generates output
+# for errors. No output means no errors were found.
+#
+# Copyright (c) 1994-1996 Sun Microsystems, Inc.
+# Copyright (c) 1998-2000 Ajuba Solutions.
+#
+# See the file "license.terms" for information on usage and redistribution of
+# this file, and for a DISCLAIMER OF ALL WARRANTIES.
+
+# Running socket tests with a remote server:
+# ------------------------------------------
+#
+# Some tests in socket.test depend on the existence of a remote server to
+# which they connect. The remote server must be an instance of tcltest and it
+# must run the script found in the file "remote.tcl" in this directory. You
+# can start the remote server on any machine reachable from the machine on
+# which you want to run the socket tests, by issuing:
+#
+# tcltest remote.tcl -port 2048 # Or choose another port number.
+#
+# If the machine you are running the remote server on has several IP
+# interfaces, you can choose which interface the server listens on for
+# connections by specifying the -address command line flag, so:
+#
+# tcltest remote.tcl -address your.machine.com
+#
+# These options can also be set by environment variables. On Unix, you can
+# type these commands to the shell from which the remote server is started:
+#
+# shell% setenv serverPort 2048
+# shell% setenv serverAddress your.machine.com
+#
+# and subsequently you can start the remote server with:
+#
+# tcltest remote.tcl
+#
+# to have it listen on port 2048 on the interface your.machine.com.
+#
+# When the server starts, it prints out a detailed message containing its
+# configuration information, and it will block until killed with a Ctrl-C.
+# Once the remote server exists, you can run the tests in socket.test with the
+# server by setting two Tcl variables:
+#
+# % set remoteServerIP <name or address of machine on which server runs>
+# % set remoteServerPort 2048
+#
+# These variables are also settable from the environment. On Unix, you can:
+#
+# shell% setenv remoteServerIP machine.where.server.runs
+# shell% senetv remoteServerPort 2048
+#
+# The preamble of the socket.test file checks to see if the variables are set
+# either in Tcl or in the environment; if they are, it attempts to connect to
+# the server. If the connection is successful, the tests using the remote
+# server will be performed; otherwise, it will attempt to start the remote
+# server (via exec) on platforms that support this, on the local host,
+# listening at port 2048. If all fails, a message is printed and the tests
+# using the remote server are not performed.
+
+package require tcltest 2
+namespace import -force ::tcltest::*
+
+# Some tests require the Thread package or exec command
+testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}]
+testConstraint exec [llength [info commands exec]]
+
+# Produce a random port number in the Dynamic/Private range
+# from 49152 through 65535.
+proc randport {} { expr {int(rand()*16383+49152)} }
+
+# Test the latency of tcp connections over the loopback interface. Some OSes
+# (e.g. NetBSD) seem to use the Nagle algorithm and delayed ACKs, so it takes
+# up to 200ms for a packet sent to localhost to arrive. We're measuring this
+# here, so that OSes that don't have this problem can run the tests at full
+# speed.
+set server [socket -server {apply {{s a p} {set ::s1 $s}}} 0]
+set s2 [socket localhost [lindex [fconfigure $server -sockname] 2]]
+vwait s1; close $server
+fconfigure $s1 -buffering line
+fconfigure $s2 -buffering line
+set t1 [clock milliseconds]
+puts $s2 test1; gets $s1
+puts $s2 test2; gets $s1
+close $s1; close $s2
+set t2 [clock milliseconds]
+set lat1 [expr {($t2-$t1)*2}]; # doubled as a safety margin
+
+# Test the latency of failed connection attempts over the loopback
+# interface. They can take more than a second under Windowos and requres
+# additional [after]s in some tests that are not needed on systems that fail
+# immediately.
+set t1 [clock milliseconds]
+catch {socket 127.0.0.1 [randport]}
+set t2 [clock milliseconds]
+set lat2 [expr {($t2-$t1)*3}]
+
+# Use the maximum of the two latency calculations, but at least 100ms
+set latency [expr {$lat1 > $lat2 ? $lat1 : $lat2}]
+set latency [expr {$latency > 100 ? $latency : 1000}]
+unset t1 t2 s1 s2 lat1 lat2 server
+
+# If remoteServerIP or remoteServerPort are not set, check in the environment
+# variables for externally set values.
+#
+
+if {![info exists remoteServerIP]} {
+ if {[info exists env(remoteServerIP)]} {
+ set remoteServerIP $env(remoteServerIP)
+ }
+}
+if {![info exists remoteServerPort]} {
+ if {[info exists env(remoteServerPort)]} {
+ set remoteServerPort $env(remoteServerPort)
+ } else {
+ if {[info exists remoteServerIP]} {
+ set remoteServerPort 2048
+ }
+ }
+}
+
+if 0 {
+ # activate this to time the tests
+ proc test {args} {
+ set name [lindex $args 0]
+ puts "[lindex [time {uplevel [linsert $args 0 tcltest::test]}] 0] @@@ $name"
+ }
+}
+
+foreach {af localhost} {
+ inet 127.0.0.1
+ inet6 ::1
+} {
+ # Check if the family is supported and set the constraint accordingly
+ testConstraint supported_$af [expr {![catch {socket -server foo -myaddr $localhost 0} sock]}]
+ catch {close $sock}
+}
+
+set sock [socket -server foo -myaddr localhost 0]
+set sockname [fconfigure $sock -sockname]
+close $sock
+testConstraint localhost_v4 [expr {"127.0.0.1" in $sockname}]
+testConstraint localhost_v6 [expr {"::1" in $sockname}]
+
+
+foreach {af localhost} {
+ any 127.0.0.1
+ inet 127.0.0.1
+ inet6 ::1
+} {
+ if {![testConstraint supported_$af]} {
+ continue
+ }
+ set ::tcl::unsupported::socketAF $af
+#
+# Check if we're supposed to do tests against the remote server
+#
+
+set doTestsWithRemoteServer 1
+if {![info exists remoteServerIP]} {
+ set remoteServerIP $localhost
+}
+if {($doTestsWithRemoteServer == 1) && (![info exists remoteServerPort])} {
+ set remoteServerPort [randport]
+}
+
+# Attempt to connect to a remote server if one is already running. If it is
+# not running or for some other reason the connect fails, attempt to start the
+# remote server on the local host listening on port 2048. This is only done on
+# platforms that support exec (i.e. not on the Mac). On platforms that do not
+# support exec, the remote server must be started by the user before running
+# the tests.
+
+set remoteProcChan ""
+set commandSocket ""
+if {$doTestsWithRemoteServer} {
+ catch {close $commandSocket}
+ if {![catch {
+ set commandSocket [socket $remoteServerIP $remoteServerPort]
+ }]} then {
+ fconfigure $commandSocket -translation crlf -buffering line
+ } elseif {![testConstraint exec]} {
+ set noRemoteTestReason "can't exec"
+ set doTestsWithRemoteServer 0
+ } else {
+ set remoteServerIP $localhost
+ # Be *extra* careful in case this file is sourced from
+ # a directory other than the current one...
+ set remoteFile [file join [pwd] [file dirname [info script]] \
+ remote.tcl]
+ if {![catch {
+ set remoteProcChan [open "|[list \
+ [interpreter] $remoteFile -serverIsSilent \
+ -port $remoteServerPort -address $remoteServerIP]" w+]
+ } msg]} then {
+ gets $remoteProcChan
+ if {[catch {
+ set commandSocket [socket $remoteServerIP $remoteServerPort]
+ } msg] == 0} then {
+ fconfigure $commandSocket -translation crlf -buffering line
+ } else {
+ set noRemoteTestReason $msg
+ set doTestsWithRemoteServer 0
+ }
+ } else {
+ set noRemoteTestReason "$msg [interpreter]"
+ set doTestsWithRemoteServer 0
+ }
+ }
+}
+
+# Some tests are run only if we are doing testing against a remote server.
+testConstraint doTestsWithRemoteServer $doTestsWithRemoteServer
+if {!$doTestsWithRemoteServer} {
+ if {[string first s $::tcltest::verbose] != -1} {
+ puts "Skipping tests with remote server. See tests/socket.test for"
+ puts "information on how to run remote server."
+ puts "Reason for not doing remote tests: $noRemoteTestReason"
+ }
+}
+
+#
+# If we do the tests, define a command to send a command to the remote server.
+#
+
+if {[testConstraint doTestsWithRemoteServer]} {
+ proc sendCommand {c} {
+ global commandSocket
+
+ if {[eof $commandSocket]} {
+ error "remote server disappeared"
+ }
+ if {[catch {puts $commandSocket $c} msg]} {
+ error "remote server disappaered: $msg"
+ }
+ if {[catch {puts $commandSocket "--Marker--Marker--Marker--"} msg]} {
+ error "remote server disappeared: $msg"
+ }
+
+ while {1} {
+ set line [gets $commandSocket]
+ if {[eof $commandSocket]} {
+ error "remote server disappaered"
+ }
+ if {$line eq "--Marker--Marker--Marker--"} {
+ lassign $result code info value
+ return -code $code -errorinfo $info $value
+ }
+ append result $line "\n"
+ }
+ }
+}
+
+proc getPort sock {
+ lindex [fconfigure $sock -sockname] 2
+}
+
+
+# ----------------------------------------------------------------------
+
+test socket_$af-1.1 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
+ socket -server
+} -returnCodes error -result {no argument given for -server option}
+test socket_$af-1.2 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
+ socket -server foo
+} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
+test socket_$af-1.3 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
+ socket -myaddr
+} -returnCodes error -result {no argument given for -myaddr option}
+test socket_$af-1.4 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
+ socket -myaddr $localhost
+} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
+test socket_$af-1.5 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
+ socket -myport
+} -returnCodes error -result {no argument given for -myport option}
+test socket_$af-1.6 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
+ socket -myport xxxx
+} -returnCodes error -result {expected integer but got "xxxx"}
+test socket_$af-1.7 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
+ socket -myport 2522
+} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
+test socket_$af-1.8 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
+ socket -froboz
+} -returnCodes error -result {bad option "-froboz": must be -async, -myaddr, -myport, or -server}
+test socket_$af-1.9 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
+ socket -server foo -myport 2521 3333
+} -returnCodes error -result {option -myport is not valid for servers}
+test socket_$af-1.10 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
+ socket host 2528 -junk
+} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
+test socket_$af-1.11 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
+ socket -server callback 2520 --
+} -returnCodes error -result {wrong # args: should be "socket ?-myaddr addr? ?-myport myport? ?-async? host port" or "socket -server command ?-myaddr addr? port"}
+test socket_$af-1.12 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
+ socket foo badport
+} -returnCodes error -result {expected integer but got "badport"}
+test socket_$af-1.13 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
+ socket -async -server
+} -returnCodes error -result {cannot set -async option for server sockets}
+test socket_$af-1.14 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
+ socket -server foo -async
+} -returnCodes error -result {cannot set -async option for server sockets}
+
+set path(script) [makeFile {} script]
+
+test socket_$af-2.1 {tcp connection} -constraints [list socket supported_$af stdio] -setup {
+ file delete $path(script)
+ set f [open $path(script) w]
+ puts $f {
+ set timer [after 10000 "set x timed_out"]
+ set f [socket -server accept 0]
+ proc accept {file addr port} {
+ global x
+ set x done
+ close $file
+ }
+ puts ready
+ puts [lindex [fconfigure $f -sockname] 2]
+ vwait x
+ after cancel $timer
+ close $f
+ puts $x
+ }
+ close $f
+ set f [open "|[list [interpreter] $path(script)]" r]
+ gets $f x
+ gets $f listen
+} -body {
+ # $x == "ready" at this point
+ set sock [socket $localhost $listen]
+ lappend x [gets $f]
+ close $sock
+ lappend x [gets $f]
+} -cleanup {
+ close $f
+} -result {ready done {}}
+test socket_$af-2.2 {tcp connection with client port specified} -setup {
+ set port [randport]
+ file delete $path(script)
+ set f [open $path(script) w]
+ puts $f {
+ set timer [after 10000 "set x timeout"]
+ set f [socket -server accept 0]
+ proc accept {file addr port} {
+ global x
+ puts "[gets $file] $port"
+ close $file
+ set x done
+ }
+ puts ready
+ puts [lindex [fconfigure $f -sockname] 2]
+ vwait x
+ after cancel $timer
+ close $f
+ }
+ close $f
+ set f [open "|[list [interpreter] $path(script)]" r]
+ gets $f x
+ gets $f listen
+} -constraints [list socket supported_$af stdio] -body {
+ # $x == "ready" at this point
+ set sock [socket -myport $port $localhost $listen]
+ puts $sock hello
+ flush $sock
+ lappend x [expr {[gets $f] eq "hello $port"}]
+ close $sock
+ return $x
+} -cleanup {
+ catch {close [socket $localhost $listen]}
+ close $f
+} -result {ready 1}
+test socket_$af-2.3 {tcp connection with client interface specified} -setup {
+ file delete $path(script)
+ set f [open $path(script) w]
+ puts $f {
+ set timer [after 2000 "set x done"]
+ set f [socket -server accept 0]
+ proc accept {file addr port} {
+ global x
+ puts "[gets $file] $addr"
+ close $file
+ set x done
+ }
+ puts [lindex [fconfigure $f -sockname] 2]
+ puts ready
+ vwait x
+ after cancel $timer
+ close $f
+ }
+ close $f
+ set f [open "|[list [interpreter] $path(script)]" r]
+ gets $f listen
+ gets $f x
+} -constraints [list socket supported_$af stdio] -body {
+ # $x == "ready" at this point
+ set sock [socket -myaddr $localhost $localhost $listen]
+ puts $sock hello
+ flush $sock
+ lappend x [gets $f]
+ close $sock
+ return $x
+} -cleanup {
+ close $f
+} -result [list ready [list hello $localhost]]
+test socket_$af-2.4 {tcp connection with server interface specified} -setup {
+ file delete $path(script)
+ set f [open $path(script) w]
+ puts $f [list set localhost $localhost]
+ puts $f {
+ set timer [after 2000 "set x done"]
+ set f [socket -server accept -myaddr $localhost 0]
+ proc accept {file addr port} {
+ global x
+ puts "[gets $file]"
+ close $file
+ set x done
+ }
+ puts ready
+ puts [lindex [fconfigure $f -sockname] 2]
+ vwait x
+ after cancel $timer
+ close $f
+ }
+ close $f
+ set f [open "|[list [interpreter] $path(script)]" r]
+ gets $f x
+ gets $f listen
+} -constraints [list socket supported_$af stdio] -body {
+ # $x == "ready" at this point
+ set sock [socket $localhost $listen]
+ puts $sock hello
+ flush $sock
+ lappend x [gets $f]
+ close $sock
+ return $x
+} -cleanup {
+ close $f
+} -result {ready hello}
+test socket_$af-2.5 {tcp connection with redundant server port} -setup {
+ file delete $path(script)
+ set f [open $path(script) w]
+ puts $f {
+ set timer [after 10000 "set x timeout"]
+ set f [socket -server accept 0]
+ proc accept {file addr port} {
+ global x
+ puts "[gets $file]"
+ close $file
+ set x done
+ }
+ puts ready
+ puts [lindex [fconfigure $f -sockname] 2]
+ vwait x
+ after cancel $timer
+ close $f
+ }
+ close $f
+ set f [open "|[list [interpreter] $path(script)]" r]
+ gets $f x
+ gets $f listen
+} -constraints [list socket supported_$af stdio] -body {
+ # $x == "ready" at this point
+ set sock [socket $localhost $listen]
+ puts $sock hello
+ flush $sock
+ lappend x [gets $f]
+ close $sock
+ return $x
+} -cleanup {
+ close $f
+} -result {ready hello}
+test socket_$af-2.6 {tcp connection} -constraints [list socket supported_$af] -body {
+ set status ok
+ if {![catch {set sock [socket $localhost [randport]]}]} {
+ if {![catch {gets $sock}]} {
+ set status broken
+ }
+ close $sock
+ }
+ set status
+} -result ok
+test socket_$af-2.7 {echo server, one line} -constraints [list socket supported_$af stdio] -setup {
+ file delete $path(script)
+ set f [open $path(script) w]
+ puts $f {
+ set timer [after 10000 "set x timeout"]
+ set f [socket -server accept 0]
+ proc accept {s a p} {
+ fileevent $s readable [list echo $s]
+ fconfigure $s -translation lf -buffering line
+ }
+ proc echo {s} {
+ set l [gets $s]
+ if {[eof $s]} {
+ global x
+ close $s
+ set x done
+ } else {
+ puts $s $l
+ }
+ }
+ puts ready
+ puts [lindex [fconfigure $f -sockname] 2]
+ vwait x
+ after cancel $timer
+ close $f
+ puts $x
+ }
+ close $f
+ set f [open "|[list [interpreter] $path(script)]" r]
+ gets $f
+ gets $f listen
+} -body {
+ set s [socket $localhost $listen]
+ fconfigure $s -buffering line -translation lf
+ puts $s "hello abcdefghijklmnop"
+ set x [gets $s]
+ close $s
+ list $x [gets $f]
+} -cleanup {
+ close $f
+} -result {{hello abcdefghijklmnop} done}
+removeFile script
+test socket_$af-2.8 {echo server, loop 50 times, single connection} -setup {
+ set path(script) [makeFile {
+ set f [socket -server accept 0]
+ proc accept {s a p} {
+ fileevent $s readable [list echo $s]
+ fconfigure $s -buffering line
+ }
+ proc echo {s} {
+ global i
+ set l [gets $s]
+ if {[eof $s]} {
+ global x
+ close $s
+ set x done
+ } else {
+ incr i
+ puts $s $l
+ }
+ }
+ set i 0
+ puts ready
+ puts [lindex [fconfigure $f -sockname] 2]
+ set timer [after 20000 "set x done"]
+ vwait x
+ after cancel $timer
+ close $f
+ puts "done $i"
+ } script]
+ set f [open "|[list [interpreter] $path(script)]" r]
+ gets $f
+ gets $f listen
+} -constraints [list socket supported_$af stdio] -body {
+ set s [socket $localhost $listen]
+ fconfigure $s -buffering line
+ catch {
+ for {set x 0} {$x < 50} {incr x} {
+ puts $s "hello abcdefghijklmnop"
+ gets $s
+ }
+ }
+ close $s
+ catch {set x [gets $f]}
+ return $x
+} -cleanup {
+ close $f
+ removeFile script
+} -result {done 50}
+set path(script) [makeFile {} script]
+test socket_$af-2.9 {socket conflict} -constraints [list socket supported_$af stdio] -body {
+ set s [socket -server accept 0]
+ file delete $path(script)
+ set f [open $path(script) w]
+ puts $f [list set ::tcl::unsupported::socketAF $::tcl::unsupported::socketAF]
+ puts $f "socket -server accept [lindex [fconfigure $s -sockname] 2]"
+ close $f
+ set f [open "|[list [interpreter] $path(script)]" r]
+ gets $f
+ after 100
+ close $f
+} -returnCodes error -cleanup {
+ close $s
+} -match glob -result {couldn't open socket: address already in use*}
+test socket_$af-2.10 {close on accept, accepted socket lives} -setup {
+ set done 0
+ set timer [after 20000 "set done timed_out"]
+} -constraints [list socket supported_$af] -body {
+ set ss [socket -server accept 0]
+ proc accept {s a p} {
+ global ss
+ close $ss
+ fileevent $s readable "readit $s"
+ fconfigure $s -trans lf
+ }
+ proc readit {s} {
+ global done
+ gets $s
+ close $s
+ set done 1
+ }
+ set cs [socket $localhost [lindex [fconfigure $ss -sockname] 2]]
+ puts $cs hello
+ close $cs
+ vwait done
+ return $done
+} -cleanup {
+ after cancel $timer
+} -result 1
+test socket_$af-2.11 {detecting new data} -constraints [list socket supported_$af] -setup {
+ proc accept {s a p} {
+ global sock
+ set sock $s
+ }
+ set s [socket -server accept 0]
+ set sock ""
+} -body {
+ set s2 [socket $localhost [lindex [fconfigure $s -sockname] 2]]
+ vwait sock
+ puts $s2 one
+ flush $s2
+ after idle {set x 1}
+ vwait x
+ fconfigure $sock -blocking 0
+ set result a:[gets $sock]
+ lappend result b:[gets $sock]
+ fconfigure $sock -blocking 1
+ puts $s2 two
+ flush $s2
+ after $latency {set x 1}; # NetBSD fails here if we do [after idle]
+ vwait x
+ fconfigure $sock -blocking 0
+ lappend result c:[gets $sock]
+} -cleanup {
+ fconfigure $sock -blocking 1
+ close $s2
+ close $s
+ close $sock
+} -result {a:one b: c:two}
+test socket_$af-2.12 {} [list socket stdio supported_$af] {
+ file delete $path(script)
+ set f [open $path(script) w]
+ puts $f {
+ set server [socket -server accept_client 0]
+ puts [lindex [chan configure $server -sockname] 2]
+ proc accept_client { client host port } {
+ chan configure $client -blocking 0 -buffering line
+ write_line $client
+ }
+ proc write_line client {
+ if { [catch { chan puts $client [string repeat . 720000]}] } {
+ puts [catch {chan close $client}]
+ } else {
+ puts signal1
+ after 0 write_line $client
+ }
+ }
+ chan event stdin readable {set forever now}
+ vwait forever
+ exit
+ }
+ close $f
+ set f [open "|[list [interpreter] $path(script)]" r+]
+ gets $f port
+ set sock [socket $localhost $port]
+ chan event $sock readable [list read_lines $sock $f]
+ proc read_lines { sock pipe } {
+ gets $pipe
+ chan close $sock
+ chan event $pipe readable [list readpipe $pipe]
+ }
+ proc readpipe {pipe} {
+ while {![string is integer [set ::done [gets $pipe]]]} {}
+ }
+ vwait ::done
+ close $f
+ set ::done
+} 0
+test socket_$af-2.13 {Bug 1758a0b603} {socket stdio} {
+ file delete $path(script)
+ set f [open $path(script) w]
+ puts $f {
+ set server [socket -server accept 0]
+ puts [lindex [chan configure $server -sockname] 2]
+ proc accept { client host port } {
+ chan configure $client -blocking 0 -buffering line -buffersize 1
+ puts $client [string repeat . 720000]
+ puts ready
+ chan event $client writable [list setup $client]
+ }
+ proc setup client {
+ chan event $client writable {set forever write}
+ after 5 {set forever timeout}
+ }
+ vwait forever
+ puts $forever
+ }
+ close $f
+ set pipe [open |[list [interpreter] $path(script)] r]
+ gets $pipe port
+ set sock [socket $localhost $port]
+ chan configure $sock -blocking 0 -buffering line
+ chan event $sock readable [list read_lines $sock $pipe ]
+ proc read_lines { sock pipe } {
+ gets $pipe
+ gets $sock line
+ after idle [list stop $sock $pipe]
+ chan event $sock readable {}
+ }
+ proc stop {sock pipe} {
+ variable done
+ close $sock
+ set done [gets $pipe]
+ }
+ variable done
+ vwait [namespace which -variable done]
+ close $pipe
+ set done
+} write
+
+test socket_$af-3.1 {socket conflict} -constraints [list socket supported_$af stdio] -setup {
+ file delete $path(script)
+ set f [open $path(script) w]
+ puts $f [list set localhost $localhost]
+ puts $f {
+ set f [socket -server accept -myaddr $localhost 0]
+ puts ready
+ puts [lindex [fconfigure $f -sockname] 2]
+ gets stdin
+ close $f
+ }
+ close $f
+ set f [open "|[list [interpreter] $path(script)]" r+]
+ gets $f
+ gets $f listen
+} -body {
+ socket -server accept -myaddr $localhost $listen
+} -cleanup {
+ puts $f bye
+ close $f
+} -returnCodes error -result {couldn't open socket: address already in use}
+test socket_$af-3.2 {server with several clients} -setup {
+ file delete $path(script)
+ set f [open $path(script) w]
+ puts $f [list set localhost $localhost]
+ puts $f {
+ set t1 [after 30000 "set x timed_out"]
+ set t2 [after 31000 "set x timed_out"]
+ set t3 [after 32000 "set x timed_out"]
+ set counter 0
+ set s [socket -server accept -myaddr $localhost 0]
+ proc accept {s a p} {
+ fileevent $s readable [list echo $s]
+ fconfigure $s -buffering line
+ }
+ proc echo {s} {
+ global x
+ set l [gets $s]
+ if {[eof $s]} {
+ close $s
+ set x done
+ } else {
+ puts $s $l
+ }
+ }
+ puts ready
+ puts [lindex [fconfigure $s -sockname] 2]
+ vwait x
+ after cancel $t1
+ vwait x
+ after cancel $t2
+ vwait x
+ after cancel $t3
+ close $s
+ puts $x
+ }
+ close $f
+ set f [open "|[list [interpreter] $path(script)]" r+]
+ set x [gets $f]
+ gets $f listen
+} -constraints [list socket supported_$af stdio] -body {
+ # $x == "ready" here
+ set s1 [socket $localhost $listen]
+ fconfigure $s1 -buffering line
+ set s2 [socket $localhost $listen]
+ fconfigure $s2 -buffering line
+ set s3 [socket $localhost $listen]
+ fconfigure $s3 -buffering line
+ for {set i 0} {$i < 100} {incr i} {
+ puts $s1 hello,s1
+ gets $s1
+ puts $s2 hello,s2
+ gets $s2
+ puts $s3 hello,s3
+ gets $s3
+ }
+ close $s1
+ close $s2
+ close $s3
+ lappend x [gets $f]
+} -cleanup {
+ close $f
+} -result {ready done}
+
+test socket_$af-4.1 {server with several clients} -setup {
+ file delete $path(script)
+ set f [open $path(script) w]
+ puts $f [list set localhost $localhost]
+ puts $f {
+ set port [gets stdin]
+ set s [socket $localhost $port]
+ fconfigure $s -buffering line
+ for {set i 0} {$i < 100} {incr i} {
+ puts $s hello
+ gets $s
+ }
+ close $s
+ puts bye
+ gets stdin
+ }
+ close $f
+ set p1 [open "|[list [interpreter] $path(script)]" r+]
+ fconfigure $p1 -buffering line
+ set p2 [open "|[list [interpreter] $path(script)]" r+]
+ fconfigure $p2 -buffering line
+ set p3 [open "|[list [interpreter] $path(script)]" r+]
+ fconfigure $p3 -buffering line
+} -constraints [list socket supported_$af stdio] -body {
+ proc accept {s a p} {
+ fconfigure $s -buffering line
+ fileevent $s readable [list echo $s]
+ }
+ proc echo {s} {
+ global x
+ set l [gets $s]
+ if {[eof $s]} {
+ close $s
+ set x done
+ } else {
+ puts $s $l
+ }
+ }
+ set t1 [after 30000 "set x timed_out"]
+ set t2 [after 31000 "set x timed_out"]
+ set t3 [after 32000 "set x timed_out"]
+ set s [socket -server accept -myaddr $localhost 0]
+ set listen [lindex [fconfigure $s -sockname] 2]
+ puts $p1 $listen
+ puts $p2 $listen
+ puts $p3 $listen
+ vwait x
+ vwait x
+ vwait x
+ after cancel $t1
+ after cancel $t2
+ after cancel $t3
+ close $s
+ set l ""
+ lappend l [list p1 [gets $p1] $x]
+ lappend l [list p2 [gets $p2] $x]
+ lappend l [list p3 [gets $p3] $x]
+} -cleanup {
+ puts $p1 bye
+ puts $p2 bye
+ puts $p3 bye
+ close $p1
+ close $p2
+ close $p3
+} -result {{p1 bye done} {p2 bye done} {p3 bye done}}
+test socket_$af-4.2 {byte order problems, socket numbers, htons} -body {
+ close [socket -server dodo -myaddr $localhost 0x3000]
+ return ok
+} -constraints [list socket supported_$af] -result ok
+
+test socket_$af-5.1 {byte order problems, socket numbers, htons} -body {
+ if {![catch {socket -server dodo 0x1} msg]} {
+ close $msg
+ return {htons problem, should be disallowed, are you running as SU?}
+ }
+ return {couldn't open socket: not owner}
+} -constraints [list socket supported_$af unix notRoot] -result {couldn't open socket: not owner}
+test socket_$af-5.2 {byte order problems, socket numbers, htons} -body {
+ if {![catch {socket -server dodo 0x10000} msg]} {
+ close $msg
+ return {port resolution problem, should be disallowed}
+ }
+ return {couldn't open socket: port number too high}
+} -constraints [list socket supported_$af] -result {couldn't open socket: port number too high}
+test socket_$af-5.3 {byte order problems, socket numbers, htons} -body {
+ if {![catch {socket -server dodo 21} msg]} {
+ close $msg
+ return {htons problem, should be disallowed, are you running as SU?}
+ }
+ return {couldn't open socket: not owner}
+} -constraints [list socket supported_$af unix notRoot] -result {couldn't open socket: not owner}
+
+test socket_$af-6.1 {accept callback error} -constraints [list socket supported_$af stdio] -setup {
+ proc myHandler {msg options} {
+ variable x $msg
+ }
+ set handler [interp bgerror {}]
+ interp bgerror {} [namespace which myHandler]
+ file delete $path(script)
+} -body {
+ set f [open $path(script) w]
+ puts $f [list set localhost $localhost]
+ puts $f {
+ gets stdin port
+ socket $localhost $port
+ }
+ close $f
+ set f [open "|[list [interpreter] $path(script)]" r+]
+ proc accept {s a p} {expr 10 / 0}
+ set s [socket -server accept -myaddr $localhost 0]
+ puts $f [lindex [fconfigure $s -sockname] 2]
+ close $f
+ set timer [after 10000 "set x timed_out"]
+ vwait x
+ after cancel $timer
+ close $s
+ return $x
+} -cleanup {
+ interp bgerror {} $handler
+} -result {divide by zero}
+
+test socket_$af-6.2 {
+ readable fileevent on server socket
+} -setup {
+ set sock [socket -server dummy 0]
+} -constraints [list socket supported_$af] -body {
+ fileevent $sock readable dummy
+} -cleanup {
+ close $sock
+} -returnCodes 1 -result "channel is not readable"
+
+test socket_$af-6.3 {writable fileevent on server socket} -setup {
+ set sock [socket -server dummy 0]
+} -constraints [list socket supported_$af] -body {
+ fileevent $sock writable dummy
+} -cleanup {
+ close $sock
+} -returnCodes 1 -result "channel is not writable"
+
+test socket_$af-7.1 {testing socket specific options} -setup {
+ file delete $path(script)
+ set f [open $path(script) w]
+ puts $f {
+ set ss [socket -server accept 0]
+ proc accept args {
+ global x
+ set x done
+ }
+ puts ready
+ puts [lindex [fconfigure $ss -sockname] 2]
+ set timer [after 10000 "set x timed_out"]
+ vwait x
+ after cancel $timer
+ }
+ close $f
+ set f [open "|[list [interpreter] $path(script)]" r]
+ gets $f
+ gets $f listen
+ set l ""
+} -constraints [list socket supported_$af stdio] -body {
+ set s [socket $localhost $listen]
+ set p [fconfigure $s -peername]
+ close $s
+ lappend l [string compare [lindex $p 0] $localhost]
+ lappend l [string compare [lindex $p 2] $listen]
+ lappend l [llength $p]
+} -cleanup {
+ close $f
+} -result {0 0 3}
+test socket_$af-7.2 {testing socket specific options} -setup {
+ file delete $path(script)
+ set f [open $path(script) w]
+ puts $f [list set ::tcl::unsupported::socketAF $::tcl::unsupported::socketAF]
+ puts $f {
+ set ss [socket -server accept 0]
+ proc accept args {
+ global x
+ set x done
+ }
+ puts ready
+ puts [lindex [fconfigure $ss -sockname] 2]
+ set timer [after 10000 "set x timed_out"]
+ vwait x
+ after cancel $timer
+ }
+ close $f
+ set f [open "|[list [interpreter] $path(script)]" r]
+ gets $f
+ gets $f listen
+} -constraints [list socket supported_$af stdio] -body {
+ set s [socket $localhost $listen]
+ set p [fconfigure $s -sockname]
+ close $s
+ list [llength $p] \
+ [regexp {^(127\.0\.0\.1|0\.0\.0\.0|::1)$} [lindex $p 0]] \
+ [expr {[lindex $p 2] == $listen}]
+} -cleanup {
+ close $f
+} -result {3 1 0}
+test socket_$af-7.3 {testing socket specific options} -constraints [list socket supported_$af] -body {
+ set s [socket -server accept -myaddr $localhost 0]
+ set l [fconfigure $s]
+ close $s
+ update
+ llength $l
+} -result 14
+test socket_$af-7.4 {testing socket specific options} -constraints [list socket supported_$af] -setup {
+ set timer [after 10000 "set x timed_out"]
+ set l ""
+} -body {
+ set s [socket -server accept -myaddr $localhost 0]
+ proc accept {s a p} {
+ global x
+ set x [fconfigure $s -sockname]
+ close $s
+ }
+ set listen [lindex [fconfigure $s -sockname] 2]
+ set s1 [socket $localhost $listen]
+ vwait x
+ lappend l [expr {[lindex $x 2] == $listen}] [llength $x]
+} -cleanup {
+ after cancel $timer
+ close $s
+ close $s1
+} -result {1 3}
+test socket_$af-7.5 {testing socket specific options} -setup {
+ set timer [after 10000 "set x timed_out"]
+ set l ""
+} -constraints [list socket supported_$af unixOrPc] -body {
+ set s [socket -server accept 0]
+ proc accept {s a p} {
+ global x
+ set x [fconfigure $s -sockname]
+ close $s
+ }
+ set listen [lindex [fconfigure $s -sockname] 2]
+ set s1 [socket $localhost $listen]
+ vwait x
+ lappend l [lindex $x 0] [expr {[lindex $x 2] == $listen}] [llength $x]
+} -cleanup {
+ after cancel $timer
+ close $s
+ close $s1
+} -result [list $localhost 1 3]
+
+test socket_$af-8.1 {testing -async flag on sockets} -constraints [list socket supported_$af] -body {
+ # NOTE: This test may fail on some Solaris 2.4 systems. If it does, check
+ # that you have these patches installed (using showrev -p):
+ #
+ # 101907-05, 101925-02, 101945-14, 101959-03, 101969-05, 101973-03,
+ # 101977-03, 101981-02, 101985-01, 102001-03, 102003-01, 102007-01,
+ # 102011-02, 102024-01, 102039-01, 102044-01, 102048-01, 102062-03,
+ # 102066-04, 102070-01, 102105-01, 102153-03, 102216-01, 102232-01,
+ # 101878-03, 101879-01, 101880-03, 101933-01, 101950-01, 102030-01,
+ # 102057-08, 102140-01, 101920-02, 101921-09, 101922-07, 101923-03
+ #
+ # If after installing these patches you are still experiencing a problem,
+ # please email jyl@eng.sun.com. We have not observed this failure on
+ # Solaris 2.5, so another option (instead of installing these patches) is
+ # to upgrade to Solaris 2.5.
+ set s [socket -server accept -myaddr $localhost 0]
+ proc accept {s a p} {
+ global x
+ puts $s bye
+ close $s
+ set x done
+ }
+ set s1 [socket -async $localhost [lindex [fconfigure $s -sockname] 2]]
+ vwait x
+ gets $s1
+} -cleanup {
+ close $s
+ close $s1
+} -result bye
+
+test socket_$af-9.1 {testing spurious events} -constraints [list socket supported_$af] -setup {
+ set len 0
+ set spurious 0
+ set done 0
+ set timer [after 10000 "set done timed_out"]
+} -body {
+ proc readlittle {s} {
+ global spurious done len
+ set l [read $s 1]
+ if {[string length $l] == 0} {
+ if {![eof $s]} {
+ incr spurious
+ } else {
+ close $s
+ set done 1
+ }
+ } else {
+ incr len [string length $l]
+ }
+ }
+ proc accept {s a p} {
+ fconfigure $s -buffering none -blocking off
+ fileevent $s readable [list readlittle $s]
+ }
+ set s [socket -server accept -myaddr $localhost 0]
+ set c [socket $localhost [lindex [fconfigure $s -sockname] 2]]
+ puts -nonewline $c 01234567890123456789012345678901234567890123456789
+ close $c
+ vwait done
+ close $s
+ list $spurious $len
+} -cleanup {
+ after cancel $timer
+} -result {0 50}
+test socket_$af-9.2 {testing async write, fileevents, flush on close} -constraints [list socket supported_$af] -setup {
+ set firstblock ""
+ for {set i 0} {$i < 5} {incr i} {set firstblock "a$firstblock$firstblock"}
+ set secondblock ""
+ for {set i 0} {$i < 16} {incr i} {
+ set secondblock "b$secondblock$secondblock"
+ }
+ set timer [after 10000 "set done timed_out"]
+ set l [socket -server accept -myaddr $localhost 0]
+ proc accept {s a p} {
+ fconfigure $s -blocking 0 -translation lf -buffersize 16384 \
+ -buffering line
+ fileevent $s readable "readable $s"
+ }
+ proc readable {s} {
+ set l [gets $s]
+ fileevent $s readable {}
+ after idle respond $s
+ }
+ proc respond {s} {
+ global firstblock
+ puts -nonewline $s $firstblock
+ after idle writedata $s
+ }
+ proc writedata {s} {
+ global secondblock
+ puts -nonewline $s $secondblock
+ close $s
+ }
+} -body {
+ set s [socket $localhost [lindex [fconfigure $l -sockname] 2]]
+ fconfigure $s -blocking 0 -trans lf -buffering line
+ set count 0
+ puts $s hello
+ proc readit {s} {
+ global count done
+ set l [read $s]
+ incr count [string length $l]
+ if {[eof $s]} {
+ close $s
+ set done 1
+ }
+ }
+ fileevent $s readable "readit $s"
+ vwait done
+ return $count
+} -cleanup {
+ close $l
+ after cancel $timer
+} -result 65566
+test socket_$af-9.3 {testing EOF stickyness} -constraints [list socket supported_$af] -setup {
+ set count 0
+ set done false
+ proc write_then_close {s} {
+ puts $s bye
+ close $s
+ }
+ proc accept {s a p} {
+ fconfigure $s -buffering line -translation lf
+ fileevent $s writable "write_then_close $s"
+ }
+ set s [socket -server accept -myaddr $localhost 0]
+} -body {
+ proc count_to_eof {s} {
+ global count done
+ set l [gets $s]
+ if {[eof $s]} {
+ incr count
+ if {$count > 9} {
+ close $s
+ set done true
+ set count {eof is sticky}
+ }
+ }
+ }
+ proc timerproc {s} {
+ global done count
+ set done true
+ set count {timer went off, eof is not sticky}
+ close $s
+ }
+ set c [socket $localhost [lindex [fconfigure $s -sockname] 2]]
+ fconfigure $c -blocking off -buffering line -translation lf
+ fileevent $c readable "count_to_eof $c"
+ set timer [after 1000 timerproc $c]
+ vwait done
+ return $count
+} -cleanup {
+ close $s
+ after cancel $timer
+} -result {eof is sticky}
+
+removeFile script
+
+test socket_$af-10.1 {testing socket accept callback error handling} \
+ -constraints [list socket supported_$af] -setup {
+ variable goterror 0
+ proc myHandler {msg options} {
+ variable goterror 1
+ }
+ set handler [interp bgerror {}]
+ interp bgerror {} [namespace which myHandler]
+} -body {
+ set s [socket -server accept -myaddr $localhost 0]
+ proc accept {s a p} {close $s; error}
+ set c [socket $localhost [lindex [fconfigure $s -sockname] 2]]
+ vwait goterror
+ close $s
+ close $c
+ return $goterror
+} -cleanup {
+ interp bgerror {} $handler
+} -result 1
+
+test socket_$af-11.1 {tcp connection} -setup {
+ set port [sendCommand {
+ set server [socket -server accept 0]
+ proc accept {s a p} {
+ puts $s done
+ close $s
+ }
+ getPort $server
+ }]
+} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
+ set s [socket $remoteServerIP $port]
+ gets $s
+} -cleanup {
+ close $s
+ sendCommand {close $server}
+} -result done
+test socket_$af-11.2 {client specifies its port} -setup {
+ set lport [randport]
+ set rport [sendCommand {
+ set server [socket -server accept 0]
+ proc accept {s a p} {
+ puts $s $p
+ close $s
+ }
+ getPort $server
+ }]
+} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
+ set s [socket -myport $lport $remoteServerIP $rport]
+ set r [gets $s]
+ expr {$r==$lport ? "ok" : "broken: $r != $port"}
+} -cleanup {
+ close $s
+ sendCommand {close $server}
+} -result ok
+test socket_$af-11.3 {trying to connect, no server} -body {
+ set status ok
+ if {![catch {set s [socket $remoteServerIp [randport]]}]} {
+ if {![catch {gets $s}]} {
+ set status broken
+ }
+ close $s
+ }
+ return $status
+} -constraints [list socket supported_$af doTestsWithRemoteServer] -result ok
+test socket_$af-11.4 {remote echo, one line} -setup {
+ set port [sendCommand {
+ set server [socket -server accept 0]
+ proc accept {s a p} {
+ fileevent $s readable [list echo $s]
+ fconfigure $s -buffering line -translation crlf
+ }
+ proc echo {s} {
+ set l [gets $s]
+ if {[eof $s]} {
+ close $s
+ } else {
+ puts $s $l
+ }
+ }
+ getPort $server
+ }]
+} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
+ set f [socket $remoteServerIP $port]
+ fconfigure $f -translation crlf -buffering line
+ puts $f hello
+ gets $f
+} -cleanup {
+ catch {close $f}
+ sendCommand {close $server}
+} -result hello
+test socket_$af-11.5 {remote echo, 50 lines} -setup {
+ set port [sendCommand {
+ set server [socket -server accept 0]
+ proc accept {s a p} {
+ fileevent $s readable [list echo $s]
+ fconfigure $s -buffering line -translation crlf
+ }
+ proc echo {s} {
+ set l [gets $s]
+ if {[eof $s]} {
+ close $s
+ } else {
+ puts $s $l
+ }
+ }
+ getPort $server
+ }]
+} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
+ set f [socket $remoteServerIP $port]
+ fconfigure $f -translation crlf -buffering line
+ for {set cnt 0} {$cnt < 50} {incr cnt} {
+ puts $f "hello, $cnt"
+ if {[gets $f] != "hello, $cnt"} {
+ break
+ }
+ }
+ return $cnt
+} -cleanup {
+ close $f
+ sendCommand {close $server}
+} -result 50
+test socket_$af-11.6 {socket conflict} -setup {
+ set s1 [socket -server accept -myaddr $localhost 0]
+} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
+ set s2 [socket -server accept -myaddr $localhost [getPort $s1]]
+ list [getPort $s2] [close $s2]
+} -cleanup {
+ close $s1
+} -returnCodes error -result {couldn't open socket: address already in use}
+test socket_$af-11.7 {server with several clients} -setup {
+ set port [sendCommand {
+ set server [socket -server accept 0]
+ proc accept {s a p} {
+ fconfigure $s -buffering line
+ fileevent $s readable [list echo $s]
+ }
+ proc echo {s} {
+ set l [gets $s]
+ if {[eof $s]} {
+ close $s
+ } else {
+ puts $s $l
+ }
+ }
+ getPort $server
+ }]
+} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
+ set s1 [socket $remoteServerIP $port]
+ fconfigure $s1 -buffering line
+ set s2 [socket $remoteServerIP $port]
+ fconfigure $s2 -buffering line
+ set s3 [socket $remoteServerIP $port]
+ fconfigure $s3 -buffering line
+ for {set i 0} {$i < 100} {incr i} {
+ puts $s1 hello,s1
+ gets $s1
+ puts $s2 hello,s2
+ gets $s2
+ puts $s3 hello,s3
+ gets $s3
+ }
+ return $i
+} -cleanup {
+ close $s1
+ close $s2
+ close $s3
+ sendCommand {close $server}
+} -result 100
+test socket_$af-11.8 {client with several servers} -setup {
+ lassign [sendCommand {
+ set s1 [socket -server "accept server1" 0]
+ set s2 [socket -server "accept server2" 0]
+ set s3 [socket -server "accept server3" 0]
+ proc accept {mp s a p} {
+ puts $s $mp
+ close $s
+ }
+ list [getPort $s1] [getPort $s2] [getPort $s3]
+ }] p1 p2 p3
+} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
+ set s1 [socket $remoteServerIP $p1]
+ set s2 [socket $remoteServerIP $p2]
+ set s3 [socket $remoteServerIP $p3]
+ list [gets $s1] [gets $s1] [eof $s1] [gets $s2] [gets $s2] [eof $s2] \
+ [gets $s3] [gets $s3] [eof $s3]
+} -cleanup {
+ close $s1
+ close $s2
+ close $s3
+ sendCommand {
+ close $s1
+ close $s2
+ close $s3
+ }
+} -result {server1 {} 1 server2 {} 1 server3 {} 1}
+test socket_$af-11.9 {accept callback error} -constraints [list socket supported_$af doTestsWithRemoteServer] -setup {
+ proc myHandler {msg options} {
+ variable x $msg
+ }
+ set handler [interp bgerror {}]
+ interp bgerror {} [namespace which myHandler]
+ set timer [after 10000 "set x timed_out"]
+} -body {
+ set s [socket -server accept 0]
+ proc accept {s a p} {expr {10 / 0}}
+ sendCommand "set port [getPort $s]"
+ if {[catch {
+ sendCommand {
+ set peername [fconfigure $callerSocket -peername]
+ set s [socket [lindex $peername 0] $port]
+ close $s
+ }
+ } msg]} then {
+ close $s
+ error $msg
+ }
+ vwait x
+ return $x
+} -cleanup {
+ close $s
+ after cancel $timer
+ interp bgerror {} $handler
+} -result {divide by zero}
+test socket_$af-11.10 {testing socket specific options} -setup {
+ set port [sendCommand {
+ set server [socket -server accept 0]
+ proc accept {s a p} {close $s}
+ getPort $server
+ }]
+} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
+ set s [socket $remoteServerIP $port]
+ set p [fconfigure $s -peername]
+ set n [fconfigure $s -sockname]
+ list [expr {[lindex $p 2] == $port}] [llength $p] [llength $n]
+} -cleanup {
+ close $s
+ sendCommand {close $server}
+} -result {1 3 3}
+test socket_$af-11.11 {testing spurious events} -setup {
+ set port [sendCommand {
+ set server [socket -server accept 0]
+ proc accept {s a p} {
+ fconfigure $s -translation "auto lf"
+ after idle writesome $s
+ }
+ proc writesome {s} {
+ for {set i 0} {$i < 100} {incr i} {
+ puts $s "line $i from remote server"
+ }
+ close $s
+ }
+ getPort $server
+ }]
+ set len 0
+ set spurious 0
+ set done 0
+ set timer [after 40000 "set done timed_out"]
+} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
+ proc readlittle {s} {
+ global spurious done len
+ set l [read $s 1]
+ if {[string length $l] == 0} {
+ if {![eof $s]} {
+ incr spurious
+ } else {
+ close $s
+ set done 1
+ }
+ } else {
+ incr len [string length $l]
+ }
+ }
+ set c [socket $remoteServerIP $port]
+ fileevent $c readable "readlittle $c"
+ vwait done
+ list $spurious $len $done
+} -cleanup {
+ after cancel $timer
+ sendCommand {close $server}
+} -result {0 2690 1}
+test socket_$af-11.12 {testing EOF stickyness} -constraints [list socket supported_$af doTestsWithRemoteServer] -setup {
+ set counter 0
+ set done 0
+ set port [sendCommand {
+ set server [socket -server accept 0]
+ proc accept {s a p} {
+ after idle close $s
+ }
+ getPort $server
+ }]
+ proc timed_out {} {
+ global c done
+ set done {timed_out, EOF is not sticky}
+ close $c
+ }
+ set after_id [after 1000 timed_out]
+} -body {
+ proc count_up {s} {
+ global counter done
+ set l [gets $s]
+ if {[eof $s]} {
+ incr counter
+ if {$counter > 9} {
+ set done {EOF is sticky}
+ close $s
+ }
+ }
+ }
+ set c [socket $remoteServerIP $port]
+ fileevent $c readable [list count_up $c]
+ vwait done
+ return $done
+} -cleanup {
+ after cancel $after_id
+ sendCommand {close $server}
+} -result {EOF is sticky}
+test socket_$af-11.13 {testing async write, async flush, async close} -setup {
+ set port [sendCommand {
+ set firstblock ""
+ for {set i 0} {$i < 5} {incr i} {
+ set firstblock "a$firstblock$firstblock"
+ }
+ set secondblock ""
+ for {set i 0} {$i < 16} {incr i} {
+ set secondblock "b$secondblock$secondblock"
+ }
+ set l [socket -server accept 0]
+ proc accept {s a p} {
+ fconfigure $s -blocking 0 -translation lf -buffersize 16384 \
+ -buffering line
+ fileevent $s readable "readable $s"
+ }
+ proc readable {s} {
+ set l [gets $s]
+ fileevent $s readable {}
+ after idle respond $s
+ }
+ proc respond {s} {
+ global firstblock
+ puts -nonewline $s $firstblock
+ after idle writedata $s
+ }
+ proc writedata {s} {
+ global secondblock
+ puts -nonewline $s $secondblock
+ close $s
+ }
+ getPort $l
+ }]
+ set timer [after 10000 "set done timed_out"]
+} -constraints [list socket supported_$af doTestsWithRemoteServer] -body {
+ proc readit {s} {
+ global count done
+ set l [read $s]
+ incr count [string length $l]
+ if {[eof $s]} {
+ close $s
+ set done 1
+ }
+ }
+ set s [socket $remoteServerIP $port]
+ fconfigure $s -blocking 0 -trans lf -buffering line
+ set count 0
+ puts $s hello
+ fileevent $s readable "readit $s"
+ vwait done
+ return $count
+} -cleanup {
+ after cancel $timer
+ sendCommand {close $l}
+} -result 65566
+
+set path(script1) [makeFile {} script1]
+set path(script2) [makeFile {} script2]
+
+test socket_$af-12.1 {testing inheritance of server sockets} -setup {
+ file delete $path(script1)
+ file delete $path(script2)
+ # Script1 is just a 10 second delay. If the server socket is inherited, it
+ # will be held open for 10 seconds
+ set f [open $path(script1) w]
+ puts $f {
+ fileevent stdin readable exit
+ after 10000 exit
+ vwait forever
+ }
+ close $f
+ # Script2 creates the server socket, launches script1, and exits.
+ # The server socket will now be closed unless script1 inherited it.
+ set f [open $path(script2) w]
+ puts $f [list set tcltest [interpreter]]
+ puts $f [list set delay $path(script1)]
+ puts $f [list set localhost $localhost]
+ puts $f {
+ set f [socket -server accept -myaddr $localhost 0]
+ proc accept { file addr port } {
+ close $file
+ }
+ exec $tcltest $delay &
+ puts [lindex [fconfigure $f -sockname] 2]
+ close $f
+ exit
+ }
+ close $f
+} -constraints [list socket supported_$af stdio exec] -body {
+ # Launch script2 and wait 5 seconds
+ ### exec [interpreter] script2 &
+ set p [open "|[list [interpreter] $path(script2)]" r]
+ # If we can still connect to the server, the socket got inherited.
+ if {[catch {close [socket $localhost $listen]}]} {
+ return {server socket was not inherited}
+ } else {
+ return {server socket was inherited}
+ }
+} -cleanup {
+ catch {close $p}
+} -result {server socket was not inherited}
+test socket_$af-12.2 {testing inheritance of client sockets} -setup {
+ file delete $path(script1)
+ file delete $path(script2)
+ # Script1 is just a 20 second delay. If the server socket is inherited, it
+ # will be held open for 20 seconds
+ set f [open $path(script1) w]
+ puts $f {
+ fileevent stdin readable exit
+ after 20000 exit
+ vwait forever
+ }
+ close $f
+ # Script2 opens the client socket and writes to it. It then launches
+ # script1 and exits. If the child process inherited the client socket, the
+ # socket will still be open.
+ set f [open $path(script2) w]
+ puts $f [list set tcltest [interpreter]]
+ puts $f [list set delay $path(script1)]
+ puts $f [list set localhost $localhost]
+ puts $f {
+ gets stdin port
+ set f [socket $localhost $port]
+ exec $tcltest $delay &
+ puts $f testing
+ flush $f
+ exit
+ }
+ close $f
+ # If the socket doesn't hit end-of-file in 10 seconds, the script1 process
+ # must have inherited the client.
+ set timeout 0
+ set after [after 10000 {set x "client socket was inherited"}]
+} -constraints [list socket supported_$af stdio exec] -body {
+ # Create the server socket
+ set server [socket -server accept -myaddr $localhost 0]
+ proc accept { file host port } {
+ # When the client connects, establish the read handler
+ global server
+ close $server
+ fileevent $file readable [list getdata $file]
+ fconfigure $file -buffering line -blocking 0
+ set ::f $file
+ }
+ proc getdata { file } {
+ # Read handler on the accepted socket.
+ global x
+ set status [catch {read $file} data]
+ if {$status != 0} {
+ set x "read failed, error was $data"
+ } elseif {$data ne ""} {
+ } elseif {[fblocked $file]} {
+ } elseif {[eof $file]} {
+ set x "client socket was not inherited"
+ } else {
+ set x "impossible case"
+ }
+ }
+ # Launch the script2 process
+ ### exec [interpreter] script2 &
+ set p [open "|[list [interpreter] $path(script2)]" w]
+ puts $p [lindex [fconfigure $server -sockname] 2] ; flush $p
+ vwait x
+ return $x
+} -cleanup {
+ fconfigure $f -blocking 1
+ close $f
+ after cancel $after
+ close $p
+} -result {client socket was not inherited}
+test socket_$af-12.3 {testing inheritance of accepted sockets} -setup {
+ file delete $path(script1)
+ file delete $path(script2)
+ set f [open $path(script1) w]
+ puts $f {
+ fileevent stdin readable exit
+ after 10000 exit
+ vwait forever
+ }
+ close $f
+ set f [open $path(script2) w]
+ puts $f [list set tcltest [interpreter]]
+ puts $f [list set delay $path(script1)]
+ puts $f [list set localhost $localhost]
+ puts $f {
+ set server [socket -server accept -myaddr $localhost 0]
+ proc accept { file host port } {
+ global tcltest delay
+ puts $file {test data on socket}
+ exec $tcltest $delay &
+ after idle exit
+ }
+ puts stdout [lindex [fconfigure $server -sockname] 2]
+ vwait forever
+ }
+ close $f
+} -constraints [list socket supported_$af stdio exec] -body {
+ # Launch the script2 process and connect to it. See how long the socket
+ # stays open
+ ## exec [interpreter] script2 &
+ set p [open "|[list [interpreter] $path(script2)]" r]
+ gets $p listen
+ set f [socket $localhost $listen]
+ fconfigure $f -buffering full -blocking 0
+ fileevent $f readable [list getdata $f]
+ # If the socket is still open after 5 seconds, the script1 process must
+ # have inherited the accepted socket.
+ set failed 0
+ set after [after 5000 [list set x "accepted socket was inherited"]]
+ proc getdata { file } {
+ # Read handler on the client socket.
+ global x
+ global failed
+ set status [catch {read $file} data]
+ if {$status != 0} {
+ set x "read failed, error was $data"
+ } elseif {[string compare {} $data]} {
+ } elseif {[fblocked $file]} {
+ } elseif {[eof $file]} {
+ set x "accepted socket was not inherited"
+ } else {
+ set x "impossible case"
+ }
+ return
+ }
+ vwait x
+ set x
+} -cleanup {
+ fconfigure $f -blocking 1
+ close $f
+ after cancel $after
+ close $p
+} -result {accepted socket was not inherited}
+
+test socket_$af-13.1 {Testing use of shared socket between two threads} -body {
+ # create a thread
+ set serverthread [thread::create -preserved [string map [list @localhost@ $localhost] {
+ set f [socket -server accept -myaddr @localhost@ 0]
+ set listen [lindex [fconfigure $f -sockname] 2]
+ proc accept {s a p} {
+ fileevent $s readable [list echo $s]
+ fconfigure $s -buffering line
+ }
+ proc echo {s} {
+ global i
+ set l [gets $s]
+ if {[eof $s]} {
+ global x
+ close $s
+ set x done
+ } else {
+ incr i
+ puts $s $l
+ }
+ }
+ set i 0
+ vwait x
+ close $f
+ }]]
+ set port [thread::send $serverthread {set listen}]
+ set s [socket $localhost $port]
+ fconfigure $s -buffering line
+ catch {
+ puts $s "hello"
+ gets $s result
+ }
+ close $s
+ thread::release $serverthread
+ append result " " [llength [thread::names]]
+} -result {hello 1} -constraints [list socket supported_$af thread]
+
+# ----------------------------------------------------------------------
+
+removeFile script1
+removeFile script2
+
+# cleanup
+if {$remoteProcChan ne ""} {
+ catch {sendCommand exit}
+}
+catch {close $commandSocket}
+catch {close $remoteProcChan}
+}
+unset ::tcl::unsupported::socketAF
+test socket-14.0.0 {[socket -async] when server only listens on IPv4} \
+ -constraints {socket supported_inet localhost_v4} \
+ -setup {
+ proc accept {s a p} {
+ global x
+ puts $s bye
+ close $s
+ set x ok
+ }
+ set server [socket -server accept -myaddr 127.0.0.1 0]
+ set port [lindex [fconfigure $server -sockname] 2]
+ } -body {
+ set client [socket -async localhost $port]
+ set after [after $latency {set x [fconfigure $client -error]}]
+ vwait x
+ set x
+ } -cleanup {
+ after cancel $after
+ close $server
+ close $client
+ unset x
+ } -result ok
+test socket-14.0.1 {[socket -async] when server only listens on IPv6} \
+ -constraints {socket supported_inet6 localhost_v6} \
+ -setup {
+ proc accept {s a p} {
+ global x
+ puts $s bye
+ close $s
+ set x ok
+ }
+ set server [socket -server accept -myaddr ::1 0]
+ set port [lindex [fconfigure $server -sockname] 2]
+ } -body {
+ set client [socket -async localhost $port]
+ set after [after $latency {set x [fconfigure $client -error]}]
+ vwait x
+ set x
+ } -cleanup {
+ after cancel $after
+ close $server
+ close $client
+ unset x
+ } -result ok
+test socket-14.1 {[socket -async] fileevent while still connecting} \
+ -constraints {socket} \
+ -setup {
+ proc accept {s a p} {
+ global x
+ puts $s bye
+ close $s
+ lappend x ok
+ }
+ set server [socket -server accept -myaddr localhost 0]
+ set port [lindex [fconfigure $server -sockname] 2]
+ set x ""
+ } -body {
+ set client [socket -async localhost $port]
+ fileevent $client writable {
+ lappend x [fconfigure $client -error]
+ fileevent $client writable {}
+ }
+ set after [after $latency {lappend x timeout}]
+ while {[llength $x] < 2 && "timeout" ni $x} {
+ vwait x
+ }
+ lsort $x; # we only want to see both events, the order doesn't matter
+ } -cleanup {
+ after cancel $after
+ close $server
+ close $client
+ unset x
+ } -result {{} ok}
+test socket-14.2 {[socket -async] fileevent connection refused} \
+ -constraints {socket} \
+ -body {
+ set client [socket -async localhost [randport]]
+ fileevent $client writable {set x ok}
+ set after [after $latency {set x timeout}]
+ vwait x
+ after cancel $after
+ lappend x [fconfigure $client -error]
+ } -cleanup {
+ after cancel $after
+ close $client
+ unset x after client
+ } -result {ok {connection refused}}
+test socket-14.3 {[socket -async] when server only listens on IPv6} \
+ -constraints {socket supported_inet6 localhost_v6} \
+ -setup {
+ proc accept {s a p} {
+ global x
+ puts $s bye
+ close $s
+ set x ok
+ }
+ set server [socket -server accept -myaddr ::1 0]
+ set port [lindex [fconfigure $server -sockname] 2]
+ } -body {
+ set client [socket -async localhost $port]
+ set after [after $latency {set x [fconfigure $client -error]}]
+ vwait x
+ set x
+ } -cleanup {
+ after cancel $after
+ close $server
+ close $client
+ unset x
+ } -result ok
+test socket-14.4 {[socket -async] and both, readdable and writable fileevents} \
+ -constraints {socket} \
+ -setup {
+ proc accept {s a p} {
+ puts $s bye
+ close $s
+ }
+ set server [socket -server accept -myaddr localhost 0]
+ set port [lindex [fconfigure $server -sockname] 2]
+ set x ""
+ } -body {
+ set client [socket -async localhost $port]
+ fileevent $client writable {
+ lappend x [fconfigure $client -error]
+ fileevent $client writable {}
+ }
+ fileevent $client readable {lappend x [gets $client]}
+ set after [after $latency {lappend x timeout}]
+ while {[llength $x] < 2 && "timeout" ni $x} {
+ vwait x
+ }
+ lsort $x
+ } -cleanup {
+ after cancel $after
+ close $client
+ close $server
+ unset x
+ } -result {{} bye}
+# FIXME: we should also have an IPv6 counterpart of this
+test socket-14.5 {[socket -async] which fails before any connect() can be made} \
+ -constraints {socket supported_inet} \
+ -body {
+ # address from rfc5737
+ socket -async -myaddr 192.0.2.42 127.0.0.1 [randport]
+ } \
+ -returnCodes 1 \
+ -result {couldn't open socket: cannot assign requested address}
+test socket-14.6.0 {[socket -async] with no event loop and server listening on IPv4} \
+ -constraints {socket supported_inet localhost_v4} \
+ -setup {
+ proc accept {s a p} {
+ global x
+ puts $s bye
+ close $s
+ set x ok
+ }
+ set server [socket -server accept -myaddr 127.0.0.1 0]
+ set port [lindex [fconfigure $server -sockname] 2]
+ set x ""
+ } \
+ -body {
+ set client [socket -async localhost $port]
+ for {set i 0} {$i < 50} {incr i } {
+ update
+ if {$x ne ""} {
+ lappend x [gets $client]
+ break
+ }
+ after 100
+ }
+ set x
+ } \
+ -cleanup {
+ close $server
+ close $client
+ unset x
+ } \
+ -result {ok bye}
+test socket-14.6.1 {[socket -async] with no event loop and server listening on IPv6} \
+ -constraints {socket supported_inet6 localhost_v6} \
+ -setup {
+ proc accept {s a p} {
+ global x
+ puts $s bye
+ close $s
+ set x ok
+ }
+ set server [socket -server accept -myaddr ::1 0]
+ set port [lindex [fconfigure $server -sockname] 2]
+ set x ""
+ } \
+ -body {
+ set client [socket -async localhost $port]
+ for {set i 0} {$i < 50} {incr i } {
+ update
+ if {$x ne ""} {
+ lappend x [gets $client]
+ break
+ }
+ after 100
+ }
+ set x
+ } \
+ -cleanup {
+ close $server
+ close $client
+ unset x
+ } \
+ -result {ok bye}
+test socket-14.7.0 {pending [socket -async] and blocking [gets], server is IPv4} \
+ -constraints {socket supported_inet localhost_v4} \
+ -setup {
+ makeFile {
+ fileevent stdin readable exit
+ set server [socket -server accept -myaddr 127.0.0.1 0]
+ proc accept {s h p} {puts $s ok; close $s; set ::x 1}
+ puts [lindex [fconfigure $server -sockname] 2]
+ flush stdout
+ vwait x
+ } script
+ set fd [open |[list [interpreter] script] RDWR]
+ set port [gets $fd]
+ } -body {
+ set sock [socket -async localhost $port]
+ list [fconfigure $sock -error] [gets $sock] [fconfigure $sock -error]
+ } -cleanup {
+ close $fd
+ close $sock
+ removeFile script
+ } -result {{} ok {}}
+test socket-14.7.1 {pending [socket -async] and blocking [gets], server is IPv6} \
+ -constraints {socket supported_inet6 localhost_v6} \
+ -setup {
+ makeFile {
+ fileevent stdin readable exit
+ set server [socket -server accept -myaddr ::1 0]
+ proc accept {s h p} {puts $s ok; close $s; set ::x 1}
+ puts [lindex [fconfigure $server -sockname] 2]
+ flush stdout
+ vwait x
+ } script
+ set fd [open |[list [interpreter] script] RDWR]
+ set port [gets $fd]
+ } -body {
+ set sock [socket -async localhost $port]
+ list [fconfigure $sock -error] [gets $sock] [fconfigure $sock -error]
+ } -cleanup {
+ close $fd
+ close $sock
+ removeFile script
+ } -result {{} ok {}}
+test socket-14.7.2 {pending [socket -async] and blocking [gets], no listener} \
+ -constraints {socket} \
+ -body {
+ set sock [socket -async localhost [randport]]
+ catch {gets $sock} x
+ list $x [fconfigure $sock -error] [fconfigure $sock -error]
+ } -cleanup {
+ close $sock
+ } -match glob -result {{error reading "sock*": socket is not connected} {connection refused} {}}
+test socket-14.8.0 {pending [socket -async] and nonblocking [gets], server is IPv4} \
+ -constraints {socket supported_inet localhost_v4} \
+ -setup {
+ makeFile {
+ fileevent stdin readable exit
+ set server [socket -server accept -myaddr 127.0.0.1 0]
+ proc accept {s h p} {puts $s ok; close $s; set ::x 1}
+ puts [lindex [fconfigure $server -sockname] 2]
+ flush stdout
+ vwait x
+ } script
+ set fd [open |[list [interpreter] script] RDWR]
+ set port [gets $fd]
+ } -body {
+ set sock [socket -async localhost $port]
+ fconfigure $sock -blocking 0
+ for {set i 0} {$i < 50} {incr i } {
+ if {[catch {gets $sock} x] || $x ne "" || ![fblocked $sock]} break
+ after 200
+ }
+ set x
+ } -cleanup {
+ close $fd
+ close $sock
+ removeFile script
+ } -result {ok}
+test socket-14.8.1 {pending [socket -async] and nonblocking [gets], server is IPv6} \
+ -constraints {socket supported_inet6 localhost_v6} \
+ -setup {
+ makeFile {
+ fileevent stdin readable exit
+ set server [socket -server accept -myaddr ::1 0]
+ proc accept {s h p} {puts $s ok; close $s; set ::x 1}
+ puts [lindex [fconfigure $server -sockname] 2]
+ flush stdout
+ vwait x
+ } script
+ set fd [open |[list [interpreter] script] RDWR]
+ set port [gets $fd]
+ } -body {
+ set sock [socket -async localhost $port]
+ fconfigure $sock -blocking 0
+ for {set i 0} {$i < 50} {incr i } {
+ if {[catch {gets $sock} x] || $x ne "" || ![fblocked $sock]} break
+ after 200
+ }
+ set x
+ } -cleanup {
+ close $fd
+ close $sock
+ removeFile script
+ } -result {ok}
+test socket-14.8.2 {pending [socket -async] and nonblocking [gets], no listener} \
+ -constraints {socket} \
+ -body {
+ set sock [socket -async localhost [randport]]
+ fconfigure $sock -blocking 0
+ for {set i 0} {$i < 50} {incr i } {
+ if {[catch {gets $sock} x] || $x ne "" || ![fblocked $sock]} break
+ after 200
+ }
+ list $x [fconfigure $sock -error] [fconfigure $sock -error]
+ } -cleanup {
+ close $sock
+ } -match glob -result {{error reading "sock*": socket is not connected} {connection refused} {}}
+test socket-14.9.0 {pending [socket -async] and blocking [puts], server is IPv4} \
+ -constraints {socket supported_inet localhost_v4} \
+ -setup {
+ makeFile {
+ fileevent stdin readable exit
+ set server [socket -server accept -myaddr 127.0.0.1 0]
+ proc accept {s h p} {set ::x $s}
+ puts [lindex [fconfigure $server -sockname] 2]
+ flush stdout
+ vwait x
+ puts [gets $x]
+ } script
+ set fd [open |[list [interpreter] script] RDWR]
+ set port [gets $fd]
+ } -body {
+ set sock [socket -async localhost $port]
+ puts $sock ok
+ flush $sock
+ list [fconfigure $sock -error] [gets $fd]
+ } -cleanup {
+ close $fd
+ close $sock
+ removeFile script
+ } -result {{} ok}
+test socket-14.9.1 {pending [socket -async] and blocking [puts], server is IPv6} \
+ -constraints {socket supported_inet6 localhost_v6} \
+ -setup {
+ makeFile {
+ fileevent stdin readable exit
+ set server [socket -server accept -myaddr ::1 0]
+ proc accept {s h p} {set ::x $s}
+ puts [lindex [fconfigure $server -sockname] 2]
+ flush stdout
+ vwait x
+ puts [gets $x]
+ } script
+ set fd [open |[list [interpreter] script] RDWR]
+ set port [gets $fd]
+ } -body {
+ set sock [socket -async localhost $port]
+ puts $sock ok
+ flush $sock
+ list [fconfigure $sock -error] [gets $fd]
+ } -cleanup {
+ close $fd
+ close $sock
+ removeFile script
+ } -result {{} ok}
+test socket-14.10.0 {pending [socket -async] and nonblocking [puts], server is IPv4} \
+ -constraints {socket supported_inet localhost_v4} \
+ -setup {
+ makeFile {
+ fileevent stdin readable exit
+ set server [socket -server accept -myaddr 127.0.0.1 0]
+ proc accept {s h p} {set ::x $s}
+ puts [lindex [fconfigure $server -sockname] 2]
+ flush stdout
+ vwait x
+ puts [gets $x]
+ } script
+ set fd [open |[list [interpreter] script] RDWR]
+ set port [gets $fd]
+ } -body {
+ set sock [socket -async localhost $port]
+ fconfigure $sock -blocking 0
+ puts $sock ok
+ flush $sock
+ fileevent $fd readable {set x 1}
+ vwait x
+ list [fconfigure $sock -error] [gets $fd]
+ } -cleanup {
+ close $fd
+ close $sock
+ removeFile script
+ } -result {{} ok}
+test socket-14.10.1 {pending [socket -async] and nonblocking [puts], server is IPv6} \
+ -constraints {socket supported_inet6 localhost_v6} \
+ -setup {
+ makeFile {
+ fileevent stdin readable exit
+ set server [socket -server accept -myaddr ::1 0]
+ proc accept {s h p} {set ::x $s}
+ puts [lindex [fconfigure $server -sockname] 2]
+ flush stdout
+ vwait x
+ puts [gets $x]
+ } script
+ set fd [open |[list [interpreter] script] RDWR]
+ set port [gets $fd]
+ } -body {
+ set sock [socket -async localhost $port]
+ fconfigure $sock -blocking 0
+ puts $sock ok
+ flush $sock
+ fileevent $fd readable {set x 1}
+ vwait x
+ list [fconfigure $sock -error] [gets $fd]
+ } -cleanup {
+ close $fd
+ close $sock
+ removeFile script
+ } -result {{} ok}
+test socket-14.11.0 {pending [socket -async] and nonblocking [puts], no listener, no flush} \
+ -constraints {socket} \
+ -body {
+ set sock [socket -async localhost [randport]]
+ fconfigure $sock -blocking 0
+ puts $sock ok
+ fileevent $sock writable {set x 1}
+ vwait x
+ close $sock
+ } -cleanup {
+ catch {close $sock}
+ unset x
+ } -result {socket is not connected} -returnCodes 1
+test socket-14.11.1 {pending [socket -async] and nonblocking [puts], no listener, flush} \
+ -constraints {socket nonPortable} \
+ -body {
+ set sock [socket -async localhost [randport]]
+ fconfigure $sock -blocking 0
+ puts $sock ok
+ flush $sock
+ fileevent $sock writable {set x 1}
+ vwait x
+ close $sock
+ } -cleanup {
+ catch {close $sock}
+ catch {unset x}
+ } -result {socket is not connected} -returnCodes 1
+test socket-14.12 {[socket -async] background progress triggered by [fconfigure -error]} \
+ -constraints {socket} \
+ -body {
+ set s [socket -async localhost [randport]]
+ for {set i 0} {$i < 50} {incr i} {
+ set x [fconfigure $s -error]
+ if {$x != ""} break
+ after 200
+ }
+ set x
+ } -cleanup {
+ close $s
+ unset x s
+ } -result {connection refused}
+
+test socket-14.13 {testing writable event when quick failure} \
+ -constraints {socket win supported_inet} \
+ -body {
+ # Test for bug 336441ed59 where a quick background fail was ignored
+
+ # Test only for windows as socket -async 255.255.255.255 fails
+ # directly on unix
+
+ # The following connect should fail very quickly
+ set a1 [after 2000 {set x timeout}]
+ set s [socket -async 255.255.255.255 43434]
+ fileevent $s writable {set x writable}
+ vwait x
+ set x
+} -cleanup {
+ catch {close $s}
+ after cancel $a1
+} -result writable
+
+test socket-14.14 {testing fileevent readable on failed async socket connect} \
+ -constraints {socket} -body {
+ # Test for bug 581937ab1e
+
+ set a1 [after 5000 {set x timeout}]
+ # This connect should fail
+ set s [socket -async localhost [randport]]
+ fileevent $s readable {set x readable}
+ vwait x
+ set x
+} -cleanup {
+ catch {close $s}
+ after cancel $a1
+} -result readable
+
+test socket-14.15 {blocking read on async socket should not trigger event handlers} \
+ -constraints socket -body {
+ set s [socket -async localhost [randport]]
+ set x ok
+ fileevent $s writable {set x fail}
+ catch {read $s}
+ close $s
+ set x
+ } -result ok
+
+# v4 and v6 is required to prevent that the async connect does not terminate
+# before the fconfigure command. There is always an additional ip to try.
+test socket-14.16 {empty -peername while [socket -async] connecting} \
+ -constraints {socket localhost_v4 localhost_v6} \
+ -body {
+ set client [socket -async localhost [randport]]
+ fconfigure $client -peername
+ } -cleanup {
+ catch {close $client}
+ } -result {}
+
+# v4 and v6 is required to prevent that the async connect does not terminate
+# before the fconfigure command. There is always an additional ip to try.
+test socket-14.17 {empty -sockname while [socket -async] connecting} \
+ -constraints {socket localhost_v4 localhost_v6} \
+ -body {
+ set client [socket -async localhost [randport]]
+ fconfigure $client -sockname
+ } -cleanup {
+ catch {close $client}
+ } -result {}
+
+# test for bug c6ed4acfd8: running async socket connect with other connect
+# established will block tcl as it goes in an infinite loop in vwait
+test socket-14.18 {bug c6ed4acfd8: running async socket connect made other connect block} \
+ -constraints {socket} \
+ -body {
+ proc accept {channel address port} {}
+ set port [randport]
+ set ssock [socket -server accept $port]
+ set csock1 [socket -async localhost [randport]]
+ set csock2 [socket localhost $port]
+ after 1000 {set done ok}
+ vwait done
+} -cleanup {
+ catch {close $ssock}
+ catch {close $csock1}
+ catch {close $csock2}
+ } -result {}
+
+set num 0
+
+set x {localhost {socket} 127.0.0.1 {supported_inet} ::1 {supported_inet6}}
+set resultok {-result "sock*" -match glob}
+set resulterr {
+ -result {couldn't open socket: connection refused}
+ -returnCodes 1
+}
+foreach {servip sc} $x {
+ foreach {cliip cc} $x {
+ set constraints socket
+ lappend constraints $sc $cc
+ set result $resulterr
+ switch -- [lsort -unique [list $servip $cliip]] {
+ localhost - 127.0.0.1 - ::1 {
+ set result $resultok
+ }
+ {127.0.0.1 localhost} {
+ if {[testConstraint localhost_v4]} {
+ set result $resultok
+ }
+ }
+ {::1 localhost} {
+ if {[testConstraint localhost_v6]} {
+ set result $resultok
+ }
+ }
+ }
+ test socket-15.1.$num "Connect to $servip from $cliip" \
+ -constraints $constraints -setup {
+ set server [socket -server accept -myaddr $servip 0]
+ proc accept {s h p} { close $s }
+ set port [lindex [fconfigure $server -sockname] 2]
+ } -body {
+ set s [socket $cliip $port]
+ } -cleanup {
+ close $server
+ catch {close $s}
+ } {*}$result
+ incr num
+ }
+}
+
+::tcltest::cleanupTests
+flush stdout
+return
+
+# Local Variables:
+# mode: tcl
+# fill-column: 78
+# End: