/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
 *
 * Author: Yu Cao <caoyu08@csnet1.cs.tsinghua.edu.cn>
 */
#define NS_LOG_APPEND_CONTEXT \
	   if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_node->GetId () << "] "; }

#include "ns3/abort.h"
#include "ns3/node.h"
#include "ns3/inet-socket-address.h"
#include "ns3/log.h"
#include "ns3/ipv4.h"
#include "ns3/ipv4-interface-address.h"
#include "ns3/ipv4-route.h"
#include "ns3/ipv4-routing-protocol.h"
#include "ns3/simulation-singleton.h"
#include "ns3/simulator.h"
#include "ns3/packet.h"
#include "ns3/uinteger.h"
#include "ns3/trace-source-accessor.h"
#include "nampt-socket.h"
#include "nampt-subflow.h"
#include "nampt-cc.h"
#include "tcp-reno.h"
#include "ipv4-end-point.h"
#include "rtt-estimator.h"
#include "ipv4-l3-protocol.h"
#include "ns3/names.h"

#include <algorithm>
#include <set>


NS_LOG_COMPONENT_DEFINE ("NaMPTSocket");

namespace ns3 {

NS_OBJECT_ENSURE_REGISTERED (NaMPTSocket);

TypeId
NaMPTSocket::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::NaMPTSocket")
	.SetParent<TcpSocket> ()
	.AddAttribute ("CongestionAlgo",
				   "The algorithm of congestion control.",
				   UintegerValue (NAMPT_CC_INDE),
				   MakeUintegerAccessor (&NaMPTSocket::m_ccAlgo),
				   MakeUintegerChecker<uint32_t> ())
	.AddAttribute ("SchedulingAlgo", 
				   "The algorithm of dispatching data stream to subflows.", 
				   UintegerValue (NAMPT_SOD), 
				   MakeUintegerAccessor (&NaMPTSocket::m_schedulingAlgo), 
				   MakeUintegerChecker<uint32_t> ())
    .AddAttribute ("AssemblingAlgo", 
    			   "The algorithm of assembling data coming from subflows.", 
    			   UintegerValue (NAMPT_NA), 
    			   MakeUintegerAccessor (&NaMPTSocket::m_assemblingAlgo), 
    			   MakeUintegerChecker<uint32_t> ())
    .AddAttribute ("gamma", 
                   "The number of packets backlogging in network", 
                   UintegerValue (2), 
                   MakeUintegerAccessor (&NaMPTSocket::m_initGamma), 
                   MakeUintegerChecker<uint32_t> ())
	.AddAttribute ("beta", 
                   "The backoff factor of cwnd when receiving ce.", 
                   UintegerValue (2), 
                   MakeUintegerAccessor (&NaMPTSocket::m_backoffBeta), 
                   MakeUintegerChecker<uint32_t> ())
	.AddAttribute ("PathManagement", 
                   "Heuristically establish subflows.", 
                   UintegerValue (0), 
                   MakeUintegerAccessor (&NaMPTSocket::m_pathManagement), 
                   MakeUintegerChecker<uint32_t> ())
	.AddAttribute ("InstantRate", 
                   "The instant rate of communication.", 
                   DoubleValue (0.0), 
                   MakeDoubleAccessor (&NaMPTSocket::m_instRate), 
                   MakeDoubleChecker<double>() )
	.AddAttribute ("TimeTag", 
                   "Start time or elapse time.", 
                   DoubleValue (0), 
                   MakeDoubleAccessor (&NaMPTSocket::m_timeTag), 
                   MakeDoubleChecker<double>() )

  ;
  return tid;
}

NaMPTSocket::NaMPTSocket (void)
  : m_node (0),
    m_tcp (0),
    m_rttTypeId (RttMeanDeviation::GetTypeId() ),
    m_socketTypeId (TcpReno::GetTypeId() ),
    m_firstSocket (0),
    m_nextAddr (0), 
    m_localToken (0),
    m_peerToken (0),
    m_localPort (0),
    m_peerPort (0),
    m_bClosed (false), 
    m_bScheduling (false),
    m_alpha (1),
    m_peakOfOutputQueue (0),
    m_flowSize (0), 
    m_nextTx (0),
    m_inputQueue (0),
    m_outputQueue (0)
{
  NS_LOG_FUNCTION (this);
  m_attributes.m_shutdownSend = false;
  m_attributes.m_shutdownRecv = false;
  
  m_outputQueue.SetMaxBufferSize (std::numeric_limits<int32_t>::max()/2 );

}

NaMPTSocket::NaMPTSocket (const NaMPTSocket& sock)
  : TcpSocket (sock), //copy object::m_tid and socket::callbacks
    m_node (sock.m_node),
    m_tcp (sock.m_tcp),
    m_rttTypeId (sock.m_rttTypeId),
    m_socketTypeId (sock.m_socketTypeId),
    m_firstSocket (sock.m_firstSocket),
    m_addresses (sock.m_addresses),
    m_nextAddr (sock.m_nextAddr), 
    m_accessPoints (sock.m_accessPoints), 
    m_localToken (sock.m_localToken),
    m_peerToken (sock.m_peerToken),
    m_localPort (sock.m_localPort),
    m_peerPort (sock.m_peerPort),
    m_bClosed (sock.m_bClosed), 
    m_bScheduling (sock.m_bScheduling),
    m_pendingSynPacket (sock.m_pendingSynPacket),
    m_alpha (sock.m_alpha),
    m_ccAlgo (sock.m_ccAlgo),
    m_schedulingAlgo (sock.m_schedulingAlgo),
    m_assemblingAlgo (sock.m_assemblingAlgo),
    m_initGamma (sock.m_initGamma), 
    m_backoffBeta (sock.m_backoffBeta), 
    m_pathManagement (sock.m_pathManagement), 
    m_attributes (sock.m_attributes),
    m_peakOfOutputQueue (sock.m_peakOfOutputQueue),
    m_instRate (sock.m_instRate), 
    m_flowSize (sock.m_flowSize), 
    m_nextTx (sock.m_nextTx),
    m_inputQueue (sock.m_inputQueue),
    m_outputQueue (sock.m_outputQueue),
    m_reschedulingQueue (sock.m_reschedulingQueue), 
    m_maxIngoingSize (sock.m_maxIngoingSize), 
    m_maxOutgoingSize (sock.m_maxOutgoingSize) 
{
  NS_LOG_FUNCTION (this);
  NS_LOG_LOGIC ("Invoked the copy constructor");
  
  // Reset all callbacks to null
  /*Callback<void, Ptr< Socket > > vPS = MakeNullCallback<void, Ptr<Socket> > ();
  Callback<void, Ptr<Socket>, const Address &> vPSA = MakeNullCallback<void, Ptr<Socket>, const Address &> ();
  Callback<bool, Ptr<Socket>, const Address &> bPSA = MakeNullCallback<bool, Ptr<Socket>, const Address &> ();
  Callback<void, Ptr<Socket>, uint32_t> vPSUI = MakeNullCallback<void, Ptr<Socket>, uint32_t> ();
  SetConnectCallback (vPS, vPS);
  SetDataSentCallback (vPSUI);
  SetSendCallback (vPSUI);
  SetRecvCallback (vPS);

  SetCloseCallbacks (vPS, vPS);
  SetAcceptCallback (bPSA, vPSA);*/
}

NaMPTSocket::~NaMPTSocket (void)
{
  NS_LOG_FUNCTION (this);
  m_node = 0;
  m_tcp = 0;
  m_firstSocket = 0;

  AddressSet_t::iterator it;
  for (it = m_addresses.begin(); it != m_addresses.end(); it++)
  	it->second = 0;
  m_addresses.clear();

  std::vector<Ptr<Packet> >::iterator vit;
  for (vit = m_pendingSynPacket.begin(); vit != m_pendingSynPacket.end(); vit++)
  	*vit = 0;
  m_pendingSynPacket.clear();

  PacketSet_t::iterator pit;
  for (pit = m_reschedulingQueue.begin(); pit != m_reschedulingQueue.end(); pit++)
  	pit->second = 0;
  m_reschedulingQueue.clear();

  m_accessPoints.clear();
  
}

/** Associate a node with this socket */
void
NaMPTSocket::SetNode (Ptr<Node> node)
{
  m_node = node;
}

/** Associate the L4 protocol (e.g. mux/demux) with this socket */
void
NaMPTSocket::SetTcp (Ptr<TcpL4Protocol> tcp)
{
  m_tcp = tcp;
}

/** Inherit from Socket class: Returns error code */
enum Socket::SocketErrno
NaMPTSocket::GetErrno (void) const
{
  if (m_firstSocket)
    return m_firstSocket->GetErrno();
  return ERROR_NOTERROR;
}

/** Inherit from Socket class: Returns socket type, NS3_SOCK_STREAM */
enum Socket::SocketType
NaMPTSocket::GetSocketType (void) const
{
  return NS3_SOCK_STREAM;
}

/** Inherit from Socket class: Returns associated node */
Ptr<Node>
NaMPTSocket::GetNode (void) const
{
  NS_LOG_FUNCTION_NOARGS ();
  return m_node;
}

/** Inherit from Socket class: Bind socket to an end-point in NaMPTL4Protocol */
int
NaMPTSocket::Bind (void)
{
  if (m_firstSocket == 0 && m_subflows.size() == 0)
  {
    // Create real socket
    m_firstSocket = CreateBaseSocket();
	m_firstSocket->m_shellSocket = this;

	// Get address list
	InitAddressSet();

	/* Now we have a real socket */
	// 1) allocate endpoint
	// 2) push_back socket
	// 3) setupcallback
	int ret = m_firstSocket->Bind();
	if (ret == 0)
	{
	  /* Modify callback functions */
	  HookPacketDelivery (m_firstSocket, Ptr<NaMPTSocket>(this) );
	}
	return ret;
  }
  return -1;
}

/** Inherit from Socket class: Bind socket (with specific address) to an end-point in NaMPTL4Protocol */
int
NaMPTSocket::Bind (const Address &address)
{
  if (m_firstSocket == 0 && m_subflows.size() == 0)
  {
    // Create real socket
    m_firstSocket = CreateBaseSocket();
	m_firstSocket->m_shellSocket = this;

	// Get address list
	InitAddressSet();
  
    /* Now we have a real socket */
	// 1) allocate endpoint
	// 2) push_back socket
	// 3) setupcallback
    int ret = m_firstSocket->Bind(address);
    if (ret == 0)
    {
   	  /* Modify callback functions */
   	  HookPacketDelivery (m_firstSocket, Ptr<NaMPTSocket>(this) );
	  // bind to net device
	  uint32_t addr = InetSocketAddress::ConvertFrom(address).GetIpv4().Get();
	  if (addr != Ipv4Address::GetAny().Get() )
	  	BindToNetDevice(m_addresses[addr]->GetDevice() );
    }
    return ret;
  }
  return -1;
}

int
NaMPTSocket::Bind6 (void)
{
  return -1;
}

/** Inherit from Socket class: Initiate connection to a remote address:port */
int
NaMPTSocket::Connect (const Address & address)
{
  NS_LOG_FUNCTION (this << address);
  if (m_localToken != 0)
  {
    m_accessPoints.push_back(InetSocketAddress::ConvertFrom(address));
	return 0;
  }
  m_accessPoints.push_back(InetSocketAddress::ConvertFrom(address));
  
  m_timeTag = Simulator::Now().GetSeconds();
  
  // If haven't do so, Bind() this socket first
  if (m_firstSocket == 0 && m_subflows.size() == 0)
  {
    if (Bind() == -1)
    {
      NS_ASSERT (m_firstSocket == 0);
	  return -1; // Bind() failed
    }
	NS_ASSERT (m_firstSocket != 0);
  }
  else if (m_firstSocket == 0 && m_subflows.size() != 0)
  	return -1;
  else
    NS_ASSERT(m_subflows.size() == 0);
  
  // Register token to NaMPTL4Protocol
  Ptr<NaMPTL4Protocol> nampt = DynamicCast<NaMPTL4Protocol>(m_tcp);
  m_localToken = nampt->RegisterToken (Ptr<NaMPTSocket>(this) );

  // connecting
  int val = m_firstSocket->Connect (address);
  if (val != 0)
  	return val;
  
  // Bind to local address
  if (m_boundnetdevice == 0)
  {
    uint32_t saddr = m_firstSocket->m_endPoint->GetLocalAddress().Get();
	NS_ASSERT(m_addresses.find(saddr) != m_addresses.end() );
	m_boundnetdevice = m_addresses[saddr]->GetDevice();
	m_firstSocket->BindToNetDevice (m_boundnetdevice);
  }
  return 0;
}

/** Inherit from Socket class: Listen on the endpoint for an incoming connection */
int
NaMPTSocket::Listen (void)
{
  NS_LOG_FUNCTION (this);
  if (m_firstSocket)
  	return m_firstSocket->Listen ();
  return -1;
}

/** Inherit from Socket class: Kill this socket and signal the peer (if any) */
int
NaMPTSocket::Close (void)
{
  NS_LOG_FUNCTION (this);
  m_bClosed = true;
  
  // unattach send callback
  SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t >() );

  // clear token
  Ptr<NaMPTL4Protocol> nampt = DynamicCast<NaMPTL4Protocol>(m_tcp);
  nampt->UnregisterToken(m_localToken);
  
  if (m_firstSocket)
  {
    if (m_firstSocket->m_closeNotified)
    {
      m_firstSocket = 0;
	  return (int)m_localToken;
    }
  	return m_firstSocket->Close ();
  }

  SubflowSet_t::iterator it;
  NS_ASSERT(m_outputQueue.Size() == 0);
  if (m_inputQueue.Size() > 0)
  {
    // select a fast path, and put all the remaining data to that subflow.
    NS_ASSERT(m_subflows.size() > 0);
    it = m_subflows.begin();
    Ptr<NaMPTSubflow> fastSubflow = it->second;
	it++;
	while (it != m_subflows.end() )
	{
	  if (it->second->m_instantRate > fastSubflow->m_instantRate)
	  	fastSubflow = it->second;
	  it++;
	}
	uint32_t oldSize = fastSubflow->m_baseSocket->m_txBuffer.MaxBufferSize();
	uint32_t dataLen = m_inputQueue.SizeFromSequence(m_nextTx);
	fastSubflow->m_baseSocket->m_txBuffer.SetMaxBufferSize(oldSize+dataLen);
	AssignPackets(dataLen, fastSubflow);
	fastSubflow->m_baseSocket->m_txBuffer.SetMaxBufferSize(oldSize);
  }
  NS_ASSERT(m_inputQueue.Size() == 0);

  it = m_subflows.begin();
  while (it != m_subflows.end() )
  {
    Ptr<NaMPTSubflow> sf = it->second;
	it++;
    sf->Close();
  }
  
  return (int)m_localToken;
}

