#a library that allows experimenting with delay spikes
#common for TCP/EIFEL/UDP/TFRC traffic

#local variables
set N 0 
set SynTime 0 
set TotalTime 0 

#procedure called when TCP connection is closed, same for FullTCP?
Agent/TCP instproc done {} { 
    global cbr1	
    $cbr1 stop
}

proc start-test {} {
    global send_size connect_int
    global ns ftp Nconn sender rcv receiver trx N cbr1 receiver1 ftp1

    incr N
    if {$N > $Nconn} {
	$ns after $connect_int "finish"
	return
    } else {	
	$ns after $connect_int "start-test"
    }

    puts "[$ns now]: starting test $N"
    flush stdout

    $rcv reset

    #reset TCP sender	
#    $sender reset	

    $ns connect $sender $receiver

#only for FullTcp?
    $receiver listen

#reuse of TCP agent works fine
    $ns after 0.01 "$ftp send $send_size"

#background traffic
    $ns after 1 "$cbr1 start"
#    $ns after 100 "$cbr1 stop"
#   $receiver1 listen
#   $ftp1 send $send_size
}

#Define a 'finish' procedure
proc finish {} {
    global ns nf tf trx rcv WithNAM N test_name traffic

    #id of nodes that appear in out.tr
    set trx_id [$trx id]
    set rcv_id [$rcv id]

#    puts "$trx_id $rcv_id"
#    set env(trx_id) $trx_id

    $ns flush-trace
    #Close the trace file
    close $nf
    close $tf
   
    #Execute nam on the trace file
    if { $WithNAM } {
	exec nam out.nam &
    }

    switch $traffic {
	EIFEL -
	TCP {
	    #Generate files to plot cwnd and t_seqno over time
	    #	exec echo $test_name >> tcp_goodput.txt 
	    exec awk -f calc_tcp_goodput.awk out.tr >>tcp_goodput.txt
	    exec awk -f calc_timeouts.awk ttl.tr >>tcp_goodput.txt

	    #this used to be eval exec - why?
	    exec echo \"snd_data\" >plots/snd.xgr
	    exec awk -v i=$trx_id {$1=="+" && $5=="tcp" && $3==i {print $2 "\t" $11}} out.tr >>plots/snd.xgr
	    exec echo \n\"snd_ack\" >>plots/snd.xgr
	    exec awk -v i=$trx_id {$1=="r" && $5=="ack" && $4==i {if ($13==0) t=$11; else t=$13; print $2 "\t" t}} out.tr >>plots/snd.xgr
	    exec echo \"rcv_data\" >plots/rcv.xgr
	    exec awk -v i=$rcv_id {$1=="r" && $5=="tcp" && $4==i {print $2 "\t" $11}} out.tr >>plots/rcv.xgr
	    exec echo \n\"rcv_ack\" >>plots/rcv.xgr	
   	    exec awk -v i=$rcv_id {$1=="+" && $5=="ack" && $3==i {if ($13==0) t=$11; else t=$13; print $2 "\t" t}} out.tr >>plots/rcv.xgr

	    cd plots
	    if {$N <10} {
		exec xgraph -P snd.xgr
		exec xgraph -P rcv.xgr
	    }  
	}
	UDP {
	    exec echo \"rcv_data\" >plots/rcv.xgr
	    exec awk -v i=$rcv_id {$1=="r" && $5=="udp" && $4==i {print $2 "\t" $11}} out.tr >>plots/rcv.xgr
	    exec echo \n\"rcv_ttl\" >>plots/rcv.xgr
	    exec cat ttl.tr >>plots/rcv.xgr
	    exec awk -f calc_udp_goodput.awk ttl.tr >>udp_goodput.txt
	    exec rm ttl.tr
	    cd plots
	    if {$N<12} {
		exec xgraph -P rcv.xgr
	    }
	}
	TFRC {
	    exec awk -v i=$trx_id {$1=="+" && $5=="tcpFriend" && $3==i {print $2 "\t" $11}} out.tr >plots/snd_data.plot
	    exec awk -v i=$trx_id {$1=="r" && $5=="tcpFriendCtl" && $4==i {print $2 "\t" $11}} out.tr >plots/snd_ack.plot
	    cd plots
	    exec xgraph -P snd_data.plot snd_ack.plot
	}   
    }
    cd ..
    exit 0
}

