Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

TCP Class Reference

#include <TCP.h>

List of all members.


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 DumbTCP, TCPTahoe, TCPReno, etc.

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


Public Member Functions

 TCP ()
virtual ~TCP ()
void addSockPair (TCPConnection *conn, IPvXAddress localAddr, IPvXAddress remoteAddr, int localPort, int remotePort)
void updateSockPair (TCPConnection *conn, IPvXAddress localAddr, IPvXAddress remoteAddr, int localPort, int remotePort)
void addForkedConnection (TCPConnection *conn, TCPConnection *newConn, IPvXAddress localAddr, IPvXAddress remoteAddr, int localPort, int remotePort)
short 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

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

Protected Attributes

TcpAppConnMap tcpAppConnMap
TcpConnMap tcpConnMap
short lastEphemeralPort
std::multiset< short > usedEphemeralPorts

Classes

struct  AppConnKey
struct  SockPair


Member Typedef Documentation

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

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


Constructor & Destructor Documentation

TCP::TCP  )  [inline]
 

00159 {}

TCP::~TCP  )  [virtual]
 

00075 {
00076     while (!tcpAppConnMap.empty())
00077     {
00078         TcpAppConnMap::iterator i = tcpAppConnMap.begin();
00079         delete (*i).second;
00080         tcpAppConnMap.erase(i);
00081     }
00082 }


Member Function Documentation

void TCP::addForkedConnection TCPConnection conn,
TCPConnection newConn,
IPvXAddress  localAddr,
IPvXAddress  remoteAddr,
int  localPort,
int  remotePort
 

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).

00348 {
00349     // update conn's socket pair, and register newConn (which'll keep LISTENing)
00350     updateSockPair(conn, localAddr, remoteAddr, localPort, remotePort);
00351     addSockPair(newConn, newConn->localAddr, newConn->remoteAddr, newConn->localPort, newConn->remotePort);
00352 
00353     // conn will get a new connId...
00354     AppConnKey key;
00355     key.appGateIndex = conn->appGateIndex;
00356     key.connId = conn->connId;
00357     tcpAppConnMap.erase(key);
00358     key.connId = conn->connId = ev.getUniqueNumber();
00359     tcpAppConnMap[key] = conn;
00360 
00361     // ...and newConn will live on with the old connId
00362     key.appGateIndex = newConn->appGateIndex;
00363     key.connId = newConn->connId;
00364     tcpAppConnMap[key] = newConn;
00365 }

void TCP::addSockPair TCPConnection conn,
IPvXAddress  localAddr,
IPvXAddress  remoteAddr,
int  localPort,
int  remotePort
 

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

00294 {
00295     // update addresses/ports in TCPConnection
00296     SockPair key;
00297     key.localAddr = conn->localAddr = localAddr;
00298     key.remoteAddr = conn->remoteAddr = remoteAddr;
00299     key.localPort = conn->localPort = localPort;
00300     key.remotePort = conn->remotePort = remotePort;
00301 
00302     // make sure connection is unique
00303     TcpConnMap::iterator it = tcpConnMap.find(key);
00304     if (it!=tcpConnMap.end())
00305     {
00306         // throw "address already in use" error
00307         if (remoteAddr.isUnspecified() && remotePort==-1)
00308             error("Address already in use: there is already a connection listening on %s:%d",
00309                   localAddr.str().c_str(), localPort);
00310         else
00311             error("Address already in use: there is already a connection %s:%d to %s:%d",
00312                   localAddr.str().c_str(), localPort, remoteAddr.str().c_str(), remotePort);
00313     }
00314 
00315     // then insert it into tcpConnMap
00316     tcpConnMap[key] = conn;
00317 
00318     // mark port as used
00319     if (localPort>=EPHEMERAL_PORTRANGE_START && localPort<EPHEMERAL_PORTRANGE_END)
00320         usedEphemeralPorts.insert(localPort);
00321 }

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

00264 {
00265     AppConnKey key;
00266     key.appGateIndex = appGateIndex;
00267     key.connId = connId;
00268 
00269     TcpAppConnMap::iterator i = tcpAppConnMap.find(key);
00270     return i==tcpAppConnMap.end() ? NULL : i->second;
00271 }

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