/** Inherit from Socket class: Signal a termination of send */
int
NaMPTSocket::ShutdownSend (void)
{
  NS_LOG_FUNCTION (this);
  
  m_attributes.m_shutdownSend = true;
  
  if (m_firstSocket)
  	return m_firstSocket->ShutdownSend ();

  SubflowSet_t::const_iterator it;
  for (it = m_subflows.begin(); it != m_subflows.end(); it ++)
  {
    it->first->ShutdownSend();
  }
  return 0;
}

/** Inherit from Socket class: Signal a termination of receive */
int
NaMPTSocket::ShutdownRecv (void)
{
  NS_LOG_FUNCTION (this);
  
  m_attributes.m_shutdownRecv = true;
  
  if (m_firstSocket)
  	return m_firstSocket->ShutdownRecv ();

  SubflowSet_t::const_iterator it;
  for (it = m_subflows.begin(); it != m_subflows.end(); it ++)
  {
    it->first->ShutdownRecv();
  }
  return 0;
}

/** Inherit from Socket class: Send a packet. Parameter flags is not used.
    Packet is ONLY payload. Invoked by upper-layer application */
int
NaMPTSocket::Send (Ptr<Packet> p, uint32_t flags)
{
  NS_LOG_FUNCTION (this << p);
  NS_ABORT_MSG_IF (flags, "use of flags is not supported in NaMPTSocket::Send()");
  if (m_firstSocket)
  	return m_firstSocket->Send (p, flags);

  // Firstly, put data into "Input Queue"
  // Next, start scheduling process ONLY once
  if (!m_inputQueue.Add(p) )
  	return -1; // overflow
  if (!m_bScheduling)
  {
    Simulator::ScheduleNow (&NaMPTSocket::SchedulingPackets, this, 
							Ptr<NaMPTSubflow>(0) );
	m_bScheduling = true;
  }
  uint32_t s = p->GetSize();
  m_flowSize += s;
  return s;

}

/** Inherit from Socket class: Here, it is the same as Send() call */
int
NaMPTSocket::SendTo (Ptr<Packet> p, uint32_t flags, const Address &address)
{
  return Send (p, flags); // SendTo() and Send() are the same in the case of TCP or NaMPT
}

/** Inherit from Socket class: Return data to upper-layer application. Parameter flags
    is not used. Data is returned as a packet of size no larger than maxSize */
Ptr<Packet>
NaMPTSocket::Recv (uint32_t maxSize, uint32_t flags)
{
  NS_LOG_FUNCTION (this);
  NS_ABORT_MSG_IF (flags, "use of flags is not supported in NaMPTSocket::Recv()");
  Ptr<Packet> p = 0;
  if (m_firstSocket)
  	p = m_firstSocket->Recv (maxSize, flags);
  else
    p = m_outputQueue.Extract(maxSize);

  if (p != 0 && p->GetSize() != 0)
  	return p;

  return 0;
}

/** Inherit from Socket class: Recv and return the remote's address */
Ptr<Packet>
NaMPTSocket::RecvFrom (uint32_t maxSize, uint32_t flags, Address &fromAddress)
{
  NS_LOG_FUNCTION (this << maxSize << flags);
  Ptr<Packet> p = 0;
  if (m_firstSocket)
  	p = m_firstSocket->RecvFrom (maxSize, flags, fromAddress);
  else
  {
    // XXX
    fromAddress = InetSocketAddress("255.255.255.255", m_peerPort);
	p = Recv(maxSize, flags);
  }
  
  if (p != 0 && p->GetSize() != 0)
  	return p;

  return 0;
}

/** Inherit from Socket class: Get the max number of bytes an app can send */
uint32_t
NaMPTSocket::GetTxAvailable (void) const
{
  NS_LOG_FUNCTION (this);
  if (m_firstSocket)
  	return m_firstSocket->GetTxAvailable();

  return m_inputQueue.Available ();
}

/** Inherit from Socket class: Get the max number of bytes an app can read */
uint32_t
NaMPTSocket::GetRxAvailable (void) const
{
  NS_LOG_FUNCTION (this);
  if (m_firstSocket)
  	return m_firstSocket->GetRxAvailable();
  
  return m_outputQueue.Available ();
}

/** Inherit from Socket class: Return local address:port */
int
NaMPTSocket::GetSockName (Address &address) const
{
  NS_LOG_FUNCTION (this);
  if (m_firstSocket)
  	return m_firstSocket->GetSockName (address);

  // XXX
  return (int)m_peerToken;
}

/** Inherit from Socket class: Broadcast */
bool
NaMPTSocket::SetAllowBroadcast (bool allowBroadcast)
{
  if (m_firstSocket)
    return m_firstSocket->SetAllowBroadcast (allowBroadcast);
  return (! allowBroadcast);
}

bool
NaMPTSocket::GetAllowBroadcast () const
{
  if (m_firstSocket)
    return m_firstSocket->GetAllowBroadcast ();
  return 0;
}

/** Inherit from Socket class: Bind this socket to the specified NetDevice */
void
NaMPTSocket::BindToNetDevice (Ptr<NetDevice> netdevice)
{
  NS_LOG_FUNCTION (netdevice);
  
  Socket::BindToNetDevice (netdevice);
  
  if (m_firstSocket)
  	m_firstSocket->BindToNetDevice (netdevice);
  else if (m_subflows.size() == 0) // need to bind
  {
    Bind();
	NS_ASSERT(m_firstSocket != 0);
	m_firstSocket->BindToNetDevice (netdevice);
  }
}

/** Below are the attribute get/set functions : Inherit from TcpSocket class */

void
NaMPTSocket::SetSndBufSize (uint32_t size)
{
  m_maxOutgoingSize = size;
  
  if (m_firstSocket)
    m_firstSocket->SetSndBufSize (size);
}

uint32_t
NaMPTSocket::GetSndBufSize (void) const
{
  return m_maxOutgoingSize;
}

void
NaMPTSocket::SetRcvBufSize (uint32_t size)
{
  m_maxIngoingSize = size;
  
  if (m_firstSocket)
	m_firstSocket->SetRcvBufSize (size);
}

uint32_t
NaMPTSocket::GetRcvBufSize (void) const
{
  return m_maxIngoingSize;
}

void
NaMPTSocket::SetSegSize (uint32_t size)
{
  m_attributes.m_segmentSize = size;
  
  if (m_firstSocket)
  	m_firstSocket->SetSegSize (size);
}

uint32_t
NaMPTSocket::GetSegSize (void) const
{
  return m_attributes.m_segmentSize;
}

void
NaMPTSocket::SetConnTimeout (Time timeout)
{
  m_attributes.m_cnTimeout = timeout;
  
  if (m_firstSocket)
  	m_firstSocket->SetConnTimeout (timeout);
}

Time
NaMPTSocket::GetConnTimeout (void) const
{
  return m_attributes.m_cnTimeout;
}

void
NaMPTSocket::SetConnCount (uint32_t count)
{
  m_attributes.m_cnRetries = count;
  
  if (m_firstSocket)
  	m_firstSocket->SetConnCount (count);
}

uint32_t
NaMPTSocket::GetConnCount (void) const
{
  return m_attributes.m_cnRetries;
}

void
NaMPTSocket::SetDelAckTimeout (Time timeout)
{
  m_attributes.m_delAckTimeout = timeout;
  
  if (m_firstSocket)
  	m_firstSocket->SetDelAckTimeout (timeout);
}

Time
NaMPTSocket::GetDelAckTimeout (void) const
{
  return m_attributes.m_delAckTimeout;
}

void
NaMPTSocket::SetDelAckMaxCount (uint32_t count)
{
  m_attributes.m_delAckMaxCount = count;
  
  if (m_firstSocket)
  	m_firstSocket->SetDelAckMaxCount (count);
}

uint32_t
NaMPTSocket::GetDelAckMaxCount (void) const
{
  return m_attributes.m_delAckMaxCount;
}

void
NaMPTSocket::SetPersistTimeout (Time timeout)
{
  m_attributes.m_persistTimeout = timeout;
  
  if (m_firstSocket)
  	m_firstSocket->SetPersistTimeout (timeout);
}

Time
NaMPTSocket::GetPersistTimeout (void) const
{
  return m_attributes.m_persistTimeout;
}

void
NaMPTSocket::SetSSThresh (uint32_t threshold)
{  
  if (m_firstSocket)
  	m_firstSocket->SetSSThresh (threshold);
}

uint32_t
NaMPTSocket::GetSSThresh (void) const
{
  if (m_firstSocket)
  	return m_firstSocket->GetSSThresh();
  
  return 65535;
}

void
NaMPTSocket::SetInitialCwnd (uint32_t cwnd)
{
  if (m_firstSocket)
  	m_firstSocket->SetInitialCwnd (cwnd);
}

uint32_t
NaMPTSocket::GetInitialCwnd (void) const
{
  if (m_firstSocket)
  	return m_firstSocket->GetInitialCwnd();
  
  return 2;
}


/*
  *********************************
  *  Below are NaMPT-related functions    *
  *********************************
*/

void
NaMPTSocket::SetRttTypeId (TypeId rttTypeId)
{
  m_rttTypeId = rttTypeId;
}

void
NaMPTSocket::SetSocketTypeId (TypeId socketTypeId)
{
  // Congestion control algorithm per path
  m_socketTypeId = socketTypeId;
}

void 
NaMPTSocket::SetFirstSocket (Ptr<TcpSocketBase> baseSock)
{
  m_firstSocket = baseSock;
}

/*
  * In fact, this static function creates NaMPTSocket used by receiver.
  * Probably, invoked by TcpSocketBase::CompleteFork()
*/
Ptr<NaMPTSocket>
NaMPTSocket::EncapsulateSocket (Ptr<TcpSocketBase> baseSock)
{
  // create shell
  Ptr<NaMPTSocket> shell = CreateObject<NaMPTSocket>();
  NS_ASSERT(shell != 0);
  
  // copy attributes for shell socket
  shell->SetConnTimeout(baseSock->m_shellSocket->GetConnTimeout() );
  shell->SetConnCount(baseSock->m_shellSocket->GetConnCount() );
  shell->SetPersistTimeout(baseSock->m_shellSocket->GetPersistTimeout() );
  shell->SetSSThresh(baseSock->m_shellSocket->GetSSThresh() );
  shell->SetInitialCwnd(baseSock->m_shellSocket->GetInitialCwnd() );
  
  shell->SetSndBufSize(baseSock->m_shellSocket->GetSndBufSize() );
  shell->SetRcvBufSize(baseSock->m_shellSocket->GetRcvBufSize() );
  shell->SetSegSize(baseSock->m_shellSocket->GetSegSize() );
  shell->SetDelAckTimeout(baseSock->m_shellSocket->GetDelAckTimeout() );
  shell->SetDelAckMaxCount(baseSock->m_shellSocket->GetDelAckMaxCount() );
  if (baseSock->m_shutdownSend)
    shell->ShutdownSend();
  if (baseSock->m_shutdownRecv)
    shell->ShutdownRecv();

  shell->m_ccAlgo = baseSock->m_shellSocket->m_ccAlgo;
  shell->m_schedulingAlgo = baseSock->m_shellSocket->m_schedulingAlgo;
  shell->m_assemblingAlgo = baseSock->m_shellSocket->m_assemblingAlgo;
  shell->m_initGamma = baseSock->m_shellSocket->m_initGamma;
  shell->m_backoffBeta = baseSock->m_shellSocket->m_backoffBeta;
  shell->m_pathManagement = baseSock->m_shellSocket->m_pathManagement;

  // Init shell
  shell->SetNode (baseSock->m_shellSocket->m_node);
  shell->SetTcp (baseSock->m_shellSocket->m_tcp);
  shell->SetSocketTypeId (baseSock->m_shellSocket->m_socketTypeId);
  shell->SetRttTypeId (baseSock->m_shellSocket->m_rttTypeId);
  shell->SetFirstSocket (baseSock);
  shell->InitAddressSet();
	
  // Hook packet delivery coming from NaMPTL4Protocol
  NaMPTSocket::HookPacketDelivery (baseSock, shell);

  // Hook callback functions set by application layer.
  // Note: Up to now, baseSock->m_shellSocket is Listen shell
  shell->SetConnectCallback (baseSock->m_shellSocket->m_connectionSucceeded, baseSock->m_shellSocket->m_connectionFailed);
  shell->SetCloseCallbacks (baseSock->m_shellSocket->m_normalClose, baseSock->m_shellSocket->m_errorClose);
  shell->SetAcceptCallback (baseSock->m_shellSocket->m_connectionRequest, baseSock->m_shellSocket->m_newConnectionCreated);
  shell->SetDataSentCallback (baseSock->m_shellSocket->m_dataSent);
  shell->SetSendCallback (baseSock->m_shellSocket->m_sendCb);
  shell->SetRecvCallback (baseSock->m_shellSocket->m_receivedData);

  // Tell baseSocket the shell
  baseSock->m_shellSocket = shell;
  return shell;
}

