# -*- Tcl -*-
# 
# Class for realtime monitoring of link statistics.
# Copyright (c) 2005, Hiroyuki Ohsaki.
# All rights reserved.
# 
# $Id: flowmonitor.tcl,v 1.1 2005/11/02 09:17:33 oosaki Exp $
# 

# This code is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY.  No author or distributor
# accepts responsibility to anyone for the consequences of using it
# or for whether it serves any particular purpose or works at all,
# unless he says so in writing.  Refer to the GNU Emacs General Public
# License for full details.

# Everyone is granted permission to copy, modify and redistribute
# this code, but only under the conditions described in the
# GNU Emacs General Public License.   A copy of this license is
# supposed to have been given to you along with GNU Emacs so you
# can know your rights and responsibilities.  It should be in a
# file named COPYING.  Among other things, the copyright notice
# and this notice must be preserved on all copies.

Class FlowMonitor

# create flowmonitor for all TCP agents, and schedule first hook
# invokation
Simulator instproc init-flowmonitor {start {interval 0.001}} {
  $self instvar fmtbl_

  foreach agent [Agent/TCP info instances] {
    set fmtbl_($agent) [new FlowMonitor $self $agent $start $interval]
    $self at $start "$fmtbl_($agent) hook"
  }
}

# save all argumets for later use
FlowMonitor instproc init {ns agent start {interval 0.001}} {
  $self instvar ns_ agent_ start_ interval_

  set ns_ $ns
  set agent_ $agent
  set start_ $start
  set interval_ $interval
}

# update all stored variables of Agent/TCP
FlowMonitor instproc reset {} {
  $self instvar agent_
  $self instvar ack_ ndatapack_ ndatabytes_ nrexmit_ nrexmitpack_ \
    nrexmitbytes_

  set ack_ [$agent_ set ack_]
  set ndatapack_ [$agent_ set ndatapack_]
  set ndatabytes_ [$agent_ set ndatabytes_]
  set nrexmit_ [$agent_ set nrexmit_]
  set nrexmitpack_ [$agent_ set nrexmitpack_]
  set nrexmitbytes_ [$agent_ set nrexmitbytes_]
}

# fetch Agent/TCP state variables, calcurate statistics, and display
# them in standard output
FlowMonitor instproc hook {} {
  $self instvar ns_ agent_ start_ interval_
  $self instvar ack_ ndatapack_ ndatabytes_ nrexmit_ nrexmitpack_ \
    nrexmitbytes_

  set now [$ns_ now]
  if { $now == $start_ } {
    $self reset
  } else {
    # agent information
    set src_addr [$agent_ set agent_addr_]
    set src_port [$agent_ set agent_port_]
    set dst_addr [$agent_ set dst_addr_]
    set dst_port [$agent_ set dst_port_]
    # TCP state variables (accumulative)
    set ack [expr [$agent_ set ack_] - $ack_]
    set psent [expr [$agent_ set ndatapack_] - $ndatapack_]
    set bsent [expr [$agent_ set ndatabytes_] - $ndatabytes_]
    set nretx [expr [$agent_ set nrexmit_] - $nrexmit_]
    set pretx [expr [$agent_ set nrexmitpack_] - $nrexmitpack_]
    set bretx [expr [$agent_ set nrexmitbytes_] - $nrexmitbytes_]
    $self reset
    # TCP state variables
    set cwnd [$agent_ set cwnd_]
    set awnd [$agent_ set awnd_]
    set maxwnd [$agent_ set window_]
    set ssthresh [$agent_ set ssthresh_]
    set rtt [$agent_ set rtt_]
    set srtt [$agent_ set srtt_]
    set rttvar [$agent_ set rttvar_]
    # throughput in bit/sec in the last interval
    set size [$agent_ set packetSize_]
    set thr [expr ($ack + 0.0) * $size * 8 / $interval_]
    # packet loss probability
    set loss 0
    if { $psent > 0 } {
      set loss [expr ($pretx + 0.0) / $psent ]
    }
    # dump all statistics
    puts [format "now=%g src=%s.%s dst=%s.%s ack=%g cwnd=%g ssth=%g rtt=%g thr=%g loss=%g" \
	    $now $src_addr $src_port $dst_addr $dst_port $ack $cwnd \
	    $ssthresh $rtt $thr $loss]
  }
  $ns_ after $interval_ "$self hook"
}