proc intercept {} {
	global ns rnd ho_int_min ho_int_max ho_len_min ho_len_max queue_ul queue_dl line_rate
	puts "[$ns now]: Intercept"; flush stdout
	$queue_ul block
	$queue_dl block

	set dly [$rnd uniform $ho_len_min $ho_len_max]
        $ns after $dly "$queue_ul unblock" 
	$ns after $dly "$queue_dl unblock"
        $ns after  [$rnd uniform $ho_int_min $ho_int_max] "intercept"
}

#send one more ADU on top of UDP
proc send_more {} {
    global ns sender N Nconn adu_size connect_int
    set N [expr ($N + 1)]
    if {$N > $Nconn} {
	$ns after 100 finish
	return
    }    
    set_ttl
    $sender set fid_ $N
    $sender send $adu_size
    $ns after $connect_int "send_more"
}

#set TTL field in IP/UDP
proc set_ttl {} {
    global ns sender ATP_TIMESCALE LIFETIME
    set expire_at [expr ($ATP_TIMESCALE * ([$ns now] + $LIFETIME))]
    $sender set ttl_ $expire_at
#    puts "ttl set to [expr ($expire_at/$ATP_TIMESCALE)]"
}

########################################################################
#
# M A I N
#
######################################################################

for { set i 0 } { $i < $argc } { incr i } {
	source [lindex $argv $i]
}

#Create a simulator object
set ns [new Simulator]

#Open the nam trace file
set nf [open out.nam w]
#commented to save disk space
#$ns namtrace-all $nf

# Prepare rnd generation
set rnd [new RNG]

#Create two nodes
set lp [$ns node]
set lp2 [$ns node]
set ms [$ns node]
set bs [$ns node]
set is [$ns node]
set is2 [$ns node]

switch -exact -- $traffic {
    UDP {   #create UDP peers
	# use pkt size of 500 - the default UDP chunk?
	set sender [new Agent/UDP]
	$sender set packetSize_ 700
	set receiver [new Agent/UDP]
    }
    TFRC    {
	set sender [new Agent/TFRC]
	$sender set packetSize_ 700
	set receiver [new Agent/TFRCSink]
    }
    TCP {    #create TCP peers	
#	Agent/TCP set timestamps_ false

#sender: TCP,TCP/Reno,TCP/Newreno,TCP/Sack1,
#TCP/FullTcp,TCP/FullTcp/Tahoe,TCP/FullTcp/Newreno,TCP/FullTcp/Sack
#receiver: TCPSink,TCPSink/DelAck,TCPSink/Sack1,TCPSink/Sack1/DelAck

	set sender [new Agent/$tcp_snd]
	set receiver [new Agent/$tcp_rcv]
#	Agent/TCP/FullTcp set nodelay_ false 
	Agent/TCP set bugFix_ false 
	#useless
	Agent/TCP set ecn_ false 	
	
	Agent/TCP/FullTcp set nam_tracevar_ true
	Agent/TCP/FullTcp set tracevar_ cwnd_   

    }
    EIFEL    {
 	Agent/TCP/FullTcp set timestamps_ true
	set sender [new Agent/TCP/FullTcp/Eifel]
	set receiver [new Agent/TCP/FullTcp/Eifel]
	Agent/TCP/FullTcp/Eifel set nam_tracevar_ true
	Agent/TCP/FullTcp/Eifel set tracevar_ cwnd_
    }
    default {
	puts "Unkown traffic type"
	exit 1
    }
}

#set sender and receiver
#bs or is
set trx $is
#ms or lp
set rcv $lp