void
NaMPTSocket::HookPacketDelivery (Ptr<TcpSocketBase> baseSocket, Ptr<NaMPTSocket> shellSocket)
{
  if (baseSocket != 0 && baseSocket->m_endPoint != 0 && shellSocket != 0)
  {
    baseSocket->m_endPoint->SetRxCallback (MakeCallback (&NaMPTSocket::ForwardUp, shellSocket) );
    //baseSocket->m_endPoint->SetDestroyCallback (MakeCallback (&NaMPTSocket::Destroy, shellSocket) );
  }
}

bool 
NaMPTSocket::HaveSignals (Ptr<Packet> packet)
{
  uint8_t buf[20];
  NS_ASSERT (packet->GetSize() >= 20); // tcp header should exist
  packet->CopyData (buf, 20);
  uint8_t hlen = buf[12] >> 4;
  return hlen > 5 ? true : false;
}

Ptr<NaMPTSubflow> 
NaMPTSocket::SwitchToMultipathMode(void)
{
  NS_ASSERT(m_firstSocket != 0);
  NS_ASSERT(m_firstSocket->m_state == SYN_SENT || m_firstSocket->m_state == SYN_RCVD);
  NS_ASSERT(m_firstSocket->m_shellSocket == this);

  // change to NaMPTCC
  // the original socket will be discarded from m_tcp->m_sockets
  m_socketTypeId = NaMPTCC::GetTypeId();
  m_firstSocket = NaMPTSocket::ConvertCongestionControl(m_firstSocket);

  // subflow
  Ptr<NaMPTSubflow> sf = SetupSubflow(m_firstSocket, true);
  sf->m_bBypassSending = true;
  NS_ASSERT(sf->m_baseSocket == m_firstSocket);

  // session name: time-socket-src-des
  if (m_timeTag == 0)
  	m_timeTag = Simulator::Now().GetSeconds();
  char buf[128];
  snprintf(buf, 128, "%.6f-%08x-%u.%u.%u.%u->%u.%u.%u.%u", 
			m_timeTag, 
			(uint32_t)this, 
			(sf->m_localAddress.Get() >> 24)&0x000000FF,
			(sf->m_localAddress.Get() >> 16)&0x000000FF,
			(sf->m_localAddress.Get() >> 8)&0x000000FF,
			(sf->m_localAddress.Get() )&0x000000FF,
			(sf->m_peerAddress.Get() >> 24)&0x000000FF,
			(sf->m_peerAddress.Get() >> 16)&0x000000FF,
			(sf->m_peerAddress.Get() >> 8)&0x000000FF,
			(sf->m_peerAddress.Get() )&0x000000FF );
  m_sessionName = buf;
	
  // init connection
  m_localPort = m_firstSocket->m_endPoint->GetLocalPort();
  m_peerPort = m_firstSocket->m_endPoint->GetPeerPort();
  m_nextTx = m_firstSocket->m_nextTxSequence;
  m_nextTx ++; // syn consumes one byte
  m_inputQueue.SetHeadSequence(m_nextTx);

  // next used addr
  AddressSet_t::const_iterator it = m_addresses.find(sf->m_localAddress.Get());
  it++;
  if (it == m_addresses.end() )
  	it = m_addresses.begin();
  m_nextAddr = it->first;

  // m_outputQueue is initialized after this function returns.

  m_firstSocket = 0; // this is important...
  return sf;
}

Ptr<NaMPTSubflow> 
NaMPTSocket::SetupSubflow(Ptr<TcpSocketBase> baseSocket, bool bFirst)
{
  Ptr<NaMPTSubflow> subflow = CreateObject<NaMPTSubflow>();

  // expand inputQueue
  uint32_t size = m_inputQueue.MaxBufferSize();
  size += baseSocket->GetSndBufSize();
  m_inputQueue.SetMaxBufferSize(size);
  
  // data structure
  subflow->m_baseSocket = baseSocket;
  subflow->m_namptSocket = Ptr<NaMPTSocket>(this);
  subflow->m_tcp = DynamicCast<NaMPTL4Protocol>(baseSocket->m_tcp);
  subflow->m_localAddress = baseSocket->m_endPoint->GetLocalAddress();
  subflow->m_peerAddress = baseSocket->m_endPoint->GetPeerAddress();

  baseSocket->m_shellSocket = 0;
  // baseSocket sees a fake m_tcp, while the real m_tcp is stored in subflow->m_tcp
  baseSocket->m_tcp = DynamicCast<TcpL4Protocol>(subflow);

  NS_ASSERT (m_subflows.find(baseSocket) == m_subflows.end() );
  m_subflows[baseSocket] = subflow;

  // hook callback
  if (!bFirst)
  {
    baseSocket->SetConnectCallback (MakeCallback(&NaMPTSocket::DoSubflowSucceeds, Ptr<NaMPTSocket>(this)), 
  								MakeCallback(&NaMPTSocket::DoSubflowFails, Ptr<NaMPTSocket>(this)) );
    baseSocket->SetAcceptCallback (MakeCallback(&NaMPTSocket::DoSubflowRequests, Ptr<NaMPTSocket>(this)), 
  								MakeCallback(&NaMPTSocket::DoSubflowAccepted, Ptr<NaMPTSocket>(this)) );
  }
  baseSocket->SetDataSentCallback (MakeCallback(&NaMPTSocket::DoSubflowDataSent, Ptr<NaMPTSocket>(this)) );  
  baseSocket->SetSendCallback(MakeCallback(&NaMPTSocket::DoSubflowSend, Ptr<NaMPTSocket>(this)) );
  baseSocket->SetRecvCallback(MakeCallback(&NaMPTSocket::DoSubflowRecv, Ptr<NaMPTSocket>(this)) );
  baseSocket->SetCloseCallbacks(MakeCallback(&NaMPTSocket::DoSubflowPeerClose, Ptr<NaMPTSocket>(this)),
  								MakeCallback(&NaMPTSocket::DoSubflowErrorClose, Ptr<NaMPTSocket>(this)) );
  // hook packet delivery
  baseSocket->m_endPoint->SetRxCallback (MakeCallback (&NaMPTSubflow::ForwardUp, subflow) );
  // It is necessary, because we need correct baseSocket->m_tcp by subflow->m_tcp
  baseSocket->m_endPoint->SetDestroyCallback (MakeCallback (&NaMPTSubflow::Destroy, subflow) );

  // hook congestion control
  Ptr<NaMPTCC> cc = DynamicCast<NaMPTCC>(baseSocket);
  cc->m_notifyNewAck = MakeCallback(&NaMPTSocket::DoSubflowNewAck, Ptr<NaMPTSocket>(this));
  cc->m_notifyDupAck = MakeCallback(&NaMPTSocket::DoSubflowDupAck, Ptr<NaMPTSocket>(this));
  cc->m_notifyTimeout = MakeCallback(&NaMPTSocket::DoSubflowTimeout, Ptr<NaMPTSocket>(this));
  if (m_ccAlgo == NAMPT_CC_DCTCP)
  {
    subflow->m_cwr = 1;
	subflow->m_enterCWR = MakeCallback (&NaMPTSocket::DoDCTCPEnterCWR, Ptr<NaMPTSocket>(this));
  }
  else if (m_ccAlgo == NAMPT_CC_XMP)
  {
  	subflow->m_cwr = 1;
	subflow->m_enterCWR = MakeCallback (&NaMPTSocket::DoXMPEnterCWR, Ptr<NaMPTSocket>(this));
  }
  
  // init begSeq, the expected ackSeq after one cwnd worthy of data has been acked.
  //subflow->m_begSeq = 1 + cc->m_cWnd.Get();
  subflow->m_begSeq = baseSocket->m_nextTxSequence.Get();

  return subflow;
}

/*
  * invoked by NaMPTL4Protocol when find join option
*/
void 
NaMPTSocket::ReceiveSubflowJoin(Ptr<Packet> p, 
				Ipv4Header const &header, Ptr<Ipv4Interface> incomingInterface)
{
  NaMPTHeader namptHeader;
  p->PeekHeader(namptHeader);
  Ptr<NaMPTSignal> sig = namptHeader.FindSignal(NAMPT_JOIN, false);
  NS_ASSERT(namptHeader.GetFlags() == TcpHeader::SYN && 
  			sig != 0 && sig->sigData.join.peerToken == m_localToken);
  // check addr and port
  Ipv4Address toAddr = header.GetDestination();
  Ipv4Address fromAddr = header.GetSource();
  NS_ASSERT(m_addresses.find(toAddr.Get()) != m_addresses.end() );

  // check incoming interface
  if (m_addresses[toAddr.Get()] != incomingInterface)
  {
    // send RST
    return ;
  }

  // construct subflow
  Ipv4EndPoint* endP = m_tcp->Allocate(toAddr, namptHeader.GetDestinationPort(), fromAddr, namptHeader.GetSourcePort() );
  if(endP == 0)
    return ; // duplicated join messages will result in it.
  Ptr<TcpSocketBase> baseSocket = CreateBaseSocket();
  baseSocket->m_endPoint = endP;
  m_tcp->m_sockets.push_back (baseSocket);
  baseSocket->SetupCallback();
  
  baseSocket->m_state = SYN_RCVD;
  baseSocket->m_rxBuffer.SetNextRxSequence(namptHeader.GetSequenceNumber() + SequenceNumber32(1) );
  baseSocket->BindToNetDevice(m_addresses[toAddr.Get()]->GetDevice() );

  Ptr<NaMPTSubflow> subflow = SetupSubflow(baseSocket, false);

  // send syn+ack
  baseSocket->SendEmptyPacket(TcpHeader::SYN | TcpHeader::ACK);
  
}

uint16_t 
NaMPTSocket::GetLocalPort (void)
{
  if (m_firstSocket && m_firstSocket->m_endPoint)
  	return m_firstSocket->m_endPoint->GetLocalPort();
  
  return m_localPort;
}

uint16_t 
NaMPTSocket::GetPeerPort (void)
{
  if (m_firstSocket && m_firstSocket->m_endPoint)
  	return m_firstSocket->m_endPoint->GetPeerPort();
  
  return m_peerPort;
}

bool 
NaMPTSocket::GetLocalAddress (Ipv4Address &addr)
{
  if (m_firstSocket && m_firstSocket->m_endPoint)
  {
    addr = m_firstSocket->m_endPoint->GetLocalAddress();
	return true;
  }

  // XXX
  SubflowSet_t::const_iterator it = m_subflows.begin();
  if (it != m_subflows.end() )
  {
    addr = it->second->m_baseSocket->m_endPoint->GetLocalAddress();
	return true;
  }
  
  return false;
}

bool 
NaMPTSocket::GetPeerAddress (Ipv4Address &addr)
{
  if (m_firstSocket && m_firstSocket->m_endPoint)
  {
    addr = m_firstSocket->m_endPoint->GetPeerAddress();
	return true;
  }

  // XXX
  SubflowSet_t::const_iterator it = m_subflows.begin();
  if (it != m_subflows.end() )
  {
    addr = it->second->m_baseSocket->m_endPoint->GetPeerAddress();
	return true;
  }
  
  return false;
}

uint32_t
NaMPTSocket::GetLocalToken (void)
{
  return m_localToken;
}

uint32_t
NaMPTSocket::GetPeerToken (void)
{
  return m_peerToken;
}


/*
  * It is called by the L3 protocol when it received a packet to pass on to
  * the NaMPT. This function replace the equivalent of TcpSocketBase that is 
  * registed in endPoint. 
  * Goal: deal with MPC
*/
void
NaMPTSocket::ForwardUp (Ptr<Packet> packet, Ipv4Header header, 
							uint16_t port, Ptr<Ipv4Interface> incomingInterface)
{
  if (m_firstSocket == 0)
    return ;

  if (m_firstSocket->m_state == SYN_SENT ||
  	  m_firstSocket->m_state == SYN_RCVD ||
  	  m_firstSocket->m_state == LISTEN )
  {
    NaMPTHeader namptHeader;
	packet->RemoveHeader(namptHeader);
	
	// Get MPC option if existed.
	Ptr<NaMPTSignal> signal = namptHeader.FindSignal (NAMPT_MPC, false);
	if (signal != 0)
    {
      //NAMPT_LOG ("MPC: " << signal->sigData.mpc.localToken);
	  if (m_firstSocket->m_state == LISTEN)
      {
        NS_ASSERT(namptHeader.GetFlags() == TcpHeader::SYN);
		NS_ASSERT(m_localToken == 0 && m_peerToken == 0);
		
        // save the syn packet.
        Ptr<Packet> p = packet->Copy();
		p->AddHeader(namptHeader);
		p->AddHeader(header);
		m_pendingSynPacket.push_back(p);
      }
	  else
	  {
        // Note: we are in NaMPTSocket context. Save peer token.
        NS_ASSERT (m_firstSocket->m_state == SYN_SENT);
		NS_ASSERT(namptHeader.GetFlags() == (TcpHeader::SYN | TcpHeader::ACK) );
        NS_ASSERT (m_localToken != 0 && m_peerToken == 0);
        m_peerToken = signal->sigData.mpc.localToken;

		// the sender setups the first subflow
		Ptr<NaMPTSubflow> sf = SwitchToMultipathMode();
		sf->m_bAvailable = true;
		sf->m_bBypassSending = false;
		m_outputQueue.SetNextRxSequence(
		  namptHeader.GetSequenceNumber() + SequenceNumber32(1) );// syn consumes one byte

		/* note: m_firstSocket is invalid */
		
		// final forwarding
		namptHeader.RemoveAllSignals ();
		packet->AddHeader (namptHeader);
		sf->m_baseSocket->ForwardUp (packet, header, port, incomingInterface);
		return ;

	  }	  

    }
	else 
	{
	  if (m_firstSocket->m_state == LISTEN)
	  	NS_ASSERT(m_localToken == 0 && m_peerToken == 0);
	  else if (m_firstSocket->m_state == SYN_SENT) //sender
	  {
		// delete token because peer unsupports MPC
	    NS_ASSERT(m_localToken != 0 && m_peerToken == 0);
        Ptr<NaMPTL4Protocol> nampt = DynamicCast<NaMPTL4Protocol>(m_tcp);
        nampt->UnregisterToken(m_localToken);
		m_localToken = 0;
	  }
	  else
	  {
	    NS_ASSERT(m_firstSocket->m_state == SYN_RCVD); // reciever
	    NS_ASSERT(m_localToken == 0 && m_peerToken == 0);
	  }
	}

	// recover traditional packet
	namptHeader.RemoveAllSignals ();
	packet->AddHeader (namptHeader);
  }

  // forwarding
  m_firstSocket->ForwardUp (packet, header, port, incomingInterface);

}

