# ns sims.tcl -flows 1 -period -seed 0 -minrto 0.2 -periodic 1
#
# RTO = 2*RTT
# Periodic
# ./sims.com
# awk -f process.awk periodic.data > periodic.nums
# awk -f ave.awk periodic.nums
#
# Random
# ./sims1.com
# awk -f process.awk uniform.data > uniform.nums
# awk -f ave.awk uniform.nums
# ./sims2.com
# awk -f process.awk uniform1.data > uniform1.nums
# awk -f ave.awk uniform1.nums
#
# RTO = 10*RTT
# Periodic
# ./sims4.com
# awk -f process.awk periodic.10.data > periodic.10.nums
# awk -f ave.awk periodic.10.nums
#
# Random
# ./sims5.com
# awk -f process.awk uniform.10.data > uniform.10.nums
# awk -f ave.awk uniform.10.nums
# ./sims6.com
# awk -f process.awk uniform1.10.data > uniform1.10.nums
# awk -f ave.awk uniform1.10.nums

# General Parameters
#####################################################################
set opt(title) zero	;
set opt(seed) -1	;
set opt(stop) 10000	;# Stop time.
set opt(ecn) 0		;
set opt(period) 0       ;# Period (in pkts) for packet drop rate.
set opt(periodic) 0     ;# 1 for periodic instead of random drops.
set opt(def_drop) 0     ;# 0 to drop 1 in period; 1 to not-drop 1
#####################################################################
# Topology
#####################################################################
set opt(rate) 10	;# speed of congested link in Mbps
set opt(delay) 10	;# delay of congested link in ms
set opt(secondDelay) 20	;# average delay of access links in ms
set opt(rtts) 1		;# 1 for a range of delays for the access links.
#####################################################################
# AQM parameters
#####################################################################
set opt(minth) 30	;
set opt(maxth) 0	;
set opt(adaptive) 1	;# 1 for Adaptive RED, 0 for plain RED 
set opt(queue) DT       ;# 0 for DropTail
			;# 1 for RED
set opt(adaptive) 1	;# 1 for Adaptive RED, 0 for plain RED 
set opt(qsize) 100	;# Queue size in packets.
#####################################################################
# Traffic generation.
#####################################################################
set opt(flows) 1 	;# number of long-lived TCP flows
set opt(window) 1000	;# window for long-lived traffic
set opt(minrto) 0.2	;# minrto in seconds
#####################################################################
# Plotting statistics.
#####################################################################
set opt(intervals) 10	;
set opt(plotQ) 0	;# 1 to plot the instantaneous and average queue 
set opt(printPkts) 1    ;# 1 to print per-connection stats.
set opt(printFIDs) 1	;# 1 to print per-FID stats
#####################################################################

remove-all-packet-headers       ; # removes all except common
add-packet-header Flags IP TCP  ; # hdrs reqd for TCP

proc getopt {argc argv} {
        global opt
        for {set i 0} {$i < $argc} {incr i} {
                set arg [lindex $argv $i]
                if {[string range $arg 0 0] != "-"} continue
                set name [string range $arg 1 end]
                set opt($name) [lindex $argv [expr $i+1]]
                puts "opt($name): $opt($name)" 
        }
}

getopt $argc $argv
## from tcl/ex/diffusion-rate-run.tcl

## set pkts [expr $opt(pagesize) * $opt(objSize)
## puts "One web session:

if {$opt(seed) > -1} {
        #puts "Seeding Random number generator with $opt(seed)"
        ns-random $opt(seed)
}
set quarterTime [expr $opt(stop) / 4.0]

set pktsize 1460
if {$opt(queue) == "DT"} {
  set qm DropTail
}
if {$opt(queue) == "RED"} {
  set qm RED
}
set almosttime [expr $opt(stop)- 0.01]
set halftime [expr $opt(stop)/2]
set tcpTick_ 0.01
Agent/TCP set tcpTick_ $tcpTick_
set out $opt(title)

#plot related functions
set quiet "false"

proc stop {} {
 	exit
}

proc printpkts { label tcp now } {
      global tcpTick_ opt
      set numTicks [$tcp set rtt_]
      set rtt [expr $numTicks * $tcpTick_]
      set pkts1 [$tcp set ack_]
      set pkts [expr $pkts1 + 1]
      puts "time: [format "%5.2f" $now] tcp $label pkts $pkts pkts_sent [$tcp set ndatapack_] rtt [format "%5.3f" $rtt]"
      set ppr [expr $pkts*$rtt/$now]
      puts "time: [format "%5.2f" $now] tcp $label ppr [format "%5.5f" $ppr]"
}

proc printdrops { fid fmon } {
        set fcl [$fmon classifier]; # flow classifier
        set flow [$fcl lookup auto 0 0 $fid]
        if {$flow != ""} {
          puts "fid: $fid per-link total_drops [$flow set pdrops_]"
          puts "fid: $fid per-link total_packets [$flow set pdepartures_]"
        }
}


