diff -r 000000000000 -r 2b3e5ec03512 test/simple-ftp-noack.tcl
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/simple-ftp-noack.tcl Thu Apr 21 14:57:45 2011 +0100
@@ -0,0 +1,342 @@
+#
+# Copyright 2004-2006 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+
+#
+# Simple client/server code that scans a directory for new data and sends
+# that data to a remote host.
+#
+# usage: simple_ftp server
+# usage: simple_ftp client
+#
+#
+
+set port 17600
+set period 1000
+
+set blocksz 8192
+
+
+
+proc time {} {
+ global starttime
+ return " [clock seconds] :: [expr [clock clicks -milliseconds] - $starttime] :: "
+}
+
+#proc time {} {
+# return [clock seconds]
+#}
+
+proc timef {} {
+ return [clock format [clock seconds]]
+}
+
+proc scan_dir {host dir} {
+ global period
+
+ puts "scanning dir $dir..."
+ set files [glob -nocomplain -- "$dir/*"]
+
+ foreach file $files {
+ file stat $file file_stat
+
+ if {$file_stat(type) != "file"} {
+ continue
+ }
+
+ set len $file_stat(size)
+ if {$len == 0} {
+ continue
+ }
+
+ set sent_file 0
+ while {$sent_file != 1} {
+ set sent_file [send_file $host $file]
+ # after 2000
+ }
+
+ file delete -force $file
+ }
+
+ after $period scan_dir $host $dir
+}
+
+proc ack_arrived {sock} {
+ global got_ack ack_timer
+ after cancel $ack_timer
+ set got_ack 1
+
+ set ack [gets $sock]
+ if [eof $sock] {
+ puts " [time] eof waiting for ack!"
+ set got_ack 0
+ fileevent $sock readable
+ return
+ }
+ if {$ack != "ACK"} {
+ puts "[time] ERROR in ack_arrived: got '$ack', expected ACK"
+ set got_ack 0
+ fileevent $sock readable
+ return
+ }
+}
+
+proc ack_timeout {} {
+ global got_ack
+ set got_ack 0
+ puts " [time] ack_timeout"
+}
+
+proc send_file {host file} {
+ global port
+ global logfd
+ global blocksz
+ global got_ack
+ global ack_timer
+ global sock
+ set fd [open $file]
+
+ puts "[time] trying to send file $file size [file size $file]"
+
+ if {! [info exists sock]} {
+ while { [ catch {socket $host $port } sock] } {
+ puts "[time] Trying to connect, will try again after 2 seconds "
+ after 2000
+ }
+
+ fconfigure $sock -translation binary
+ fconfigure $sock -encoding binary
+ }
+
+ if [catch {
+ puts -nonewline $sock "[file tail $file] "
+ flush $sock
+# after 500
+ puts $sock "[file size $file]"
+ flush $sock
+ }] {
+ puts $sock "[time] failure in sending header "
+ close $sock
+ unset sock
+ close $fd
+ return -1
+ }
+
+ # read the handshake ack
+ # set got_ack -1
+ # fileevent $sock readable "ack_arrived $sock"
+ # set ack_timer [after 10000 ack_timeout]
+ # vwait got_ack
+
+ # if {!$got_ack} {
+ # puts "[time] timeout waiting for handshake ack"
+ # close $fd
+ # close $sock
+ # unset sock
+ # return -1
+ # }
+ # puts "[time] got handshake ack -- sending file"
+
+
+ while {![eof $fd]} {
+ if {[catch {
+ set payload [read $fd $blocksz]
+ puts "[time] sending [string length $payload] byte chunk"
+ puts -nonewline $sock $payload
+ flush $sock
+ } ]} {
+
+ puts "[time] failure at sender "
+ close $sock
+ unset sock
+ close $fd
+ return -1
+ }
+ }
+
+ close $fd
+
+ puts "[time] :: file actually sent $file"
+ puts $logfd "[time] :: file actually sent [file tail $file] "
+ flush $logfd
+
+ return 1
+ # wait for an ack or timeout
+ # puts "[time] sent whole file, waiting for ack"
+ # fconfigure $sock -blocking 0
+ # set got_ack -1
+ # fileevent $sock readable "ack_arrived $sock"
+ # set ack_timer [after 5000 ack_timeout]
+ # vwait got_ack
+
+ # if {$got_ack} {
+ # puts "[time] :: file actually sent $file"
+ # puts $logfd "[time] :: file actually sent [file tail $file] "
+ # flush $logfd
+ #
+ # return 1
+# } else {
+# puts "[time] :: file sent but not acked"
+# close $sock
+# unset sock
+# return -1
+
+ }
+}
+
+proc recv_files {dest_dir} {
+ global port
+ global conns
+ puts "[time] waiting for files: $dest_dir"
+ set conns(main) [socket -server "new_client $dest_dir" $port]
+}
+
+
+proc new_client {dest_dir sock addr port} {
+ global conns
+
+ puts "[time] Accept $sock from $addr port $port"
+
+ # Used for debugging
+ set conns(addr,$sock) [list $addr $port]
+
+ fconfigure $sock -translation binary
+ fconfigure $sock -encoding binary
+ fconfigure $sock -blocking 0
+
+ fileevent $sock readable "header_arrived $dest_dir $sock"
+}
+
+proc header_arrived {dest_dir sock} {
+ global length_remaining
+ global conns
+ global partial
+
+ puts "[time] header arrived"
+
+ if {[eof $sock]} {
+ puts "[time] Close $conns(addr,$sock) EOF received header.. "
+ close $sock
+ unset conns(addr,$sock)
+ return
+ }
+
+ # try to read a line
+ set L [gets $sock]
+ while {$L == ""} {
+ puts "[time] partial header line received... waiting for more"
+ after 20
+ set L [gets $sock]
+ }
+
+ if {[info exists partial($sock)]} {
+ puts "[time] merging partial line '$partial($sock)' with '$L'"
+ set L "$partial($sock)$L"
+ unset partial($sock)
+ }
+
+ foreach {filename length} $L {}
+
+ puts "[time] getting file $filename length $length"
+
+ # puts $sock "ACK"
+ # flush $sock
+
+ set to_fd [open "$dest_dir/$filename" w]
+ set length_remaining($sock) $length
+
+ fileevent $sock readable "file_arrived $filename $to_fd $dest_dir $sock"
+}
+
+
+proc file_arrived {file to_fd dest_dir sock} {
+
+ global logfd
+ global conns
+ global length_remaining
+
+ if {[eof $sock]} {
+ puts "[time] Close $conns(addr,$sock) EOF received file"
+ close $sock
+ unset conns(addr,$sock)
+ return
+ }
+
+
+ set payload [read $sock $length_remaining($sock)]
+ puts -nonewline $to_fd $payload
+ set got [string length $payload]
+ set todo [expr $length_remaining($sock) - $got]
+ puts "got $got byte chunk ($todo to go)"
+
+ if {$todo < 0} {
+ error "negative todo"
+ }
+
+ if {$todo == 0} {
+ # puts $sock "ACK"
+ # flush $sock
+ # puts "[time] sending ack for file $file"
+
+ fileevent $sock readable "header_arrived $dest_dir $sock"
+ puts $logfd "[time] :: got file [file tail $file] at [timef]"
+ close $to_fd
+ flush $logfd
+
+ }
+
+ set length_remaining($sock) $todo
+}
+
+
+# Define a bgerror proc to print the error stack when errors occur in
+# event handlers
+proc bgerror {err} {
+ global errorInfo
+ puts "tcl error: $err\n$errorInfo"
+}
+
+proc usage {} {
+ puts "usage: simple_ftp server "
+ puts "usage: simple_ftp client "
+ exit -1
+}
+
+set argc [llength $argv]
+if {$argc < 3} {
+ usage
+}
+
+
+set mode [lindex $argv 0]
+set dir [lindex $argv 1]
+set logfile [lindex $argv 2]
+set logfd [open $logfile w]
+
+set starttime [clock clicks -milliseconds]
+puts "Starting in $mode, dir is $dir at [timef]"
+
+
+if {$mode == "server"} {
+ recv_files $dir
+} elseif {$mode == "client"} {
+ set host [lindex $argv 3]
+ scan_dir $host $dir
+} else {
+ error "unknown mode $mode"
+}
+
+vwait forever