Ptr<TcpSocketBase> 
NaMPTSocket::CreateBaseSocket(void)
{
  ObjectFactory socketFactory;
  ObjectFactory rttFactory;
  socketFactory.SetTypeId(m_socketTypeId);
  rttFactory.SetTypeId (m_rttTypeId);
  
  Ptr<TcpSocketBase> baseSock = socketFactory.Create<TcpSocketBase> ();
  baseSock->SetNode (m_node);
  baseSock->SetTcp (m_tcp);
  baseSock->SetRtt (rttFactory.Create<RttEstimator>() );

  // Force to modify default attributes. see TcpSocket.
  baseSock->SetConnTimeout(Seconds(1.0) );
  baseSock->SetConnCount(3);
  baseSock->m_cnCount = baseSock->GetConnCount(); //  ugly ...
  baseSock->SetPersistTimeout(Seconds(1.0) );
  baseSock->SetSSThresh(0xFFFFFFFF);
  baseSock->SetInitialCwnd(2);
  // copy other attributes from shell
  baseSock->SetSndBufSize(GetSndBufSize() );
  baseSock->SetRcvBufSize(GetRcvBufSize() );
  baseSock->SetSegSize(GetSegSize() );
  baseSock->SetDelAckTimeout(GetDelAckTimeout() );
  baseSock->SetDelAckMaxCount(GetDelAckMaxCount() );
  if (m_attributes.m_shutdownSend)
  	baseSock->ShutdownSend();
  if (m_attributes.m_shutdownRecv)
  	baseSock->ShutdownRecv();

  // Open cwnd, ugly method
  TcpStates_t savedState = baseSock->m_state;
  baseSock->Listen();
  baseSock->m_state = savedState;
  
  return baseSock;
}

Ptr<TcpSocketBase> 
NaMPTSocket::ConvertCongestionControl(Ptr<TcpSocketBase> baseSock)
{
  //Ptr<NaMPTCC> cc = Ptr<NaMPTCC>(new NaMPTCC(*PeekPointer(baseSock) ), false);
  Ptr<NaMPTCC> cc = CreateObject<NaMPTCC>(NaMPTCC(*PeekPointer(baseSock)) );

  // Copy uncopied variables
  cc->m_endPoint = baseSock->m_endPoint;
  cc->m_delAckCount = baseSock->m_delAckCount;
  cc->m_rto = baseSock->m_rto;
  cc->m_lastRtt = baseSock->m_lastRtt;
  cc->m_cnCount = baseSock->m_cnCount;

  // Copy app callback functions
  cc->SetConnectCallback (baseSock->m_connectionSucceeded, baseSock->m_connectionFailed);
  cc->SetCloseCallbacks (baseSock->m_normalClose, baseSock->m_errorClose);
  cc->SetAcceptCallback (baseSock->m_connectionRequest, baseSock->m_newConnectionCreated);
  cc->SetDataSentCallback (baseSock->m_dataSent);
  cc->SetSendCallback (baseSock->m_sendCb);
  cc->SetRecvCallback (baseSock->m_receivedData);

  // Copy congestion-control-related variables
  cc->SetInitialCwnd (baseSock->GetInitialCwnd() );
  cc->SetSSThresh (baseSock->GetSSThresh() );
  cc->InitializeCwnd();

  // Discard baseSock
  Callback<void, Ptr< Socket > > vPS = MakeNullCallback<void, Ptr<Socket> > ();
  Callback<void, Ptr<Socket>, const Address &> vPSA = MakeNullCallback<void, Ptr<Socket>, const Address &> ();
  Callback<bool, Ptr<Socket>, const Address &> bPSA = MakeNullCallback<bool, Ptr<Socket>, const Address &> ();
  Callback<void, Ptr<Socket>, uint32_t> vPSUI = MakeNullCallback<void, Ptr<Socket>, uint32_t> ();
  baseSock->SetConnectCallback (vPS, vPS);
  baseSock->SetDataSentCallback (vPSUI);
  baseSock->SetSendCallback (vPSUI);
  baseSock->SetRecvCallback (vPS);
  baseSock->SetCloseCallbacks (vPS, vPS);
  baseSock->SetAcceptCallback (bPSA, vPSA);
  
  //baseSock->m_endPoint = 0;
  //baseSock->m_tcp = 0;
  baseSock->Destroy(); // this function has done the above two steps.
  cc->m_tcp->m_sockets.push_back(cc); // here, cc saves the real m_tcp.
  cc->SetupCallback();

  // return new sock
  return cc;
}

Ptr<NaMPTSubflow> 
NaMPTSocket::GetSubflow(Ptr<Socket> sock)
{
  SubflowSet_t::iterator it = m_subflows.find(sock);
  if(it == m_subflows.end() )
  	return 0;
  return it->second;
}

void 
NaMPTSocket::InitAddressSet(void)
{
  if (m_node == 0)
  	return ;
  Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol>();
  if (ipv4 == 0)
  	return ;
  uint32_t nInterface = ipv4->GetNInterfaces();
  for (uint32_t i = 0; i < nInterface; i++)
  {
    Ptr<Ipv4Interface> itf = ipv4->GetInterface(i);
	if (itf->GetAddress(0).GetLocal() == Ipv4Address::GetLoopback() )
	  continue;
	uint32_t nAddress = itf->GetNAddresses();
	for (uint32_t j = 0; j < nAddress; j++)
    {
      uint32_t addr = itf->GetAddress(j).GetLocal().Get();
	  m_addresses[addr] = itf;
    }
  }
}

void
NaMPTSocket::AdvertizeAddresses(Ptr<NaMPTSubflow> subflow)
{
  /*
  std::set<uint32_t> addrSet;
  SubflowSet_t::const_iterator sfIter;
  for (sfIter = m_subflows.begin(); sfIter != m_subflows.end(); sfIter++)
  {
    addrSet.insert(sfIter->second->m_localAddress.Get() );
  }
  */
  AddressSet_t::const_iterator addrIter = m_addresses.begin();
  m_nextAddr = addrIter->first;
  for (; addrIter != m_addresses.end(); addrIter++)
  {
    //if (addrSet.find(addrIter->first) != addrSet.end() )
	//  continue;
	
	Ptr<NaMPTSignal> signal = subflow->SendSignal(NAMPT_ADDR);
	signal->sigData.addr.ipv4Addr = addrIter->first;
  }
  
}

void 
NaMPTSocket::TryPeerAddress(uint32_t addr)
{
  if (m_bClosed)
  	return ;
  // no try other addresses
  if (m_pathManagement & NAMPT_PM_SINGLE_SUBFLOW)
  	return ;
  // multip-points mode
  if (m_pathManagement & NAMPT_PM_ACCESS_POINTS)
  {
    TryMultiPoints();
	return ;
  }
  // only use the first src address
  if (m_pathManagement & NAMPT_PM_SINGLE_SRC)
  {
    uint32_t src = m_subflows.begin()->second->m_localAddress.Get();
    AddSubflow(src, m_localPort, addr, m_peerPort);
	return ;
  }
  // round robin
  if (m_pathManagement & NAMPT_PM_SRC_ROUNDROBIN)
  {
    if (AddSubflow(m_nextAddr, m_localPort, addr, m_peerPort) )
    {
      // next src addr
      AddressSet_t::const_iterator i = m_addresses.find(m_nextAddr);
      i++;
      if (i == m_addresses.end() )
        i = m_addresses.begin();
      m_nextAddr = i->first;
    }
    return ;
  }
  
  AddressSet_t::const_iterator it = m_addresses.begin();
  m_nextAddr = it->first;
  for (; it != m_addresses.end(); it++)
  {
	// try immediately
	AddSubflow(it->first, m_localPort, addr, m_peerPort);
  }
  
}

void
NaMPTSocket::TryMultiPoints(void)
{
  if (m_accessPoints.size() == 0)
  	return ;
  
  uint32_t srcAddr = m_subflows.begin()->second->m_localAddress.Get();
  while(m_accessPoints.size() > 1) //  the first point has been used
  {
    InetSocketAddress des = m_accessPoints.back();
    AddSubflow (srcAddr, m_localPort, des.GetIpv4().Get(), des.GetPort(), false);
	m_accessPoints.pop_back();
  }
  m_accessPoints.clear();
}

bool 
NaMPTSocket::AddSubflow(uint32_t srcAddr, uint16_t srcPort, uint32_t desAddr, uint16_t desPort, bool bCheck)
{
 if (bCheck)
 {
    // check if ips are in the same lan.
    uint32_t lanAddr = 0;
    uint32_t lanMask = 0xFFFFFF00;
    if (m_pathManagement & NAMPT_PM_DETECT_LAN)
    {
      if ((srcAddr&lanMask) == (desAddr&lanMask) )
  	  lanAddr = srcAddr&lanMask;
    }
  
    // check if path has already existed
    SubflowSet_t::const_iterator it;
    for (it = m_subflows.begin(); it != m_subflows.end(); it++)
    {
      if (srcAddr == it->second->m_localAddress.Get() && 
  		desAddr == it->second->m_peerAddress.Get() )
  	  return false;
  	if ((m_pathManagement & NAMPT_PM_SRC_ROUNDROBIN) &&
  		desAddr == it->second->m_peerAddress.Get() )
  	  return false;
  	if (lanAddr != 0 && 
  		lanAddr == (it->second->m_localAddress.Get()&lanMask) && 
  		lanAddr == (it->second->m_peerAddress.Get()&lanMask) )
  	  return false;
    }
  }
  // construct subflow
  Ipv4EndPoint* endpoint = m_tcp->Allocate(Ipv4Address(srcAddr), srcPort, Ipv4Address(desAddr), desPort);
  if (endpoint == 0)
  	return false;
  Ptr<TcpSocketBase> baseSocket = CreateBaseSocket();
  baseSocket->m_endPoint = endpoint;
  m_tcp->m_sockets.push_back(baseSocket);
  baseSocket->SetupCallback();
  
  baseSocket->BindToNetDevice(m_addresses[srcAddr]->GetDevice() );
  baseSocket->m_state = SYN_SENT;
  
  Ptr<NaMPTSubflow> subflow = SetupSubflow(baseSocket, false);
  baseSocket->SendEmptyPacket (TcpHeader::SYN);
  
  return true;
}

void 
NaMPTSocket::ReschedulingPackets(Ptr<NaMPTSubflow> subflow)
{
  if(subflow->m_baseSocket->m_txBuffer.Size() == 0)
  	return ;

  subflow->m_cnRescheduling += 1;

  // Copy all data in m_txBuffer to input queue
  DSNDB_t::iterator it;
  PacketSet_t::iterator pt;
  uint32_t offSet, dataLen;
  Ptr<Packet> pkt;
  SequenceNumber32 dSeq;
  SequenceNumber32 sfSeq = subflow->m_baseSocket->m_txBuffer.HeadSequence();
  SequenceNumber32 sfEnd = subflow->m_baseSocket->m_txBuffer.TailSequence();

/*
                                                --------------------
m_nextRescheduling    ^                      ^  
                                    case1               case2 
*/
  NS_ASSERT(sfEnd >= subflow->m_nextRescheduling); 
  if(sfSeq < subflow->m_nextRescheduling) // case2
  	sfSeq = subflow->m_nextRescheduling;
  
  while(sfSeq < sfEnd)
  {
    it = subflow->m_localDSN.lower_bound(sfSeq);
	if (it == subflow->m_localDSN.end() || sfSeq < it->first)
	  it--;
	NS_ASSERT(it->second->m_sfSeq <= sfSeq && sfSeq < it->second->m_sfEnd);
	offSet = sfSeq - it->second->m_sfSeq;
	dSeq = it->second->m_dataSeq + offSet;
	NS_ASSERT(it->second->m_dataLen > offSet);
	dataLen = it->second->m_dataLen - offSet;
	pkt = subflow->m_baseSocket->m_txBuffer.CopyFromSequence(dataLen, sfSeq);
	NS_ASSERT(pkt != 0 && pkt->GetSize() == dataLen);

    // validating
    if(m_reschedulingQueue.size() > 0)
    {
      pt = m_reschedulingQueue.lower_bound(dSeq);
	  if(pt == m_reschedulingQueue.end() )
      {
        pt--;
		NS_ASSERT(dSeq >= pt->first + SequenceNumber32(pt->second->GetSize()) );
      }
	  else
      {
        NS_ASSERT(dSeq + SequenceNumber32(dataLen) <= pt->first);
		if(pt != m_reschedulingQueue.begin() )
        {
          pt--;
		  NS_ASSERT(dSeq >= pt->first + SequenceNumber32(pt->second->GetSize()) );
        }
      }
    }

	// rescheduling
	m_reschedulingQueue[dSeq] = pkt;
	sfSeq += dataLen;

	// statistic
	subflow->m_byteRescheduling += pkt->GetSize();
	
  }

  // Remove unsent data
  it = subflow->m_localDSN.begin();
  for(; it != subflow->m_localDSN.end(); it++)
  {
    if(it->second->m_bAdvertized)
	  continue;
	
	sfSeq = it->first;
	NS_ASSERT(sfSeq >= subflow->m_baseSocket->m_highTxMark);
	while(it != subflow->m_localDSN.end() )
    {
      NS_ASSERT(it->second->m_bAdvertized == false);
	  DSNDB_t::iterator itTmp = it++;
	  itTmp->second = 0;
	  subflow->m_localDSN.erase(itTmp);
    }

    /*
                 ------XXXXXXXXXXX
                ^          ^                     ^
               hq      sfSeq               sfEnd
      */
    SequenceNumber32 headSeq = subflow->m_baseSocket->m_txBuffer.HeadSequence();
	NS_ASSERT(sfSeq < sfEnd && sfSeq >= headSeq);
	dataLen = sfSeq - headSeq;
	if(dataLen > 0)
	{
	  pkt = subflow->m_baseSocket->m_txBuffer.CopyFromSequence(dataLen, headSeq);
	  NS_ASSERT(pkt->GetSize() == dataLen);
	}
	subflow->m_baseSocket->m_txBuffer.DiscardUpTo(sfEnd);
	NS_ASSERT(subflow->m_baseSocket->m_txBuffer.Size() == 0 &&
			  subflow->m_baseSocket->m_txBuffer.HeadSequence() == sfEnd);
	subflow->m_baseSocket->m_txBuffer.SetHeadSequence(headSeq);
	if(dataLen > 0)
	{
	  subflow->m_baseSocket->m_txBuffer.Add(pkt);
	  NS_ASSERT(subflow->m_baseSocket->m_txBuffer.Size() == dataLen);
	}
	
	sfEnd = sfSeq; // for following marking
	break;
  }

  // marking
  subflow->m_nextRescheduling = sfEnd;
  
}

