#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 ns ftp Nconn sender rcv receiver trx N cbr1 receiver1 ftp1
    global send_size connect_int 
    $self instvar node_

    #if it's not sender's close, go away 
    if {$node_ != $trx} {
#	puts "receiver close"
	return
    }
    set N [expr ($N + 1)]
    if {$N > $Nconn} {
	finish
	return
    }

#    if {$N > 1} { $cbr1 stop }		
    puts "starting test $N"
    flush stdout

    #$ms?
    $ns at [expr ($N*$connect_int)] "$rcv reset"
#    $ns at [expr ($N*$connect_int+1)] "$cbr1 start"
    $ns at [expr ($N*$connect_int)] "$ns connect $sender $receiver" 
    $ns at [expr ($N*$connect_int)] "$receiver listen"
    #[expr ($connect_int / 10)]
    $ns at [expr ($N*$connect_int)] "$ftp send $send_size"

#    $ns at [expr ($N*$connect_int)] "$receiver1 listen"
#    $ns at [expr ($N*$connect_int)] "$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

	    #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
#	    eval exec {awk {$1=="+" && $5=="tcp" && $3==$trx_id {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 ..
    $ns halt
    delete $ns
    return
#    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"
	$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
#
######################################################################

#Create a simulator object
set ns [new Simulator]

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

#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 ms [$ns node]
set bs [$ns node]
set is [$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
$ns duplex-link $bs $ms $line_rate $prop_delay DropTail
$ns duplex-link $lp $ms 112kpbs 10ms DropTail 
$ns duplex-link $bs $is 1Mbps 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]

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 $trx $udp1
$ns attach-agent $rcv $null1
set cbr1 [new Application/Traffic/CBR]
$cbr1 set rate_ 10Kb
$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 {$sender done}
    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"

#main entry function for this module
proc run_atp {} {
    global ns
    #Run the simulation
    $ns run
}


