merge new TCP code
This commit is contained in:
@@ -27,18 +27,27 @@ NS_LOG_COMPONENT_DEFINE ("OutputStreamWrapper");
|
||||
namespace ns3 {
|
||||
|
||||
OutputStreamWrapper::OutputStreamWrapper (std::string filename, std::ios::openmode filemode)
|
||||
: m_ostream (new std::ofstream ())
|
||||
: m_destroyable (true)
|
||||
{
|
||||
std::ofstream* os = new std::ofstream ();
|
||||
os->open (filename.c_str (), filemode);
|
||||
m_ostream = os;
|
||||
FatalImpl::RegisterStream (m_ostream);
|
||||
NS_ABORT_MSG_UNLESS (os->is_open (), "AsciiTraceHelper::CreateFileStream(): " <<
|
||||
"Unable to Open " << filename << " for mode " << filemode);
|
||||
}
|
||||
|
||||
OutputStreamWrapper::OutputStreamWrapper (std::ostream* os)
|
||||
: m_ostream (os), m_destroyable (false)
|
||||
{
|
||||
FatalImpl::RegisterStream (m_ostream);
|
||||
m_ostream->open (filename.c_str (), filemode);
|
||||
NS_ABORT_MSG_UNLESS (m_ostream->is_open (), "AsciiTraceHelper::CreateFileStream(): " <<
|
||||
"Unable to Open " << filename << " for mode " << filemode);
|
||||
NS_ABORT_MSG_UNLESS (m_ostream->good (), "Output stream is not vaild for writing.");
|
||||
}
|
||||
|
||||
OutputStreamWrapper::~OutputStreamWrapper ()
|
||||
{
|
||||
FatalImpl::UnregisterStream (m_ostream);
|
||||
delete m_ostream;
|
||||
if (m_destroyable) delete m_ostream;
|
||||
m_ostream = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ class OutputStreamWrapper : public SimpleRefCount<OutputStreamWrapper>
|
||||
{
|
||||
public:
|
||||
OutputStreamWrapper (std::string filename, std::ios::openmode filemode);
|
||||
OutputStreamWrapper (std::ostream* os);
|
||||
~OutputStreamWrapper ();
|
||||
|
||||
/**
|
||||
@@ -83,7 +84,8 @@ public:
|
||||
std::ostream *GetStream (void);
|
||||
|
||||
private:
|
||||
std::ofstream *m_ostream;
|
||||
std::ostream *m_ostream;
|
||||
bool m_destroyable;
|
||||
};
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
@@ -171,6 +171,9 @@ PointToPointHelper::EnableAsciiInternal (
|
||||
asciiTraceHelper.HookDefaultDropSinkWithoutContext<Queue> (queue, "Drop", theStream);
|
||||
asciiTraceHelper.HookDefaultDequeueSinkWithoutContext<Queue> (queue, "Dequeue", theStream);
|
||||
|
||||
// PhyRxDrop trace source for "d" event
|
||||
asciiTraceHelper.HookDefaultDropSinkWithoutContext<PointToPointNetDevice> (device, "PhyRxDrop", theStream);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -204,6 +207,10 @@ PointToPointHelper::EnableAsciiInternal (
|
||||
oss.str ("");
|
||||
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/TxQueue/Drop";
|
||||
Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultDropSinkWithContext, stream));
|
||||
|
||||
oss.str ("");
|
||||
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::PointToPointNetDevice/PhyRxDrop";
|
||||
Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultDropSinkWithContext, stream));
|
||||
}
|
||||
|
||||
NetDeviceContainer
|
||||
|
||||
@@ -37,8 +37,6 @@
|
||||
#include "nsc-tcp-socket-factory-impl.h"
|
||||
#include "sim_interface.h"
|
||||
|
||||
#include "tcp-typedefs.h"
|
||||
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <dlfcn.h>
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "nsc-tcp-l4-protocol.h"
|
||||
#include "nsc-tcp-socket-impl.h"
|
||||
#include "ns3/simulation-singleton.h"
|
||||
#include "tcp-typedefs.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/uinteger.h"
|
||||
@@ -39,8 +38,8 @@
|
||||
// for ntohs().
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "sim_interface.h"
|
||||
|
||||
#include "sim_errno.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("NscTcpSocketImpl");
|
||||
@@ -63,7 +62,7 @@ NscTcpSocketImpl::GetTypeId ()
|
||||
return tid;
|
||||
}
|
||||
|
||||
NscTcpSocketImpl::NscTcpSocketImpl ()
|
||||
NscTcpSocketImpl::NscTcpSocketImpl ()
|
||||
: m_endPoint (0),
|
||||
m_node (0),
|
||||
m_tcp (0),
|
||||
@@ -795,6 +794,18 @@ NscTcpSocketImpl::GetDelAckMaxCount (void) const
|
||||
return m_delAckMaxCount;
|
||||
}
|
||||
|
||||
void
|
||||
NscTcpSocketImpl::SetPersistTimeout (Time timeout)
|
||||
{
|
||||
m_persistTimeout = timeout;
|
||||
}
|
||||
|
||||
Time
|
||||
NscTcpSocketImpl::GetPersistTimeout (void) const
|
||||
{
|
||||
return m_persistTimeout;
|
||||
}
|
||||
|
||||
enum Socket::SocketErrno
|
||||
NscTcpSocketImpl::GetNativeNs3Errno(int error) const
|
||||
{
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/inet-socket-address.h"
|
||||
#include "ns3/event-id.h"
|
||||
#include "tcp-typedefs.h"
|
||||
#include "pending-data.h"
|
||||
#include "ns3/sequence-number.h"
|
||||
|
||||
@@ -126,6 +125,8 @@ private:
|
||||
virtual Time GetDelAckTimeout (void) const;
|
||||
virtual void SetDelAckMaxCount (uint32_t count);
|
||||
virtual uint32_t GetDelAckMaxCount (void) const;
|
||||
virtual void SetPersistTimeout (Time timeout);
|
||||
virtual Time GetPersistTimeout (void) const;
|
||||
|
||||
enum Socket::SocketErrno GetNativeNs3Errno(int err) const;
|
||||
uint32_t m_delAckMaxCount;
|
||||
@@ -146,7 +147,7 @@ private:
|
||||
bool m_connected;
|
||||
|
||||
//manage the state information
|
||||
States_t m_state;
|
||||
TracedValue<TcpStates_t> m_state;
|
||||
bool m_closeOnEmpty;
|
||||
|
||||
//needed to queue data when in SYN_SENT state
|
||||
@@ -167,6 +168,7 @@ private:
|
||||
// Timer-related members
|
||||
Time m_cnTimeout;
|
||||
uint32_t m_cnCount;
|
||||
Time m_persistTimeout;
|
||||
|
||||
// Temporary queue for delivering data to application
|
||||
std::queue<Ptr<Packet> > m_deliveryQueue;
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <iostream>
|
||||
#include "tcp-socket-impl.h"
|
||||
#include "tcp-header.h"
|
||||
#include "ns3/buffer.h"
|
||||
#include "ns3/address-utils.h"
|
||||
|
||||
@@ -35,9 +35,8 @@
|
||||
#include "ipv4-end-point.h"
|
||||
#include "ipv4-l3-protocol.h"
|
||||
#include "tcp-socket-factory-impl.h"
|
||||
#include "tcp-socket-impl.h"
|
||||
#include "tcp-newreno.h"
|
||||
#include "rtt-estimator.h"
|
||||
#include "tcp-typedefs.h"
|
||||
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
@@ -49,269 +48,6 @@ namespace ns3 {
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (TcpL4Protocol);
|
||||
|
||||
//State Machine things --------------------------------------------------------
|
||||
TcpStateMachine::TcpStateMachine()
|
||||
: aT (LAST_STATE, StateActionVec_t(LAST_EVENT)),
|
||||
eV (MAX_FLAGS)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
// Create the state table
|
||||
// Closed state
|
||||
aT[CLOSED][APP_LISTEN] = SA (LISTEN, NO_ACT);
|
||||
aT[CLOSED][APP_CONNECT] = SA (SYN_SENT, SYN_TX);
|
||||
aT[CLOSED][APP_SEND] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSED][SEQ_RECV] = SA (CLOSED, NO_ACT);
|
||||
aT[CLOSED][APP_CLOSE] = SA (CLOSED, NO_ACT);
|
||||
aT[CLOSED][TIMEOUT] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSED][ACK_RX] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSED][SYN_RX] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSED][SYN_ACK_RX] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSED][FIN_RX] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSED][FIN_ACK_RX] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSED][RST_RX] = SA (CLOSED, CANCEL_TM);
|
||||
aT[CLOSED][BAD_FLAGS] = SA (CLOSED, RST_TX);
|
||||
|
||||
// Listen State
|
||||
// For the listen state, anything other than CONNECT or SEND
|
||||
// is simply ignored....this likely indicates the child TCP
|
||||
// has finished and issued unbind call, but the remote end
|
||||
// has not yet closed.
|
||||
aT[LISTEN][APP_LISTEN] = SA (LISTEN, NO_ACT);
|
||||
aT[LISTEN][APP_CONNECT] = SA (SYN_SENT, SYN_TX);
|
||||
aT[LISTEN][APP_SEND] = SA (SYN_SENT, SYN_TX);
|
||||
aT[LISTEN][SEQ_RECV] = SA (LISTEN, NO_ACT);
|
||||
aT[LISTEN][APP_CLOSE] = SA (CLOSED, NO_ACT);
|
||||
aT[LISTEN][TIMEOUT] = SA (LISTEN, NO_ACT);
|
||||
aT[LISTEN][ACK_RX] = SA (LISTEN, NO_ACT);
|
||||
aT[LISTEN][SYN_RX] = SA (LISTEN, SYN_ACK_TX);//stay in listen and fork
|
||||
aT[LISTEN][SYN_ACK_RX] = SA (LISTEN, NO_ACT);
|
||||
aT[LISTEN][FIN_RX] = SA (LISTEN, NO_ACT);
|
||||
aT[LISTEN][FIN_ACK_RX] = SA (LISTEN, NO_ACT);
|
||||
aT[LISTEN][RST_RX] = SA (LISTEN, NO_ACT);
|
||||
aT[LISTEN][BAD_FLAGS] = SA (LISTEN, NO_ACT);
|
||||
|
||||
// Syn Sent State
|
||||
aT[SYN_SENT][APP_LISTEN] = SA (CLOSED, RST_TX);
|
||||
aT[SYN_SENT][APP_CONNECT] = SA (SYN_SENT, SYN_TX);
|
||||
aT[SYN_SENT][APP_SEND] = SA (SYN_SENT, NO_ACT);
|
||||
aT[SYN_SENT][SEQ_RECV] = SA (ESTABLISHED, NEW_SEQ_RX);
|
||||
aT[SYN_SENT][APP_CLOSE] = SA (CLOSED, RST_TX);
|
||||
aT[SYN_SENT][TIMEOUT] = SA (CLOSED, NO_ACT);
|
||||
aT[SYN_SENT][ACK_RX] = SA (SYN_SENT, NO_ACT);
|
||||
aT[SYN_SENT][SYN_RX] = SA (SYN_RCVD, SYN_ACK_TX);
|
||||
aT[SYN_SENT][SYN_ACK_RX] = SA (ESTABLISHED, ACK_TX_1);
|
||||
aT[SYN_SENT][FIN_RX] = SA (CLOSED, RST_TX);
|
||||
aT[SYN_SENT][FIN_ACK_RX] = SA (CLOSED, RST_TX);
|
||||
aT[SYN_SENT][RST_RX] = SA (CLOSED, APP_NOTIFY);
|
||||
aT[SYN_SENT][BAD_FLAGS] = SA (CLOSED, RST_TX);
|
||||
|
||||
// Syn Recvd State
|
||||
aT[SYN_RCVD][APP_LISTEN] = SA (CLOSED, RST_TX);
|
||||
aT[SYN_RCVD][APP_CONNECT] = SA (CLOSED, RST_TX);
|
||||
aT[SYN_RCVD][APP_SEND] = SA (CLOSED, RST_TX);
|
||||
aT[SYN_RCVD][SEQ_RECV] = SA (ESTABLISHED, NEW_SEQ_RX);
|
||||
aT[SYN_RCVD][APP_CLOSE] = SA (FIN_WAIT_1, FIN_TX);
|
||||
aT[SYN_RCVD][TIMEOUT] = SA (CLOSED, RST_TX);
|
||||
aT[SYN_RCVD][ACK_RX] = SA (ESTABLISHED, SERV_NOTIFY);
|
||||
aT[SYN_RCVD][SYN_RX] = SA (SYN_RCVD, SYN_ACK_TX);
|
||||
aT[SYN_RCVD][SYN_ACK_RX] = SA (CLOSED, RST_TX);
|
||||
aT[SYN_RCVD][FIN_RX] = SA (CLOSED, RST_TX);
|
||||
aT[SYN_RCVD][FIN_ACK_RX] = SA (CLOSE_WAIT, PEER_CLOSE);
|
||||
aT[SYN_RCVD][RST_RX] = SA (CLOSED, CANCEL_TM);
|
||||
aT[SYN_RCVD][BAD_FLAGS] = SA (CLOSED, RST_TX);
|
||||
|
||||
// Established State
|
||||
aT[ESTABLISHED][APP_LISTEN] = SA (CLOSED, RST_TX);
|
||||
aT[ESTABLISHED][APP_CONNECT]= SA (CLOSED, RST_TX);
|
||||
aT[ESTABLISHED][APP_SEND] = SA (ESTABLISHED,TX_DATA);
|
||||
aT[ESTABLISHED][SEQ_RECV] = SA (ESTABLISHED,NEW_SEQ_RX);
|
||||
aT[ESTABLISHED][APP_CLOSE] = SA (FIN_WAIT_1, FIN_TX);
|
||||
aT[ESTABLISHED][TIMEOUT] = SA (ESTABLISHED,RETX);
|
||||
aT[ESTABLISHED][ACK_RX] = SA (ESTABLISHED,NEW_ACK);
|
||||
aT[ESTABLISHED][SYN_RX] = SA (SYN_RCVD, SYN_ACK_TX);
|
||||
aT[ESTABLISHED][SYN_ACK_RX] = SA (ESTABLISHED,NO_ACT);
|
||||
aT[ESTABLISHED][FIN_RX] = SA (CLOSE_WAIT, PEER_CLOSE);
|
||||
aT[ESTABLISHED][FIN_ACK_RX] = SA (CLOSE_WAIT, PEER_CLOSE);
|
||||
aT[ESTABLISHED][RST_RX] = SA (CLOSED, CANCEL_TM);
|
||||
aT[ESTABLISHED][BAD_FLAGS] = SA (CLOSED, RST_TX);
|
||||
|
||||
// Close Wait State
|
||||
aT[CLOSE_WAIT][APP_LISTEN] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSE_WAIT][APP_CONNECT] = SA (SYN_SENT, SYN_TX);
|
||||
aT[CLOSE_WAIT][APP_SEND] = SA (CLOSE_WAIT, TX_DATA);
|
||||
aT[CLOSE_WAIT][SEQ_RECV] = SA (CLOSE_WAIT, NEW_SEQ_RX);
|
||||
aT[CLOSE_WAIT][APP_CLOSE] = SA (LAST_ACK, FIN_ACK_TX);
|
||||
aT[CLOSE_WAIT][TIMEOUT] = SA (CLOSE_WAIT, NO_ACT);
|
||||
aT[CLOSE_WAIT][ACK_RX] = SA (CLOSE_WAIT, NEW_ACK);
|
||||
aT[CLOSE_WAIT][SYN_RX] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSE_WAIT][SYN_ACK_RX] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSE_WAIT][FIN_RX] = SA (CLOSE_WAIT, ACK_TX);
|
||||
aT[CLOSE_WAIT][FIN_ACK_RX] = SA (CLOSE_WAIT, ACK_TX);
|
||||
aT[CLOSE_WAIT][RST_RX] = SA (CLOSED, CANCEL_TM);
|
||||
aT[CLOSE_WAIT][BAD_FLAGS] = SA (CLOSED, RST_TX);
|
||||
|
||||
// Close Last Ack State
|
||||
aT[LAST_ACK][APP_LISTEN] = SA (CLOSED, RST_TX);
|
||||
aT[LAST_ACK][APP_CONNECT] = SA (SYN_SENT, SYN_TX);
|
||||
aT[LAST_ACK][APP_SEND] = SA (CLOSED, RST_TX);
|
||||
aT[LAST_ACK][SEQ_RECV] = SA (LAST_ACK, NEW_SEQ_RX);
|
||||
aT[LAST_ACK][APP_CLOSE] = SA (CLOSED, NO_ACT);
|
||||
aT[LAST_ACK][TIMEOUT] = SA (CLOSED, NO_ACT);
|
||||
aT[LAST_ACK][ACK_RX] = SA (LAST_ACK, NO_ACT);
|
||||
aT[LAST_ACK][FIN_ACKED] = SA (CLOSED, APP_CLOSED);
|
||||
aT[LAST_ACK][SYN_RX] = SA (CLOSED, RST_TX);
|
||||
aT[LAST_ACK][SYN_ACK_RX] = SA (CLOSED, RST_TX);
|
||||
aT[LAST_ACK][FIN_RX] = SA (LAST_ACK, FIN_ACK_TX);
|
||||
aT[LAST_ACK][FIN_ACK_RX] = SA (CLOSED, NO_ACT);
|
||||
aT[LAST_ACK][RST_RX] = SA (CLOSED, CANCEL_TM);
|
||||
aT[LAST_ACK][BAD_FLAGS] = SA (CLOSED, RST_TX);
|
||||
|
||||
// FIN_WAIT_1 state
|
||||
aT[FIN_WAIT_1][APP_LISTEN] = SA (CLOSED, RST_TX);
|
||||
aT[FIN_WAIT_1][APP_CONNECT] = SA (CLOSED, RST_TX);
|
||||
aT[FIN_WAIT_1][APP_SEND] = SA (CLOSED, RST_TX);
|
||||
aT[FIN_WAIT_1][SEQ_RECV] = SA (FIN_WAIT_1, NEW_SEQ_RX);
|
||||
aT[FIN_WAIT_1][APP_CLOSE] = SA (FIN_WAIT_1, NO_ACT);
|
||||
aT[FIN_WAIT_1][TIMEOUT] = SA (FIN_WAIT_1, NO_ACT);
|
||||
aT[FIN_WAIT_1][ACK_RX] = SA (FIN_WAIT_1, NEW_ACK);
|
||||
aT[FIN_WAIT_1][FIN_ACKED] = SA (FIN_WAIT_2, NEW_ACK);
|
||||
aT[FIN_WAIT_1][SYN_RX] = SA (CLOSED, RST_TX);
|
||||
aT[FIN_WAIT_1][SYN_ACK_RX] = SA (CLOSED, RST_TX);
|
||||
aT[FIN_WAIT_1][FIN_RX] = SA (CLOSING, ACK_TX);
|
||||
aT[FIN_WAIT_1][FIN_ACK_RX] = SA (TIMED_WAIT, ACK_TX);
|
||||
aT[FIN_WAIT_1][RST_RX] = SA (CLOSED, CANCEL_TM);
|
||||
aT[FIN_WAIT_1][BAD_FLAGS] = SA (CLOSED, RST_TX);
|
||||
|
||||
// FIN_WAIT_2 state
|
||||
aT[FIN_WAIT_2][APP_LISTEN] = SA (CLOSED, RST_TX);
|
||||
aT[FIN_WAIT_2][APP_CONNECT] = SA (CLOSED, RST_TX);
|
||||
aT[FIN_WAIT_2][APP_SEND] = SA (CLOSED, RST_TX);
|
||||
aT[FIN_WAIT_2][SEQ_RECV] = SA (FIN_WAIT_2, NEW_SEQ_RX);
|
||||
aT[FIN_WAIT_2][APP_CLOSE] = SA (FIN_WAIT_2, NO_ACT);
|
||||
aT[FIN_WAIT_2][TIMEOUT] = SA (FIN_WAIT_2, NO_ACT);
|
||||
aT[FIN_WAIT_2][ACK_RX] = SA (FIN_WAIT_2, NEW_ACK);
|
||||
aT[FIN_WAIT_2][SYN_RX] = SA (CLOSED, RST_TX);
|
||||
aT[FIN_WAIT_2][SYN_ACK_RX] = SA (CLOSED, RST_TX);
|
||||
aT[FIN_WAIT_2][FIN_RX] = SA (TIMED_WAIT, ACK_TX);
|
||||
aT[FIN_WAIT_2][FIN_ACK_RX] = SA (TIMED_WAIT, ACK_TX);
|
||||
aT[FIN_WAIT_2][RST_RX] = SA (CLOSED, CANCEL_TM);
|
||||
aT[FIN_WAIT_2][BAD_FLAGS] = SA (CLOSED, RST_TX);
|
||||
|
||||
// CLOSING state
|
||||
aT[CLOSING][APP_LISTEN] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSING][APP_CONNECT] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSING][APP_SEND] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSING][SEQ_RECV] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSING][APP_CLOSE] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSING][TIMEOUT] = SA (CLOSING, NO_ACT);
|
||||
aT[CLOSING][ACK_RX] = SA (CLOSING, NO_ACT);
|
||||
aT[CLOSING][FIN_ACKED] = SA (TIMED_WAIT, NO_ACT);
|
||||
aT[CLOSING][SYN_RX] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSING][SYN_ACK_RX] = SA (CLOSED, RST_TX);
|
||||
aT[CLOSING][FIN_RX] = SA (CLOSED, ACK_TX);
|
||||
aT[CLOSING][FIN_ACK_RX] = SA (CLOSED, ACK_TX);
|
||||
aT[CLOSING][RST_RX] = SA (CLOSED, CANCEL_TM);
|
||||
aT[CLOSING][BAD_FLAGS] = SA (CLOSED, RST_TX);
|
||||
|
||||
// TIMED_WAIT state
|
||||
aT[TIMED_WAIT][APP_LISTEN] = SA (TIMED_WAIT, NO_ACT);
|
||||
aT[TIMED_WAIT][APP_CONNECT] = SA (TIMED_WAIT, NO_ACT);
|
||||
aT[TIMED_WAIT][APP_SEND] = SA (TIMED_WAIT, NO_ACT);
|
||||
aT[TIMED_WAIT][SEQ_RECV] = SA (TIMED_WAIT, NO_ACT);
|
||||
aT[TIMED_WAIT][APP_CLOSE] = SA (TIMED_WAIT, NO_ACT);
|
||||
aT[TIMED_WAIT][TIMEOUT] = SA (TIMED_WAIT, NO_ACT);
|
||||
aT[TIMED_WAIT][ACK_RX] = SA (TIMED_WAIT, NO_ACT);
|
||||
aT[TIMED_WAIT][SYN_RX] = SA (TIMED_WAIT, NO_ACT);
|
||||
aT[TIMED_WAIT][SYN_ACK_RX] = SA (TIMED_WAIT, NO_ACT);
|
||||
aT[TIMED_WAIT][FIN_RX] = SA (TIMED_WAIT, NO_ACT);
|
||||
aT[TIMED_WAIT][FIN_ACK_RX] = SA (TIMED_WAIT, NO_ACT);
|
||||
aT[TIMED_WAIT][RST_RX] = SA (TIMED_WAIT, NO_ACT);
|
||||
aT[TIMED_WAIT][BAD_FLAGS] = SA (TIMED_WAIT, NO_ACT);
|
||||
|
||||
// Create the flags lookup table
|
||||
eV[ 0x00] = SEQ_RECV; // No flags
|
||||
eV[ 0x01] = FIN_RX; // Fin
|
||||
eV[ 0x02] = SYN_RX; // Syn
|
||||
eV[ 0x03] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x04] = RST_RX; // Rst
|
||||
eV[ 0x05] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x06] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x07] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x08] = SEQ_RECV; // Psh flag is not used
|
||||
eV[ 0x09] = FIN_RX; // Fin
|
||||
eV[ 0x0a] = SYN_RX; // Syn
|
||||
eV[ 0x0b] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x0c] = RST_RX; // Rst
|
||||
eV[ 0x0d] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x0e] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x0f] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x10] = ACK_RX; // Ack
|
||||
eV[ 0x11] = FIN_ACK_RX;// Fin/Ack
|
||||
eV[ 0x12] = SYN_ACK_RX;// Syn/Ack
|
||||
eV[ 0x13] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x14] = RST_RX; // Rst
|
||||
eV[ 0x15] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x16] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x17] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x18] = ACK_RX; // Ack
|
||||
eV[ 0x19] = FIN_ACK_RX;// Fin/Ack
|
||||
eV[ 0x1a] = SYN_ACK_RX;// Syn/Ack
|
||||
eV[ 0x1b] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x1c] = RST_RX; // Rst
|
||||
eV[ 0x1d] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x1e] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x1f] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x20] = SEQ_RECV; // No flags (Urgent not presently used)
|
||||
eV[ 0x21] = FIN_RX; // Fin
|
||||
eV[ 0x22] = SYN_RX; // Syn
|
||||
eV[ 0x23] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x24] = RST_RX; // Rst
|
||||
eV[ 0x25] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x26] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x27] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x28] = SEQ_RECV; // Psh flag is not used
|
||||
eV[ 0x29] = FIN_RX; // Fin
|
||||
eV[ 0x2a] = SYN_RX; // Syn
|
||||
eV[ 0x2b] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x2c] = RST_RX; // Rst
|
||||
eV[ 0x2d] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x2e] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x2f] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x30] = ACK_RX; // Ack (Urgent not used)
|
||||
eV[ 0x31] = FIN_ACK_RX;// Fin/Ack
|
||||
eV[ 0x32] = SYN_ACK_RX;// Syn/Ack
|
||||
eV[ 0x33] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x34] = RST_RX; // Rst
|
||||
eV[ 0x35] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x36] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x37] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x38] = ACK_RX; // Ack
|
||||
eV[ 0x39] = FIN_ACK_RX;// Fin/Ack
|
||||
eV[ 0x3a] = SYN_ACK_RX;// Syn/Ack
|
||||
eV[ 0x3b] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x3c] = RST_RX; // Rst
|
||||
eV[ 0x3d] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x3e] = BAD_FLAGS; // Illegal
|
||||
eV[ 0x3f] = BAD_FLAGS; // Illegal
|
||||
}
|
||||
|
||||
SA TcpStateMachine::Lookup (States_t s, Events_t e)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << s << e);
|
||||
return aT[s][e];
|
||||
}
|
||||
|
||||
Events_t TcpStateMachine::FlagsEvent (uint8_t f)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << f);
|
||||
// Lookup event from flags
|
||||
if (f >= MAX_FLAGS) return BAD_FLAGS;
|
||||
return eV[f]; // Look up flags event
|
||||
}
|
||||
|
||||
static TcpStateMachine tcpStateMachine; //only instance of a TcpStateMachine
|
||||
|
||||
//TcpL4Protocol stuff----------------------------------------------------------
|
||||
|
||||
#undef NS_LOG_APPEND_CONTEXT
|
||||
@@ -321,29 +57,26 @@ static TcpStateMachine tcpStateMachine; //only instance of a TcpStateMachine
|
||||
/* see http://www.iana.org/assignments/protocol-numbers */
|
||||
const uint8_t TcpL4Protocol::PROT_NUMBER = 6;
|
||||
|
||||
ObjectFactory
|
||||
TcpL4Protocol::GetDefaultRttEstimatorFactory (void)
|
||||
{
|
||||
ObjectFactory factory;
|
||||
factory.SetTypeId (RttMeanDeviation::GetTypeId ());
|
||||
return factory;
|
||||
}
|
||||
|
||||
TypeId
|
||||
TcpL4Protocol::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::TcpL4Protocol")
|
||||
.SetParent<Ipv4L4Protocol> ()
|
||||
.AddConstructor<TcpL4Protocol> ()
|
||||
.AddAttribute ("RttEstimatorFactory",
|
||||
"How RttEstimator objects are created.",
|
||||
ObjectFactoryValue (GetDefaultRttEstimatorFactory ()),
|
||||
MakeObjectFactoryAccessor (&TcpL4Protocol::m_rttFactory),
|
||||
MakeObjectFactoryChecker ())
|
||||
.AddAttribute ("RttEstimatorType",
|
||||
"Type of RttEstimator objects.",
|
||||
TypeIdValue (RttMeanDeviation::GetTypeId()),
|
||||
MakeTypeIdAccessor (&TcpL4Protocol::m_rttTypeId),
|
||||
MakeTypeIdChecker ())
|
||||
.AddAttribute ("SocketType",
|
||||
"Socket type of TCP objects.",
|
||||
TypeIdValue (TcpNewReno::GetTypeId()),
|
||||
MakeTypeIdAccessor (&TcpL4Protocol::m_socketTypeId),
|
||||
MakeTypeIdChecker ())
|
||||
.AddAttribute ("SocketList", "The list of sockets associated to this protocol.",
|
||||
ObjectVectorValue (),
|
||||
MakeObjectVectorAccessor (&TcpL4Protocol::m_sockets),
|
||||
MakeObjectVectorChecker<TcpSocketImpl> ())
|
||||
MakeObjectVectorChecker<TcpSocketBase> ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
@@ -403,7 +136,7 @@ void
|
||||
TcpL4Protocol::DoDispose (void)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
for (std::vector<Ptr<TcpSocketImpl> >::iterator i = m_sockets.begin (); i != m_sockets.end (); i++)
|
||||
for (std::vector<Ptr<TcpSocketBase> >::iterator i = m_sockets.begin (); i != m_sockets.end (); i++)
|
||||
{
|
||||
*i = 0;
|
||||
}
|
||||
@@ -420,11 +153,15 @@ TcpL4Protocol::DoDispose (void)
|
||||
}
|
||||
|
||||
Ptr<Socket>
|
||||
TcpL4Protocol::CreateSocket (void)
|
||||
TcpL4Protocol::CreateSocket (TypeId socketTypeId)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
Ptr<RttEstimator> rtt = m_rttFactory.Create<RttEstimator> ();
|
||||
Ptr<TcpSocketImpl> socket = CreateObject<TcpSocketImpl> ();
|
||||
ObjectFactory rttFactory;
|
||||
ObjectFactory socketFactory;
|
||||
rttFactory.SetTypeId(m_rttTypeId);
|
||||
socketFactory.SetTypeId(socketTypeId);
|
||||
Ptr<RttEstimator> rtt = rttFactory.Create<RttEstimator> ();
|
||||
Ptr<TcpSocketBase> socket = socketFactory.Create<TcpSocketBase> ();
|
||||
socket->SetNode (m_node);
|
||||
socket->SetTcp (this);
|
||||
socket->SetRtt (rtt);
|
||||
@@ -432,6 +169,12 @@ TcpL4Protocol::CreateSocket (void)
|
||||
return socket;
|
||||
}
|
||||
|
||||
Ptr<Socket>
|
||||
TcpL4Protocol::CreateSocket (void)
|
||||
{
|
||||
return CreateSocket (m_socketTypeId);
|
||||
}
|
||||
|
||||
Ipv4EndPoint *
|
||||
TcpL4Protocol::Allocate (void)
|
||||
{
|
||||
|
||||
@@ -37,7 +37,7 @@ class Socket;
|
||||
class TcpHeader;
|
||||
class Ipv4EndPointDemux;
|
||||
class Ipv4Interface;
|
||||
class TcpSocketImpl;
|
||||
class TcpSocketBase;
|
||||
class Ipv4EndPoint;
|
||||
|
||||
/**
|
||||
@@ -69,6 +69,7 @@ public:
|
||||
* of the TCP protocol
|
||||
*/
|
||||
Ptr<Socket> CreateSocket (void);
|
||||
Ptr<Socket> CreateSocket (TypeId socketTypeId);
|
||||
|
||||
Ipv4EndPoint *Allocate (void);
|
||||
Ipv4EndPoint *Allocate (Ipv4Address address);
|
||||
@@ -115,16 +116,16 @@ protected:
|
||||
private:
|
||||
Ptr<Node> m_node;
|
||||
Ipv4EndPointDemux *m_endPoints;
|
||||
ObjectFactory m_rttFactory;
|
||||
TypeId m_rttTypeId;
|
||||
TypeId m_socketTypeId;
|
||||
private:
|
||||
friend class TcpSocketImpl;
|
||||
friend class TcpSocketBase;
|
||||
void SendPacket (Ptr<Packet>, const TcpHeader &,
|
||||
Ipv4Address, Ipv4Address, Ptr<NetDevice> oif = 0);
|
||||
static ObjectFactory GetDefaultRttEstimatorFactory (void);
|
||||
TcpL4Protocol (const TcpL4Protocol &o);
|
||||
TcpL4Protocol &operator = (const TcpL4Protocol &o);
|
||||
|
||||
std::vector<Ptr<TcpSocketImpl> > m_sockets;
|
||||
std::vector<Ptr<TcpSocketBase> > m_sockets;
|
||||
};
|
||||
|
||||
}; // namespace ns3
|
||||
|
||||
221
src/internet-stack/tcp-newreno.cc
Normal file
221
src/internet-stack/tcp-newreno.cc
Normal file
@@ -0,0 +1,221 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 Adrian Sai-wah Tam
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
|
||||
*/
|
||||
|
||||
#define NS_LOG_APPEND_CONTEXT \
|
||||
if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_node->GetId () << "] "; }
|
||||
|
||||
#include "tcp-newreno.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/node.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpNewReno");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (TcpNewReno);
|
||||
|
||||
TypeId
|
||||
TcpNewReno::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::TcpNewReno")
|
||||
.SetParent<TcpSocketBase> ()
|
||||
.AddConstructor<TcpNewReno> ()
|
||||
.AddTraceSource ("CongestionWindow",
|
||||
"The TCP connection's congestion window",
|
||||
MakeTraceSourceAccessor (&TcpNewReno::m_cWnd))
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TcpNewReno::TcpNewReno (void) : m_inFastRec (false)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
TcpNewReno::TcpNewReno (const TcpNewReno& sock)
|
||||
: TcpSocketBase (sock),
|
||||
m_cWnd (sock.m_cWnd),
|
||||
m_ssThresh (sock.m_ssThresh),
|
||||
m_initialCWnd (sock.m_initialCWnd),
|
||||
m_inFastRec (false)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC ("Invoked the copy constructor");
|
||||
}
|
||||
|
||||
TcpNewReno::~TcpNewReno (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
TcpNewReno::SetNode (Ptr<Node> node)
|
||||
{
|
||||
TcpSocketBase::SetNode (node);
|
||||
/*
|
||||
* Initialize congestion window, default to 1 MSS (RFC2001, sec.1) and must
|
||||
* not be larger than 2 MSS (RFC2581, sec.3.1). Both m_initiaCWnd and
|
||||
* m_segmentSize are set by the attribute system in ns3::TcpSocket.
|
||||
*/
|
||||
m_cWnd = m_initialCWnd * m_segmentSize;
|
||||
}
|
||||
|
||||
/** Limit the size of in-flight data by cwnd and receiver's rxwin */
|
||||
uint32_t
|
||||
TcpNewReno::Window (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return std::min (m_rWnd.Get (), m_cWnd.Get ());
|
||||
}
|
||||
|
||||
Ptr<TcpSocketBase>
|
||||
TcpNewReno::Fork (void)
|
||||
{
|
||||
return CopyObject<TcpNewReno> (this);
|
||||
}
|
||||
|
||||
/** New ACK (up to seqnum seq) received. Increase cwnd and call TcpSocketBase::NewAck() */
|
||||
void
|
||||
TcpNewReno::NewAck (const SequenceNumber32& seq)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << seq);
|
||||
NS_LOG_LOGIC ("TcpNewReno receieved ACK for seq " << seq <<
|
||||
" cwnd " << m_cWnd <<
|
||||
" ssthresh " << m_ssThresh);
|
||||
|
||||
// Check for exit condition of fast recovery
|
||||
if (m_inFastRec && seq < m_recover)
|
||||
{ // Partial ACK, partial window deflation (RFC2582 sec.3 bullet #5 paragraph 3)
|
||||
m_cWnd += m_segmentSize; // increase cwnd
|
||||
NS_LOG_INFO ("Partial ACK in fast recovery: cwnd set to " << m_cWnd);
|
||||
TcpSocketBase::NewAck(seq); // update m_nextTxSequence and send new data if allowed by window
|
||||
DoRetransmit (); // Assume the next seq is lost. Retransmit lost packet
|
||||
return;
|
||||
}
|
||||
else if (m_inFastRec && seq >= m_recover)
|
||||
{ // Full ACK (RFC2582 sec.3 bullet #5 paragraph 2, option 1)
|
||||
m_cWnd = std::min (m_ssThresh, BytesInFlight () + m_segmentSize);
|
||||
m_inFastRec = false;
|
||||
NS_LOG_INFO ("Received full ACK. Leaving fast recovery with cwnd set to " << m_cWnd);
|
||||
}
|
||||
|
||||
// Increase of cwnd based on current phase (slow start or congestion avoidance)
|
||||
if (m_cWnd < m_ssThresh)
|
||||
{ // Slow start mode, add one segSize to cWnd. Default m_ssThresh is 65535. (RFC2001, sec.1)
|
||||
m_cWnd += m_segmentSize;
|
||||
NS_LOG_INFO ("In SlowStart, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
|
||||
}
|
||||
else
|
||||
{ // Congestion avoidance mode, increase by (segSize*segSize)/cwnd. (RFC2581, sec.3.1)
|
||||
// To increase cwnd for one segSize per RTT, it should be (ackBytes*segSize)/cwnd
|
||||
double adder = static_cast<double> (m_segmentSize * m_segmentSize) / m_cWnd.Get ();
|
||||
adder = std::max (1.0, adder);
|
||||
m_cWnd += static_cast<uint32_t> (adder);
|
||||
NS_LOG_INFO ("In CongAvoid, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
|
||||
}
|
||||
|
||||
// Complete newAck processing
|
||||
TcpSocketBase::NewAck (seq);
|
||||
}
|
||||
|
||||
/** Cut cwnd and enter fast recovery mode upon triple dupack */
|
||||
void
|
||||
TcpNewReno::DupAck (const TcpHeader& t, uint32_t count)
|
||||
{
|
||||
if (count == 3 && ! m_inFastRec)
|
||||
{ // triple duplicate ack triggers fast retransmit (RFC2582 sec.3 bullet #1)
|
||||
m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2);
|
||||
m_cWnd = m_ssThresh + 3 * m_segmentSize;
|
||||
m_recover = m_highTxMark;
|
||||
m_inFastRec = true;
|
||||
NS_LOG_INFO ("Triple dupack. Enter fast recovery mode. Reset cwnd to " << m_cWnd <<
|
||||
", ssthresh to " << m_ssThresh << " at fast recovery seqnum " << m_recover);
|
||||
DoRetransmit ();
|
||||
}
|
||||
else if (m_inFastRec)
|
||||
{ // Increase cwnd for every additional dupack (RFC2582, sec.3 bullet #3)
|
||||
m_cWnd += m_segmentSize;
|
||||
NS_LOG_INFO ("Dupack in fast recovery mode. Increase cwnd to " << m_cWnd);
|
||||
SendPendingData (m_connected);
|
||||
};
|
||||
}
|
||||
|
||||
/** Retransmit timeout */
|
||||
void
|
||||
TcpNewReno::Retransmit (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC (this << " ReTxTimeout Expired at time " << Simulator::Now ().GetSeconds ());
|
||||
m_inFastRec = false;
|
||||
|
||||
// If erroneous timeout in closed/timed-wait state, just return
|
||||
if (m_state == CLOSED || m_state == TIME_WAIT) return;
|
||||
// If all data are received, just return
|
||||
if (m_txBuffer.HeadSequence () >= m_nextTxSequence) return;
|
||||
|
||||
// According to RFC2581 sec.3.1, upon RTO, ssthresh is set to half of flight
|
||||
// size and cwnd is set to 1*MSS, then the lost packet is retransmitted and
|
||||
// TCP back to slow start
|
||||
m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2);
|
||||
m_cWnd = m_segmentSize;
|
||||
m_nextTxSequence = m_txBuffer.HeadSequence (); // Restart from highest Ack
|
||||
NS_LOG_INFO ("RTO. Reset cwnd to " << m_cWnd <<
|
||||
", ssthresh to " << m_ssThresh << ", restart from seqnum " << m_nextTxSequence);
|
||||
m_rtt->IncreaseMultiplier (); // Double the next RTO
|
||||
DoRetransmit (); // Retransmit the packet
|
||||
}
|
||||
|
||||
void
|
||||
TcpNewReno::SetSegSize (uint32_t size)
|
||||
{
|
||||
NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpNewReno::SetSegSize() cannot change segment size after connection started.");
|
||||
m_segmentSize = size;
|
||||
m_cWnd = m_initialCWnd * m_segmentSize;
|
||||
}
|
||||
|
||||
void
|
||||
TcpNewReno::SetSSThresh (uint32_t threshold)
|
||||
{
|
||||
m_ssThresh = threshold;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpNewReno::GetSSThresh (void) const
|
||||
{
|
||||
return m_ssThresh;
|
||||
}
|
||||
|
||||
void
|
||||
TcpNewReno::SetInitialCwnd (uint32_t cwnd)
|
||||
{
|
||||
NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpNewReno::SetInitialCwnd() cannot change initial cwnd after connection started.");
|
||||
m_initialCWnd = cwnd;
|
||||
m_cWnd = m_initialCWnd * m_segmentSize;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpNewReno::GetInitialCwnd (void) const
|
||||
{
|
||||
return m_initialCWnd;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
74
src/internet-stack/tcp-newreno.h
Normal file
74
src/internet-stack/tcp-newreno.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 Adrian Sai-wah Tam
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef TCP_NEWRENO_H
|
||||
#define TCP_NEWRENO_H
|
||||
|
||||
#include "tcp-socket-base.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \ingroup socket
|
||||
* \ingroup tcp
|
||||
*
|
||||
* \brief An implementation of a stream socket using TCP.
|
||||
*
|
||||
* This class contains the NewReno implementation of TCP, as of RFC2582.
|
||||
*/
|
||||
class TcpNewReno : public TcpSocketBase
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
/**
|
||||
* Create an unbound tcp socket.
|
||||
*/
|
||||
TcpNewReno (void);
|
||||
TcpNewReno (const TcpNewReno& sock);
|
||||
virtual ~TcpNewReno (void);
|
||||
|
||||
// Set associated Node, TcpL4Protocol, RttEstimator to this socket
|
||||
virtual void SetNode (Ptr<Node> node);
|
||||
|
||||
protected:
|
||||
virtual uint32_t Window (void); // Return the max possible number of unacked bytes
|
||||
virtual Ptr<TcpSocketBase> Fork (void); // Call CopyObject<TcpNewReno> to clone me
|
||||
virtual void NewAck (SequenceNumber32 const& seq); // Inc cwnd and call NewAck() of parent
|
||||
virtual void DupAck (const TcpHeader& t, uint32_t count); // Halving cwnd and reset nextTxSequence
|
||||
virtual void Retransmit (void); // Exit fast recovery upon retransmit timeout
|
||||
|
||||
// Implementing ns3::TcpSocket -- Attribute get/set
|
||||
virtual void SetSegSize (uint32_t size);
|
||||
virtual void SetSSThresh (uint32_t threshold);
|
||||
virtual uint32_t GetSSThresh (void) const;
|
||||
virtual void SetInitialCwnd (uint32_t cwnd);
|
||||
virtual uint32_t GetInitialCwnd (void) const;
|
||||
|
||||
protected:
|
||||
TracedValue<uint32_t> m_cWnd; //< Congestion window
|
||||
uint32_t m_ssThresh; //< Slow Start Threshold
|
||||
uint32_t m_initialCWnd; //< Initial cWnd value
|
||||
SequenceNumber32 m_recover; //< Previous highest Tx seqnum for fast recovery
|
||||
bool m_inFastRec; //< currently in fast recovery
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* TCP_NEWRENO_H */
|
||||
212
src/internet-stack/tcp-reno.cc
Normal file
212
src/internet-stack/tcp-reno.cc
Normal file
@@ -0,0 +1,212 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 Adrian Sai-wah Tam
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
|
||||
*/
|
||||
|
||||
#define NS_LOG_APPEND_CONTEXT \
|
||||
if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_node->GetId () << "] "; }
|
||||
|
||||
#include "tcp-reno.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/node.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpReno");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (TcpReno);
|
||||
|
||||
TypeId
|
||||
TcpReno::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::TcpReno")
|
||||
.SetParent<TcpSocketBase> ()
|
||||
.AddConstructor<TcpReno> ()
|
||||
.AddTraceSource ("CongestionWindow",
|
||||
"The TCP connection's congestion window",
|
||||
MakeTraceSourceAccessor (&TcpReno::m_cWnd))
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TcpReno::TcpReno (void) : m_inFastRec (false)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
TcpReno::TcpReno (const TcpReno& sock)
|
||||
: TcpSocketBase (sock),
|
||||
m_cWnd (sock.m_cWnd),
|
||||
m_ssThresh (sock.m_ssThresh),
|
||||
m_initialCWnd (sock.m_initialCWnd),
|
||||
m_inFastRec (false)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC ("Invoked the copy constructor");
|
||||
}
|
||||
|
||||
TcpReno::~TcpReno (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
TcpReno::SetNode (Ptr<Node> node)
|
||||
{
|
||||
TcpSocketBase::SetNode (node);
|
||||
/*
|
||||
* Initialize congestion window, default to 1 MSS (RFC2001, sec.1) and must
|
||||
* not be larger than 2 MSS (RFC2581, sec.3.1). Both m_initiaCWnd and
|
||||
* m_segmentSize are set by the attribute system in ns3::TcpSocket.
|
||||
*/
|
||||
m_cWnd = m_initialCWnd * m_segmentSize;
|
||||
}
|
||||
|
||||
/** Limit the size of in-flight data by cwnd and receiver's rxwin */
|
||||
uint32_t
|
||||
TcpReno::Window (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return std::min (m_rWnd.Get (), m_cWnd.Get ());
|
||||
}
|
||||
|
||||
Ptr<TcpSocketBase>
|
||||
TcpReno::Fork (void)
|
||||
{
|
||||
return CopyObject<TcpReno> (this);
|
||||
}
|
||||
|
||||
/** New ACK (up to seqnum seq) received. Increase cwnd and call TcpSocketBase::NewAck() */
|
||||
void
|
||||
TcpReno::NewAck (const SequenceNumber32& seq)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << seq);
|
||||
NS_LOG_LOGIC ("TcpReno receieved ACK for seq " << seq <<
|
||||
" cwnd " << m_cWnd <<
|
||||
" ssthresh " << m_ssThresh);
|
||||
|
||||
// Check for exit condition of fast recovery
|
||||
if (m_inFastRec)
|
||||
{ // RFC2001, sec.4; RFC2581, sec.3.2
|
||||
// First new ACK after fast recovery: reset cwnd
|
||||
m_cWnd = m_ssThresh;
|
||||
m_inFastRec = false;
|
||||
NS_LOG_INFO ("Reset cwnd to " << m_cWnd);
|
||||
};
|
||||
|
||||
// Increase of cwnd based on current phase (slow start or congestion avoidance)
|
||||
if (m_cWnd < m_ssThresh)
|
||||
{ // Slow start mode, add one segSize to cWnd. Default m_ssThresh is 65535. (RFC2001, sec.1)
|
||||
m_cWnd += m_segmentSize;
|
||||
NS_LOG_INFO ("In SlowStart, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
|
||||
}
|
||||
else
|
||||
{ // Congestion avoidance mode, increase by (segSize*segSize)/cwnd. (RFC2581, sec.3.1)
|
||||
// To increase cwnd for one segSize per RTT, it should be (ackBytes*segSize)/cwnd
|
||||
double adder = static_cast<double> (m_segmentSize * m_segmentSize) / m_cWnd.Get ();
|
||||
adder = std::max (1.0, adder);
|
||||
m_cWnd += static_cast<uint32_t> (adder);
|
||||
NS_LOG_INFO ("In CongAvoid, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
|
||||
}
|
||||
|
||||
// Complete newAck processing
|
||||
TcpSocketBase::NewAck (seq);
|
||||
}
|
||||
|
||||
// Fast recovery and fast retransmit
|
||||
void
|
||||
TcpReno::DupAck (const TcpHeader& t, uint32_t count)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << "t " << count);
|
||||
if (count == 3 && ! m_inFastRec)
|
||||
{ // triple duplicate ack triggers fast retransmit (RFC2581, sec.3.2)
|
||||
m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2);
|
||||
m_cWnd = m_ssThresh + 3 * m_segmentSize;
|
||||
m_inFastRec = true;
|
||||
NS_LOG_INFO ("Triple dupack. Reset cwnd to " << m_cWnd << ", ssthresh to " << m_ssThresh);
|
||||
DoRetransmit ();
|
||||
}
|
||||
else if (m_inFastRec)
|
||||
{ // In fast recovery, inc cwnd for every additional dupack (RFC2581, sec.3.2)
|
||||
m_cWnd += m_segmentSize;
|
||||
NS_LOG_INFO ("Increased cwnd to " << m_cWnd);
|
||||
SendPendingData (m_connected);
|
||||
};
|
||||
}
|
||||
|
||||
// Retransmit timeout
|
||||
void TcpReno::Retransmit (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC (this << " ReTxTimeout Expired at time " << Simulator::Now ().GetSeconds ());
|
||||
m_inFastRec = false;
|
||||
|
||||
// If erroneous timeout in closed/timed-wait state, just return
|
||||
if (m_state == CLOSED || m_state == TIME_WAIT) return;
|
||||
// If all data are received, just return
|
||||
if (m_txBuffer.HeadSequence () >= m_nextTxSequence) return;
|
||||
|
||||
// According to RFC2581 sec.3.1, upon RTO, ssthresh is set to half of flight
|
||||
// size and cwnd is set to 1*MSS, then the lost packet is retransmitted and
|
||||
// TCP back to slow start
|
||||
m_ssThresh = std::max (2 * m_segmentSize, BytesInFlight () / 2);
|
||||
m_cWnd = m_segmentSize;
|
||||
m_nextTxSequence = m_txBuffer.HeadSequence (); // Restart from highest Ack
|
||||
NS_LOG_INFO ("RTO. Reset cwnd to " << m_cWnd <<
|
||||
", ssthresh to " << m_ssThresh << ", restart from seqnum " << m_nextTxSequence);
|
||||
m_rtt->IncreaseMultiplier (); // Double the next RTO
|
||||
DoRetransmit (); // Retransmit the packet
|
||||
}
|
||||
|
||||
void
|
||||
TcpReno::SetSegSize (uint32_t size)
|
||||
{
|
||||
NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpReno::SetSegSize() cannot change segment size after connection started.");
|
||||
m_segmentSize = size;
|
||||
m_cWnd = m_initialCWnd * m_segmentSize;
|
||||
}
|
||||
|
||||
void
|
||||
TcpReno::SetSSThresh (uint32_t threshold)
|
||||
{
|
||||
m_ssThresh = threshold;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpReno::GetSSThresh (void) const
|
||||
{
|
||||
return m_ssThresh;
|
||||
}
|
||||
|
||||
void
|
||||
TcpReno::SetInitialCwnd (uint32_t cwnd)
|
||||
{
|
||||
NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpReno::SetInitialCwnd() cannot change initial cwnd after connection started.");
|
||||
m_initialCWnd = cwnd;
|
||||
m_cWnd = m_initialCWnd * m_segmentSize;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpReno::GetInitialCwnd (void) const
|
||||
{
|
||||
return m_initialCWnd;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
75
src/internet-stack/tcp-reno.h
Normal file
75
src/internet-stack/tcp-reno.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 Adrian Sai-wah Tam
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef TCP_RENO_H
|
||||
#define TCP_RENO_H
|
||||
|
||||
#include "tcp-socket-base.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \ingroup socket
|
||||
* \ingroup tcp
|
||||
*
|
||||
* \brief An implementation of a stream socket using TCP.
|
||||
*
|
||||
* This class contains the Reno implementation of TCP, according to RFC2581,
|
||||
* except sec.4.1 "re-starting idle connections", which we do not detect for
|
||||
* idleness and thus no slow start upon resumption.
|
||||
*/
|
||||
class TcpReno : public TcpSocketBase
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
/**
|
||||
* Create an unbound tcp socket.
|
||||
*/
|
||||
TcpReno (void);
|
||||
TcpReno (const TcpReno& sock);
|
||||
virtual ~TcpReno (void);
|
||||
|
||||
// Set associated Node, TcpL4Protocol, RttEstimator to this socket
|
||||
virtual void SetNode (Ptr<Node> node);
|
||||
|
||||
protected:
|
||||
virtual uint32_t Window (void); // Return the max possible number of unacked bytes
|
||||
virtual Ptr<TcpSocketBase> Fork (void); // Call CopyObject<TcpReno> to clone me
|
||||
virtual void NewAck (const SequenceNumber32& seq); // Inc cwnd and call NewAck() of parent
|
||||
virtual void DupAck (const TcpHeader& t, uint32_t count); // Fast retransmit
|
||||
virtual void Retransmit (void); // Retransmit timeout
|
||||
|
||||
// Implementing ns3::TcpSocket -- Attribute get/set
|
||||
virtual void SetSegSize (uint32_t size);
|
||||
virtual void SetSSThresh (uint32_t threshold);
|
||||
virtual uint32_t GetSSThresh (void) const;
|
||||
virtual void SetInitialCwnd (uint32_t cwnd);
|
||||
virtual uint32_t GetInitialCwnd (void) const;
|
||||
|
||||
protected:
|
||||
TracedValue<uint32_t> m_cWnd; //< Congestion window
|
||||
uint32_t m_ssThresh; //< Slow Start Threshold
|
||||
uint32_t m_initialCWnd; //< Initial cWnd value
|
||||
bool m_inFastRec; //< currently in fast recovery
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* TCP_RENO_H */
|
||||
91
src/internet-stack/tcp-rfc793.cc
Normal file
91
src/internet-stack/tcp-rfc793.cc
Normal file
@@ -0,0 +1,91 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 Adrian Sai-wah Tam
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
|
||||
*/
|
||||
|
||||
#include "tcp-rfc793.h"
|
||||
#include "ns3/log.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpRfc793");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (TcpRfc793);
|
||||
|
||||
TypeId
|
||||
TcpRfc793::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::TcpRfc793")
|
||||
.SetParent<TcpSocketBase> ()
|
||||
.AddConstructor<TcpRfc793> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TcpRfc793::TcpRfc793 (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
SetDelAckMaxCount(0); // Delayed ACK is not in RFC793
|
||||
}
|
||||
|
||||
TcpRfc793::TcpRfc793 (const TcpRfc793& sock) : TcpSocketBase (sock)
|
||||
{
|
||||
}
|
||||
|
||||
TcpRfc793::~TcpRfc793 (void)
|
||||
{
|
||||
}
|
||||
|
||||
Ptr<TcpSocketBase>
|
||||
TcpRfc793::Fork (void)
|
||||
{
|
||||
return CopyObject<TcpRfc793> (this);
|
||||
}
|
||||
|
||||
void
|
||||
TcpRfc793::DupAck (const TcpHeader& t, uint32_t count)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
TcpRfc793::SetSSThresh (uint32_t threshold)
|
||||
{
|
||||
NS_LOG_WARN ("DoD TCP does not perform slow start");
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpRfc793::GetSSThresh (void) const
|
||||
{
|
||||
NS_LOG_WARN ("DoD TCP does not perform slow start");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
TcpRfc793::SetInitialCwnd (uint32_t cwnd)
|
||||
{
|
||||
NS_LOG_WARN ("DoD TCP does not have congestion window");
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpRfc793::GetInitialCwnd (void) const
|
||||
{
|
||||
NS_LOG_WARN ("DoD TCP does not have congestion window");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
61
src/internet-stack/tcp-rfc793.h
Normal file
61
src/internet-stack/tcp-rfc793.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 Adrian Sai-wah Tam
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef TCP_RFC793_H
|
||||
#define TCP_RFC793_H
|
||||
|
||||
#include "tcp-socket-base.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \ingroup socket
|
||||
* \ingroup tcp
|
||||
*
|
||||
* \brief An implementation of a stream socket using TCP.
|
||||
*
|
||||
* This class contains an RFC793 implementation of TCP, as well as a sockets
|
||||
* interface for talking to TCP. This serves as a base for other TCP functions
|
||||
* where the sliding window mechanism is handled here. This class provides
|
||||
* connection orientation and sliding window flow control.
|
||||
*/
|
||||
class TcpRfc793 : public TcpSocketBase
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
/**
|
||||
* Create an unbound tcp socket.
|
||||
*/
|
||||
TcpRfc793 (void);
|
||||
TcpRfc793 (const TcpRfc793& sock);
|
||||
virtual ~TcpRfc793 (void);
|
||||
|
||||
protected:
|
||||
virtual Ptr<TcpSocketBase> Fork (); // Call CopyObject<TcpRfc793> to clone me
|
||||
virtual void DupAck (const TcpHeader& t, uint32_t count);
|
||||
virtual void SetSSThresh (uint32_t threshold);
|
||||
virtual uint32_t GetSSThresh (void) const;
|
||||
virtual void SetInitialCwnd (uint32_t cwnd);
|
||||
virtual uint32_t GetInitialCwnd (void) const;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* TCP_RFC793_H */
|
||||
264
src/internet-stack/tcp-rx-buffer.cc
Normal file
264
src/internet-stack/tcp-rx-buffer.cc
Normal file
@@ -0,0 +1,264 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 Adrian Sai-wah Tam
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
|
||||
*/
|
||||
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/fatal-error.h"
|
||||
#include "ns3/log.h"
|
||||
#include "tcp-rx-buffer.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpRxBuffer");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
TypeId
|
||||
TcpRxBuffer::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::TcpRxBuffer")
|
||||
.SetParent<Object> ()
|
||||
.AddConstructor<TcpRxBuffer> ()
|
||||
.AddTraceSource ("NextRxSequence",
|
||||
"Next sequence number expected (RCV.NXT)",
|
||||
MakeTraceSourceAccessor (&TcpRxBuffer::m_nextRxSeq))
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
/* A user is supposed to create a TcpSocket through a factory. In TcpSocket,
|
||||
* there are attributes SndBufSize and RcvBufSize to control the default Tx and
|
||||
* Rx window sizes respectively, with default of 128 KiByte. The attribute
|
||||
* RcvBufSize is passed to TcpRxBuffer by TcpSocketBase::SetRcvBufSize() and in
|
||||
* turn, TcpRxBuffer:SetMaxBufferSize(). Therefore, the m_maxBuffer value
|
||||
* initialized below is insignificant.
|
||||
*/
|
||||
TcpRxBuffer::TcpRxBuffer (uint32_t n)
|
||||
: m_nextRxSeq(n), m_gotFin(false), m_size(0), m_maxBuffer(32768), m_availBytes(0)
|
||||
{
|
||||
}
|
||||
|
||||
TcpRxBuffer::~TcpRxBuffer ()
|
||||
{
|
||||
}
|
||||
|
||||
SequenceNumber32
|
||||
TcpRxBuffer::NextRxSequence (void) const
|
||||
{
|
||||
return m_nextRxSeq;
|
||||
}
|
||||
|
||||
void
|
||||
TcpRxBuffer::SetNextRxSequence (const SequenceNumber32& s)
|
||||
{
|
||||
m_nextRxSeq = s;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpRxBuffer::MaxBufferSize (void) const
|
||||
{
|
||||
return m_maxBuffer;
|
||||
}
|
||||
|
||||
void
|
||||
TcpRxBuffer::SetMaxBufferSize (uint32_t s)
|
||||
{
|
||||
m_maxBuffer = s;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpRxBuffer::Size (void) const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpRxBuffer::Available () const
|
||||
{
|
||||
return m_availBytes;
|
||||
}
|
||||
|
||||
void
|
||||
TcpRxBuffer::IncNextRxSequence ()
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
// Increment nextRxSeq is valid only if we don't have any data buffered,
|
||||
// this is supposed to be called only during the three-way handshake
|
||||
NS_ASSERT (m_size == 0);
|
||||
m_nextRxSeq++;
|
||||
}
|
||||
|
||||
// Return the highest sequence number that this TcpRxBuffer can accept
|
||||
SequenceNumber32
|
||||
TcpRxBuffer::MaxRxSequence (void) const
|
||||
{
|
||||
if (m_gotFin)
|
||||
{ // No data allowed beyond FIN
|
||||
return m_finSeq;
|
||||
}
|
||||
else if (m_data.size ())
|
||||
{ // No data allowed beyond Rx window allowed
|
||||
return m_data.begin()->first + SequenceNumber32 (m_maxBuffer);
|
||||
}
|
||||
return m_nextRxSeq + SequenceNumber32 (m_maxBuffer);
|
||||
}
|
||||
|
||||
void
|
||||
TcpRxBuffer::SetFinSequence (const SequenceNumber32& s)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
|
||||
m_gotFin = true;
|
||||
m_finSeq = s;
|
||||
if (m_nextRxSeq == m_finSeq) ++m_nextRxSeq;
|
||||
}
|
||||
|
||||
bool
|
||||
TcpRxBuffer::Finished (void)
|
||||
{
|
||||
return (m_gotFin && m_finSeq < m_nextRxSeq);
|
||||
}
|
||||
|
||||
bool
|
||||
TcpRxBuffer::Add (Ptr<Packet> p, TcpHeader const& tcph)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << p << tcph);
|
||||
|
||||
uint32_t pktSize = p->GetSize ();
|
||||
SequenceNumber32 headSeq = tcph.GetSequenceNumber ();
|
||||
SequenceNumber32 tailSeq = headSeq + SequenceNumber32 (pktSize);
|
||||
NS_LOG_LOGIC ("Add pkt " << p << " len=" << pktSize << " seq=" << headSeq
|
||||
<< ", when NextRxSeq=" << m_nextRxSeq << ", buffsize=" << m_size);
|
||||
|
||||
// Trim packet to fit Rx window specification
|
||||
if (headSeq < m_nextRxSeq) headSeq = m_nextRxSeq;
|
||||
if (m_data.size ())
|
||||
{
|
||||
SequenceNumber32 maxSeq = m_data.begin ()->first + SequenceNumber32 (m_maxBuffer);
|
||||
if (maxSeq < tailSeq) tailSeq = maxSeq;
|
||||
if (tailSeq < headSeq) headSeq = tailSeq;
|
||||
}
|
||||
// Remove overlapped bytes from packet
|
||||
BufIterator i = m_data.begin ();
|
||||
while (i != m_data.end () && i->first <= tailSeq)
|
||||
{
|
||||
SequenceNumber32 lastByteSeq = i->first + SequenceNumber32 (i->second->GetSize ());
|
||||
if (lastByteSeq > headSeq)
|
||||
{
|
||||
if (i->first > headSeq && lastByteSeq < tailSeq)
|
||||
{ // Rare case: Existing packet is embedded fully in the new packet
|
||||
m_size -= i->second->GetSize();
|
||||
m_data.erase (i++);
|
||||
continue;
|
||||
}
|
||||
if (i->first <= headSeq)
|
||||
{ // Incoming head is overlapped
|
||||
headSeq = lastByteSeq;
|
||||
}
|
||||
if (lastByteSeq >= tailSeq)
|
||||
{ // Incoming tail is overlapped
|
||||
tailSeq = i->first;
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
// We now know how much we are going to store, trim the packet
|
||||
if (headSeq >= tailSeq)
|
||||
{
|
||||
NS_LOG_LOGIC ("Nothing to buffer");
|
||||
return false; // Nothing to buffer anyway
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t start = headSeq - tcph.GetSequenceNumber ();
|
||||
uint32_t length = tailSeq - headSeq;
|
||||
p = p->CreateFragment (start, length);
|
||||
NS_ASSERT (length == p->GetSize ());
|
||||
}
|
||||
// Insert packet into buffer
|
||||
NS_ASSERT (m_data.find (headSeq) == m_data.end ()); // Shouldn't be there yet
|
||||
m_data [ headSeq ] = p;
|
||||
NS_LOG_LOGIC ("Buffered packet of seqno=" << headSeq << " len=" << p->GetSize ());
|
||||
// Update variables
|
||||
m_size += p->GetSize (); // Occupancy
|
||||
for (BufIterator i = m_data.begin (); i != m_data.end (); ++i)
|
||||
{
|
||||
if (i->first < m_nextRxSeq)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (i->first > m_nextRxSeq)
|
||||
{
|
||||
break;
|
||||
};
|
||||
m_nextRxSeq = i->first + SequenceNumber32 (i->second->GetSize ());
|
||||
m_availBytes += i->second->GetSize ();
|
||||
}
|
||||
NS_LOG_LOGIC ("Updated buffer occupancy=" << m_size << " nextRxSeq=" << m_nextRxSeq);
|
||||
if (m_gotFin && m_nextRxSeq == m_finSeq)
|
||||
{ // Account for the FIN packet
|
||||
++m_nextRxSeq;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
Ptr<Packet>
|
||||
TcpRxBuffer::Extract (uint32_t maxSize)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << maxSize);
|
||||
|
||||
uint32_t extractSize = std::min (maxSize, m_availBytes);
|
||||
NS_LOG_LOGIC ("Requested to extract " << extractSize << " bytes from TcpRxBuffer of size=" << m_size);
|
||||
if (extractSize == 0) return 0; // No contiguous block to return
|
||||
NS_ASSERT (m_data.size ()); // At least we have something to extract
|
||||
Ptr<Packet> outPkt = Create<Packet> (); // The packet that contains all the data to return
|
||||
BufIterator i;
|
||||
while (extractSize)
|
||||
{ // Check the buffered data for delivery
|
||||
i = m_data.begin ();
|
||||
NS_ASSERT (i->first <= m_nextRxSeq); // in-sequence data expected
|
||||
// Check if we send the whole pkt or just a partial
|
||||
uint32_t pktSize = i->second->GetSize ();
|
||||
if (pktSize <= extractSize)
|
||||
{ // Whole packet is extracted
|
||||
outPkt->AddAtEnd (i->second);
|
||||
m_data.erase (i);
|
||||
m_size -= pktSize;
|
||||
m_availBytes -= pktSize;
|
||||
extractSize -= pktSize;
|
||||
}
|
||||
else
|
||||
{ // Partial is extracted and done
|
||||
outPkt->AddAtEnd (i->second->CreateFragment (0, extractSize));
|
||||
m_data[i->first + SequenceNumber32 (extractSize)] = i->second->CreateFragment (extractSize, pktSize - extractSize);
|
||||
m_data.erase (i);
|
||||
m_size -= extractSize;
|
||||
m_availBytes -= extractSize;
|
||||
extractSize = 0;
|
||||
}
|
||||
}
|
||||
if (outPkt->GetSize () == 0)
|
||||
{
|
||||
NS_LOG_LOGIC ("Nothing extracted.");
|
||||
return 0;
|
||||
}
|
||||
NS_LOG_LOGIC ("Extracted " << outPkt->GetSize( ) << " bytes, bufsize=" << m_size
|
||||
<< ", num pkts in buffer=" << m_data.size ());
|
||||
return outPkt;
|
||||
}
|
||||
|
||||
} //namepsace ns3
|
||||
89
src/internet-stack/tcp-rx-buffer.h
Normal file
89
src/internet-stack/tcp-rx-buffer.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 Adrian Sai-wah Tam
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __TCP_RX_BUFFER_H__
|
||||
#define __TCP_RX_BUFFER_H__
|
||||
|
||||
#include <map>
|
||||
#include "ns3/traced-value.h"
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
#include "ns3/sequence-number.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/tcp-header.h"
|
||||
|
||||
namespace ns3 {
|
||||
class Packet;
|
||||
|
||||
/**
|
||||
* \ingroup tcp
|
||||
*
|
||||
* \brief class for the reordering buffer that keeps the data from lower layer, i.e.
|
||||
* TcpL4Protocol, sent to the application
|
||||
*/
|
||||
class TcpRxBuffer : public Object
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
TcpRxBuffer (uint32_t n = 0);
|
||||
virtual ~TcpRxBuffer ();
|
||||
|
||||
// Accessors
|
||||
SequenceNumber32 NextRxSequence (void) const;
|
||||
SequenceNumber32 MaxRxSequence (void) const;
|
||||
void IncNextRxSequence (void);
|
||||
void SetNextRxSequence (const SequenceNumber32& s);
|
||||
void SetFinSequence (const SequenceNumber32& s);
|
||||
uint32_t MaxBufferSize (void) const;
|
||||
void SetMaxBufferSize (uint32_t s);
|
||||
uint32_t Size (void) const;
|
||||
uint32_t Available () const;
|
||||
bool Finished (void);
|
||||
|
||||
/**
|
||||
* Insert a packet into the buffer and update the availBytes counter to
|
||||
* reflect the number of bytes ready to send to the application. This
|
||||
* function handles overlap by triming the head of the inputted packet and
|
||||
* removing data from the buffer that overlaps the tail of the inputted
|
||||
* packet
|
||||
*
|
||||
* \return True when success, false otherwise.
|
||||
*/
|
||||
bool Add (Ptr<Packet> p, TcpHeader const& tcph);
|
||||
|
||||
/**
|
||||
* Extract data from the head of the buffer as indicated by nextRxSeq.
|
||||
* The extracted data is going to be forwarded to the application.
|
||||
*/
|
||||
Ptr<Packet> Extract (uint32_t maxSize);
|
||||
public:
|
||||
typedef std::map<SequenceNumber32, Ptr<Packet> >::iterator BufIterator;
|
||||
TracedValue<SequenceNumber32> m_nextRxSeq; //< Seqnum of the first missing byte in data (RCV.NXT)
|
||||
SequenceNumber32 m_finSeq; //< Seqnum of the FIN packet
|
||||
bool m_gotFin; //< Did I received FIN packet?
|
||||
uint32_t m_size; //< Number of total data bytes in the buffer, not necessarily contiguous
|
||||
uint32_t m_maxBuffer; //< Upper bound of the number of data bytes in buffer (RCV.WND)
|
||||
uint32_t m_availBytes; //< Number of bytes available to read, i.e. contiguous block at head
|
||||
std::map<SequenceNumber32, Ptr<Packet> > m_data;
|
||||
//< Corresponding data (may be null)
|
||||
};
|
||||
|
||||
}//namepsace ns3
|
||||
|
||||
#endif /* __TCP_RX_BUFFER_H__ */
|
||||
1755
src/internet-stack/tcp-socket-base.cc
Normal file
1755
src/internet-stack/tcp-socket-base.cc
Normal file
File diff suppressed because it is too large
Load Diff
222
src/internet-stack/tcp-socket-base.h
Normal file
222
src/internet-stack/tcp-socket-base.h
Normal file
@@ -0,0 +1,222 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 Adrian Sai-wah Tam
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
|
||||
*/
|
||||
#ifndef TCP_SOCKET_BASE_H
|
||||
#define TCP_SOCKET_BASE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <queue>
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/traced-value.h"
|
||||
#include "ns3/tcp-socket.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/ipv4-header.h"
|
||||
#include "ns3/ipv4-interface.h"
|
||||
#include "ns3/event-id.h"
|
||||
#include "tcp-tx-buffer.h"
|
||||
#include "tcp-rx-buffer.h"
|
||||
#include "rtt-estimator.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Ipv4EndPoint;
|
||||
class Node;
|
||||
class Packet;
|
||||
class TcpL4Protocol;
|
||||
class TcpHeader;
|
||||
|
||||
/**
|
||||
* \ingroup socket
|
||||
* \ingroup tcp
|
||||
*
|
||||
* \brief A base class for implementation of a stream socket using TCP.
|
||||
*
|
||||
* This class contains the essential components of TCP, as well as a sockets
|
||||
* interface for upper layers to call. This serves as a base for other TCP
|
||||
* functions where the sliding window mechanism is handled here. This class
|
||||
* provides connection orientation and sliding window flow control. Part of
|
||||
* this class is modified from the original NS-3 TCP socket implementation
|
||||
* (TcpSocketImpl) by Raj Bhattacharjea.
|
||||
*/
|
||||
class TcpSocketBase : public TcpSocket
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
/**
|
||||
* Create an unbound TCP socket
|
||||
*/
|
||||
TcpSocketBase (void);
|
||||
|
||||
/**
|
||||
* Clone a TCP socket, for use upon receiving a connection request in LISTEN state
|
||||
*/
|
||||
TcpSocketBase (const TcpSocketBase& sock);
|
||||
virtual ~TcpSocketBase (void);
|
||||
|
||||
// Set associated Node, TcpL4Protocol, RttEstimator to this socket
|
||||
virtual void SetNode (Ptr<Node> node);
|
||||
virtual void SetTcp (Ptr<TcpL4Protocol> tcp);
|
||||
virtual void SetRtt (Ptr<RttEstimator> rtt);
|
||||
|
||||
// Necessary implementations of null functions from ns3::Socket
|
||||
virtual enum SocketErrno GetErrno (void) const; // returns m_errno
|
||||
virtual enum SocketType GetSocketType (void) const;// returns socket type
|
||||
virtual Ptr<Node> GetNode (void) const; // returns m_node
|
||||
virtual int Bind (void); // Bind a socket by setting up endpoint in TcpL4Protocol
|
||||
virtual int Bind (const Address &address); // ... endpoint of specific addr or port
|
||||
virtual int Connect (const Address &address); // Setup endpoint and call ProcessAction() to connect
|
||||
virtual int Listen (void); // Verify the socket is in a correct state and call ProcessAction() to listen
|
||||
virtual int Close (void); // Close by app: Kill socket upon tx buffer emptied
|
||||
virtual int ShutdownSend (void); // Assert the m_shutdownSend flag to prevent send to network
|
||||
virtual int ShutdownRecv (void); // Assert the m_shutdownRecv flag to prevent forward to app
|
||||
virtual int Send (Ptr<Packet> p, uint32_t flags); // Call by app to send data to network
|
||||
virtual int SendTo (Ptr<Packet> p, uint32_t flags, const Address &toAddress); // Same as Send(), toAddress is insignificant
|
||||
virtual Ptr<Packet> Recv (uint32_t maxSize, uint32_t flags); // Return a packet to be forwarded to app
|
||||
virtual Ptr<Packet> RecvFrom (uint32_t maxSize, uint32_t flags, Address &fromAddress); // ... and write the remote address at fromAddress
|
||||
virtual uint32_t GetTxAvailable (void) const; // Available Tx buffer size
|
||||
virtual uint32_t GetRxAvailable (void) const; // Available-to-read data size, i.e. value of m_rxAvailable
|
||||
virtual int GetSockName (Address &address) const; // Return local addr:port in address
|
||||
virtual void BindToNetDevice (Ptr<NetDevice> netdevice); // NetDevice with my m_endPoint
|
||||
|
||||
protected:
|
||||
// Implementing ns3::TcpSocket -- Attribute get/set
|
||||
virtual void SetSndBufSize (uint32_t size);
|
||||
virtual uint32_t GetSndBufSize (void) const;
|
||||
virtual void SetRcvBufSize (uint32_t size);
|
||||
virtual uint32_t GetRcvBufSize (void) const;
|
||||
virtual void SetSegSize (uint32_t size);
|
||||
virtual uint32_t GetSegSize (void) const;
|
||||
virtual void SetSSThresh (uint32_t threshold) = 0;
|
||||
virtual uint32_t GetSSThresh (void) const = 0;
|
||||
virtual void SetInitialCwnd (uint32_t cwnd) = 0;
|
||||
virtual uint32_t GetInitialCwnd (void) const = 0;
|
||||
virtual void SetConnTimeout (Time timeout);
|
||||
virtual Time GetConnTimeout (void) const;
|
||||
virtual void SetConnCount (uint32_t count);
|
||||
virtual uint32_t GetConnCount (void) const;
|
||||
virtual void SetDelAckTimeout (Time timeout);
|
||||
virtual Time GetDelAckTimeout (void) const;
|
||||
virtual void SetDelAckMaxCount (uint32_t count);
|
||||
virtual uint32_t GetDelAckMaxCount (void) const;
|
||||
virtual void SetPersistTimeout (Time timeout);
|
||||
virtual Time GetPersistTimeout (void) const;
|
||||
virtual bool SetAllowBroadcast (bool allowBroadcast);
|
||||
virtual bool GetAllowBroadcast () const;
|
||||
|
||||
// Helper functions: Connection set up
|
||||
int SetupCallback (void); // Common part of the two Bind(), i.e. set callback and remembering local addr:port
|
||||
int DoConnect (void); // Sending a SYN packet to make a connection if the state allows
|
||||
void ConnectionSucceeded (void); // Schedule-friendly wrapper for Socket::NotifyConnectionSucceeded()
|
||||
int SetupEndpoint (void); // Configure m_endpoint for local addr for given remote addr
|
||||
void CompleteFork (Ptr<Packet>, const TcpHeader&, const Address& fromAddress, const Address& toAdress);
|
||||
|
||||
// Helper functions: Transfer operation
|
||||
void ForwardUp (Ptr<Packet> packet, Ipv4Header header, uint16_t port, Ptr<Ipv4Interface> incomingInterface); //Get a pkt from L3
|
||||
bool SendPendingData (bool withAck = false); // Send as much as the window allows
|
||||
void SendEmptyPacket (uint8_t flags); // Send a empty packet that carries a flag, e.g. ACK
|
||||
void SendRST (void); // Send reset and tear down this socket
|
||||
bool OutOfRange (SequenceNumber32 s) const; // Check if a sequence number is within rx window
|
||||
|
||||
// Helper functions: Connection close
|
||||
int DoClose (void); // Close a socket by sending RST, FIN, or FIN+ACK, depend on the current state
|
||||
void CloseAndNotify (void); // To CLOSED state, notify upper layer, and deallocate end point
|
||||
void Destroy (void); // Kill this socket by zeroing its attributes
|
||||
void DeallocateEndPoint (void); // Deallocate m_endPoint
|
||||
void PeerClose (Ptr<Packet>, const TcpHeader&); // Received a FIN from peer, notify rx buffer
|
||||
void DoPeerClose (void); // FIN is in sequence, notify app and respond with a FIN
|
||||
void CancelAllTimers (void); // Cancel all timer when endpoint is deleted
|
||||
|
||||
// State transition functions
|
||||
void ProcessEstablished (Ptr<Packet>, const TcpHeader&); // Received a packet upon ESTABLISHED state
|
||||
void ProcessListen (Ptr<Packet>, const TcpHeader&, const Address&, const Address&); // Process the newly received ACK
|
||||
void ProcessSynSent (Ptr<Packet>, const TcpHeader&); // Received a packet upon SYN_SENT
|
||||
void ProcessSynRcvd (Ptr<Packet>, const TcpHeader&, const Address&, const Address&); // Received a packet upon SYN_RCVD
|
||||
void ProcessWait (Ptr<Packet>, const TcpHeader&); // Received a packet upon CLOSE_WAIT, FIN_WAIT_1, FIN_WAIT_2
|
||||
void ProcessClosing (Ptr<Packet>, const TcpHeader&); // Received a packet upon CLOSING
|
||||
void ProcessLastAck (Ptr<Packet>, const TcpHeader&); // Received a packet upon LAST_ACK
|
||||
|
||||
// Window management
|
||||
virtual uint32_t UnAckDataCount (void); // Return count of number of unacked bytes
|
||||
virtual uint32_t BytesInFlight (void); // Return total bytes in flight
|
||||
virtual uint32_t Window (void); // Return the max possible number of unacked bytes
|
||||
virtual uint32_t AvailableWindow (void); // Return unfilled portion of window
|
||||
virtual uint16_t AdvertisedWindowSize (void); // The amount of Rx window announced to the peer
|
||||
|
||||
// Manage data tx/rx
|
||||
virtual Ptr<TcpSocketBase> Fork (void) = 0; // Call CopyObject<> to clone me
|
||||
virtual void ReceivedAck (Ptr<Packet>, const TcpHeader&); // Received an ACK packet
|
||||
virtual void ReceivedData (Ptr<Packet>, const TcpHeader&); // Recv of a data, put into buffer, call L7 to get it if necessary
|
||||
virtual void EstimateRtt (const TcpHeader&); // RTT accounting
|
||||
virtual void NewAck (SequenceNumber32 const& seq); // Update buffers w.r.t. ACK
|
||||
virtual void DupAck (const TcpHeader& t, uint32_t count) = 0; // Received dupack
|
||||
virtual void ReTxTimeout (void); // Call Retransmit() upon RTO event
|
||||
virtual void Retransmit (void); // Halving cwnd and call DoRetransmit()
|
||||
virtual void DelAckTimeout (void); // Action upon delay ACK timeout, i.e. send an ACK
|
||||
virtual void LastAckTimeout (void); // Timeout at LAST_ACK, close the connection
|
||||
virtual void PersistTimeout (void); // Send 1 byte probe to get an updated window size
|
||||
virtual void DoRetransmit (void); // Retransmit the oldest packet
|
||||
|
||||
protected:
|
||||
// Counters and events
|
||||
EventId m_retxEvent; //< Retransmission event
|
||||
EventId m_lastAckEvent; //< Last ACK timeout event
|
||||
EventId m_delAckEvent; //< Delayed ACK timeout event
|
||||
EventId m_persistEvent; //< Persist event: Send 1 byte to probe for a non-zero Rx window
|
||||
uint32_t m_dupAckCount; //< Dupack counter
|
||||
uint32_t m_delAckCount; //< Delayed ACK counter
|
||||
uint32_t m_delAckMaxCount; //< Number of packet to fire an ACK before delay timeout
|
||||
uint32_t m_cnCount; //< Count of remaining connection retries
|
||||
TracedValue<Time> m_rto; //< Retransmit timeout
|
||||
TracedValue<Time> m_lastRtt; //< Last RTT sample collected
|
||||
Time m_delAckTimeout; //< Time to delay an ACK
|
||||
Time m_persistTimeout; //< Time between sending 1-byte probes
|
||||
Time m_cnTimeout; //< Timeout for connection retry
|
||||
|
||||
// Connections to other layers of TCP/IP
|
||||
Ipv4EndPoint* m_endPoint;
|
||||
Ptr<Node> m_node;
|
||||
Ptr<TcpL4Protocol> m_tcp;
|
||||
|
||||
// Round trip time estimation
|
||||
Ptr<RttEstimator> m_rtt;
|
||||
|
||||
// Rx and Tx buffer management
|
||||
TracedValue<SequenceNumber32> m_nextTxSequence; //< Next seqnum to be sent (SND.NXT), ReTx pushes it back
|
||||
TracedValue<SequenceNumber32> m_highTxMark; //< Highest seqno ever sent, regardless of ReTx
|
||||
TcpRxBuffer m_rxBuffer; //< Rx buffer (reordering buffer)
|
||||
TcpTxBuffer m_txBuffer; //< Tx buffer
|
||||
|
||||
// State-related attributes
|
||||
TracedValue<TcpStates_t> m_state; //< TCP state
|
||||
enum SocketErrno m_errno; //< Socket error code
|
||||
bool m_closeNotified; //< Told app to close socket
|
||||
bool m_closeOnEmpty; //< Close socket upon tx buffer emptied
|
||||
bool m_shutdownSend; //< Send no longer allowed
|
||||
bool m_shutdownRecv; //< Receive no longer allowed
|
||||
bool m_connected; //< Connection established
|
||||
|
||||
// Window management
|
||||
uint32_t m_segmentSize; //< Segment size
|
||||
TracedValue<uint32_t> m_rWnd; //< Flow control window at remote side
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* TCP_SOCKET_BASE_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,254 +0,0 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 Georgia Tech Research Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Raj Bhattacharjea <raj.b@gatech.edu>
|
||||
*/
|
||||
#ifndef TCP_SOCKET_IMPL_H
|
||||
#define TCP_SOCKET_IMPL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <queue>
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/traced-value.h"
|
||||
#include "ns3/tcp-socket.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/ipv4-address.h"
|
||||
#include "ns3/event-id.h"
|
||||
#include "ns3/ipv4-header.h"
|
||||
#include "ipv4-interface.h"
|
||||
#include "tcp-typedefs.h"
|
||||
#include "pending-data.h"
|
||||
#include "ns3/sequence-number.h"
|
||||
#include "rtt-estimator.h"
|
||||
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Ipv4EndPoint;
|
||||
class Node;
|
||||
class Packet;
|
||||
class TcpL4Protocol;
|
||||
class TcpHeader;
|
||||
|
||||
/**
|
||||
* \ingroup socket
|
||||
* \ingroup tcp
|
||||
*
|
||||
* \brief An implementation of a stream socket using TCP.
|
||||
*
|
||||
* This class contains an implementation of TCP Tahoe, as well as a sockets
|
||||
* interface for talking to TCP. Features include connection orientation,
|
||||
* reliability through cumulative acknowledgements, congestion and flow
|
||||
* control. Finite send buffer semantics are modeled, but as of yet, finite
|
||||
* receive buffer modelling is unimplemented.
|
||||
*
|
||||
* The closedown of these sockets is as of yet not compliant with the relevant
|
||||
* RFCs, i.e. the FIN handshaking isn't correct. While this is visible at the
|
||||
* PCAP tracing level, it has no effect on the statistics users are interested
|
||||
* in, i.e. throughput, delay, etc. of actual payload data.
|
||||
*
|
||||
* Asynchronous callbacks to provide notifications to higher layers that a
|
||||
* protocol event has occured, such as space freeing up in the send buffer
|
||||
* or new data arriving in the receive buffer.
|
||||
*/
|
||||
class TcpSocketImpl : public TcpSocket
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
/**
|
||||
* Create an unbound tcp socket.
|
||||
*/
|
||||
TcpSocketImpl ();
|
||||
TcpSocketImpl (const TcpSocketImpl& sock);
|
||||
virtual ~TcpSocketImpl ();
|
||||
|
||||
void SetNode (Ptr<Node> node);
|
||||
void SetTcp (Ptr<TcpL4Protocol> tcp);
|
||||
void SetRtt (Ptr<RttEstimator> rtt);
|
||||
|
||||
virtual enum SocketErrno GetErrno (void) const;
|
||||
virtual enum SocketType GetSocketType (void) const;
|
||||
virtual Ptr<Node> GetNode (void) const;
|
||||
virtual int Bind (void);
|
||||
virtual int Bind (const Address &address);
|
||||
virtual int Close (void);
|
||||
virtual int ShutdownSend (void);
|
||||
virtual int ShutdownRecv (void);
|
||||
virtual int Connect(const Address &address);
|
||||
virtual int Listen(void);
|
||||
virtual uint32_t GetTxAvailable (void) const;
|
||||
virtual int Send (Ptr<Packet> p, uint32_t flags);
|
||||
virtual int SendTo(Ptr<Packet> p, uint32_t flags, const Address &toAddress);
|
||||
virtual uint32_t GetRxAvailable (void) const;
|
||||
virtual Ptr<Packet> Recv (uint32_t maxSize, uint32_t flags);
|
||||
virtual Ptr<Packet> RecvFrom (uint32_t maxSize, uint32_t flags,
|
||||
Address &fromAddress);
|
||||
virtual int GetSockName (Address &address) const;
|
||||
virtual void BindToNetDevice (Ptr<NetDevice> netdevice);
|
||||
virtual bool SetAllowBroadcast (bool allowBroadcast);
|
||||
virtual bool GetAllowBroadcast () const;
|
||||
|
||||
private:
|
||||
friend class Tcp;
|
||||
// invoked by Tcp class
|
||||
int FinishBind (void);
|
||||
void ForwardUp (Ptr<Packet> p, Ipv4Header header, uint16_t port,
|
||||
Ptr<Ipv4Interface> incomingInterface);
|
||||
void Destroy (void);
|
||||
int DoSendTo (Ptr<Packet> p, const Address &daddr);
|
||||
int DoSendTo (Ptr<Packet> p, Ipv4Address daddr, uint16_t dport);
|
||||
void SendEmptyPacket(uint8_t flags);
|
||||
void SendRST();
|
||||
|
||||
//methods for state
|
||||
bool ProcessAction (Actions_t a);
|
||||
bool ProcessAction (Actions_t a, const TcpHeader& tcpHeader,
|
||||
Ipv4Address saddr, Ipv4Address daddr);
|
||||
bool ProcessPacketAction (Actions_t a, Ptr<Packet> p,
|
||||
const TcpHeader& tcpHeader,
|
||||
const Address& fromAddress,
|
||||
const Address& toAddress);
|
||||
Actions_t ProcessEvent (Events_t e);
|
||||
bool SendPendingData(bool withAck = false);
|
||||
void CompleteFork(Ptr<Packet>, const TcpHeader&, const Address& fromAddress, const Address& toAddress);
|
||||
void ConnectionSucceeded();
|
||||
|
||||
//methods for window management
|
||||
virtual uint32_t UnAckDataCount(); // Return count of number of unacked bytes
|
||||
virtual uint32_t BytesInFlight(); // Return total bytes in flight
|
||||
virtual uint32_t Window(); // Return window size (integer)
|
||||
virtual uint32_t AvailableWindow();// Return unfilled portion of window
|
||||
|
||||
//methods for Rx buffer management
|
||||
uint32_t RxBufferFreeSpace();
|
||||
uint16_t AdvertisedWindowSize();
|
||||
|
||||
// Manage data tx/rx
|
||||
void NewRx (Ptr<Packet>, const TcpHeader&, const Address& fromAddress, const Address& toAddress);
|
||||
void RxBufFinishInsert (SequenceNumber32);
|
||||
Ptr<TcpSocketImpl> Copy ();
|
||||
virtual void NewAck (SequenceNumber32 seq);
|
||||
virtual void DupAck (const TcpHeader& t, uint32_t count);
|
||||
virtual void ReTxTimeout ();
|
||||
void DelAckTimeout ();
|
||||
void LastAckTimeout ();
|
||||
void PersistTimeout ();
|
||||
void Retransmit ();
|
||||
void CommonNewAck (SequenceNumber32 seq, bool skipTimer = false);
|
||||
// All timers are cancelled when the endpoint is deleted, to insure
|
||||
// we don't have additional activity
|
||||
void CancelAllTimers();
|
||||
// attribute related
|
||||
virtual void SetSndBufSize (uint32_t size);
|
||||
virtual uint32_t GetSndBufSize (void) const;
|
||||
virtual void SetRcvBufSize (uint32_t size);
|
||||
virtual uint32_t GetRcvBufSize (void) const;
|
||||
virtual void SetSegSize (uint32_t size);
|
||||
virtual uint32_t GetSegSize (void) const;
|
||||
virtual void SetSSThresh (uint32_t threshold);
|
||||
virtual uint32_t GetSSThresh (void) const;
|
||||
virtual void SetInitialCwnd (uint32_t cwnd);
|
||||
virtual uint32_t GetInitialCwnd (void) const;
|
||||
virtual void SetConnTimeout (Time timeout);
|
||||
virtual Time GetConnTimeout (void) const;
|
||||
virtual void SetConnCount (uint32_t count);
|
||||
virtual uint32_t GetConnCount (void) const;
|
||||
virtual void SetDelAckTimeout (Time timeout);
|
||||
virtual Time GetDelAckTimeout (void) const;
|
||||
virtual void SetDelAckMaxCount (uint32_t count);
|
||||
virtual uint32_t GetDelAckMaxCount (void) const;
|
||||
|
||||
bool m_skipRetxResched;
|
||||
uint32_t m_dupAckCount;
|
||||
EventId m_retxEvent;
|
||||
EventId m_lastAckEvent;
|
||||
|
||||
EventId m_delAckEvent;
|
||||
uint32_t m_delAckCount;
|
||||
uint32_t m_delAckMaxCount;
|
||||
Time m_delAckTimeout;
|
||||
|
||||
Ipv4EndPoint *m_endPoint;
|
||||
Ptr<Node> m_node;
|
||||
Ptr<TcpL4Protocol> m_tcp;
|
||||
|
||||
enum SocketErrno m_errno;
|
||||
bool m_shutdownSend;
|
||||
bool m_shutdownRecv;
|
||||
bool m_connected;
|
||||
|
||||
//manage the state information
|
||||
States_t m_state;
|
||||
bool m_closeNotified;
|
||||
bool m_closeRequestNotified;
|
||||
bool m_closeOnEmpty;
|
||||
bool m_pendingClose;
|
||||
|
||||
|
||||
//sequence info, sender side
|
||||
SequenceNumber32 m_nextTxSequence;
|
||||
SequenceNumber32 m_highTxMark;
|
||||
SequenceNumber32 m_highestRxAck;
|
||||
SequenceNumber32 m_lastRxAck;
|
||||
|
||||
//sequence info, receiver side
|
||||
SequenceNumber32 m_nextRxSequence; //next expected sequence
|
||||
|
||||
//sequence number where fin was sent or received
|
||||
SequenceNumber32 m_finSequence;
|
||||
|
||||
//Rx buffer
|
||||
UnAckData_t m_bufferedData; //buffer which sorts out of sequence data
|
||||
//Rx buffer state
|
||||
uint32_t m_rxAvailable; // amount of data available for reading through Recv
|
||||
uint32_t m_rxBufSize; //size in bytes of the data in the rx buf
|
||||
//note that these two are not the same: rxAvailbale is the number of
|
||||
//contiguous sequenced bytes that can be read, rxBufSize is the TOTAL size
|
||||
//including out of sequence data, such that m_rxAvailable <= m_rxBufSize
|
||||
|
||||
//this is kind of the tx buffer
|
||||
PendingData* m_pendingData;
|
||||
SequenceNumber32 m_firstPendingSequence;
|
||||
|
||||
// Window management
|
||||
uint32_t m_segmentSize; //SegmentSize
|
||||
uint32_t m_rxWindowSize; //Flow control window
|
||||
TracedValue<uint32_t> m_cWnd; //Congestion window
|
||||
uint32_t m_ssThresh; //Slow Start Threshold
|
||||
uint32_t m_initialCWnd; //Initial cWnd value
|
||||
|
||||
//persist timer management
|
||||
Time m_persistTime;
|
||||
EventId m_persistEvent;
|
||||
|
||||
|
||||
// Round trip time estimation
|
||||
Ptr<RttEstimator> m_rtt;
|
||||
Time m_lastMeasuredRtt;
|
||||
|
||||
// Timer-related members
|
||||
Time m_cnTimeout;
|
||||
uint32_t m_cnCount;
|
||||
|
||||
// Attributes
|
||||
uint32_t m_sndBufSize; // buffer limit for the outgoing queue
|
||||
uint32_t m_rxBufMaxSize; // maximum receive socket buffer size
|
||||
};
|
||||
|
||||
}//namespace ns3
|
||||
|
||||
#endif /* TCP_SOCKET_IMPL_H */
|
||||
190
src/internet-stack/tcp-tahoe.cc
Normal file
190
src/internet-stack/tcp-tahoe.cc
Normal file
@@ -0,0 +1,190 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 Adrian Sai-wah Tam
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
|
||||
*/
|
||||
|
||||
#define NS_LOG_APPEND_CONTEXT \
|
||||
if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_node->GetId () << "] "; }
|
||||
|
||||
#include "tcp-tahoe.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/node.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpTahoe");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (TcpTahoe);
|
||||
|
||||
TypeId
|
||||
TcpTahoe::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::TcpTahoe")
|
||||
.SetParent<TcpSocketBase> ()
|
||||
.AddConstructor<TcpTahoe> ()
|
||||
.AddTraceSource ("CongestionWindow",
|
||||
"The TCP connection's congestion window",
|
||||
MakeTraceSourceAccessor (&TcpTahoe::m_cWnd))
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
TcpTahoe::TcpTahoe (void) : m_initialCWnd (0)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
}
|
||||
|
||||
TcpTahoe::TcpTahoe (const TcpTahoe& sock)
|
||||
: TcpSocketBase (sock),
|
||||
m_cWnd (sock.m_cWnd),
|
||||
m_ssThresh (sock.m_ssThresh),
|
||||
m_initialCWnd (sock.m_initialCWnd)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC ("Invoked the copy constructor");
|
||||
}
|
||||
|
||||
TcpTahoe::~TcpTahoe (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
TcpTahoe::SetNode (Ptr<Node> node)
|
||||
{
|
||||
TcpSocketBase::SetNode (node);
|
||||
/*
|
||||
* Initialize congestion window, default to 1 MSS (RFC2001, sec.1) and must
|
||||
* not be larger than 2 MSS (RFC2581, sec.3.1). Both m_initiaCWnd and
|
||||
* m_segmentSize are set by the attribute system in ns3::TcpSocket.
|
||||
*/
|
||||
m_cWnd = m_initialCWnd * m_segmentSize;
|
||||
}
|
||||
|
||||
/** Limit the size of in-flight data by cwnd and receiver's rxwin */
|
||||
uint32_t
|
||||
TcpTahoe::Window (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
return std::min (m_rWnd.Get (), m_cWnd.Get ());
|
||||
}
|
||||
|
||||
Ptr<TcpSocketBase>
|
||||
TcpTahoe::Fork (void)
|
||||
{
|
||||
return CopyObject<TcpTahoe> (this);
|
||||
}
|
||||
|
||||
/** New ACK (up to seqnum seq) received. Increase cwnd and call TcpSocketBase::NewAck() */
|
||||
void
|
||||
TcpTahoe::NewAck (SequenceNumber32 const& seq)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << seq);
|
||||
NS_LOG_LOGIC ("TcpTahoe receieved ACK for seq " << seq <<
|
||||
" cwnd " << m_cWnd <<
|
||||
" ssthresh " << m_ssThresh);
|
||||
if (m_cWnd < m_ssThresh)
|
||||
{ // Slow start mode, add one segSize to cWnd. Default m_ssThresh is 65535. (RFC2001, sec.1)
|
||||
m_cWnd += m_segmentSize;
|
||||
NS_LOG_INFO ("In SlowStart, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
|
||||
}
|
||||
else
|
||||
{ // Congestion avoidance mode, increase by (segSize*segSize)/cwnd. (RFC2581, sec.3.1)
|
||||
// To increase cwnd for one segSize per RTT, it should be (ackBytes*segSize)/cwnd
|
||||
double adder = static_cast<double> (m_segmentSize * m_segmentSize) / m_cWnd.Get ();
|
||||
adder = std::max (1.0, adder);
|
||||
m_cWnd += static_cast<uint32_t> (adder);
|
||||
NS_LOG_INFO ("In CongAvoid, updated to cwnd " << m_cWnd << " ssthresh " << m_ssThresh);
|
||||
}
|
||||
TcpSocketBase::NewAck (seq); // Complete newAck processing
|
||||
}
|
||||
|
||||
/** Cut down ssthresh upon triple dupack */
|
||||
void
|
||||
TcpTahoe::DupAck (const TcpHeader& t, uint32_t count)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << "t " << count);
|
||||
if (count == 3)
|
||||
{ // triple duplicate ack triggers fast retransmit (RFC2001, sec.3)
|
||||
NS_LOG_INFO ("Triple Dup Ack: old ssthresh " << m_ssThresh << " cwnd " << m_cWnd);
|
||||
// fast retransmit in Tahoe means triggering RTO earlier. Tx is restarted
|
||||
// from the highest ack and run slow start again.
|
||||
// (Fall & Floyd 1996, sec.1)
|
||||
m_ssThresh = std::max (static_cast<unsigned> (m_cWnd / 2), m_segmentSize * 2); // Half ssthresh
|
||||
m_cWnd = m_segmentSize; // Run slow start again
|
||||
m_nextTxSequence = m_txBuffer.HeadSequence (); // Restart from highest Ack
|
||||
NS_LOG_INFO ("Triple Dup Ack: new ssthresh " << m_ssThresh << " cwnd " << m_cWnd);
|
||||
NS_LOG_LOGIC ("Triple Dup Ack: retransmit missing segment at " << Simulator::Now ().GetSeconds ());
|
||||
DoRetransmit ();
|
||||
}
|
||||
}
|
||||
|
||||
/** Retransmit timeout */
|
||||
void TcpTahoe::Retransmit (void)
|
||||
{
|
||||
NS_LOG_FUNCTION (this);
|
||||
NS_LOG_LOGIC (this << " ReTxTimeout Expired at time " << Simulator::Now ().GetSeconds ());
|
||||
// If erroneous timeout in closed/timed-wait state, just return
|
||||
if (m_state == CLOSED || m_state == TIME_WAIT) return;
|
||||
// If all data are received, just return
|
||||
if (m_txBuffer.HeadSequence () >= m_nextTxSequence) return;
|
||||
|
||||
m_ssThresh = std::max (static_cast<unsigned> (m_cWnd / 2), m_segmentSize * 2); // Half ssthresh
|
||||
m_cWnd = m_segmentSize; // Set cwnd to 1 segSize (RFC2001, sec.2)
|
||||
m_nextTxSequence = m_txBuffer.HeadSequence (); // Restart from highest Ack
|
||||
m_rtt->IncreaseMultiplier (); // Double the next RTO
|
||||
DoRetransmit (); // Retransmit the packet
|
||||
}
|
||||
|
||||
void
|
||||
TcpTahoe::SetSegSize (uint32_t size)
|
||||
{
|
||||
NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpTahoe::SetSegSize() cannot change segment size after connection started.");
|
||||
m_segmentSize = size;
|
||||
m_cWnd = m_initialCWnd * m_segmentSize;
|
||||
}
|
||||
|
||||
void
|
||||
TcpTahoe::SetSSThresh (uint32_t threshold)
|
||||
{
|
||||
m_ssThresh = threshold;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpTahoe::GetSSThresh (void) const
|
||||
{
|
||||
return m_ssThresh;
|
||||
}
|
||||
|
||||
void
|
||||
TcpTahoe::SetInitialCwnd (uint32_t cwnd)
|
||||
{
|
||||
NS_ABORT_MSG_UNLESS (m_state == CLOSED, "TcpTahoe::SetInitialCwnd() cannot change initial cwnd after connection started.");
|
||||
m_initialCWnd = cwnd;
|
||||
m_cWnd = m_initialCWnd * m_segmentSize;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpTahoe::GetInitialCwnd (void) const
|
||||
{
|
||||
return m_initialCWnd;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
78
src/internet-stack/tcp-tahoe.h
Normal file
78
src/internet-stack/tcp-tahoe.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 Adrian Sai-wah Tam
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef TCP_TAHOE_H
|
||||
#define TCP_TAHOE_H
|
||||
|
||||
#include "tcp-socket-base.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \ingroup socket
|
||||
* \ingroup tcp
|
||||
*
|
||||
* \brief An implementation of a stream socket using TCP.
|
||||
*
|
||||
* This class contains the Tahoe implementation of TCP. Tahoe is not officially
|
||||
* published in RFC. The reference for implementing this is based on
|
||||
* Kevin Fall and Sally Floyd, "Simulation-based Comparisons of Tahoe, Reno, and SACK TCP", CCR, 1996
|
||||
* http://inst.eecs.berkeley.edu/~ee122/fa05/projects/Project2/proj2_spec_files/sacks.pdf
|
||||
* In summary, we have slow start, congestion avoidance, and fast retransmit.
|
||||
* The implementation of these algorithms are based on W. R. Stevens's book and
|
||||
* also RFC2001.
|
||||
*/
|
||||
class TcpTahoe : public TcpSocketBase
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
/**
|
||||
* Create an unbound tcp socket.
|
||||
*/
|
||||
TcpTahoe (void);
|
||||
TcpTahoe (const TcpTahoe& sock);
|
||||
virtual ~TcpTahoe (void);
|
||||
|
||||
// Set associated Node, TcpL4Protocol, RttEstimator to this socket
|
||||
virtual void SetNode (Ptr<Node> node);
|
||||
|
||||
protected:
|
||||
virtual uint32_t Window (void); // Return the max possible number of unacked bytes
|
||||
virtual Ptr<TcpSocketBase> Fork (void); // Call CopyObject<TcpTahoe> to clone me
|
||||
virtual void NewAck (SequenceNumber32 const& seq); // Inc cwnd and call NewAck() of parent
|
||||
virtual void DupAck (const TcpHeader& t, uint32_t count); // Treat 3 dupack as timeout
|
||||
virtual void Retransmit (void); // Retransmit time out
|
||||
|
||||
// Implementing ns3::TcpSocket -- Attribute get/set
|
||||
virtual void SetSegSize (uint32_t size);
|
||||
virtual void SetSSThresh (uint32_t threshold);
|
||||
virtual uint32_t GetSSThresh (void) const;
|
||||
virtual void SetInitialCwnd (uint32_t cwnd);
|
||||
virtual uint32_t GetInitialCwnd (void) const;
|
||||
|
||||
protected:
|
||||
TracedValue<uint32_t> m_cWnd; //< Congestion window
|
||||
uint32_t m_ssThresh; //< Slow Start Threshold
|
||||
uint32_t m_initialCWnd; //< Initial cWnd value
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* TCP_TAHOE_H */
|
||||
250
src/internet-stack/tcp-tx-buffer.cc
Normal file
250
src/internet-stack/tcp-tx-buffer.cc
Normal file
@@ -0,0 +1,250 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 Adrian Sai-wah Tam
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/fatal-error.h"
|
||||
#include "ns3/log.h"
|
||||
#include "tcp-tx-buffer.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TcpTxBuffer");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
TypeId
|
||||
TcpTxBuffer::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::TcpTxBuffer")
|
||||
.SetParent<Object> ()
|
||||
.AddConstructor<TcpTxBuffer> ()
|
||||
.AddTraceSource ("UnackSequence",
|
||||
"First unacknowledged sequence number (SND.UNA)",
|
||||
MakeTraceSourceAccessor (&TcpTxBuffer::m_firstByteSeq))
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
/* A user is supposed to create a TcpSocket through a factory. In TcpSocket,
|
||||
* there are attributes SndBufSize and RcvBufSize to control the default Tx and
|
||||
* Rx window sizes respectively, with default of 128 KiByte. The attribute
|
||||
* SndBufSize is passed to TcpTxBuffer by TcpSocketBase::SetSndBufSize() and in
|
||||
* turn, TcpTxBuffer:SetMaxBufferSize(). Therefore, the m_maxBuffer value
|
||||
* initialized below is insignificant.
|
||||
*/
|
||||
TcpTxBuffer::TcpTxBuffer (uint32_t n)
|
||||
: m_firstByteSeq(n), m_size (0), m_maxBuffer(32768), m_data (0)
|
||||
{
|
||||
}
|
||||
|
||||
TcpTxBuffer::~TcpTxBuffer (void)
|
||||
{
|
||||
}
|
||||
|
||||
SequenceNumber32
|
||||
TcpTxBuffer::HeadSequence (void) const
|
||||
{
|
||||
return m_firstByteSeq;
|
||||
}
|
||||
|
||||
SequenceNumber32
|
||||
TcpTxBuffer::TailSequence (void) const
|
||||
{
|
||||
return m_firstByteSeq + SequenceNumber32 (m_size);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpTxBuffer::Size (void) const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpTxBuffer::MaxBufferSize (void) const
|
||||
{
|
||||
return m_maxBuffer;
|
||||
}
|
||||
|
||||
void
|
||||
TcpTxBuffer::SetMaxBufferSize (uint32_t n)
|
||||
{
|
||||
m_maxBuffer = n;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpTxBuffer::Available (void) const
|
||||
{
|
||||
return m_maxBuffer - m_size;
|
||||
}
|
||||
|
||||
bool
|
||||
TcpTxBuffer::Add (Ptr<Packet> p)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << p);
|
||||
NS_LOG_LOGIC ("Packet of size " << p->GetSize () << " appending to window starting at "
|
||||
<< m_firstByteSeq << ", availSize="<< Available ());
|
||||
if (p->GetSize () <= Available ())
|
||||
{
|
||||
if (p->GetSize () > 0)
|
||||
{
|
||||
m_data.push_back (p);
|
||||
m_size += p->GetSize ();
|
||||
NS_LOG_LOGIC ("Updated size=" << m_size << ", lastSeq=" << m_firstByteSeq + SequenceNumber32 (m_size));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
NS_LOG_LOGIC ("Rejected. Not enough room to buffer packet.");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TcpTxBuffer::SizeFromSequence (const SequenceNumber32& seq) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this << seq);
|
||||
// Sequence of last byte in buffer
|
||||
SequenceNumber32 lastSeq = m_firstByteSeq + SequenceNumber32 (m_size);
|
||||
// Non-negative size
|
||||
NS_LOG_LOGIC ("HeadSeq=" << m_firstByteSeq << ", lastSeq=" << lastSeq << ", size=" << m_size <<
|
||||
", returns " << lastSeq - seq);
|
||||
return lastSeq - seq;
|
||||
}
|
||||
|
||||
Ptr<Packet>
|
||||
TcpTxBuffer::CopyFromSequence (uint32_t numBytes, const SequenceNumber32& seq)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << numBytes << seq);
|
||||
uint32_t s = std::min (numBytes, SizeFromSequence (seq)); // Real size to extract. Insure not beyond end of data
|
||||
if (s == 0)
|
||||
{
|
||||
return Create<Packet> (); // Empty packet returned
|
||||
}
|
||||
if (m_data.size () == 0)
|
||||
{ // No actual data, just return dummy-data packet of correct size
|
||||
return Create<Packet> (s);
|
||||
}
|
||||
|
||||
// Extract data from the buffer and return
|
||||
uint32_t offset = seq - m_firstByteSeq.Get ();
|
||||
uint32_t count = 0; // Offset of the first byte of a packet in the buffer
|
||||
uint32_t pktSize = 0;
|
||||
bool beginFound = false;
|
||||
int pktCount = 0;
|
||||
Ptr<Packet> outPacket;
|
||||
NS_LOG_LOGIC ("There are " << m_data.size () << " number of packets in buffer");
|
||||
for (BufIterator i = m_data.begin (); i != m_data.end (); ++i)
|
||||
{
|
||||
pktCount++;
|
||||
pktSize = (*i)->GetSize ();
|
||||
if (!beginFound)
|
||||
{ // Look for first fragment
|
||||
if (count + pktSize > offset)
|
||||
{
|
||||
NS_LOG_LOGIC ("First byte found in packet #" << pktCount << " at buffer offset " << count
|
||||
<< ", packet len=" << pktSize);
|
||||
beginFound = true;
|
||||
uint32_t packetOffset = offset - count;
|
||||
uint32_t fragmentLength = count + pktSize - offset;
|
||||
if (fragmentLength >= s)
|
||||
{ // Data to be copied falls entirely in this packet
|
||||
return (*i)->CreateFragment (packetOffset, s);
|
||||
}
|
||||
else
|
||||
{ // This packet only fulfills part of the request
|
||||
outPacket = (*i)->CreateFragment (packetOffset, fragmentLength);
|
||||
}
|
||||
NS_LOG_LOGIC ("Output packet is now of size " << outPacket->GetSize ());
|
||||
}
|
||||
}
|
||||
else if (count + pktSize >= offset + s)
|
||||
{ // Last packet fragment found
|
||||
NS_LOG_LOGIC ("Last byte found in packet #" << pktCount << " at buffer offset " << count
|
||||
<< ", packet len=" << pktSize);
|
||||
uint32_t fragmentLength = offset + s - count;
|
||||
Ptr<Packet> endFragment = (*i)->CreateFragment (0, fragmentLength);
|
||||
outPacket->AddAtEnd (endFragment);
|
||||
NS_LOG_LOGIC ("Output packet is now of size " << outPacket->GetSize ());
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_LOGIC ("Appending to output the packet #" << pktCount << " of offset " << count << " len=" << pktSize);
|
||||
outPacket->AddAtEnd (*i);
|
||||
NS_LOG_LOGIC ("Output packet is now of size " << outPacket->GetSize ());
|
||||
}
|
||||
count += pktSize;
|
||||
}
|
||||
NS_ASSERT (outPacket->GetSize () == s);
|
||||
return outPacket;
|
||||
}
|
||||
|
||||
void
|
||||
TcpTxBuffer::SetHeadSequence (const SequenceNumber32& seq)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << seq);
|
||||
m_firstByteSeq = seq;
|
||||
}
|
||||
|
||||
void
|
||||
TcpTxBuffer::DiscardUpTo (const SequenceNumber32& seq)
|
||||
{
|
||||
NS_LOG_FUNCTION (this << seq);
|
||||
NS_LOG_LOGIC ("current data size=" << m_size << ", headSeq=" << m_firstByteSeq << ", maxBuffer=" << m_maxBuffer
|
||||
<< ", numPkts=" << m_data.size ());
|
||||
// Cases do not need to scan the buffer
|
||||
if (m_firstByteSeq >= seq) return;
|
||||
|
||||
// Scan the buffer and discard packets
|
||||
uint32_t offset = seq - m_firstByteSeq.Get (); // Number of bytes to remove
|
||||
uint32_t pktSize;
|
||||
NS_LOG_LOGIC ("Offset=" << offset);
|
||||
BufIterator i = m_data.begin ();
|
||||
while (i != m_data.end ())
|
||||
{
|
||||
if (offset > (*i)->GetSize ())
|
||||
{ // This packet is behind the seqnum. Remove this packet from the buffer
|
||||
pktSize = (*i)->GetSize ();
|
||||
m_size -= pktSize;
|
||||
offset -= pktSize;
|
||||
m_firstByteSeq += pktSize;
|
||||
i = m_data.erase (i);
|
||||
NS_LOG_LOGIC ("Removed one packet of size " << pktSize << ", offset=" << offset);
|
||||
}
|
||||
else if (offset > 0)
|
||||
{ // Part of the packet is behind the seqnum. Fragment
|
||||
pktSize = (*i)->GetSize () - offset;
|
||||
*i = (*i)->CreateFragment (offset, pktSize);
|
||||
m_size -= offset;
|
||||
m_firstByteSeq += offset;
|
||||
NS_LOG_LOGIC ("Fragmented one packet by size " << offset << ", new size=" << pktSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Catching the case of ACKing a FIN
|
||||
if (m_size == 0)
|
||||
{
|
||||
m_firstByteSeq = seq;
|
||||
}
|
||||
NS_LOG_LOGIC ("size=" << m_size << " headSeq=" << m_firstByteSeq << " maxBuffer=" << m_maxBuffer
|
||||
<<" numPkts="<< m_data.size ());
|
||||
NS_ASSERT (m_firstByteSeq == seq);
|
||||
}
|
||||
|
||||
} // namepsace ns3
|
||||
121
src/internet-stack/tcp-tx-buffer.h
Normal file
121
src/internet-stack/tcp-tx-buffer.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 Adrian Sai-wah Tam
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __TCP_TX_BUFFER_H__
|
||||
#define __TCP_TX_BUFFER_H__
|
||||
|
||||
#include <list>
|
||||
#include "ns3/traced-value.h"
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/sequence-number.h"
|
||||
#include "ns3/ptr.h"
|
||||
|
||||
namespace ns3 {
|
||||
class Packet;
|
||||
|
||||
/**
|
||||
* \ingroup tcp
|
||||
*
|
||||
* \brief class for keeping the data sent by the application to the TCP socket, i.e.
|
||||
* the sending buffer.
|
||||
*/
|
||||
class TcpTxBuffer : public Object
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
TcpTxBuffer (uint32_t n = 0);
|
||||
virtual ~TcpTxBuffer (void);
|
||||
|
||||
// Accessors
|
||||
|
||||
/**
|
||||
* Returns the first byte's sequence number
|
||||
*/
|
||||
SequenceNumber32 HeadSequence (void) const;
|
||||
|
||||
/**
|
||||
* Returns the last byte's sequence number + 1
|
||||
*/
|
||||
SequenceNumber32 TailSequence (void) const;
|
||||
|
||||
/**
|
||||
* Returns total number of bytes in this Tx buffer
|
||||
*/
|
||||
uint32_t Size (void) const;
|
||||
|
||||
/**
|
||||
* Returns the Tx window size
|
||||
*/
|
||||
uint32_t MaxBufferSize (void) const;
|
||||
|
||||
/**
|
||||
* Set the Tx window size
|
||||
*/
|
||||
void SetMaxBufferSize (uint32_t n);
|
||||
|
||||
/**
|
||||
* Returns the available capacity in this Tx window
|
||||
*/
|
||||
uint32_t Available (void) const;
|
||||
|
||||
/**
|
||||
* Append a data packet to the end of the buffer
|
||||
*
|
||||
* \param p The packet to be appended to the Tx buffer
|
||||
* \return Boolean to indicate success
|
||||
*/
|
||||
bool Add (Ptr<Packet> p);
|
||||
|
||||
/**
|
||||
* Returns the number of bytes from the buffer in the range [seq, tailSequence)
|
||||
*/
|
||||
uint32_t SizeFromSequence (const SequenceNumber32& seq) const;
|
||||
|
||||
/**
|
||||
* Copy data of size numBytes into a packet, data from the range [seq, seq+numBytes)
|
||||
*/
|
||||
Ptr<Packet> CopyFromSequence (uint32_t numBytes, const SequenceNumber32& seq);
|
||||
|
||||
/**
|
||||
* Set the m_firstByteSeq to seq. Supposed to be called only when the
|
||||
* connection is just set up and we did not send any data out yet.
|
||||
*/
|
||||
void SetHeadSequence (const SequenceNumber32& seq);
|
||||
|
||||
/**
|
||||
* Discard data up to but not including this sequence number.
|
||||
*
|
||||
* \param seq The sequence number of the head byte
|
||||
*/
|
||||
void DiscardUpTo (const SequenceNumber32& seq);
|
||||
|
||||
private:
|
||||
typedef std::list<Ptr<Packet> >::iterator BufIterator;
|
||||
|
||||
TracedValue<SequenceNumber32> m_firstByteSeq; //< Sequence number of the first byte in data (SND.UNA)
|
||||
uint32_t m_size; //< Number of data bytes
|
||||
uint32_t m_maxBuffer; //< Max number of data bytes in buffer (SND.WND)
|
||||
std::list<Ptr<Packet> > m_data; //< Corresponding data (may be null)
|
||||
};
|
||||
|
||||
} // namepsace ns3
|
||||
|
||||
#endif
|
||||
@@ -1,112 +0,0 @@
|
||||
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2007 Georgia Tech Research Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Raj Bhattacharjea <raj.b@gatech.edu>
|
||||
* typedefs for tcp state machine
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "ns3/sequence-number.h"
|
||||
|
||||
#ifndef TCP_TYPEDEFS_H
|
||||
#define TCP_TYPEDEFS_H
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
typedef enum { MAX_FLAGS = 0x40 } TCPMaxFlags_t; // Flags are 6 bits
|
||||
|
||||
typedef enum {
|
||||
CLOSED, // 0
|
||||
LISTEN, // 1
|
||||
SYN_SENT, // 2
|
||||
SYN_RCVD, // 3
|
||||
ESTABLISHED, // 4
|
||||
CLOSE_WAIT, // 5
|
||||
LAST_ACK, // 6
|
||||
FIN_WAIT_1, // 7
|
||||
FIN_WAIT_2, // 8
|
||||
CLOSING, // 9
|
||||
TIMED_WAIT, // 10
|
||||
LAST_STATE } States_t;
|
||||
|
||||
typedef enum {
|
||||
APP_LISTEN, // 0
|
||||
APP_CONNECT, // 1
|
||||
APP_SEND, // 2
|
||||
SEQ_RECV, // 3
|
||||
APP_CLOSE, // 4
|
||||
TIMEOUT, // 5
|
||||
ACK_RX, // 6
|
||||
SYN_RX, // 7
|
||||
SYN_ACK_RX, // 8
|
||||
FIN_RX, // 9
|
||||
FIN_ACK_RX, // 10
|
||||
FIN_ACKED, // 11
|
||||
RST_RX, // 12
|
||||
BAD_FLAGS, // 13
|
||||
LAST_EVENT } Events_t;
|
||||
|
||||
typedef enum {
|
||||
NO_ACT, // 0
|
||||
ACK_TX, // 1
|
||||
ACK_TX_1, // 2 - ACK response to syn
|
||||
RST_TX, // 3
|
||||
SYN_TX, // 4
|
||||
SYN_ACK_TX, // 5
|
||||
FIN_TX, // 6
|
||||
FIN_ACK_TX, // 7
|
||||
NEW_ACK, // 8
|
||||
NEW_SEQ_RX, // 9
|
||||
RETX, // 10
|
||||
TX_DATA, // 11
|
||||
PEER_CLOSE, // 12
|
||||
APP_CLOSED, // 13
|
||||
CANCEL_TM, // 14
|
||||
APP_NOTIFY, // 15 - Notify app that connection failed
|
||||
SERV_NOTIFY, // 16 - Notify server tcp that connection completed
|
||||
LAST_ACTION } Actions_t;
|
||||
|
||||
class SA // State/Action pair
|
||||
{
|
||||
public:
|
||||
SA () : state (LAST_STATE), action (LAST_ACTION) { }
|
||||
SA (States_t s, Actions_t a) : state (s), action (a) { }
|
||||
public:
|
||||
States_t state;
|
||||
Actions_t action;
|
||||
};
|
||||
typedef std::vector<SA> StateActionVec_t;
|
||||
typedef std::vector<StateActionVec_t> StateActions_t; // One per current state
|
||||
typedef std::vector<Events_t> EventVec_t; // For flag events lookup
|
||||
|
||||
//type for managing buffered out of sequence data
|
||||
typedef std::map<SequenceNumber32, Ptr<Packet> > UnAckData_t;
|
||||
|
||||
class TcpStateMachine {
|
||||
public:
|
||||
TcpStateMachine ();
|
||||
SA Lookup (States_t, Events_t);
|
||||
Events_t FlagsEvent (uint8_t); // Lookup event from flags
|
||||
|
||||
public:
|
||||
StateActions_t aT; // Action table
|
||||
EventVec_t eV; // Flags event lookup
|
||||
};
|
||||
|
||||
}//namespace ns3
|
||||
#endif //TCP_TYPEDEFS_H
|
||||
@@ -109,7 +109,6 @@ def build(bld):
|
||||
'arp-cache.cc',
|
||||
'arp-l3-protocol.cc',
|
||||
'udp-socket-impl.cc',
|
||||
'tcp-socket-impl.cc',
|
||||
'ipv4-end-point-demux.cc',
|
||||
'udp-socket-factory-impl.cc',
|
||||
'tcp-socket-factory-impl.cc',
|
||||
@@ -139,6 +138,13 @@ def build(bld):
|
||||
'icmpv6-l4-protocol.cc',
|
||||
'ipv6-test.cc',
|
||||
'ipv6-extension-header-test-suite.cc',
|
||||
'tcp-socket-base.cc',
|
||||
'tcp-rfc793.cc',
|
||||
'tcp-tahoe.cc',
|
||||
'tcp-reno.cc',
|
||||
'tcp-newreno.cc',
|
||||
'tcp-rx-buffer.cc',
|
||||
'tcp-tx-buffer.cc',
|
||||
]
|
||||
|
||||
headers = bld.new_task_gen('ns3header')
|
||||
|
||||
@@ -176,7 +176,7 @@ SimpleNetDevice::GetMulticast (Ipv4Address multicastGroup) const
|
||||
|
||||
Address SimpleNetDevice::GetMulticast (Ipv6Address addr) const
|
||||
{
|
||||
return Mac48Address::GetMulticast (addr);
|
||||
return Mac48Address::GetMulticast (addr);
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -32,6 +32,8 @@ namespace ns3 {
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (TcpSocket);
|
||||
|
||||
const char* const TcpSocket::TcpStateName[LAST_STATE] = {"CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", "ESTABLISHED", "CLOSE_WAIT", "LAST_ACK", "FIN_WAIT_1", "FIN_WAIT_2", "CLOSING", "TIME_WAIT" };
|
||||
|
||||
TypeId
|
||||
TcpSocket::GetTypeId (void)
|
||||
{
|
||||
@@ -83,7 +85,7 @@ TcpSocket::GetTypeId (void)
|
||||
"Timeout value for TCP delayed acks, in seconds",
|
||||
TimeValue (Seconds (0.2)),
|
||||
MakeTimeAccessor (&TcpSocket::GetDelAckTimeout,
|
||||
&TcpSocket::SetDelAckTimeout),
|
||||
&TcpSocket::SetDelAckTimeout),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("DelAckCount",
|
||||
"Number of packets to wait before sending a TCP ack",
|
||||
@@ -91,6 +93,12 @@ TcpSocket::GetTypeId (void)
|
||||
MakeUintegerAccessor (&TcpSocket::GetDelAckMaxCount,
|
||||
&TcpSocket::SetDelAckMaxCount),
|
||||
MakeUintegerChecker<uint32_t> ())
|
||||
.AddAttribute ("PersistTimeout",
|
||||
"Persist timeout to probe for rx window",
|
||||
TimeValue (Seconds (6)),
|
||||
MakeTimeAccessor (&TcpSocket::GetPersistTimeout,
|
||||
&TcpSocket::SetPersistTimeout),
|
||||
MakeTimeChecker ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,21 @@ namespace ns3 {
|
||||
class Node;
|
||||
class Packet;
|
||||
|
||||
/* Names of the 11 TCP states */
|
||||
typedef enum {
|
||||
CLOSED, // 0
|
||||
LISTEN, // 1
|
||||
SYN_SENT, // 2
|
||||
SYN_RCVD, // 3
|
||||
ESTABLISHED, // 4
|
||||
CLOSE_WAIT, // 5
|
||||
LAST_ACK, // 6
|
||||
FIN_WAIT_1, // 7
|
||||
FIN_WAIT_2, // 8
|
||||
CLOSING, // 9
|
||||
TIME_WAIT, // 10
|
||||
LAST_STATE } TcpStates_t;
|
||||
|
||||
/**
|
||||
* \ingroup socket
|
||||
*
|
||||
@@ -51,6 +66,9 @@ public:
|
||||
TcpSocket (void);
|
||||
virtual ~TcpSocket (void);
|
||||
|
||||
// Literal names of TCP states for use in log messages */
|
||||
static const char* const TcpStateName[LAST_STATE];
|
||||
|
||||
private:
|
||||
// Indirect the attribute setting and getting through private virtual methods
|
||||
virtual void SetSndBufSize (uint32_t size) = 0;
|
||||
@@ -71,6 +89,8 @@ private:
|
||||
virtual Time GetDelAckTimeout (void) const = 0;
|
||||
virtual void SetDelAckMaxCount (uint32_t count) = 0;
|
||||
virtual uint32_t GetDelAckMaxCount (void) const = 0;
|
||||
virtual void SetPersistTimeout (Time timeout) = 0;
|
||||
virtual Time GetPersistTimeout (void) const = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user