uint64_t 
NaMPTSocket::CalculateLinkedAlpha(Ptr<NaMPTCC> sock, uint32_t segmentSize)
{
  // update rates if needed.
  if (sock)
  {
    Ptr<NaMPTSubflow> subflow = GetSubflow(sock);
	if (subflow)
	{
	  subflow->m_equilibrium = 0;
	  uint32_t r = subflow->m_rtt->GetCurrentEstimate().GetMicroSeconds();
	  if (subflow->m_bAvailable && r > 0)
	  	subflow->m_equilibrium = 8.0 * sock->m_cWnd.Get() / r; // Mbps
      subflow->m_instantRate = subflow->m_instantRate * 0.875 + 
                              0.125 * subflow->m_equilibrium;
	}
  }
/*
	alpha = max {w/rtt^2} / ( sum {w/rtt } )^2

	increase cwnd by "alpha" pkts per ack
	or, by "cwnd * alpha" pkts per round
	for any subflows.
*/
  // note: the unit of rates is Mbps
  m_instRate = 0;
  uint32_t nAvail = 0;
  uint64_t best_cwnd = 0, best_rtt = 0;
  uint64_t max_numerator = 0, sum_denominator = 0, alpha = 1;
  SubflowSet_t::const_iterator it = m_subflows.begin();
  for (; it != m_subflows.end(); it++)
  {
	  if (!it->second->m_bAvailable ||
		  it->second->m_equilibrium == 0)
		continue;
	  nAvail ++;

	  uint64_t cwnd = DynamicCast<NaMPTCC>(it->second->m_baseSocket)->m_cWnd.Get() / segmentSize;
	  uint32_t rtt = it->second->m_rtt->GetCurrentEstimate().GetMicroSeconds();
	  uint64_t tmp = (cwnd << 32) / (rtt * rtt);
	  if (tmp >= max_numerator)
	  {
	  	max_numerator = tmp;
		best_cwnd = cwnd;
		best_rtt = rtt;
	  }
	  sum_denominator += (cwnd << 10) / rtt;
	  m_instRate += it->second->m_instantRate;
  }
  if (nAvail > 1 && sum_denominator > 0)
  {
	  sum_denominator *= best_rtt;
	  sum_denominator *= sum_denominator;
	  alpha = (best_cwnd << 32) / sum_denominator;
	  if (alpha == 0)
	  	alpha = 1;
  }
  return alpha;
}


/**************************************************
  **************************************************
  **************************************************
*/

void 
NaMPTSocket::DoSubflowSucceeds(Ptr<Socket> sock)
{
  Ptr<NaMPTSubflow> sf = GetSubflow(sock);
  if(sf == 0)
  	return ;
  sf->m_bAvailable = true;
  if (m_bClosed)
  {
    Simulator::ScheduleNow(&NaMPTSubflow::Close, sf);
	return;
  }
  DoSubflowSend(sock, sock->GetTxAvailable() );
}

void 
NaMPTSocket::DoSubflowFails(Ptr<Socket> sock)
{
  Ptr<NaMPTSubflow> sf = GetSubflow(sock);
  if(sf == 0)
    return ;

  NAMPT_LOG("Subflow fails: " << sf->m_localAddress << " ---> " << sf->m_peerAddress);
}

bool 
NaMPTSocket::DoSubflowRequests(Ptr<Socket> sock, const Address& from)
{
  // this function should not be invoked.
  NS_ASSERT (false);
  return true;
}

void 
NaMPTSocket::DoSubflowAccepted(Ptr<Socket> sock, const Address& from)
{
  Ptr<NaMPTSubflow> sf = GetSubflow(sock);
  if(sf == 0)
  	return ;
  sf->m_bAvailable = true;
  DoSubflowSend(sock, sock->GetTxAvailable() );
}

void 
NaMPTSocket::DoSubflowDataSent(Ptr<Socket> sock, uint32_t bytes)
{
  // just notify application
  NotifyDataSent (bytes);
}

void 
NaMPTSocket::DoSubflowSend(Ptr<Socket> sock, uint32_t txAvailable)
{
  SchedulingPackets(GetSubflow(sock) );
}

void 
NaMPTSocket::DoSubflowRecv(Ptr<Socket> sock)
{
  Ptr<NaMPTSubflow> sf = GetSubflow(sock);

  if (m_outputQueue.Available() > 0)
  	NotifyDataRecv();

  if(sf == 0)
  	return ;

  switch (m_assemblingAlgo)
  {
    case NAMPT_NA: // read data as much as possible
    default:
	  NaiveAssembling(sf);
  }

  if (m_outputQueue.Available() > 0)
  	NotifyDataRecv();

  // statistics
  m_peakOfOutputQueue = std::max(m_peakOfOutputQueue, m_outputQueue.Size() );
  //NAMPT_LOG("BUF: " << m_outputQueue.Size() );
  
  return ;
  
}

void 
NaMPTSocket::DoSubflowPeerClose(Ptr<Socket> sock)
{
  Ptr<NaMPTSubflow> sf = GetSubflow(sock);
  if (sf == 0)
  	return ;

  // I never send data
  sf->m_bAvailable = false;
  sock->SetSendCallback(MakeNullCallback<void, Ptr<Socket>, uint32_t> ());
  NS_ASSERT(sf->m_baseSocket->m_txBuffer.Size() == 0);
  sock->ShutdownSend(); //  baseSocket will invoke Close() due to ShutdownSend()

  // change the close callback functions
  sf->m_baseSocket->m_closeNotified = false;
  sock->SetCloseCallbacks(MakeCallback(&NaMPTSocket::DoSubflowNormalClose, this),
  						MakeCallback(&NaMPTSocket::DoSubflowErrorClose, this) );

}

void 
NaMPTSocket::DoSubflowNormalClose(Ptr<Socket> sock)
{
  Ptr<NaMPTSubflow> sf = GetSubflow(sock);
  if(sf == 0)
  	return ;

  // 1) Move outgoing queue into input queue
  // 2) Move ingoing queue into output queue, because
  // if m_rxBuffer is not null (because of non-in-sequence data),
  // RST will be sent.
  CleanupSubflow(sf);
  NS_ASSERT(sf->m_baseSocket->m_rxBuffer.Size() == 0);
  NS_ASSERT(sf->m_baseSocket->m_txBuffer.Size() == 0);

  // output subflow's info
  sf->OutputInfo();
  if (m_flowSize > 0)
  {
	  NAMPT_LOG2("SFLOW " << m_sessionName << " " << 
	  	sf->m_rtt->GetCurrentEstimate().GetMicroSeconds() << " " << 
	  	sf->m_baseSocket->m_rtt->GetCurrentEstimate().GetMicroSeconds() << " " << 
	  	sf->m_sndPackets << " " << 
	  	sf->m_cnTimeout << " " << 
	  	sf->m_cnFastRetrans);
  }

  // remove sf from m_subflows. 
  SubflowSet_t::iterator it = m_subflows.find(sock);
  it->second = 0;
  m_subflows.erase(it);
  sf = 0;

  // notify app
  if (m_subflows.size() == 0)
  {
    // clear token
    Ptr<NaMPTL4Protocol> nampt = DynamicCast<NaMPTL4Protocol>(m_tcp);
	nampt->UnregisterToken(m_localToken);

	// show statistics
	if (m_flowSize > 0)
	{
	  m_timeTag = Simulator::Now().GetSeconds() - m_timeTag;
	  m_instRate = m_flowSize * 0.000008 / m_timeTag; // Mbps
	  NAMPT_LOG2("FLOW " << m_sessionName << " " << 
	  			m_flowSize << " " << 
	  			m_timeTag << " " << // elapse time
	  			m_instRate);
	}
	/*else
	{
	  NAMPT_LOG("PeakOfOutputQueue: " << m_peakOfOutputQueue);
	}*/
	
    NotifyNormalClose();
  }
}

void 
NaMPTSocket::DoSubflowErrorClose(Ptr<Socket> sock)
{
}


bool 
NaMPTSocket::DoSubflowNewAck(Ptr<NaMPTCC> sock, const SequenceNumber32& ackSeq)
{
  Ptr<NaMPTSubflow> subflow = GetSubflow(sock);
  if (subflow == 0)
  	return true;
  //uint32_t oldWnd = sock->m_cWnd.Get();
  switch(m_ccAlgo)
  {
    case NAMPT_CC_LIA:
      {
		uint32_t cwnd = sock->m_cWnd / sock->m_segmentSize;
		if (subflow->m_cnAcks == 0)
			subflow->m_refWin = cwnd;
		subflow->m_cnAcks++;
	  	if (sock->m_cWnd < sock->m_ssThresh)
	  	{
	  	  // slow start
		  sock->m_cWnd += sock->m_segmentSize;
		  m_alpha = CalculateLinkedAlpha(sock, sock->m_segmentSize);
	  	}
		else // ca 
		{
		  if (m_alpha == 0)
		  	m_alpha = CalculateLinkedAlpha(sock, sock->m_segmentSize);
		  if (m_alpha <= 1)
		  	subflow->m_refWin = cwnd;
		  else
		  {
            uint64_t tmp = 1;
            subflow->m_refWin = (tmp << 12) / m_alpha;
            if (subflow->m_refWin < cwnd)
              subflow->m_refWin = cwnd;
		  }

		  if (subflow->m_cnAcks >= subflow->m_refWin)
		  {
		    sock->m_cWnd += sock->m_segmentSize;
			m_alpha = CalculateLinkedAlpha(sock, sock->m_segmentSize);
		  }
		}
		// per round
		if (subflow->m_cnAcks >= subflow->m_refWin)
		{
			subflow->m_rounds++;	
			cwnd = sock->m_cWnd / sock->m_segmentSize;
			NAMPT_LOG("DIFF " << subflow->m_localAddress << "->" << 
					subflow->m_peerAddress << " " << 
					0 << " " <<
					cwnd << " " << sock->m_ssThresh/sock->m_segmentSize << " " << 
					0 << " " <<
					subflow->m_instantRate << " " <<
					subflow->m_rtt->GetCurrentEstimate().GetMicroSeconds() << "/" << 
					subflow->m_baseRTT.GetMicroSeconds() << "/" << 
 					subflow->m_rtt->RetransmitTimeout().GetMicroSeconds() 
 					);
			
			NAMPT_LOG("CONN " << m_sessionName << " " << 
					m_instRate << " " << 
					m_alpha);
			
			subflow->m_cnAcks = 0;
			subflow->m_cnRTT = 0;
			subflow->m_sumRTT = 0;
			subflow->m_minRTT = Seconds(60.0);
		}
      }
	  break;
	case NAMPT_CC_DCTCP:
      {
        // do per-round tasks
        if(ackSeq > subflow->m_begSeq)
        {
          subflow->m_rounds++;
          // cwnd of the last round
          double cwnd = sock->m_cWnd.Get() / sock->m_segmentSize;
          if (subflow->m_cwr == 2)
            cwnd = subflow->m_refWin;
      
          // measurement parameters
          uint32_t rtt = subflow->m_rtt->GetCurrentEstimate().GetMicroSeconds();
		  
          double g = 0.0625;
          double marking = subflow->m_nECE / cwnd;
          subflow->m_marking = (1.0 - g) * subflow->m_marking + g * marking;
		  if (subflow->m_marking > 1.0)
		  	subflow->m_marking = 1.0;
      
          // update rates in the last round.
          double lastRate = 8.0 * cwnd * sock->m_segmentSize / rtt; // Mbps
          subflow->m_instantRate = subflow->m_instantRate * 0.875 + 0.125 * lastRate;
          subflow->m_equilibrium = lastRate;
      
          double totalRate = 0;
          m_instRate = 0;
          Time minRTT = Seconds(60.0);
          SubflowSet_t::iterator it = m_subflows.begin();
          for (; it != m_subflows.end(); it++)
          {
            if (!it->second->m_bAvailable || 
          	   it->second->m_equilibrium == 0) // otherwise, minRTT may be zero
          	  continue;
            totalRate += it->second->m_equilibrium;
            m_instRate += it->second->m_instantRate;
            minRTT = Min(minRTT, it->second->m_rtt->GetCurrentEstimate());
          }
      	
          // update weights for next round
          if (totalRate > 0)
          {
            subflow->m_weight = rtt * subflow->m_equilibrium / totalRate;
            subflow->m_weight /= minRTT.GetMicroSeconds();
            NS_ASSERT(subflow->m_weight > 0);
          }
      
          // In the safe area, increase cwnd.
          if (subflow->m_cwr == 1)
          {
          	if (sock->m_cWnd < sock->m_ssThresh)
          	  sock->m_cWnd += sock->m_segmentSize; // ss
          	else
          	{ // ca
          	  subflow->m_incCum += subflow->m_weight;
          	  uint32_t a = subflow->m_incCum;
          	  subflow->m_incCum -= a;
          	  sock->m_cWnd += a * sock->m_segmentSize;
          	}
          }
      
          NAMPT_LOG("DIFF " << subflow->m_localAddress << "->" << 
          		  subflow->m_peerAddress << " " << 
          		  0 << " " << 
          		  cwnd << " " << sock->m_ssThresh/sock->m_segmentSize << " " << 
          		  subflow->m_weight << " " << 
          		  subflow->m_instantRate << " " <<
          		  rtt << "/" << 
          		  subflow->m_baseRTT.GetMicroSeconds() << "/" << 
          		  subflow->m_rtt->RetransmitTimeout().GetMicroSeconds() << " " << 
          		  subflow->m_nECE << " " << 
          		  subflow->m_marking
          		  );
      
          NAMPT_LOG("CONN " << m_sessionName << " " << 
          		  m_instRate);
      	
          // repare for next round
          subflow->m_refWin = sock->m_cWnd.Get() / sock->m_segmentSize;
          subflow->m_nECE = 0;
          subflow->m_begSeq = sock->m_nextTxSequence;
          subflow->m_cnRTT = 0;
          subflow->m_sumRTT = 0;
          subflow->m_minRTT = Seconds(60.0);
        }
		else if (subflow->m_cwr == 1 && sock->m_cWnd < sock->m_ssThresh)
		  sock->m_cWnd += sock->m_segmentSize; // ss
		// quit from cwr
		if (subflow->m_cwr == 2 && ackSeq >= subflow->m_cwrHighSeq)
		  subflow->m_cwr = 1;
      }
      break;
	case NAMPT_CC_XMP:
	  {
		// do per-round tasks
		if(ackSeq > subflow->m_begSeq)
		{
		  subflow->m_rounds++;
		  // cwnd of the last round
		  double cwnd = sock->m_cWnd.Get() / sock->m_segmentSize;
		  if (subflow->m_cwr == 2)
		  	cwnd = subflow->m_refWin;
	  
		  // measurement parameters. 
	      uint32_t rtt = subflow->m_rtt->GetCurrentEstimate().GetMicroSeconds();

		  // update rates in the last round.
		  double lastRate = 8.0 * cwnd * sock->m_segmentSize / rtt; // Mbps
		  subflow->m_instantRate = subflow->m_instantRate * 0.875 + 0.125 * lastRate;
		  subflow->m_equilibrium = lastRate;
	  
		  double totalRate = 0;
		  m_instRate = 0;
		  Time minRTT = Seconds(60.0);
          SubflowSet_t::iterator it = m_subflows.begin();
          for (; it != m_subflows.end(); it++)
          {
            if (!it->second->m_bAvailable || 
                 it->second->m_equilibrium == 0) // otherwise, minRTT may be zero
              continue;
            totalRate += it->second->m_equilibrium;
            m_instRate += it->second->m_instantRate;
            minRTT = Min(minRTT, it->second->m_rtt->GetCurrentEstimate());
          }
		  
		  // update weights for next round
		  if (totalRate > 0)
		  {
			subflow->m_weight = rtt * subflow->m_equilibrium / totalRate;
			subflow->m_weight /= minRTT.GetMicroSeconds();
			NS_ASSERT(subflow->m_weight > 0);
		  }

          // In the safe area, increase cwnd.
		  if (subflow->m_cwr == 1)
		  {
            if (sock->m_cWnd < sock->m_ssThresh)
              sock->m_cWnd += sock->m_segmentSize; // ss
            else
            { // ca
              subflow->m_incCum += subflow->m_weight * m_initGamma;
              uint32_t a = subflow->m_incCum;
              subflow->m_incCum -= a;
              sock->m_cWnd += a * sock->m_segmentSize;
            }
		  }

          NAMPT_LOG("DIFF " << subflow->m_localAddress << "->" << 
                    subflow->m_peerAddress << " " << 
                    0 << " " << 
                    cwnd << " " << sock->m_ssThresh/sock->m_segmentSize << " " << 
                    subflow->m_weight << " " << 
                    subflow->m_instantRate << " " <<
                    rtt << "/" << 
                    subflow->m_baseRTT.GetMicroSeconds() << "/" << 
                    subflow->m_rtt->RetransmitTimeout().GetMicroSeconds() << " " << 
                    subflow->m_nECE
                    );
	  
          NAMPT_LOG("CONN " << m_sessionName << " " << 
                    m_instRate);
          
          // repare for next round
          subflow->m_refWin = sock->m_cWnd.Get() / sock->m_segmentSize;
          subflow->m_nECE = 0;
          subflow->m_begSeq = sock->m_nextTxSequence;
          subflow->m_cnRTT = 0;
          subflow->m_sumRTT = 0;
          subflow->m_minRTT = Seconds(60.0);
		}
		else if (subflow->m_cwr == 1 && sock->m_cWnd < sock->m_ssThresh)
		  sock->m_cWnd += sock->m_segmentSize; // ss
		// quit from cwr
		if (subflow->m_cwr == 2 && ackSeq >= subflow->m_cwrHighSeq)
		  subflow->m_cwr = 1;
	  }
	  break;
    case NAMPT_CC_WVEGAS:
	  {
	  	// do per-round tasks
	  	if(ackSeq > subflow->m_begSeq)
	  	{
	  	  subflow->m_rounds++;
		  
		  double cwnd = sock->m_cWnd.Get() / sock->m_segmentSize;
		  uint32_t rtt = subflow->m_rtt->GetCurrentEstimate().GetMicroSeconds(); // init value
		  if(subflow->m_cnRTT >= 2)
		  	rtt = subflow->m_sumRTT / subflow->m_cnRTT; // us
		  uint32_t baseRTT = subflow->m_baseRTT.GetMicroSeconds();
		  NS_ASSERT(rtt >= baseRTT);
		  double diff = cwnd * (rtt - baseRTT) / rtt; // pkts
		  uint32_t idiff = diff * 100;
		  uint32_t igamma = subflow->m_gamma * 100;
		  
          // update rates in the last round
          double lastRate = 8.0 * cwnd * sock->m_segmentSize / rtt; // Mbps
          subflow->m_instantRate = subflow->m_instantRate * 0.9 + 0.1 * lastRate;
          if (idiff >= igamma)
		  	subflow->m_equilibrium = lastRate;
		  
          m_instRate = 0;
          double totalRate = 0;
          SubflowSet_t::const_iterator it = m_subflows.begin();
          for (; it != m_subflows.end(); it++)
          {
            if (!it->second->m_bAvailable ||
                 it->second->m_equilibrium == 0)
              continue;
            totalRate += it->second->m_equilibrium;
            m_instRate += it->second->m_instantRate;
          }
		  
          // update weights 
          if (idiff >= igamma && totalRate > 0)
          {
            subflow->m_weight = subflow->m_equilibrium / totalRate;
            subflow->m_gamma = subflow->m_weight * m_initGamma;
            NS_ASSERT(subflow->m_gamma > 0);
          }

          // control windows for the next round
          if (idiff < igamma)
          {
		    sock->m_cWnd += sock->m_segmentSize;
          }
		  else if (idiff > igamma)
		  {
		    sock->m_cWnd -= sock->m_segmentSize;
		  }

		  // try to drain link queues if needed
		  //if (idiff > igamma)
		  {
		    uint32_t q = rtt - baseRTT; // us
		    if (subflow->m_minQueueDelay == 0 || subflow->m_minQueueDelay > q)
			  subflow->m_minQueueDelay = q;
			if ((float)q >= 1.2 * subflow->m_minQueueDelay)
			{
			  subflow->m_minQueueDelay = 0;
			  double backoff = 0.25 * baseRTT / rtt; // more smaller, more faster
			  uint32_t newWin = cwnd * backoff;
			  sock->m_cWnd = newWin * sock->m_segmentSize;
			}
		  }

		  // lower-bound
		  sock->m_cWnd = std::max (sock->m_cWnd.Get(), 2 * sock->m_segmentSize);
		  if (idiff >= igamma)
		  	sock->m_ssThresh = std::min(sock->m_ssThresh, sock->m_cWnd.Get() );

          NAMPT_LOG("DIFF " << subflow->m_localAddress << "->" << 
				  subflow->m_peerAddress << " " << 
				  diff << " " << 
				  cwnd << " " << sock->m_ssThresh/sock->m_segmentSize << " " << 
				  subflow->m_weight << " " << 
				  subflow->m_instantRate << " " <<
				  rtt << "/" << 
				  subflow->m_baseRTT.GetMicroSeconds() << "/" << 
				  subflow->m_rtt->RetransmitTimeout().GetMicroSeconds()
				  );
		  
          NAMPT_LOG("CONN " << m_sessionName << " " << 
                    m_instRate);

          // repare for next round
          subflow->m_begSeq = sock->m_nextTxSequence;
          subflow->m_cnRTT = 0;
          subflow->m_sumRTT = 0;
          subflow->m_minRTT = Seconds(60.0);
	  	}
		else if (sock->m_cWnd < sock->m_ssThresh)
		  sock->m_cWnd += sock->m_segmentSize; // ss
	  }
	  break;
    case NAMPT_CC_INDE:
	default:
      {
        if (sock->m_cWnd < sock->m_ssThresh)
          sock->m_cWnd += sock->m_segmentSize;
        else
        {
          double adder = static_cast<double> (sock->m_segmentSize * sock->m_segmentSize) / sock->m_cWnd.Get ();
		  adder = std::max (1.0, adder);
          sock->m_cWnd += static_cast<uint32_t> (adder);
        }
	  }
  }

  // up-bound of cwnd
  //if (sock->m_cWnd > sock->m_rWnd)
  //	sock->m_cWnd = oldWnd;

  // push it forward because of wrap-around, see NaMPTSocket::ReschedulingPackets()
  subflow->m_nextRescheduling = ackSeq;
  
  return true;
}

void 
NaMPTSocket::DoDCTCPEnterCWR(Ptr<NaMPTSubflow> subflow, Ptr<NaMPTCC> sock)
{
	uint32_t cwnd = sock->m_cWnd.Get() / sock->m_segmentSize;
	subflow->m_refWin = cwnd;
	if (sock->m_cWnd >= sock->m_ssThresh)
	{
		// shrink cwnd
		uint32_t reduced = cwnd * subflow->m_marking / 2.0;
		reduced = (reduced == 0) ? 1 : reduced;
		cwnd = (cwnd > reduced) ? cwnd - reduced : 0;
		cwnd  = (cwnd < 2) ? 2 : cwnd;
		sock->m_cWnd = cwnd * sock->m_segmentSize;
	}
	if (sock->m_cWnd < sock->m_ssThresh)
		sock->m_ssThresh = sock->m_cWnd.Get();
}

void 
NaMPTSocket::DoXMPEnterCWR(Ptr<NaMPTSubflow> subflow, Ptr<NaMPTCC> sock)
{
	uint32_t cwnd = sock->m_cWnd.Get() / sock->m_segmentSize;
	subflow->m_refWin = cwnd;
	if (sock->m_cWnd >= sock->m_ssThresh)
	{
		// shrink cwnd
		uint32_t reduced = cwnd / float(m_backoffBeta);
		reduced = (reduced == 0) ? 1 : reduced;
		cwnd = (cwnd > reduced) ? cwnd - reduced : 0;
		cwnd  = (cwnd < 2) ? 2 : cwnd;
		sock->m_cWnd = cwnd * sock->m_segmentSize;
	}
	if (sock->m_cWnd < sock->m_ssThresh)
		sock->m_ssThresh = sock->m_cWnd.Get();
}

bool 
NaMPTSocket::DoSubflowDupAck(Ptr<NaMPTCC> sock, const SequenceNumber32& ackSeq, uint32_t count)
{
  Ptr<NaMPTSubflow> subflow = GetSubflow(sock);
  if (subflow == 0)
  	return true;
  switch(m_ccAlgo)
  {
	case NAMPT_CC_DCTCP:
	case NAMPT_CC_XMP:
	case NAMPT_CC_WVEGAS:
	case NAMPT_CC_LIA:
		if (count == 3 && !sock->m_inFastRec)
		{
		  int pktInFlight = sock->BytesInFlight() / sock->m_segmentSize;
		  sock->m_ssThresh = std::max (1, pktInFlight / 2);
		  sock->m_ssThresh *= sock->m_segmentSize;
		  sock->m_cWnd = sock->m_ssThresh + 3 * sock->m_segmentSize;
		  m_alpha = 0;

          uint32_t rtt = subflow->m_rtt->GetCurrentEstimate().GetMicroSeconds();
		  double curRate = 0;
          if (rtt > 0)
		  	curRate = 8.0 * sock->m_ssThresh / rtt; // Mbps
          subflow->m_instantRate = subflow->m_instantRate * 0.875 + 0.125 * curRate;
          subflow->m_equilibrium = curRate;
		}
		else if (sock->m_inFastRec)
		{
		  sock->m_cWnd += sock->m_segmentSize;
		}
		break;
	case NAMPT_CC_INDE:
	default:
      if (count == 3 && !sock->m_inFastRec)
      {
        sock->m_ssThresh = std::max (2 * sock->m_segmentSize, sock->BytesInFlight() / 2);
        sock->m_cWnd = sock->m_ssThresh + 3 * sock->m_segmentSize;
      }
      else if (sock->m_inFastRec)
      {
        sock->m_cWnd += sock->m_segmentSize;
      }
  }

  // statistic 
  if (count == 3 && !sock->m_inFastRec)
  {
    subflow->m_cnFastRetrans += 1;
	NAMPT_LOG("LOSS " << subflow->m_localAddress << "->" << 
		  subflow->m_peerAddress << " " << 
		  sock->m_cWnd/sock->m_segmentSize << "/" << sock->m_ssThresh/sock->m_segmentSize << " " << 
		  sock->m_txBuffer.HeadSequence() << "/" << 
		  sock->m_nextTxSequence << "/" << 
		  sock->m_highTxMark << "/" << 
		  subflow->m_begSeq << " " << 
		  subflow->m_rtt->RetransmitTimeout().GetMicroSeconds() << "/" << 
		  sock->m_rto.Get().GetMicroSeconds() );
  }
  
  return true;
}

