diff options
Diffstat (limited to 'tcl8.6/tests/socket.test')
-rw-r--r-- | tcl8.6/tests/socket.test | 2413 |
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: |