proc dropPktsPeriodic {link fid offset period def_drop} {
    ErrorModel/Periodic set default_drop_ $def_drop
    set emod [new ErrorModule Fid]
    set errmodel1 [new ErrorModel/Periodic]
    $errmodel1 unit pkt
    $errmodel1 set offset_ $offset
    $errmodel1 set period_ $period
    # Why doesn't the line below work?
    # $errmodel1 set default_drop_ $def_drop
    $link errormodule $emod
    $emod insert $errmodel1
    $emod bind $errmodel1 $fid
}

proc dropPktsUniform {link fid rate} {
    global ns
    set emod [new ErrorModule Fid]
    set errmodel1 [new ErrorModel/Uniform $rate pkt]
    $errmodel1 unit pkt
    $errmodel1 set rate_ $rate
    $link errormodule $emod
    $emod insert $errmodel1
    $emod bind $errmodel1 $fid
    return $errmodel1
}

set ns [new Simulator]
set node_(r1) [$ns node]
set node_(r2) [$ns node]
set node_(r3) [$ns node]


if {$opt(ecn) == 1} {
   Queue/RED set setbit_ true
}
Queue/RED set summarystats_ true
Queue/DropTail set summarystats_ true
Queue/RED set adaptive_ $opt(adaptive)
Queue/RED set q_weight_ 0.0
Queue/RED set thresh_ $opt(minth)
Queue/RED set maxthresh_ $opt(maxth)

Agent/TCP set ecn_ $opt(ecn) 
Agent/TCP set packetSize_ $pktsize
Agent/TCP set window_ $opt(window)
Agent/TCP set minrto_ $opt(minrto)

$ns duplex-link $node_(r1) $node_(r2) [set opt(rate)]Mb [expr $opt(delay)/2]ms $qm
$ns duplex-link $node_(r2) $node_(r3) [set opt(rate)]Mb [expr $opt(delay)/2]ms $qm
Agent/TCP set overhead_ [expr 8*$pktsize/($opt(rate)*1000000) ]

$ns queue-limit $node_(r1) $node_(r2) $opt(qsize)
$ns queue-limit $node_(r2) $node_(r1) $opt(qsize)
$ns queue-limit $node_(r2) $node_(r3) $opt(qsize)
$ns queue-limit $node_(r3) $node_(r2) $opt(qsize)

set slink [$ns link $node_(r1) $node_(r2)] ; 
set rlink [$ns link $node_(r2) $node_(r1)] ; 
set fmon [$ns makeflowmon Fid]
$ns attach-fmon $slink $fmon
set squeue [$slink queue]
set rqueue [$rlink queue]

# Set up forward TCP connection
for {set i 0} {$i < $opt(flows)} {incr i} {
    set node_(s$i) [$ns node]
    set node_(k$i) [$ns node]
    set delay2 $opt(secondDelay)
    set delay2a $opt(secondDelay)
    $ns duplex-link $node_(s$i) $node_(r1) 100Mb [expr $delay2]ms DropTail
    $ns duplex-link $node_(k$i) $node_(r3) 100Mb [expr $delay2a]ms DropTail
    set tcp$i [$ns create-connection TCP/Sack1 $node_(s$i) TCPSink/Sack1 $node_(k$i) 0]
    [set tcp$i] set packetSize_ 500
    set ftp$i [[set tcp$i] attach-app FTP]
    set tmp [new RandomVariable/Uniform]
    set starttime [expr 1.0 * [$tmp value] * $quarterTime ]
    $ns at $starttime "[set ftp$i] start"
    if {$opt(printPkts) == 1} {
      $ns at $halftime "printpkts $i [set tcp$i] $halftime"
      $ns at $almosttime "printpkts $i [set tcp$i] $almosttime"
    }
    $ns at $opt(stop) "[set ftp$i] stop"
}

if {$opt(period) > 0} {
   if {$opt(def_drop) == 0} {
      set droprate [expr 1.0/$opt(period)]
   } else {
      set droprate [expr ($opt(period)-1.0)/$opt(period)]
   }
   puts "droprate: [format "%5.3f" $droprate]"
   if {$opt(periodic) == 1} {
     dropPktsPeriodic [$ns link $node_(r1) $node_(r2)] 0 5 $opt(period) $opt(def_drop)
   } else {
     dropPktsUniform [$ns link $node_(r1) $node_(r2)] 0 $droprate 
   }
}

Agent/TCP set window_ 64
set count 100

if {$opt(printFIDs) == 1 } {
  $ns at [expr $opt(stop) - 0.004]  "printdrops 0 $fmon"
}
$ns at $opt(stop) "stop"

$ns run