bool 
NaMPTSocket::DoSubflowTimeout(Ptr<NaMPTCC> sock)
{
  Ptr<NaMPTSubflow> subflow = GetSubflow(sock);
  if (subflow == 0)
  	return true;
  switch(m_ccAlgo)
  {
	case NAMPT_CC_DCTCP:
	case NAMPT_CC_XMP:
	case NAMPT_CC_WVEGAS:
	case NAMPT_CC_LIA:
      {
	  	int pktInFlight = sock->BytesInFlight() / sock->m_segmentSize;
        sock->m_ssThresh = std::max (1, pktInFlight / 2);
		sock->m_ssThresh *= sock->m_segmentSize;
        sock->m_cWnd = 2 * sock->m_segmentSize;
		m_alpha = CalculateLinkedAlpha (sock, sock->m_segmentSize);
		if (subflow->m_cwr > 0)
		  subflow->m_cwr = 1;
		
	  	subflow->m_nECE = 0;
        //subflow->m_begSeq = sock->m_txBuffer.HeadSequence()+sock->m_cWnd.Get();
		subflow->m_begSeq = sock->m_txBuffer.HeadSequence();
        subflow->m_minRTT = Seconds(60.0);
        subflow->m_cnRTT = 0;
        subflow->m_sumRTT = 0;
      }
	  break;
	case NAMPT_CC_INDE:
	default:
	  {
		sock->m_ssThresh = std::max (2 * sock->m_segmentSize, sock->BytesInFlight() / 2);
		sock->m_cWnd = 2 * sock->m_segmentSize;
      }
  }
  
  // statistic
  subflow->m_cnTimeout += 1;
  NAMPT_LOG("LOSS " << subflow->m_localAddress << "->" << 
		subflow->m_peerAddress << " " << 
		sock->m_cWnd/sock->m_segmentSize << "/" << sock->m_ssThresh/sock->m_segmentSize << " " << 
		sock->m_txBuffer.HeadSequence() << "/" << 
		sock->m_nextTxSequence << "/" << 
		sock->m_highTxMark << "/" << 
		subflow->m_begSeq << " " << 
		subflow->m_rtt->RetransmitTimeout().GetMicroSeconds() << "/" << 
		sock->m_rto.Get().GetMicroSeconds() );
  return true;
}

bool
NaMPTSocket::SchedulingQuota(Ptr<NaMPTSubflow> subflow, uint32_t& minQuota, uint32_t& maxQuota)
{
  minQuota = 0, maxQuota = 0;
  if (!subflow->m_bAvailable)
  	return false;
  
  uint32_t	freeWin = subflow->FreeSizeOfSendingWindow();
  uint32_t	backlog = subflow->BacklogOfOutgoingQueue();
  uint32_t	freeBuf = subflow->FreeSizeOfOutgoingQueue();
  /*
     Case: sndBuffer < cwnd
     
	          freeWin
	================|--------- cwnd (Window)
	      ======-------|---------  txBuffer (OutgoingQueue)
	       freeBuf   backlog	   unAcked
  */
  maxQuota = subflow->SegmentRound(freeBuf);
  if (backlog >= freeWin) // enough to send
  	return false;
  
  minQuota = subflow->SegmentRound(freeWin - backlog);
  if (minQuota == 0)
  	return false;
  // expand txBuffer
  if (minQuota > maxQuota)
  {
    uint32_t size = subflow->m_baseSocket->GetSndBufSize();
	uint32_t total = m_inputQueue.MaxBufferSize();
	NS_ASSERT(total >= size);
	total -= size;
	size += minQuota - maxQuota;
    subflow->m_baseSocket->SetSndBufSize(size);
	total += size;
	m_inputQueue.SetMaxBufferSize(total);
    freeBuf = subflow->FreeSizeOfOutgoingQueue();
	maxQuota = subflow->SegmentRound(freeBuf);
	NS_ASSERT(minQuota <= maxQuota);
  }
  return true;
}

void 
NaMPTSocket::SchedulingPackets(Ptr<NaMPTSubflow> subflow)
{
  /*
  	  PULL data by subflows when ...
  		1) a new subflow is created
  		2) the subflow receives acks
  	  
  	  PUSH data by connection when ...
  		1) app sends data
   */

  // minQuota is used by SOD, while maxQuota is used by RR
  uint32_t minQuota = 0, maxQuota = 0;
  if (subflow != 0 && !SchedulingQuota(subflow, minQuota, maxQuota) )
  	return ;

  // set flag
  m_bScheduling = true;
  
  // scheduling
  switch (m_schedulingAlgo)
  {
    case NAMPT_RR:
	  goto nampt_round_robin;
	case NAMPT_SOD:
	default:
	  goto nampt_scheduling_on_demand;
  }

nampt_round_robin:
{
  std::vector<Ptr<NaMPTSubflow> > candidates;
  std::vector<uint32_t> quotas;
  uint32_t idx = 0;
  for (SubflowSet_t::iterator it = m_subflows.begin(); it != m_subflows.end(); it++)
  {
    SchedulingQuota(it->second, minQuota, maxQuota);
	if (maxQuota == 0)
	  continue;
	candidates.push_back(it->second);
	quotas.push_back(maxQuota);
	if (subflow == it->second)
	  idx = candidates.size()-1;
  }
  while (candidates.size() > 1)
  {
    idx = idx % candidates.size();
	
    uint32_t s = candidates[idx]->SegmentSize();
	NS_ASSERT(quotas[idx] >= s);
    if (!AssignPackets(s, candidates[idx]) )
	  break; // no data
	quotas[idx] -= s;
	if (quotas[idx] < s) // zero
	{
	  candidates.erase(candidates.begin()+idx);
	  quotas.erase(quotas.begin()+idx);
	}
	else
	  idx++;
  }
  if (candidates.size() == 1)
  {
    AssignPackets(quotas[0], candidates[0]);
  }
}
goto nampt_scheduling_exit;

nampt_scheduling_on_demand:
{
  if (subflow != 0) // pull
  {
    if (minQuota > 0)
      AssignPackets(minQuota, subflow);
  }
  else			  // push
  {
    for (SubflowSet_t::iterator it = m_subflows.begin(); it != m_subflows.end(); it++)
    {
      SchedulingQuota(it->second, minQuota, maxQuota);
	  if (minQuota == 0)
	  	continue;
	  if (!AssignPackets(minQuota, it->second) )
	  	break; // no data
    }
  }
}
goto nampt_scheduling_exit;

nampt_scheduling_exit:
  // clear flag
  m_bScheduling = false;
  return ;
}

void 
NaMPTSocket::NaiveAssembling(Ptr<NaMPTSubflow> subflow)
{
  Ptr<Packet> pkt;
  SequenceNumber32 dataSeq;
  TcpHeader hd;
  do
  {
    pkt = subflow->Recv(std::numeric_limits<int32_t>::max(), dataSeq);
    if (pkt == 0)
  	  break;
    NS_ASSERT (pkt->GetSize() > 0);
	subflow->m_goodBytes += pkt->GetSize();
    //hd.SetSequenceNumber(dataSeq);
    //m_outputQueue.Add(pkt, hd);

	// ignore dataseq
	// ---------------
	hd.SetSequenceNumber(m_outputQueue.NextRxSequence() );
	m_outputQueue.Add(pkt, hd);
	//----------------
  }
  while(true);
}

bool 
NaMPTSocket::AssignPackets(uint32_t maxSize, Ptr<NaMPTSubflow> subflow)
{
  uint32_t uLen;
  Ptr<Packet> pkt;
  NS_ASSERT(maxSize > 0);

  // Firstly, deal with rescheduled data
  while(m_reschedulingQueue.size() > 0)
  {
    PacketSet_t::iterator it = m_reschedulingQueue.begin();
	SequenceNumber32 dSeq = it->first;
	pkt = it->second;
	it->second = 0;
	m_reschedulingQueue.erase(it);

	uLen = std::min(maxSize, pkt->GetSize() );
	if(uLen < pkt->GetSize() )
    {
      Ptr<Packet> p1 = pkt->CreateFragment(0, uLen);
	  Ptr<Packet> p2 = pkt->CreateFragment(uLen, pkt->GetSize()-uLen);
	  m_reschedulingQueue[dSeq+SequenceNumber32(uLen)] = p2;
	  pkt = p1;
    }

    if (subflow->Send(pkt, dSeq) != uLen)
      NS_ASSERT(false);

    maxSize -= uLen;
	if(maxSize == 0)
	  break;
  }

  if(maxSize == 0)
    return true;
  
  // Secondly, deal with input queue
  uLen = m_inputQueue.SizeFromSequence(m_nextTx);
  if (uLen < maxSize && !m_bClosed)
  {
    uint32_t uFree = m_inputQueue.Available();
	if (uFree > 0)
      NotifySend(uFree);
	uLen = m_inputQueue.SizeFromSequence(m_nextTx);
  }

  uLen = std::min(uLen, maxSize);
  if(uLen == 0)
  	return false; // no data

  pkt = m_inputQueue.CopyFromSequence(uLen, m_nextTx);
  NS_ASSERT(pkt != 0);

  uLen = pkt->GetSize();
  if (subflow->Send(pkt, m_nextTx) != uLen)
    NS_ASSERT(false);
  m_nextTx += uLen;
  m_inputQueue.DiscardUpTo(m_nextTx);

  return true;
}

void 
NaMPTSocket::CleanupSubflow(Ptr<NaMPTSubflow> subflow)
{
  // deliver ingoing queue to output queue
  NaiveAssembling(subflow);
  if (m_outputQueue.Available() > 0)
  	NotifyDataRecv();
  
  // clear non-in-sequence data
  /*TcpHeader hd;
  Ptr<Packet> pkt = Create<Packet>(subflow->m_baseSocket->m_segmentSize);
  TcpRxBuffer& rb = subflow->m_baseSocket->m_rxBuffer;
  while(rb.Size() != 0)
  {
    hd.SetSequenceNumber(rb.NextRxSequence() );
	rb.Add(pkt, hd);
	rb.Extract(std::numeric_limits<int32_t>::max() );
  }*/

  // Shift outgoing queue
  //ReschedulingPackets(subflow);

  // Resize inputQueue
  uint32_t size = 0;
  SubflowSet_t::const_iterator it = m_subflows.begin();
  for (; it != m_subflows.end(); it++)
  {
    if (it->second == subflow)
	  continue;
	size += it->second->m_baseSocket->GetSndBufSize();
  }
  m_inputQueue.SetMaxBufferSize(size);
  
}


/**************************************************
*/

void
NaMPTSocket::SetConnectCallback (Callback<void, Ptr<Socket> > connectionSucceeded,
									     Callback<void, Ptr<Socket> > connectionFailed)
{
  // Save app's callback functions
  Socket::SetConnectCallback (connectionSucceeded, connectionFailed);

  // Set NaMPTSocket's callback functions
  if (m_firstSocket)
    m_firstSocket->SetConnectCallback (
                 MakeCallback (&NaMPTSocket::DoConnectionSucceeds, Ptr<NaMPTSocket> (this) ),
                 MakeCallback (&NaMPTSocket::DoConnectionFails, Ptr<NaMPTSocket> (this) )
                 );
}

void
NaMPTSocket::SetCloseCallbacks (Callback<void, Ptr<Socket> > normalClose,
									   Callback<void, Ptr<Socket> > errorClose)
{
  // Save app's callback functions
  Socket::SetCloseCallbacks (normalClose, errorClose);

  // Set NaMPTSocket's callback functions
  if (m_firstSocket)
	m_firstSocket->SetCloseCallbacks (
				 MakeCallback (&NaMPTSocket::DoNormalClose, Ptr<NaMPTSocket> (this) ),
				 MakeCallback (&NaMPTSocket::DoErrorClose, Ptr<NaMPTSocket> (this) )
				 );
}


void
NaMPTSocket::SetAcceptCallback (Callback<bool, Ptr<Socket>, const Address &> connectionRequest,
									   Callback<void, Ptr<Socket>, const Address&> newConnectionCreated)
{
  // Save app's callback functions
  Socket::SetAcceptCallback (connectionRequest, newConnectionCreated);

  // Set NaMPTSocket's callback functions
  if (m_firstSocket)
	m_firstSocket->SetAcceptCallback (
				 MakeCallback (&NaMPTSocket::DoConnectionRequests, Ptr<NaMPTSocket> (this) ),
				 MakeCallback (&NaMPTSocket::DoConnectionAccepted, Ptr<NaMPTSocket> (this) )
				 );
}


void
NaMPTSocket::SetDataSentCallback (Callback<void, Ptr<Socket>, uint32_t> dataSent)
{
  // Save app's callback functions
  Socket::SetDataSentCallback (dataSent);

  // Set NaMPTSocket's callback functions
  if (m_firstSocket)
	m_firstSocket->SetDataSentCallback (
				 MakeCallback (&NaMPTSocket::DoDataSent, Ptr<NaMPTSocket> (this) )
				 );
}


void
NaMPTSocket::SetSendCallback (Callback<void, Ptr<Socket>, uint32_t> sendCb)
{
  // Save app's callback functions
  Socket::SetSendCallback (sendCb);

  // Set NaMPTSocket's callback functions
  if (m_firstSocket)
	m_firstSocket->SetSendCallback (
				 MakeCallback (&NaMPTSocket::DoSendMore, Ptr<NaMPTSocket> (this) )
				 );
}


void
NaMPTSocket::SetRecvCallback (Callback<void, Ptr<Socket> > receivedData)
{
  // Save app's callback functions
  Socket::SetRecvCallback (receivedData);

  // Set NaMPTSocket's callback functions
  if (m_firstSocket)
	m_firstSocket->SetRecvCallback (
				 MakeCallback (&NaMPTSocket::DoRead, Ptr<NaMPTSocket> (this) )
				 );
}

void 
NaMPTSocket::DoConnectionSucceeds (Ptr<Socket> sock)
{
  NotifyConnectionSucceeded ();
}

void 
NaMPTSocket::DoConnectionFails (Ptr<Socket> sock)
{
  NotifyConnectionFailed ();
}

void 
NaMPTSocket::DoNormalClose (Ptr<Socket> sock)
{
  NotifyNormalClose ();
}

void
NaMPTSocket::DoErrorClose (Ptr<Socket> sock)
{
  NotifyErrorClose ();
}

bool 
NaMPTSocket::DoConnectionRequests (Ptr<Socket> sock, const Address& from)
{
  return NotifyConnectionRequest (from);
}

void 
NaMPTSocket::DoConnectionAccepted (Ptr<Socket> sock, const Address& from)
{
  NotifyNewConnectionCreated (this, from);
}

void 
NaMPTSocket::DoDataSent (Ptr<Socket> sock, uint32_t txSize)
{
  NotifyDataSent (txSize);
}

void 
NaMPTSocket::DoSendMore (Ptr<Socket> sock, uint32_t txAvailable)
{
  NotifySend (txAvailable);
}

void 
NaMPTSocket::DoRead (Ptr<Socket> sock)
{
  NotifyDataRecv ();
}

/***********************************************
  ***********************************************
  ***********************************************
*/

TypeId 
NaMPTSignal::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::NaMPTSignal")
    .SetParent<Object> ()
    .AddConstructor<NaMPTSignal> ()
    ;
  return tid;
}

NaMPTSignal::NaMPTSignal (void)
	: sigType (NAMPT_NONE),
	  sigLen (2)
{
}

NaMPTSignal::NaMPTSignal (TcpOptionType_t t)
{
  sigType = t;
  switch (sigType)
  {
    case NAMPT_MPC:
		sigLen = 6; break;
    case NAMPT_JOIN:
		sigLen = 6; break;
    case NAMPT_EXTHD:
		sigLen = 4; break;
    case NAMPT_ADDR:
		sigLen = 10; break;
    case NAMPT_DSN:
		sigLen = 22; break;
	case NAMPT_FIN:
		sigLen = 6; break;
	case NAMPT_ACK:
		sigLen = 6; break;
    default:
		NS_ABORT_MSG ("Unknown Signal: " << sigType);
  }
}

NaMPTSignal::~NaMPTSignal (void)
{
}


/**********************************************
  **********************************************
  **********************************************
*/

TypeId 
NaMPTHeader::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::NaMPTHeader")
    .SetParent<TcpHeader> ()
    .AddConstructor<NaMPTHeader> ()
    ;
  return tid;
}

NaMPTHeader::NaMPTHeader ()
{
}

NaMPTHeader::NaMPTHeader (NaMPTHeader &res)
	: TcpHeader (res)
{
  std::vector<Ptr<NaMPTSignal> >::iterator it;
  Ptr<NaMPTSignal> sig = res.GetFirstSignal (it);
  while (sig != 0)
  {
    m_signals.push_back (CopyObject<NaMPTSignal> (sig) );
    sig = res.GetNextSignal (it);
  }
}

NaMPTHeader::NaMPTHeader (const TcpHeader &res)
	: TcpHeader (res)
{
}

NaMPTHeader::~NaMPTHeader ()
{
  RemoveAllSignals ();
}

TypeId 
NaMPTHeader::GetInstanceTypeId (void) const
{
  return GetTypeId ();
}

void
NaMPTHeader::Print (std::ostream &os)  const
{
  TcpHeader::Print (os);
  os << " Signals={";
  std::vector<Ptr<NaMPTSignal> >::const_iterator it;
  for (it = m_signals.begin(); it != m_signals.end(); it++)
  {
    os << " [";
    switch ( (*it)->sigType )
    {
      case NAMPT_MPC:
	  	os << "MPC: " << (*it)->sigData.mpc.localToken;
		break;
      case NAMPT_JOIN:
	  	os << "JOIN: " << (*it)->sigData.join.peerToken;
		break;
	 case NAMPT_ADDR:
	 	os << "ADDR(" << (*it)->sigData.addr.sigSeq << "): ";
	 	Ipv4Address( (*it)->sigData.addr.ipv4Addr).Print (os);
		break;
	 case NAMPT_DSN:
	 	os << "DSN(" << (*it)->sigData.dsn.sigSeq << "): ";
	 	os << (*it)->sigData.dsn.dataSeq << ", ";
		os << (*it)->sigData.dsn.dataLen << ", ";
		os << (*it)->sigData.dsn.sfSeq;
		break;
	 case NAMPT_FIN:
	 	os << "SIGFIN: " << (*it)->sigData.fin.sigSeq;
		break;
	 case NAMPT_ACK:
	 	os << "SIGACK: " << (*it)->sigData.ack.sigSeq;
		break;;
     default:
	  	NS_ABORT_MSG ("Unknown Signal: " << (*it)->sigType );
    }
    os << "]";
  }
  os << " } " << std::endl;
}

uint32_t 
NaMPTHeader::GetSerializedSize (void)  const
{
  // regular hd + extended hd
  NS_ASSERT (m_length <= 15);
  uint32_t len = m_length * 4;
  
  std::vector<Ptr<NaMPTSignal> >::const_iterator it;
  for (it = m_signals.begin(); it != m_signals.end(); it++)
  {
    if ( (*it)->sigType <= NAMPT_JOIN)
      continue;
    len += (*it)->sigLen;
  }
  
  return len;
}

void
NaMPTHeader::Serialize (Buffer::Iterator start)  const
{
  //bool savedFlag = m_calcChecksum;
  //m_calcChecksum = false;
  TcpHeader::Serialize (start);
  //m_calcChecksum = savedFlag;
  
  // add tcp options
  Buffer::Iterator i = start;
  Buffer::Iterator k = start;
  i.Next(20);

  uint16_t optLen = 0;
  std::vector<Ptr<NaMPTSignal> >::const_iterator it;
  for (it = m_signals.begin(); it != m_signals.end(); it++)
  {
    if ( (*it)->sigType > NAMPT_JOIN)
      break;
    uint8_t len = (*it)->sigLen;
    uint8_t *dat = (uint8_t *)&(*it)->sigData;
    i.WriteU8 ( (*it)->sigType);
    i.WriteU8 (len);
    NS_ASSERT (len >= 2);
    optLen += len;
    len -= 2;
    while (len)
    {
      i.WriteU8 (*dat);
	  dat ++; len --;
    }
  }
  
  // add exthd option if needed
  if (it != m_signals.end() )
  {
    i.WriteU8 (NAMPT_EXTHD);
    uint8_t len = NaMPTSignal(NAMPT_EXTHD).sigLen;
    i.WriteU8 (len);
    optLen += len;
    k = i;
    i.WriteU16 (0);
  }
  
  // add pading if needed.
  NS_ASSERT (m_length*4-20 >= optLen);
  uint8_t padLen = m_length*4 - 20 - optLen;
  NS_ASSERT (padLen < 4);
  while (padLen != 0)
  {
    i.WriteU8 (NAMPT_NONE);
    padLen --;
  }

  // add other signals to extended header (or payload)
  optLen = 0;
  while (it != m_signals.end () )
  {
    uint8_t len = (*it)->sigLen;
    uint8_t *dat = (uint8_t *)&(*it)->sigData;
    i.WriteU8 ( (*it)->sigType);
    i.WriteU8 (len);
    optLen += len;
    len -= 2;
    while (len)
    {
      i.WriteU8 (*dat);
      dat ++; len --;
    }
    it ++;
  }
  if (k.GetDistanceFrom(start) != 0)
  {
    NS_ASSERT (optLen != 0);
    k.WriteU16 (optLen);
  }
  NS_ASSERT (i.GetDistanceFrom(start) == GetSerializedSize() );

  // Re-calculate checksum
  if (m_calcChecksum)
  {
    // reset checksum
    i = start;
    i.Next (16);
    i.WriteU16 (0);

    // bogus header, input param is the total tcp length ( hd + payload)
    uint16_t bogusChecksum = CalculateHeaderChecksum (start.GetSize () );
    i = start;
    uint16_t checksum = i.CalculateIpChecksum(start.GetSize (), bogusChecksum);
    
    i = start;
    i.Next(16);
    i.WriteU16(checksum);
  }
}

uint32_t
NaMPTHeader::Deserialize (Buffer::Iterator start)
{
  bool savedFlag = m_calcChecksum;
  m_calcChecksum = false;
  TcpHeader::Deserialize (start);
  m_calcChecksum = savedFlag;
  
  Buffer::Iterator i = start;
  i.Next(20);

  /* Because m_length will be modified when AddSignal(),
        we should saved the original value obtained from packet
  */
  const uint8_t hdLen = m_length;

  // read options if needed.
  NS_ASSERT (hdLen >= 5 && hdLen < 16);
  uint16_t optLen = hdLen*4 - 20;
  uint16_t extLen = 0;
  while (optLen != 0 && !i.IsEnd() )
  {
    TcpOptionType_t sigType = (TcpOptionType_t)i.ReadU8 ();	
    if (sigType == NAMPT_NONE) // option end
    {
      NS_ASSERT (optLen > 0 && optLen < 4);
      break;
    }
	
    uint8_t sigLen = i.ReadU8 ();
    NS_ASSERT (sigLen == NaMPTSignal(sigType).sigLen);
    NS_ASSERT (optLen >= sigLen);
    optLen -= sigLen;
    sigLen -= 2;

    uint8_t *dat = 0;
    Ptr<NaMPTSignal> sig = 0;
    if (sigType == NAMPT_EXTHD) // extended header
    {
      dat = (uint8_t *)&extLen;
    }
    else
    {
      sig = AddSignal (sigType);
      NS_ASSERT (sig != 0);
      dat = (uint8_t *)&sig->sigData;
    }

    while (sigLen != 0)
    {
      *dat = i.ReadU8 ();
      dat ++; sigLen --;
    }
    
  }

  // read extended header if needed
  i = start;
  i.Next (hdLen * 4);
  while (extLen != 0)
  {
    TcpOptionType_t sigType = (TcpOptionType_t)i.ReadU8 ();
    uint8_t sigLen = i.ReadU8 ();

    Ptr<NaMPTSignal> sig = AddSignal (sigType);
    NS_ASSERT (sig != 0 && sigLen == sig->sigLen);
    NS_ASSERT (extLen >= sigLen);
    extLen -= sigLen;
    sigLen -= 2;

    uint8_t * dat = (uint8_t *)&sig->sigData;
    while (sigLen != 0)
    {
      *dat = i.ReadU8 ();
      dat ++; sigLen --;
    }
  }
  NS_ASSERT (hdLen == m_length);
  
  // Checksum
  if (m_calcChecksum)
  {
    uint16_t bogusChecksum = CalculateHeaderChecksum (start.GetSize () );
    i = start;
    uint16_t checksum = i.CalculateIpChecksum(start.GetSize (), bogusChecksum);
    m_goodChecksum = (checksum == 0);
  }

  return GetSerializedSize ();
}

Ptr<NaMPTSignal> 
NaMPTHeader::GetFirstSignal (std::vector<Ptr<NaMPTSignal> >::iterator &iter)
{
  iter = m_signals.begin();
  if (iter == m_signals.end() )
    return 0;
  return (*iter);
}

Ptr<NaMPTSignal> 
NaMPTHeader::GetNextSignal (std::vector<Ptr<NaMPTSignal> >::iterator &iter)
{
  iter ++;
  if (iter == m_signals.end() )
    return 0;
  return (*iter);
}

Ptr<NaMPTSignal> 
NaMPTHeader::AddSignal (TcpOptionType_t sigType)
{
  // If exists, don't insert it.
  Ptr<NaMPTSignal> sig = 0;
  if (sigType <= NAMPT_JOIN)
  {
    sig = FindSignal (sigType, false);
    if (sig != 0)
      return 0;
  }
  // Note: insert signal according to ascending order of sigType
  sig = CreateObject<NaMPTSignal> (sigType);
  std::vector<Ptr<NaMPTSignal> >::iterator it;
  for (it = m_signals.begin(); it != m_signals.end(); it++)
  {
    if ( (*it)->sigType <= sigType)
      continue;
    m_signals.insert (it, sig);
    break;
  }
  if (it == m_signals.end() )
    m_signals.push_back (sig);

  UpdateLength ();
  return sig;
}

void 
NaMPTHeader::AddSignal(Ptr<NaMPTSignal> signal)
{
  Ptr<NaMPTSignal> sig = AddSignal(signal->sigType);
  if (sig == 0)
  	return ;
  uint8_t *src = (uint8_t *)&signal->sigData;
  uint8_t *des = (uint8_t *)&sig->sigData;
  memcpy (des, src, sig->sigLen);
  return ;
}

Ptr<NaMPTSignal> 
NaMPTHeader::FindSignal (TcpOptionType_t sigType, bool bRemove)
{
  std::vector<Ptr<NaMPTSignal> >::iterator it;
  for (it = m_signals.begin(); it != m_signals.end(); it++)
  {
    if ( (*it)->sigType != sigType && sigType != NAMPT_NONE)
      continue;
	
    Ptr<NaMPTSignal> p = (*it);
    if (bRemove)
    {
      (*it) = 0;
      m_signals.erase (it);
	  UpdateLength ();
    }
    return p;
  }
  return 0;
}

void 
NaMPTHeader::RemoveAllSignals (void)
{
  std::vector<Ptr<NaMPTSignal> >::iterator it;
  for (it = m_signals.begin(); it != m_signals.end(); it++)
  {
    (*it) = 0;
  }
  m_signals.clear();

  UpdateLength ();
}

void
NaMPTHeader::UpdateLength (void)
{
  uint16_t optLen = 0;
  std::vector<Ptr<NaMPTSignal> >::const_iterator it;
  for (it = m_signals.begin(); it != m_signals.end(); it++)
  {
    if ( (*it)->sigType > NAMPT_JOIN)
      break;
    optLen += (*it)->sigLen;
  }
  if (it != m_signals.end() )
    optLen += NaMPTSignal(NAMPT_EXTHD).sigLen;
  NS_ASSERT (optLen <= 40);
  
  m_length = 5;
  m_length += (optLen % 4) == 0 ? optLen / 4 : (optLen / 4) + 1;
}


} // namespace ns3