#Create a duplex link between the nodes
#temporally took away DropExpired and DropTail
$ns duplex-link $bs $ms $line_rate $prop_delay DropTail
#112
$ns duplex-link $lp $ms 3Mbps 10ms DropTail 
$ns duplex-link $lp2 $ms 3Mbps 10ms DropTail
$ns duplex-link $bs $is 3Mbps 50ms DropTail
$ns duplex-link $bs $is2 3Mbps 50ms DropTail

set link_dl [$ns link $bs $ms]
set link_ul [$ns link $ms $bs] 
$link_dl cost 0
$link_ul cost 0

set queue_dl [$link_dl queue]
set queue_ul [$link_ul queue]

Trace set show_tcphdr_ 1
set tf [open out.tr w]
#$ns trace-all $tf
$ns trace-queue $is $bs $tf
$ns trace-queue $bs $is $tf

if [info exists drop_front_on] { 
 $queue_dl set drop_front_ true
}

if [info exists droplist_dl] {
  set errmodel_dl [new ErrorModel/List] 
  $errmodel_dl droplist $droplist_dl
  #$link_dl install-error $errmodel_dl
  $ns link-lossmodel $errmodel_dl $bs $ms
}

if [info exists droplist_ul] {
  set errmodel_ul [new ErrorModel/List] 
  $errmodel_ul droplist $droplist_ul
  #$link_dl install-error $errmodel_ul
  $ns link-lossmodel $errmodel_ul $ms $bs
}

###
# Configure bottleneck link bs<->ms
###
$ns queue-limit $bs $ms $buf_size
$ns queue-limit $ms $bs $buf_size
#$queue_dl setTtlFix $FixTtl 
#$queue_ul setTtlFix $FixTtl
#$queue_dl expire $expire
#$queue_ul expire $expire

###
# Construct foreground traffic
###
$ns attach-agent $trx $sender
#$sender set close_on_empty_ true
set ftp [new Application/FTP]
$ftp attach-agent $sender
$ns attach-agent $rcv $receiver
$ns connect $sender $receiver


###
# Construct competing CBR traffic
###
set udp1 [new Agent/UDP]
$udp1 set packetSize_ 536
set null1 [new Agent/Null]
$ns attach-agent $is2 $udp1
$ns attach-agent $lp2 $null1
set cbr1 [new Application/Traffic/CBR]
$cbr1 set rate_ $cbr_rate
$cbr1 set packetSize_ 500
$cbr1 attach-agent $udp1
$ns connect $udp1 $null1
##$ns after 10 "$cbr1 start"
#$ns after 100 "$cbr1 stop"

###
# Construct competing TCP traffic
###
set sender1 [new Agent/TCP/Reno]
set receiver1 [new Agent/TCPSink]
$sender1 set eifel_ false
$ns attach-agent $trx $sender1
$ns attach-agent $rcv $receiver1
#$ns connect $sender1 $receiver1
#set ftp1 [new Application/FTP]
#$ftp1 attach-agent $sender1

###
# Construct random error losses
###
#set errg [new ErrorModel]
#$errg set rate_ 0.05
#$ns lossmodel $errg $bs $ms

# Add agent traces and variable trace
$ns add-agent-trace $sender sender
$ns add-agent-trace $receiver receiver
$ns monitor-agent-trace $sender
$ns monitor-agent-trace $receiver

###
# Variable that get recorded into nam trace
###
$sender tracevar cwnd_
$sender tracevar ssthresh_
$sender tracevar maxseq_
$sender tracevar ack_
$sender tracevar t_seqno_
$sender tracevar rtt_
$sender tracevar srtt_
$sender tracevar rttvar_
$sender tracevar backoff_

switch $traffic {
    EIFEL -
    TCP {start-test}
    UDP {$ns after $connect_int "send_more" }
    TFRC {
	$ns after $connect_int "$sender start"
        $ns after 80 "finish"
    }
}

#schedule first delay
$ns after $first_delay "intercept"

$ns run


