#include <TCP.h>
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 TCPConnection * | createConnection (int appGateIndex, int connId) |
virtual TCPConnection * | findConnForSegment (TCPSegment *tcpseg, IPvXAddress srcAddr, IPvXAddress destAddr) |
virtual TCPConnection * | findConnForApp (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< ushort > | usedEphemeralPorts |
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.
typedef std::map<AppConnKey,TCPConnection*> TCP::TcpAppConnMap [protected] |
typedef std::map<SockPair,TCPConnection*> TCP::TcpConnMap [protected] |
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); } }
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[]. }
ushort TCP::lastEphemeralPort [protected] |
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().
TcpAppConnMap TCP::tcpAppConnMap [protected] |
Definition at line 137 of file TCP.h.
Referenced by addForkedConnection(), findConnForApp(), handleMessage(), initialize(), removeConnection(), updateDisplayString(), and ~TCP().
TcpConnMap TCP::tcpConnMap [protected] |
Definition at line 138 of file TCP.h.
Referenced by addSockPair(), findConnForSegment(), finish(), initialize(), removeConnection(), and updateSockPair().
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().