00225 {
00226     SockPair key;
00227     key.localAddr = destAddr;
00228     key.remoteAddr = srcAddr;
00229     key.localPort = tcpseg->destPort();
00230     key.remotePort = tcpseg->srcPort();
00231     SockPair save = key;
00232 
00233     // try with fully qualified SockPair
00234     TcpConnMap::iterator i;
00235     i = tcpConnMap.find(key);
00236     if (i!=tcpConnMap.end())
00237         return i->second;
00238 
00239     // try with localAddr missing (only localPort specified in passive/active open)
00240     key.localAddr = IPvXAddress();
00241     i = tcpConnMap.find(key);
00242     if (i!=tcpConnMap.end())
00243         return i->second;
00244 
00245     // try fully qualified local socket + blank remote socket (for incoming SYN)
00246     key = save;
00247     key.remoteAddr = IPvXAddress();
00248     key.remotePort = -1;
00249     i = tcpConnMap.find(key);
00250     if (i!=tcpConnMap.end())
00251         return i->second;
00252 
00253     // try with blank remote socket, and localAddr missing (for incoming SYN)
00254     key.localAddr = IPvXAddress();
00255     i = tcpConnMap.find(key);
00256     if (i!=tcpConnMap.end())
00257         return i->second;
00258 
00259     // given up
00260     return NULL;
00261 }

void TCP::finish  )  [protected, virtual]
 

00393 {
00394     tcpEV << fullPath() << ": finishing with " << tcpConnMap.size() << " connections open.\n";
00395 }

short TCP::getEphemeralPort  ) 
 

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

00274 {
00275     // start at the last allocated port number + 1, and search for an unused one
00276     short searchUntil = lastEphemeralPort++;
00277     if (lastEphemeralPort == EPHEMERAL_PORTRANGE_END) // wrap
00278         lastEphemeralPort = EPHEMERAL_PORTRANGE_START;
00279 
00280     while (usedEphemeralPorts.find(lastEphemeralPort)!=usedEphemeralPorts.end())
00281     {
00282         if (lastEphemeralPort == searchUntil) // got back to starting point?
00283             error("Ephemeral port range %d..%d exhausted, all ports occupied", EPHEMERAL_PORTRANGE_START, EPHEMERAL_PORTRANGE_END);
00284         lastEphemeralPort++;
00285         if (lastEphemeralPort == EPHEMERAL_PORTRANGE_END) // wrap
00286             lastEphemeralPort = EPHEMERAL_PORTRANGE_START;
00287     }
00288 
00289     // found a free one, return it
00290     return lastEphemeralPort;
00291 }

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

00086 {
00087     if (msg->isSelfMessage())
00088     {
00089         TCPConnection *conn = (TCPConnection *) msg->contextPointer();
00090         bool ret = conn->processTimer(msg);
00091         if (!ret)
00092             removeConnection(conn);
00093     }
00094     else if (msg->arrivedOn("from_ip") || msg->arrivedOn("from_ipv6"))
00095     {
00096         if (dynamic_cast<ICMPMessage *>(msg) || dynamic_cast<ICMPv6Message *>(msg))
00097         {
00098             tcpEV << "ICMP error received -- discarding\n"; // TODO implement processsing ICMP errors
00099             delete msg;
00100         }
00101         else
00102         {
00103             // must be a TCPSegment
00104             TCPSegment *tcpseg = check_and_cast<TCPSegment *>(msg);
00105 
00106             // get src/dest addresses
00107             IPvXAddress srcAddr, destAddr;
00108             if (dynamic_cast<IPControlInfo *>(tcpseg->controlInfo())!=NULL)
00109             {
00110                 IPControlInfo *controlInfo = (IPControlInfo *)tcpseg->removeControlInfo();
00111                 srcAddr = controlInfo->srcAddr();
00112                 destAddr = controlInfo->destAddr();
00113                 delete controlInfo;
00114             }
00115             else if (dynamic_cast<IPv6ControlInfo *>(tcpseg->controlInfo())!=NULL)
00116             {
00117                 IPv6ControlInfo *controlInfo = (IPv6ControlInfo *)tcpseg->removeControlInfo();
00118                 srcAddr = controlInfo->srcAddr();
00119                 destAddr = controlInfo->destAddr();
00120                 delete controlInfo;
00121             }
00122             else
00123             {
00124                 error("(%s)%s arrived without control info", tcpseg->className(), tcpseg->name());
00125             }
00126 
00127             // process segment
00128             TCPConnection *conn = findConnForSegment(tcpseg, srcAddr, destAddr);
00129             if (!conn)
00130             {
00131                 TCPConnection::segmentArrivalWhileClosed(tcpseg, srcAddr, destAddr);
00132                 delete tcpseg;
00133                 return;
00134             }
00135             bool ret = conn->processTCPSegment(tcpseg, srcAddr, destAddr);
00136             if (!ret)
00137                 removeConnection(conn);
00138         }
00139     }
00140     else // must be from app
00141     {
00142         TCPCommand *controlInfo = check_and_cast<TCPCommand *>(msg->controlInfo());
00143         int appGateIndex = msg->arrivalGate()->index();
00144         int connId = controlInfo->connId();
00145 
00146         TCPConnection *conn = findConnForApp(appGateIndex, connId);
00147 
00148         if (!conn)
00149         {
00150             conn = new TCPConnection(this,appGateIndex,connId);
00151 
00152             // add into appConnMap here; it'll be added to connMap during processing
00153             // the OPEN command in TCPConnection's processAppCommand().
00154             AppConnKey key;
00155             key.appGateIndex = appGateIndex;
00156             key.connId = connId;
00157             tcpAppConnMap[key] = conn;
00158 
00159             tcpEV << "TCP connection created for " << msg << "\n";
00160         }
00161         bool ret = conn->processAppCommand(msg);
00162         if (!ret)
00163             removeConnection(conn);
00164     }
00165 
00166     if (ev.isGUI())
00167         updateDisplayString();
00168 }

void TCP::initialize  )  [protected, virtual]
 

00060 {
00061     lastEphemeralPort = EPHEMERAL_PORTRANGE_START;
00062     WATCH(lastEphemeralPort);
00063 
00064     WATCH_PTRMAP(tcpConnMap);
00065     WATCH_PTRMAP(tcpAppConnMap);
00066 
00067     recordStatistics = par("recordStats");
00068 
00069     cModule *netw = simulation.systemModule();
00070     testing = netw->hasPar("testing") && netw->par("testing").boolValue();
00071     logverbose = !testing && netw->hasPar("logverbose") && netw->par("logverbose").boolValue();
00072 }

void TCP::removeConnection TCPConnection conn  )  [protected]
 

00368 {
00369     tcpEV << "Deleting TCP connection\n";
00370 
00371     AppConnKey key;
00372     key.appGateIndex = conn->appGateIndex;
00373     key.connId = conn->connId;
00374     tcpAppConnMap.erase(key);
00375 
00376     SockPair key2;
00377     key2.localAddr = conn->localAddr;
00378     key2.remoteAddr = conn->remoteAddr;
00379     key2.localPort = conn->localPort;
00380     key2.remotePort = conn->remotePort;
00381     tcpConnMap.erase(key2);
00382 
00383     // IMPORTANT: usedEphemeralPorts.erase(conn->localPort) is NOT GOOD because it
00384     // deletes ALL occurrences of the port from the multiset.
00385     std::multiset<short>::iterator it = usedEphemeralPorts.find(conn->localPort);
00386     if (it!=usedEphemeralPorts.end())
00387         usedEphemeralPorts.erase(it);
00388 
00389     delete conn;
00390 }

void TCP::updateDisplayString  )  [protected]
 

00171 {
00172     if (ev.disabled())
00173     {
00174         // in express mode, we don't bother to update the display
00175         // (std::map's iteration is not very fast if map is large)
00176         displayString().setTagArg("t",0,"");
00177         return;
00178     }
00179 
00180     //char buf[40];
00181     //sprintf(buf,"%d conns", tcpAppConnMap.size());
00182     //displayString().setTagArg("t",0,buf);
00183 
00184     int numINIT=0, numCLOSED=0, numLISTEN=0, numSYN_SENT=0, numSYN_RCVD=0,
00185         numESTABLISHED=0, numCLOSE_WAIT=0, numLAST_ACK=0, numFIN_WAIT_1=0,
00186         numFIN_WAIT_2=0, numCLOSING=0, numTIME_WAIT=0;
00187 
00188     for (TcpAppConnMap::iterator i=tcpAppConnMap.begin(); i!=tcpAppConnMap.end(); ++i)
00189     {
00190         int state = (*i).second->getFsmState();
00191         switch(state)
00192         {
00193            case TCP_S_INIT:        numINIT++; break;
00194            case TCP_S_CLOSED:      numCLOSED++; break;
00195            case TCP_S_LISTEN:      numLISTEN++; break;
00196            case TCP_S_SYN_SENT:    numSYN_SENT++; break;
00197            case TCP_S_SYN_RCVD:    numSYN_RCVD++; break;
00198            case TCP_S_ESTABLISHED: numESTABLISHED++; break;
00199            case TCP_S_CLOSE_WAIT:  numCLOSE_WAIT++; break;
00200            case TCP_S_LAST_ACK:    numLAST_ACK++; break;
00201            case TCP_S_FIN_WAIT_1:  numFIN_WAIT_1++; break;
00202            case TCP_S_FIN_WAIT_2:  numFIN_WAIT_2++; break;
00203            case TCP_S_CLOSING:     numCLOSING++; break;
00204            case TCP_S_TIME_WAIT:   numTIME_WAIT++; break;
00205         }
00206     }
00207     char buf2[200];
00208     buf2[0] = '\0';
00209     if (numINIT>0)       sprintf(buf2+strlen(buf2), "init:%d ", numINIT);
00210     if (numCLOSED>0)     sprintf(buf2+strlen(buf2), "closed:%d ", numCLOSED);
00211     if (numLISTEN>0)     sprintf(buf2+strlen(buf2), "listen:%d ", numLISTEN);
00212     if (numSYN_SENT>0)   sprintf(buf2+strlen(buf2), "syn_sent:%d ", numSYN_SENT);
00213     if (numSYN_RCVD>0)   sprintf(buf2+strlen(buf2), "syn_rcvd:%d ", numSYN_RCVD);
00214     if (numESTABLISHED>0) sprintf(buf2+strlen(buf2),"estab:%d ", numESTABLISHED);
00215     if (numCLOSE_WAIT>0) sprintf(buf2+strlen(buf2), "close_wait:%d ", numCLOSE_WAIT);
00216     if (numLAST_ACK>0)   sprintf(buf2+strlen(buf2), "last_ack:%d ", numLAST_ACK);
00217     if (numFIN_WAIT_1>0) sprintf(buf2+strlen(buf2), "fin_wait_1:%d ", numFIN_WAIT_1);
00218     if (numFIN_WAIT_2>0) sprintf(buf2+strlen(buf2), "fin_wait_2:%d ", numFIN_WAIT_2);
00219     if (numCLOSING>0)    sprintf(buf2+strlen(buf2), "closing:%d ", numCLOSING);
00220     if (numTIME_WAIT>0)  sprintf(buf2+strlen(buf2), "time_wait:%d ", numTIME_WAIT);
00221     displayString().setTagArg("t",0,buf2);
00222 }

void TCP::updateSockPair TCPConnection conn,
IPvXAddress  localAddr,
IPvXAddress  remoteAddr,
int  localPort,
int  remotePort
 

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

00324 {
00325     // find with existing address/port pair...
00326     SockPair key;
00327     key.localAddr = conn->localAddr;
00328     key.remoteAddr = conn->remoteAddr;
00329     key.localPort = conn->localPort;
00330     key.remotePort = conn->remotePort;
00331     TcpConnMap::iterator it = tcpConnMap.find(key);
00332     ASSERT(it!=tcpConnMap.end() && it->second==conn);
00333 
00334     // ...and remove from the old place in tcpConnMap
00335     tcpConnMap.erase(it);
00336 
00337     // then update addresses/ports, and re-insert it with new key into tcpConnMap
00338     key.localAddr = conn->localAddr = localAddr;
00339     key.remoteAddr = conn->remoteAddr = remoteAddr;
00340     ASSERT(conn->localPort == localPort);
00341     key.remotePort = conn->remotePort = remotePort;
00342     tcpConnMap[key] = conn;
00343 
00344     // localPort doesn't change (see ASSERT above), so there's no need to update usedEphemeralPorts[].
00345 }


Member Data Documentation

short TCP::lastEphemeralPort [protected]
 

bool TCP::logverbose [static]
 

bool TCP::recordStatistics
 

TcpAppConnMap TCP::tcpAppConnMap [protected]
 

TcpConnMap TCP::tcpConnMap [protected]
 

bool TCP::testing [static]
 

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


The documentation for this class was generated from the following files:
Generated on Sat Apr 1 20:52:24 2006 for INET Framework for OMNeT++/OMNEST by  doxygen 1.4.1