2506 lines
76 KiB
Plaintext
2506 lines
76 KiB
Plaintext
# 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:
|