OpenFPGA/libs/EXTERNAL/tcl8.6.12/tests/socket.test

2506 lines
76 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
::tcltest::loadTestedCommands
# A bad interaction between socket creation, macOS, and unattended CI
# environments make this whole file impractical to run; too many weird hangs.
if {[info exists ::env(MAC_CI)]} {
return
}
# 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 {} {
# firstly try dynamic port via server-socket(0):
set port 0x7fffffff
catch {
set port [lindex [fconfigure [set s [socket -server {} 0]] -sockname] 2]
close $s
}
while {[catch {
close [socket -server {} $port]
} msg]} {
if {[incr i] > 1000} {return -code error "too many iterations to get free random port: $msg"}
# try random port:
set port [expr {int(rand()*16383+49152)}]
}
return $port
}
# 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 200ms
set latency [expr {$lat1 > $lat2 ? $lat1 : $lat2}]
set latency [expr {$latency > 200 ? $latency : 200}]
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] >= 0} {
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
}
# Some tests in this file are known to hang *occasionally* on OSX; stop the
# worst offenders.
testConstraint notOSX [expr {$::tcl_platform(os) ne "Darwin"}]
# Here "Windows" means derived platforms as Cygwin or Msys2 too.
testConstraint notWindows [expr {![regexp {^(Windows|MSYS|CYGWIN)} $::tcl_platform(os)]}]
# ----------------------------------------------------------------------
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 $latency {set x 1}; # Spurious failures in Travis CI, if we do [after idle]
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 notOSX notWindows] -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 notOSX notWindows] -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 unixOrWin] -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]
proc transf_test {{testmode transfer} {maxIter 1000} {maxTime 10000}} {
try {
set ::count 0
set ::testmode $testmode
set port 0
set srvsock {}
# if binding on port 0 is not possible (system related, blocked on ISPs etc):
if {[catch {close [socket -async $::localhost $port]}]} {
# simplest server on random port (immediatelly closing a connect):
set port [randport]
set srvsock [socket -server {apply {{ch args} {close $ch}}} -myaddr $::localhost $port]
# socket on windows has some issues yet (e. g. bug [b6d0d8cc2c]), so we simply decrease iteration count (to 1/4):
if {$::tcl_platform(platform) eq "windows" && $maxIter > 50} {
set ::count [expr {$maxIter / 4 * 3 - 1}]; # bypass 3/4 iterations
}
}
tcltest::DebugPuts 2 "== test \[$::localhost\]:$port $testmode =="
set ::parent [thread::id]
# helper thread creating async connection and initiating transfer (detach) to parent:
set ::helper [thread::create]
thread::send -async $::helper [list \
lassign [list $::parent $::localhost $port $testmode] \
::parent ::localhost ::port ::testmode
]
thread::send -async $::helper {
set ::helper [thread::id]
proc iteration {args} {
set fd [socket -async $::localhost $::port]
if {"helper-writable" in $::testmode} {;# to test both sides during connect
fileevent $fd writable [list apply {{fd} {
if {[thread::id] ne $::helper} {
thread::send -async $::parent {set ::count "ERROR: invalid thread, $::helper is expecting"}
close $fd
return
}
}} $fd]
};#
thread::detach $fd
thread::send -async $::parent [list transf_parent $fd {*}$args]
}
iteration first
}
# parent proc commiting transfer attempt (attach) and checking acquire was successful:
proc transf_parent {fd args} {
tcltest::DebugPuts 2 "** trma / $::count ** $args **"
thread::attach $fd
if {"parent-close" in $::testmode} {;# to test close during connect
set ::count $::count
close $fd
return
};#
fileevent $fd writable [list apply {{fd} {
if {[thread::id] ne $::parent} {
thread::send -async $::parent {set ::count "ERROR: invalid thread, $::parent is expecting"}
close $fd
return
}
set ::count $::count
close $fd
}} $fd]
}
# repeat maxIter times (up to maxTime ms as timeout):
set tout [after $maxTime {set ::count "TIMEOUT"}]
while 1 {
vwait ::count
if {![string is integer $::count]} {
# if timeout just skip (test was successful until now):
if {$::count eq "TIMEOUT"} {::tcltest::Skip "timing issue"}
break
}
if {[incr ::count] >= $maxIter} break
tcltest::DebugPuts 2 "** iter / $::count **"
thread::send -async $::helper [list iteration nr $::count]
}
update
set ::count
} finally {
catch {after cancel $tout}
if {$srvsock ne {}} {close $srvsock}
if {[info exists ::helper]} {thread::release -wait $::helper}
tcltest::DebugPuts 2 "== stop / $::count =="
unset -nocomplain ::count ::testmode ::parent ::helper
}
}
test socket_$af-13.2.tr1 {Testing socket transfer between threads during async connect} -body {
transf_test {transfer} 1000
} -result 1000 -constraints [list socket supported_$af thread]
test socket_$af-13.2.tr2 {Testing socket transfer between threads during async connect} -body {
transf_test {transfer helper-writable} 100
} -result 100 -constraints [list socket supported_$af thread]
test socket_$af-13.2.cl1 {Testing socket transfer between threads during async connect} -body {
transf_test {parent-close} 100
} -result 100 -constraints [list socket supported_$af thread]
test socket_$af-13.2.cl2 {Testing socket transfer between threads during async connect} -body {
transf_test {parent-close helper-writable} 100
} -result 100 -constraints [list socket supported_$af thread]
catch {rename transf_parent {}}
rename transf_test {}
# ----------------------------------------------------------------------
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} -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]
} -constraints {socket supported_inet localhost_v4} -body {
set client [socket -async localhost $port]
set after [after $latency {set x [fconfigure $client -error]}]
vwait x
set x
} -cleanup {
catch {after cancel $after}
catch {close $server}
catch {close $client}
unset -nocomplain x
} -result ok
test socket-14.0.1 {[socket -async] when server only listens on IPv6} -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]
} -constraints {socket supported_inet6 localhost_v6} -body {
set client [socket -async localhost $port]
set after [after $latency {set x [fconfigure $client -error]}]
vwait x
set x
} -cleanup {
catch {after cancel $after}
catch {close $server}
catch {close $client}
unset -nocomplain x
} -result ok
test socket-14.1 {[socket -async] fileevent while still connecting} -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 ""
} -constraints socket -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 {
catch {after cancel $after}
catch {close $server}
catch {close $client}
unset -nocomplain x
} -result {{} ok}
test socket-14.2 {[socket -async] fileevent connection refused} -setup {
set after [after $latency set x timeout]
} -body {
set client [socket -async localhost [randport]]
fileevent $client writable {set x ok}
vwait x
lappend x [fconfigure $client -error]
} -constraints socket -cleanup {
catch {after cancel $after}
catch {close $client}
unset -nocomplain x after client
} -result {ok {connection refused}}
test socket-14.3 {[socket -async] when server only listens on IPv6} -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]
} -constraints {socket supported_inet6 localhost_v6} -body {
set client [socket -async localhost $port]
set after [after $latency {set x [fconfigure $client -error]}]
vwait x
set x
} -cleanup {
catch {after cancel $after}
catch {close $server}
catch {close $client}
unset -nocomplain x
} -result ok
test socket-14.4 {[socket -async] and both, readdable and writable fileevents} -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 ""
} -constraints socket -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 {
catch {after cancel $after}
catch {close $client}
catch {close $server}
unset -nocomplain 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} -body {
# address from rfc5737
socket -async -myaddr 192.0.2.42 127.0.0.1 [randport]
} -constraints {socket supported_inet notOSX} -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} -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 ""
} -constraints {socket supported_inet localhost_v4} -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 {
catch {close $server}
catch {close $client}
unset -nocomplain x
} -result {ok bye}
test socket-14.6.1 {[socket -async] with no event loop and server listening on IPv6} -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 ""
} -constraints {socket supported_inet6 localhost_v6} -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 {
catch {close $server}
catch {close $client}
unset -nocomplain x
} -result {ok bye}
test socket-14.7.0 {pending [socket -async] and blocking [gets], server is IPv4} -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]
} -constraints {socket supported_inet localhost_v4 notOSX} -body {
set sock [socket -async localhost $port]
list [fconfigure $sock -error] [gets $sock] [fconfigure $sock -error]
} -cleanup {
catch {close $fd}
catch {close $sock}
removeFile script
} -result {{} ok {}}
test socket-14.7.1 {pending [socket -async] and blocking [gets], server is IPv6} -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]
} -constraints {socket supported_inet6 localhost_v6 notOSX} -body {
set sock [socket -async localhost $port]
list [fconfigure $sock -error] [gets $sock] [fconfigure $sock -error]
} -cleanup {
catch {close $fd}
catch {close $sock}
removeFile script
} -result {{} ok {}}
test socket-14.7.2 {pending [socket -async] and blocking [gets], no listener} -setup {
set sock [socket -server error 0]
set unusedPort [lindex [fconfigure $sock -sockname] 2]
close $sock
} -body {
set sock [socket -async localhost $unusedPort]
catch {gets $sock} x
list $x [fconfigure $sock -error] [fconfigure $sock -error]
} -constraints {socket notOSX} -cleanup {
catch {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} -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]
} -constraints {socket supported_inet localhost_v4} -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 {
catch {close $fd}
catch {close $sock}
removeFile script
} -result {ok}
test socket-14.8.1 {pending [socket -async] and nonblocking [gets], server is IPv6} -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]
} -constraints {socket supported_inet6 localhost_v6} -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 {
catch {close $fd}
catch {close $sock}
removeFile script
} -result {ok}
test socket-14.8.2 {pending [socket -async] and nonblocking [gets], no listener} -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]
} -constraints socket -cleanup {
catch {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} -setup {
makeFile {
fileevent stdin readable exit
after 10000 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]
} -constraints {socket supported_inet localhost_v4 notOSX} -body {
set sock [socket -async localhost $port]
puts $sock ok
flush $sock
list [fconfigure $sock -error] [gets $fd]
} -cleanup {
catch {close $fd}
catch {close $sock}
removeFile script
} -result {{} ok}
test socket-14.9.1 {pending [socket -async] and blocking [puts], server is IPv6} -setup {
makeFile {
fileevent stdin readable exit
after 10000 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]
} -constraints {socket supported_inet6 localhost_v6 notOSX} -body {
set sock [socket -async localhost $port]
puts $sock ok
flush $sock
list [fconfigure $sock -error] [gets $fd]
} -cleanup {
catch {close $fd}
catch {close $sock}
removeFile script
} -result {{} ok}
test socket-14.10.0 {pending [socket -async] and nonblocking [puts], server is IPv4} -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]
set after [after $latency set x timeout]
} -constraints {socket supported_inet localhost_v4} -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 {
after cancel $after
catch {close $fd}
catch {close $sock}
removeFile script
} -result {{} ok}
test socket-14.10.1 {pending [socket -async] and nonblocking [puts], server is IPv6} -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]
set after [after $latency set x timeout]
} -constraints {socket supported_inet6 localhost_v6} -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 {
after cancel $after
catch {close $fd}
catch {close $sock}
removeFile script
} -result {{} ok}
test socket-14.11.0 {pending [socket -async] and nonblocking [puts], no listener, no flush} -setup {
set after [after $latency set x timeout]
} -body {
set sock [socket -async localhost [randport]]
fconfigure $sock -blocking 0
puts $sock ok
fileevent $sock writable {set x 1}
vwait x
close $sock
} -constraints socket -cleanup {
after cancel $after
catch {close $sock}
unset -nocomplain x
} -result {socket is not connected} -returnCodes 1
test socket-14.11.1 {pending [socket -async] and nonblocking [puts], no listener, flush} -setup {
set after [after $latency set x timeout]
} -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
} -constraints {socket nonPortable} -cleanup {
after cancel $timeout
catch {close $sock}
unset -nocomplain x
} -result {socket is not connected} -returnCodes 1
test socket-14.12 {[socket -async] background progress triggered by [fconfigure -error]} -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
} -constraints socket -cleanup {
catch {close $s}
unset -nocomplain x s
} -result {connection refused}
test socket-14.13 {testing writable event when quick failure} -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 $latency {set x timeout}]
set s [socket -async 255.255.255.255 43434]
fileevent $s writable {set x writable}
vwait x
set x
} -constraints {socket win supported_inet} -cleanup {
catch {close $s}
after cancel $a1
} -result writable
test socket-14.14 {testing fileevent readable on failed async socket connect} -body {
# Test for bug 581937ab1e
set a1 [after $latency {set x timeout}]
# This connect should fail
set s [socket -async localhost [randport]]
fileevent $s readable {set x readable}
vwait x
set x
} -constraints socket -cleanup {
catch {close $s}
after cancel $a1
} -result readable
test socket-14.15 {blocking read on async socket should not trigger event handlers} -setup {
set subprocess [open "|[list [interpreter]]" r+]
fconfigure $subprocess -blocking 0 -buffering none
} -constraints socket -body {
puts $subprocess {
set s [socket -async localhost [randport]]
set x ok
fileevent $s writable {set x fail}
catch {read $s}
close $s
puts $x
exit
}
set after [after $latency set x timeout]
fileevent $subprocess readable [list gets $subprocess x]
vwait x
return $x
} -cleanup {
catch {after cancel $after}
if {![testConstraint win]} {
catch {exec kill [pid $subprocess]}
}
catch {close $subprocess}
unset -nocomplain 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} -body {
set client [socket -async localhost [randport]]
fconfigure $client -peername
} -constraints {socket localhost_v4 localhost_v6 notOSX} -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} -body {
set client [socket -async localhost [randport]]
fconfigure $client -sockname
} -constraints {socket localhost_v4 localhost_v6 notOSX} -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} -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
} -constraints {socket notOSX} -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 [list socket $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" -setup {
set server [socket -server accept -myaddr $servip 0]
proc accept {s h p} { close $s }
set port [lindex [fconfigure $server -sockname] 2]
} -constraints $constraints -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: