Classes | Public Member Functions | Public Attributes | Static Public Attributes | Protected Types | Protected Member Functions | Protected Attributes

TCP Class Reference

#include <TCP.h>

List of all members.

Classes

struct  AppConnKey
struct  SockPair

Public Member Functions

 TCP ()
virtual ~TCP ()
virtual void addSockPair (TCPConnection *conn, IPvXAddress localAddr, IPvXAddress remoteAddr, int localPort, int remotePort)
virtual void updateSockPair (TCPConnection *conn, IPvXAddress localAddr, IPvXAddress remoteAddr, int localPort, int remotePort)
virtual void addForkedConnection (TCPConnection *conn, TCPConnection *newConn, IPvXAddress localAddr, IPvXAddress remoteAddr, int localPort, int remotePort)
virtual ushort getEphemeralPort ()

Public Attributes

bool recordStatistics

Static Public Attributes

static bool testing
static bool logverbose

Protected Types

typedef std::map< AppConnKey,
TCPConnection * > 
TcpAppConnMap
typedef std::map< SockPair,
TCPConnection * > 
TcpConnMap

Protected Member Functions

virtual TCPConnectioncreateConnection (int appGateIndex, int connId)
virtual TCPConnectionfindConnForSegment (TCPSegment *tcpseg, IPvXAddress srcAddr, IPvXAddress destAddr)
virtual TCPConnectionfindConnForApp (int appGateIndex, int connId)
virtual void segmentArrivalWhileClosed (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest)
virtual void removeConnection (TCPConnection *conn)
virtual void updateDisplayString ()
virtual void initialize ()
virtual void handleMessage (cMessage *msg)
virtual void finish ()

Protected Attributes

TcpAppConnMap tcpAppConnMap
TcpConnMap tcpConnMap
ushort lastEphemeralPort
std::multiset< ushortusedEphemeralPorts

Detailed Description

Implements the TCP protocol. This section describes the internal architecture of the TCP model.

Usage and compliance with various RFCs are discussed in the corresponding NED documentation for TCP. Also, you may want to check the TCPSocket class which makes it easier to use TCP from applications.

The TCP protocol implementation is composed of several classes (discussion follows below):

TCP subclassed from cSimpleModule. It manages socketpair-to-connection mapping, and dispatches segments and user commands to the appropriate TCPConnection object.

TCPConnection manages the connection, with the help of other objects. TCPConnection itself implements the basic TCP "machinery": takes care of the state machine, stores the state variables (TCB), sends/receives SYN, FIN, RST, ACKs, etc.

TCPConnection internally relies on 3 objects. The first two are subclassed from TCPSendQueue and TCPReceiveQueue. They manage the actual data stream, so TCPConnection itself only works with sequence number variables. This makes it possible to easily accomodate need for various types of simulated data transfer: real byte stream, "virtual" bytes (byte counts only), and sequence of cMessage objects (where every message object is mapped to a TCP sequence number range).

Currently implemented send queue and receive queue classes are TCPVirtualDataSendQueue and TCPVirtualDataRcvQueue which implement queues with "virtual" bytes (byte counts only).

The third object is subclassed from TCPAlgorithm. Control over retransmissions, congestion control and ACK sending are "outsourced" from TCPConnection into TCPAlgorithm: delayed acks, slow start, fast rexmit, etc. are all implemented in TCPAlgorithm subclasses. This simplifies the design of TCPConnection and makes it a lot easier to implement new TCP variations such as NewReno, Vegas or LinuxTCP as TCPAlgorithm subclasses.

Currently implemented TCPAlgorithm classes are TCPReno, TCPTahoe, TCPNewReno, TCPNoCongestionControl and DumbTCP.

The concrete TCPAlgorithm class to use can be chosen per connection (in OPEN) or in a module parameter.

Definition at line 96 of file TCP.h.


Member Typedef Documentation

typedef std::map<AppConnKey,TCPConnection*> TCP::TcpAppConnMap [protected]

Definition at line 134 of file TCP.h.

typedef std::map<SockPair,TCPConnection*> TCP::TcpConnMap [protected]

Definition at line 135 of file TCP.h.


Constructor & Destructor Documentation

TCP::TCP (  )  [inline]

Definition at line 161 of file TCP.h.

{}

TCP::~TCP (  )  [virtual]

Definition at line 73 of file TCP.cc.

{
    while (!tcpAppConnMap.empty())
    {
        TcpAppConnMap::iterator i = tcpAppConnMap.begin();
        delete (*i).second;
        tcpAppConnMap.erase(i);
    }
}


Member Function Documentation

void TCP::addForkedConnection ( TCPConnection conn,
TCPConnection newConn,
IPvXAddress  localAddr,
IPvXAddress  remoteAddr,
int  localPort,
int  remotePort 
) [virtual]

Update conn's socket pair, and register newConn (which'll keep LISTENing). Also, conn will get a new connId (and newConn will live on with its old connId).

Definition at line 359 of file TCP.cc.

Referenced by TCPConnection::processSegmentInListen().

{
    // update conn's socket pair, and register newConn (which'll keep LISTENing)
    updateSockPair(conn, localAddr, remoteAddr, localPort, remotePort);
    addSockPair(newConn, newConn->localAddr, newConn->remoteAddr, newConn->localPort, newConn->remotePort);

    // conn will get a new connId...
    AppConnKey key;
    key.appGateIndex = conn->appGateIndex;
    key.connId = conn->connId;
    tcpAppConnMap.erase(key);
    key.connId = conn->connId = ev.getUniqueNumber();
    tcpAppConnMap[key] = conn;

    // ...and newConn will live on with the old connId
    key.appGateIndex = newConn->appGateIndex;
    key.connId = newConn->connId;
    tcpAppConnMap[key] = newConn;
}

void TCP::addSockPair ( TCPConnection conn,
IPvXAddress  localAddr,
IPvXAddress  remoteAddr,
int  localPort,
int  remotePort 
) [virtual]

To be called from TCPConnection when a new connection gets created, during processing of OPEN_ACTIVE or OPEN_PASSIVE.

Definition at line 305 of file TCP.cc.

Referenced by addForkedConnection(), TCPConnection::process_OPEN_ACTIVE(), and TCPConnection::process_OPEN_PASSIVE().

{
    // update addresses/ports in TCPConnection
    SockPair key;
    key.localAddr = conn->localAddr = localAddr;
    key.remoteAddr = conn->remoteAddr = remoteAddr;
    key.localPort = conn->localPort = localPort;
    key.remotePort = conn->remotePort = remotePort;

    // make sure connection is unique
    TcpConnMap::iterator it = tcpConnMap.find(key);
    if (it!=tcpConnMap.end())
    {
        // throw "address already in use" error
        if (remoteAddr.isUnspecified() && remotePort==-1)
            error("Address already in use: there is already a connection listening on %s:%d",
                  localAddr.str().c_str(), localPort);
        else
            error("Address already in use: there is already a connection %s:%d to %s:%d",
                  localAddr.str().c_str(), localPort, remoteAddr.str().c_str(), remotePort);
    }

    // then insert it into tcpConnMap
    tcpConnMap[key] = conn;

    // mark port as used
    if (localPort>=EPHEMERAL_PORTRANGE_START && localPort<EPHEMERAL_PORTRANGE_END)
        usedEphemeralPorts.insert(localPort);
}

TCPConnection * TCP::createConnection ( int  appGateIndex,
int  connId 
) [protected, virtual]

Factory method; may be overriden for customizing TCP

Definition at line 169 of file TCP.cc.

Referenced by handleMessage().

{
    return new TCPConnection(this, appGateIndex, connId);
}

TCPConnection * TCP::findConnForApp ( int  appGateIndex,
int  connId 
) [protected, virtual]

Definition at line 275 of file TCP.cc.

Referenced by handleMessage().

{
    AppConnKey key;
    key.appGateIndex = appGateIndex;
    key.connId = connId;

    TcpAppConnMap::iterator i = tcpAppConnMap.find(key);
    return i==tcpAppConnMap.end() ? NULL : i->second;
}

TCPConnection * TCP::findConnForSegment ( TCPSegment tcpseg,
IPvXAddress  srcAddr,
IPvXAddress  destAddr 
) [protected, virtual]

Definition at line 236 of file TCP.cc.

Referenced by handleMessage().

{
    SockPair key;
    key.localAddr = destAddr;
    key.remoteAddr = srcAddr;
    key.localPort = tcpseg->getDestPort();
    key.remotePort = tcpseg->getSrcPort();
    SockPair save = key;

    // try with fully qualified SockPair
    TcpConnMap::iterator i;
    i = tcpConnMap.find(key);
    if (i!=tcpConnMap.end())
        return i->second;

    // try with localAddr missing (only localPort specified in passive/active open)
    key.localAddr = IPvXAddress();
    i = tcpConnMap.find(key);
    if (i!=tcpConnMap.end())
        return i->second;

    // try fully qualified local socket + blank remote socket (for incoming SYN)
    key = save;
    key.remoteAddr = IPvXAddress();
    key.remotePort = -1;
    i = tcpConnMap.find(key);
    if (i!=tcpConnMap.end())
        return i->second;

    // try with blank remote socket, and localAddr missing (for incoming SYN)
    key.localAddr = IPvXAddress();
    i = tcpConnMap.find(key);
    if (i!=tcpConnMap.end())
        return i->second;

    // given up
    return NULL;
}

void TCP::finish (  )  [protected, virtual]

Definition at line 404 of file TCP.cc.

{
    tcpEV << getFullPath() << ": finishing with " << tcpConnMap.size() << " connections open.\n";
}

ushort TCP::getEphemeralPort (  )  [virtual]

To be called from TCPConnection: reserves an ephemeral port for the connection.

Definition at line 285 of file TCP.cc.

Referenced by TCPConnection::process_OPEN_ACTIVE().

{
    // start at the last allocated port number + 1, and search for an unused one
    ushort searchUntil = lastEphemeralPort++;
    if (lastEphemeralPort == EPHEMERAL_PORTRANGE_END) // wrap
        lastEphemeralPort = EPHEMERAL_PORTRANGE_START;

    while (usedEphemeralPorts.find(lastEphemeralPort)!=usedEphemeralPorts.end())
    {
        if (lastEphemeralPort == searchUntil) // got back to starting point?
            error("Ephemeral port range %d..%d exhausted, all ports occupied", EPHEMERAL_PORTRANGE_START, EPHEMERAL_PORTRANGE_END);
        lastEphemeralPort++;
        if (lastEphemeralPort == EPHEMERAL_PORTRANGE_END) // wrap
            lastEphemeralPort = EPHEMERAL_PORTRANGE_START;
    }

    // found a free one, return it
    return lastEphemeralPort;
}

void TCP::handleMessage ( cMessage *  msg  )  [protected, virtual]

Definition at line 83 of file TCP.cc.

{
    if (msg->isSelfMessage())
    {
        TCPConnection *conn = (TCPConnection *) msg->getContextPointer();
        bool ret = conn->processTimer(msg);
        if (!ret)
            removeConnection(conn);
    }
    else if (msg->arrivedOn("ipIn") || msg->arrivedOn("ipv6In"))
    {
        if (dynamic_cast<ICMPMessage *>(msg) || dynamic_cast<ICMPv6Message *>(msg))
        {
            tcpEV << "ICMP error received -- discarding\n"; // FIXME can ICMP packets really make it up to TCP???
            delete msg;
        }
        else
        {
            // must be a TCPSegment
            TCPSegment *tcpseg = check_and_cast<TCPSegment *>(msg);

            // get src/dest addresses
            IPvXAddress srcAddr, destAddr;
            if (dynamic_cast<IPControlInfo *>(tcpseg->getControlInfo())!=NULL)
            {
                IPControlInfo *controlInfo = (IPControlInfo *)tcpseg->removeControlInfo();
                srcAddr = controlInfo->getSrcAddr();
                destAddr = controlInfo->getDestAddr();
                delete controlInfo;
            }
            else if (dynamic_cast<IPv6ControlInfo *>(tcpseg->getControlInfo())!=NULL)
            {
                IPv6ControlInfo *controlInfo = (IPv6ControlInfo *)tcpseg->removeControlInfo();
                srcAddr = controlInfo->getSrcAddr();
                destAddr = controlInfo->getDestAddr();
                delete controlInfo;
            }
            else
            {
                error("(%s)%s arrived without control info", tcpseg->getClassName(), tcpseg->getName());
            }

            // process segment
            TCPConnection *conn = findConnForSegment(tcpseg, srcAddr, destAddr);
            if (conn)
            {
                bool ret = conn->processTCPSegment(tcpseg, srcAddr, destAddr);
                if (!ret)
                    removeConnection(conn);
            }
            else
            {
                segmentArrivalWhileClosed(tcpseg, srcAddr, destAddr);
            }
        }
    }
    else // must be from app
    {
        TCPCommand *controlInfo = check_and_cast<TCPCommand *>(msg->getControlInfo());
        int appGateIndex = msg->getArrivalGate()->getIndex();
        int connId = controlInfo->getConnId();

        TCPConnection *conn = findConnForApp(appGateIndex, connId);

        if (!conn)
        {
            conn = createConnection(appGateIndex, connId);

            // add into appConnMap here; it'll be added to connMap during processing
            // the OPEN command in TCPConnection's processAppCommand().
            AppConnKey key;
            key.appGateIndex = appGateIndex;
            key.connId = connId;
            tcpAppConnMap[key] = conn;

            tcpEV << "TCP connection created for " << msg << "\n";
        }
        bool ret = conn->processAppCommand(msg);
        if (!ret)
            removeConnection(conn);
    }

    if (ev.isGUI())
        updateDisplayString();
}

void TCP::initialize (  )  [protected, virtual]

Definition at line 58 of file TCP.cc.

{
    lastEphemeralPort = EPHEMERAL_PORTRANGE_START;
    WATCH(lastEphemeralPort);

    WATCH_PTRMAP(tcpConnMap);
    WATCH_PTRMAP(tcpAppConnMap);

    recordStatistics = par("recordStats");

    cModule *netw = simulation.getSystemModule();
    testing = netw->hasPar("testing") && netw->par("testing").boolValue();
    logverbose = !testing && netw->hasPar("logverbose") && netw->par("logverbose").boolValue();
}

void TCP::removeConnection ( TCPConnection conn  )  [protected, virtual]

Definition at line 379 of file TCP.cc.

Referenced by handleMessage().

{
    tcpEV << "Deleting TCP connection\n";

    AppConnKey key;
    key.appGateIndex = conn->appGateIndex;
    key.connId = conn->connId;
    tcpAppConnMap.erase(key);

    SockPair key2;
    key2.localAddr = conn->localAddr;
    key2.remoteAddr = conn->remoteAddr;
    key2.localPort = conn->localPort;
    key2.remotePort = conn->remotePort;
    tcpConnMap.erase(key2);

    // IMPORTANT: usedEphemeralPorts.erase(conn->localPort) is NOT GOOD because it
    // deletes ALL occurrences of the port from the multiset.
    std::multiset<ushort>::iterator it = usedEphemeralPorts.find(conn->localPort);
    if (it!=usedEphemeralPorts.end())
        usedEphemeralPorts.erase(it);

    delete conn;
}

void TCP::segmentArrivalWhileClosed ( TCPSegment tcpseg,
IPvXAddress  src,
IPvXAddress  dest 
) [protected, virtual]

Definition at line 174 of file TCP.cc.

Referenced by handleMessage().

{
    TCPConnection *tmp = new TCPConnection();
    tmp->segmentArrivalWhileClosed(tcpseg, srcAddr, destAddr);
    delete tmp;
    delete tcpseg;
}

void TCP::updateDisplayString (  )  [protected, virtual]

Definition at line 182 of file TCP.cc.

Referenced by handleMessage().

{
    if (ev.isDisabled())
    {
        // in express mode, we don't bother to update the display
        // (std::map's iteration is not very fast if map is large)
        getDisplayString().setTagArg("t",0,"");
        return;
    }

    //char buf[40];
    //sprintf(buf,"%d conns", tcpAppConnMap.size());
    //getDisplayString().setTagArg("t",0,buf);

    int numINIT=0, numCLOSED=0, numLISTEN=0, numSYN_SENT=0, numSYN_RCVD=0,
        numESTABLISHED=0, numCLOSE_WAIT=0, numLAST_ACK=0, numFIN_WAIT_1=0,
        numFIN_WAIT_2=0, numCLOSING=0, numTIME_WAIT=0;

    for (TcpAppConnMap::iterator i=tcpAppConnMap.begin(); i!=tcpAppConnMap.end(); ++i)
    {
        int state = (*i).second->getFsmState();
        switch(state)
        {
           case TCP_S_INIT:        numINIT++; break;
           case TCP_S_CLOSED:      numCLOSED++; break;
           case TCP_S_LISTEN:      numLISTEN++; break;
           case TCP_S_SYN_SENT:    numSYN_SENT++; break;
           case TCP_S_SYN_RCVD:    numSYN_RCVD++; break;
           case TCP_S_ESTABLISHED: numESTABLISHED++; break;
           case TCP_S_CLOSE_WAIT:  numCLOSE_WAIT++; break;
           case TCP_S_LAST_ACK:    numLAST_ACK++; break;
           case TCP_S_FIN_WAIT_1:  numFIN_WAIT_1++; break;
           case TCP_S_FIN_WAIT_2:  numFIN_WAIT_2++; break;
           case TCP_S_CLOSING:     numCLOSING++; break;
           case TCP_S_TIME_WAIT:   numTIME_WAIT++; break;
        }
    }
    char buf2[200];
    buf2[0] = '\0';
    if (numINIT>0)       sprintf(buf2+strlen(buf2), "init:%d ", numINIT);
    if (numCLOSED>0)     sprintf(buf2+strlen(buf2), "closed:%d ", numCLOSED);
    if (numLISTEN>0)     sprintf(buf2+strlen(buf2), "listen:%d ", numLISTEN);
    if (numSYN_SENT>0)   sprintf(buf2+strlen(buf2), "syn_sent:%d ", numSYN_SENT);
    if (numSYN_RCVD>0)   sprintf(buf2+strlen(buf2), "syn_rcvd:%d ", numSYN_RCVD);
    if (numESTABLISHED>0) sprintf(buf2+strlen(buf2),"estab:%d ", numESTABLISHED);
    if (numCLOSE_WAIT>0) sprintf(buf2+strlen(buf2), "close_wait:%d ", numCLOSE_WAIT);
    if (numLAST_ACK>0)   sprintf(buf2+strlen(buf2), "last_ack:%d ", numLAST_ACK);
    if (numFIN_WAIT_1>0) sprintf(buf2+strlen(buf2), "fin_wait_1:%d ", numFIN_WAIT_1);
    if (numFIN_WAIT_2>0) sprintf(buf2+strlen(buf2), "fin_wait_2:%d ", numFIN_WAIT_2);
    if (numCLOSING>0)    sprintf(buf2+strlen(buf2), "closing:%d ", numCLOSING);
    if (numTIME_WAIT>0)  sprintf(buf2+strlen(buf2), "time_wait:%d ", numTIME_WAIT);
    getDisplayString().setTagArg("t",0,buf2);
}

void TCP::updateSockPair ( TCPConnection conn,
IPvXAddress  localAddr,
IPvXAddress  remoteAddr,
int  localPort,
int  remotePort 
) [virtual]

To be called from TCPConnection when socket pair (key for TcpConnMap) changes (e.g. becomes fully qualified).

Definition at line 335 of file TCP.cc.

Referenced by addForkedConnection(), TCPConnection::processSegmentInListen(), and TCPConnection::processSegmentInSynSent().

{
    // find with existing address/port pair...
    SockPair key;
    key.localAddr = conn->localAddr;
    key.remoteAddr = conn->remoteAddr;
    key.localPort = conn->localPort;
    key.remotePort = conn->remotePort;
    TcpConnMap::iterator it = tcpConnMap.find(key);
    ASSERT(it!=tcpConnMap.end() && it->second==conn);

    // ...and remove from the old place in tcpConnMap
    tcpConnMap.erase(it);

    // then update addresses/ports, and re-insert it with new key into tcpConnMap
    key.localAddr = conn->localAddr = localAddr;
    key.remoteAddr = conn->remoteAddr = remoteAddr;
    ASSERT(conn->localPort == localPort);
    key.remotePort = conn->remotePort = remotePort;
    tcpConnMap[key] = conn;

    // localPort doesn't change (see ASSERT above), so there's no need to update usedEphemeralPorts[].
}


Member Data Documentation

Definition at line 140 of file TCP.h.

Referenced by getEphemeralPort(), and initialize().

bool TCP::logverbose [static]

Definition at line 156 of file TCP.h.

Referenced by initialize().

Definition at line 158 of file TCP.h.

Referenced by TCPBaseAlg::initialize(), and initialize().

bool TCP::testing [static]

Definition at line 155 of file TCP.h.

Referenced by initialize().

std::multiset<ushort> TCP::usedEphemeralPorts [protected]

Definition at line 141 of file TCP.h.

Referenced by addSockPair(), getEphemeralPort(), and removeConnection().


The documentation for this class was generated from the following files: