SimpleTCP.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2004 Andras Varga
00003 // Copyright (C) 2010 Institut fuer Telematik, Karlsruher Institut fuer Technologie (KIT)
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00018 //
00019 
00031 #include <omnetpp.h>
00032 
00033 #include <CommonMessages_m.h>
00034 #include <GlobalNodeListAccess.h>
00035 #include <GlobalStatisticsAccess.h>
00036 
00037 #include <SimpleInfo.h>
00038 #include <SimpleUDP.h>
00039 #include "IPDatagram_m.h"
00040 #include "TCPSegment.h"
00041 #include "SimpleTCP.h"
00042 #include "TCPCommand_m.h"
00043 #include "IPControlInfo.h"
00044 #include "IPv6ControlInfo.h"
00045 #include "ICMPMessage_m.h"
00046 #include "ICMPv6Message_m.h"
00047 #include "IPAddressResolver.h"
00048 #include "TCPSendQueue.h"
00049 #include "TCPSACKRexmitQueue.h"
00050 #include "TCPReceiveQueue.h"
00051 #include "TCPAlgorithm.h"
00052 
00053 #define EPHEMERAL_PORTRANGE_START 1024
00054 #define EPHEMERAL_PORTRANGE_END   5000
00055 
00056 Define_Module( SimpleTCP );
00057 
00058 
00059 
00060 static std::ostream& operator<<(std::ostream& os, const TCP::SockPair& sp)
00061 {
00062     os << "loc=" << IPvXAddress(sp.localAddr) << ":" << sp.localPort << " "
00063        << "rem=" << IPvXAddress(sp.remoteAddr) << ":" << sp.remotePort;
00064     return os;
00065 }
00066 
00067 static std::ostream& operator<<(std::ostream& os, const TCP::AppConnKey& app)
00068 {
00069     os << "connId=" << app.connId << " appGateIndex=" << app.appGateIndex;
00070     return os;
00071 }
00072 
00073 static std::ostream& operator<<(std::ostream& os, const TCPConnection& conn)
00074 {
00075     os << "connId=" << conn.connId << " " << TCPConnection::stateName(conn.getFsmState())
00076        << " state={" << const_cast<TCPConnection&>(conn).getState()->info() << "}";
00077     return os;
00078 }
00079 
00080 void SimpleTCP::initialize(int stage)
00081 {
00082     if (stage == MIN_STAGE_UNDERLAY) {
00083         lastEphemeralPort = EPHEMERAL_PORTRANGE_START;
00084         WATCH(lastEphemeralPort);
00085 
00086         WATCH_PTRMAP(tcpConnMap);
00087         WATCH_PTRMAP(tcpAppConnMap);
00088 
00089         recordStatistics = par("recordStats");
00090 
00091         cModule *netw = simulation.getSystemModule();
00092         testing = netw->hasPar("testing") && netw->par("testing").boolValue();
00093         logverbose = !testing && netw->hasPar("logverbose") && netw->par("logverbose").boolValue();
00094 
00095         // start of modifications
00096 
00097         sad.numSent = 0;
00098         sad.numQueueLost = 0;
00099         sad.numPartitionLost = 0;
00100         sad.numDestUnavailableLost = 0;
00101         WATCH(sad.numQueueLost);
00102         WATCH(sad.numPartitionLost);
00103         WATCH(sad.numDestUnavailableLost);
00104 
00105         sad.globalNodeList = GlobalNodeListAccess().get();
00106         sad.globalStatistics = GlobalStatisticsAccess().get();
00107         sad.constantDelay = par("constantDelay");
00108         sad.useCoordinateBasedDelay = par("useCoordinateBasedDelay");
00109 
00110         sad.delayFaultTypeString = par("delayFaultType").stdstringValue();
00111         sad.delayFaultTypeMap["live_all"] = sad.delayFaultLiveAll;
00112         sad.delayFaultTypeMap["live_planetlab"] = sad.delayFaultLivePlanetlab;
00113         sad.delayFaultTypeMap["simulation"] = sad.delayFaultSimulation;
00114 
00115         switch (sad.delayFaultTypeMap[sad.delayFaultTypeString]) {
00116         case StatisticsAndDelay::delayFaultLiveAll:
00117         case StatisticsAndDelay::delayFaultLivePlanetlab:
00118         case StatisticsAndDelay::delayFaultSimulation:
00119             sad.faultyDelay = true;
00120             break;
00121         default:
00122             sad.faultyDelay = false;
00123         }
00124 
00125         sad.jitter = par("jitter");
00126         sad.nodeEntry = NULL;
00127         WATCH_PTR(sad.nodeEntry);
00128     }
00129 }
00130 
00131 void SimpleTCP::finish()
00132 {
00133     sad.globalStatistics->addStdDev("SimpleTCP: Packets sent",
00134                                 sad.numSent);
00135     sad.globalStatistics->addStdDev("SimpleTCP: Packets dropped due to queue overflows",
00136                                 sad.numQueueLost);
00137     sad.globalStatistics->addStdDev("SimpleTCP: Packets dropped due to network partitions",
00138                                 sad.numPartitionLost);
00139     sad.globalStatistics->addStdDev("SimpleTCP: Packets dropped due to unavailable destination",
00140                                 sad.numDestUnavailableLost);
00141 }
00142 
00143 void SimpleTCP::handleMessage(cMessage *msg)
00144 {
00145     if (msg->isSelfMessage())
00146     {
00147         SimpleTCPConnection *conn = (SimpleTCPConnection *) msg->getContextPointer();
00148         bool ret = conn->processTimer(msg);
00149         if (!ret)
00150             removeConnection(conn);
00151     }
00152     else if (msg->arrivedOn("ipIn") || msg->arrivedOn("ipv6In"))
00153     {
00154         if (dynamic_cast<ICMPMessage *>(msg) || dynamic_cast<ICMPv6Message *>(msg))
00155         {
00156             tcpEV << "ICMP error received -- discarding\n"; // FIXME can ICMP packets really make it up to TCP???
00157             delete msg;
00158         }
00159         else
00160         {
00161             // must be a TCPSegment
00162             TCPSegment *tcpseg = check_and_cast<TCPSegment *>(msg);
00163 
00164             // get src/dest addresses
00165             IPvXAddress srcAddr, destAddr;
00166             if (dynamic_cast<IPControlInfo *>(tcpseg->getControlInfo())!=NULL)
00167             {
00168                 IPControlInfo *controlInfo = (IPControlInfo *)tcpseg->removeControlInfo();
00169                 srcAddr = controlInfo->getSrcAddr();
00170                 destAddr = controlInfo->getDestAddr();
00171                 delete controlInfo;
00172             }
00173             else if (dynamic_cast<IPv6ControlInfo *>(tcpseg->getControlInfo())!=NULL)
00174             {
00175                 IPv6ControlInfo *controlInfo = (IPv6ControlInfo *)tcpseg->removeControlInfo();
00176                 srcAddr = controlInfo->getSrcAddr();
00177                 destAddr = controlInfo->getDestAddr();
00178                 delete controlInfo;
00179             }
00180             else
00181             {
00182                 error("(%s)%s arrived without control info", tcpseg->getClassName(), tcpseg->getName());
00183             }
00184 
00185             // process segment
00186             SimpleTCPConnection *conn = dynamic_cast<SimpleTCPConnection*>(findConnForSegment(tcpseg, srcAddr, destAddr));
00187 
00188             if (conn)
00189             {
00190                 bool ret = conn->processTCPSegment(tcpseg, srcAddr, destAddr);
00191                 if (!ret)
00192                     removeConnection(conn);
00193             }
00194             else
00195             {
00196                 segmentArrivalWhileClosed(tcpseg, srcAddr, destAddr);
00197             }
00198         }
00199     }
00200     else // must be from app
00201     {
00202         TCPCommand *controlInfo = check_and_cast<TCPCommand *>(msg->getControlInfo());
00203         int appGateIndex = msg->getArrivalGate()->getIndex();
00204         int connId = controlInfo->getConnId();
00205 
00206         SimpleTCPConnection *conn = (SimpleTCPConnection*)findConnForApp(appGateIndex, connId);
00207 
00208         if (!conn)
00209         {
00210             conn = createConnection(appGateIndex, connId);
00211 
00212             // add into appConnMap here; it'll be added to connMap during processing
00213             // the OPEN command in SimpleTCPConnection's processAppCommand().
00214             AppConnKey key;
00215             key.appGateIndex = appGateIndex;
00216             key.connId = connId;
00217             tcpAppConnMap[key] = conn;
00218 
00219             tcpEV << "TCP connection created for " << msg << "\n";
00220         }
00221         bool ret = conn->processAppCommand(msg);
00222         if (!ret)
00223             removeConnection(conn);
00224     }
00225 
00226     if (ev.isGUI())
00227         updateDisplayString();
00228 }
00229 
00230 void SimpleTCP::setNodeEntry(SimpleNodeEntry* entry)
00231 {
00232     sad.nodeEntry = entry;
00233 }
00234 
00235 SimpleTCPConnection *SimpleTCP::createConnection(int appGateIndex, int connId)
00236 {
00237     return new SimpleTCPConnection(this, appGateIndex, connId);
00238 }
00239 
00240 void SimpleTCP::segmentArrivalWhileClosed(TCPSegment *tcpseg, IPvXAddress srcAddr, IPvXAddress destAddr)
00241 {
00242     SimpleTCPConnection *tmp = new SimpleTCPConnection();
00243     tmp->segmentArrivalWhileClosed(tcpseg, srcAddr, destAddr);
00244     delete tmp;
00245     delete tcpseg;
00246 }
00247 
00248 SimpleTCPConnection *SimpleTCPConnection::cloneListeningConnection()
00249 {
00250     SimpleTCPConnection *conn = new SimpleTCPConnection(tcpMain,appGateIndex,connId);
00251 
00252     // following code to be kept consistent with initConnection()
00253     const char *sendQueueClass = sendQueue->getClassName();
00254     conn->sendQueue = check_and_cast<TCPSendQueue *>(createOne(sendQueueClass));
00255     conn->sendQueue->setConnection(conn);
00256 
00257     const char *receiveQueueClass = receiveQueue->getClassName();
00258     conn->receiveQueue = check_and_cast<TCPReceiveQueue *>(createOne(receiveQueueClass));
00259     conn->receiveQueue->setConnection(conn);
00260 
00261     // create SACK retransmit queue
00262     rexmitQueue = new TCPSACKRexmitQueue();
00263     rexmitQueue->setConnection(this);
00264 
00265     const char *tcpAlgorithmClass = tcpAlgorithm->getClassName();
00266     conn->tcpAlgorithm = check_and_cast<TCPAlgorithm *>(createOne(tcpAlgorithmClass));
00267     conn->tcpAlgorithm->setConnection(conn);
00268 
00269     conn->state = conn->tcpAlgorithm->getStateVariables();
00270     configureStateVariables();
00271     conn->tcpAlgorithm->initialize();
00272 
00273     // put it into LISTEN, with our localAddr/localPort
00274     conn->state->active = false;
00275     conn->state->fork = true;
00276     conn->localAddr = localAddr;
00277     conn->localPort = localPort;
00278     FSM_Goto(conn->fsm, TCP_S_LISTEN);
00279 
00280     return conn;
00281 }
00282 
00283 
00284 void SimpleTCPConnection::sendRst(uint32 seq, IPvXAddress src, IPvXAddress dest, int srcPort, int destPort)
00285 {
00286     TCPSegment *tcpseg = createTCPSegment("RST");
00287 
00288     tcpseg->setSrcPort(srcPort);
00289     tcpseg->setDestPort(destPort);
00290 
00291     tcpseg->setRstBit(true);
00292     tcpseg->setSequenceNo(seq);
00293 
00294     // send it
00295     SimpleTCPConnection::sendToIP(tcpseg, src, dest);
00296 }
00297 
00298 void SimpleTCPConnection::sendRstAck(uint32 seq, uint32 ack, IPvXAddress src, IPvXAddress dest, int srcPort, int destPort)
00299 {
00300     TCPSegment *tcpseg = createTCPSegment("RST+ACK");
00301 
00302     tcpseg->setSrcPort(srcPort);
00303     tcpseg->setDestPort(destPort);
00304 
00305     tcpseg->setRstBit(true);
00306     tcpseg->setAckBit(true);
00307     tcpseg->setSequenceNo(seq);
00308     tcpseg->setAckNo(ack);
00309 
00310     // send it
00311     SimpleTCPConnection::sendToIP(tcpseg, src, dest);
00312 }
00313 
00314 void SimpleTCPConnection::sendToIP(TCPSegment *tcpseg)
00315 {
00316     StatisticsAndDelay& sad = dynamic_cast<SimpleTCP*>(tcpMain)->sad;
00317     // record seq (only if we do send data) and ackno
00318     if (sndNxtVector && tcpseg->getPayloadLength()!=0)
00319         sndNxtVector->record(tcpseg->getSequenceNo());
00320     if (sndAckVector)
00321         sndAckVector->record(tcpseg->getAckNo());
00322 
00323     // final touches on the segment before sending
00324     tcpseg->setSrcPort(localPort);
00325     tcpseg->setDestPort(remotePort);
00326     ASSERT(tcpseg->getHeaderLength() >= TCP_HEADER_OCTETS);     // TCP_HEADER_OCTETS = 20 (without options)
00327     ASSERT(tcpseg->getHeaderLength() <= TCP_MAX_HEADER_OCTETS); // TCP_MAX_HEADER_OCTETS = 60
00328 
00329     // add header byte length for the skipped IP header
00330     int ipHeaderBytes = 0;
00331     if (remoteAddr.isIPv6()) {
00332         ipHeaderBytes = IPv6_HEADER_BYTES;
00333     } else {
00334         ipHeaderBytes = IP_HEADER_BYTES;
00335     }
00336     tcpseg->setByteLength(tcpseg->getHeaderLength() +
00337                           tcpseg->getPayloadLength() + ipHeaderBytes);
00338 
00339     tcpEV << "Sending: ";
00340     printSegmentBrief(tcpseg);
00341 
00342     // TBD reuse next function for sending
00343 
00344 
00345     /* main modifications for SimpleTCP start here */
00346 
00347     const IPvXAddress& src = IPAddressResolver().addressOf(tcpMain->getParentModule());
00348     //const IPvXAddress& src = localAddr;
00349     const IPvXAddress& dest = remoteAddr;
00350 
00351     SimpleInfo* info = dynamic_cast<SimpleInfo*>(sad.globalNodeList->getPeerInfo(dest));
00352     sad.numSent++;
00353 
00354     if (info == NULL) {
00355         EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
00356            << "    No route to host " << dest
00357            << endl;
00358 
00359         delete tcpseg;
00360         sad.numDestUnavailableLost++;
00361         return;
00362     }
00363 
00364     SimpleNodeEntry* destEntry = info->getEntry();
00365 
00366     // calculate delay
00367     simtime_t totalDelay = 0;
00368     if (src != dest) {
00369         SimpleNodeEntry::SimpleDelay temp;
00370         if (sad.faultyDelay) {
00371             SimpleInfo* thisInfo = static_cast<SimpleInfo*>(sad.globalNodeList->getPeerInfo(src));
00372             temp = sad.nodeEntry->calcDelay(tcpseg, *destEntry,
00373                                         !(thisInfo->getNpsLayer() == 0 ||
00374                                           info->getNpsLayer() == 0)); //TODO
00375         } else {
00376             temp = sad.nodeEntry->calcDelay(tcpseg, *destEntry);
00377         }
00378         if (sad.useCoordinateBasedDelay == false) {
00379             totalDelay = sad.constantDelay;
00380         } else if (temp.second == false) {
00381             EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
00382                << "    Send queue full: packet " << tcpseg << " dropped"
00383                << endl;
00384             delete tcpseg;
00385             sad.numQueueLost++;
00386             return;
00387         } else {
00388             totalDelay = temp.first;
00389         }
00390     }
00391 
00392     SimpleInfo* thisInfo = dynamic_cast<SimpleInfo*>(sad.globalNodeList->getPeerInfo(src));
00393 
00394     if (!sad.globalNodeList->areNodeTypesConnected(thisInfo->getTypeID(), info->getTypeID())) {
00395         EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
00396                    << "    Partition " << thisInfo->getTypeID() << "->" << info->getTypeID()
00397                    << " is not connected"
00398                    << endl;
00399         delete tcpseg;
00400         sad.numPartitionLost++;
00401         return;
00402     }
00403 
00404     if (sad.jitter) {
00405         // jitter
00406         //totalDelay += truncnormal(0, SIMTIME_DBL(totalDelay) * jitter);
00407 
00408         //workaround (bug in truncnormal(): sometimes returns inf)
00409         double temp = truncnormal(0, SIMTIME_DBL(totalDelay) * sad.jitter);
00410         while (temp == INFINITY || temp != temp) { // reroll if temp is INF or NaN
00411             std::cerr << "\n******* SimpleTCPConnection: truncnormal() -> inf !!\n"
00412                       << std::endl;
00413             temp = truncnormal(0, SIMTIME_DBL(totalDelay) * sad.jitter);
00414         }
00415 
00416         totalDelay += temp;
00417     }
00418 
00419 
00420 
00421     EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
00422        << "    Packet " << tcpseg << " sent with delay = " << totalDelay
00423        << endl;
00424 
00425     //RECORD_STATS(globalStatistics->addStdDev("SimpleTCP: delay", totalDelay));
00426 
00427 
00428     /* main modifications for SimpleTCP end here */
00429 
00430     if (!remoteAddr.isIPv6())
00431     {
00432         // send over IPv4
00433         IPControlInfo *controlInfo = new IPControlInfo();
00434         controlInfo->setProtocol(IP_PROT_TCP);
00435         controlInfo->setSrcAddr(src.get4());
00436         controlInfo->setDestAddr(dest.get4());
00437         tcpseg->setControlInfo(controlInfo);
00438 
00439         tcpMain->sendDirect(tcpseg, totalDelay, 0, destEntry->getTcpIPv4Gate());
00440     }
00441     else
00442     {
00443         // send over IPv6
00444         IPv6ControlInfo *controlInfo = new IPv6ControlInfo();
00445         controlInfo->setProtocol(IP_PROT_TCP);
00446         controlInfo->setSrcAddr(src.get6());
00447         controlInfo->setDestAddr(dest.get6());
00448         tcpseg->setControlInfo(controlInfo);
00449 
00450         tcpMain->sendDirect(tcpseg, totalDelay, 0, destEntry->getTcpIPv6Gate());
00451     }
00452 }
00453 
00454 void SimpleTCPConnection::sendToIP(TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest)
00455 {
00456 
00457     /* main modifications for SimpleTCP start here */
00458     StatisticsAndDelay& sad = dynamic_cast<SimpleTCP*>(tcpMain)->sad;
00459 
00460     SimpleInfo* info = dynamic_cast<SimpleInfo*>(sad.globalNodeList->getPeerInfo(dest));
00461     sad.numSent++;
00462 
00463     if (info == NULL) {
00464         EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
00465            << "    No route to host " << dest
00466            << endl;
00467 
00468         delete tcpseg;
00469         sad.numDestUnavailableLost++;
00470         return;
00471     }
00472 
00473     SimpleNodeEntry* destEntry = info->getEntry();
00474 
00475     // calculate delay
00476     simtime_t totalDelay = 0;
00477     if (src != dest) {
00478         SimpleNodeEntry::SimpleDelay temp;
00479         if (sad.faultyDelay) {
00480             SimpleInfo* thisInfo = static_cast<SimpleInfo*>(sad.globalNodeList->getPeerInfo(src));
00481             temp = sad.nodeEntry->calcDelay(tcpseg, *destEntry,
00482                                         !(thisInfo->getNpsLayer() == 0 ||
00483                                           info->getNpsLayer() == 0)); //TODO
00484         } else {
00485             temp = sad.nodeEntry->calcDelay(tcpseg, *destEntry);
00486         }
00487         if (sad.useCoordinateBasedDelay == false) {
00488             totalDelay = sad.constantDelay;
00489         } else if (temp.second == false) {
00490             EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
00491                << "    Send queue full: packet " << tcpseg << " dropped"
00492                << endl;
00493             delete tcpseg;
00494             sad.numQueueLost++;
00495             return;
00496         } else {
00497             totalDelay = temp.first;
00498         }
00499     }
00500 
00501     SimpleInfo* thisInfo = dynamic_cast<SimpleInfo*>(sad.globalNodeList->getPeerInfo(src));
00502 
00503     if (!sad.globalNodeList->areNodeTypesConnected(thisInfo->getTypeID(), info->getTypeID())) {
00504         EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
00505                    << "    Partition " << thisInfo->getTypeID() << "->" << info->getTypeID()
00506                    << " is not connected"
00507                    << endl;
00508         delete tcpseg;
00509         sad.numPartitionLost++;
00510         return;
00511     }
00512 
00513     if (sad.jitter) {
00514         // jitter
00515         //totalDelay += truncnormal(0, SIMTIME_DBL(totalDelay) * jitter);
00516 
00517         //workaround (bug in truncnormal(): sometimes returns inf)
00518         double temp = truncnormal(0, SIMTIME_DBL(totalDelay) * sad.jitter);
00519         while (temp == INFINITY || temp != temp) { // reroll if temp is INF or NaN
00520             std::cerr << "\n******* SimpleTCPConnection: truncnormal() -> inf !!\n"
00521                       << std::endl;
00522             temp = truncnormal(0, SIMTIME_DBL(totalDelay) * sad.jitter);
00523         }
00524 
00525         totalDelay += temp;
00526     }
00527 
00528 
00529 
00530     EV << "[SimpleTCPConnection::sendToIP() @ " << src << "]\n"
00531        << "    Packet " << tcpseg << " sent with delay = " << totalDelay
00532        << endl;
00533 
00534     //RECORD_STATS(globalStatistics->addStdDev("SimpleTCP: delay", totalDelay));
00535 
00536 
00537     /* main modifications for SimpleTCP end here */
00538 
00539     tcpEV << "Sending: ";
00540     printSegmentBrief(tcpseg);
00541 
00542     if (!dest.isIPv6())
00543     {
00544         // send over IPv4
00545         IPControlInfo *controlInfo = new IPControlInfo();
00546         controlInfo->setProtocol(IP_PROT_TCP);
00547         controlInfo->setSrcAddr(src.get4());
00548         controlInfo->setDestAddr(dest.get4());
00549         tcpseg->setControlInfo(controlInfo);
00550 
00551         check_and_cast<TCP *>(simulation.getContextModule())->sendDirect(tcpseg, totalDelay, 0, destEntry->getTcpIPv4Gate());
00552     }
00553     else
00554     {
00555         // send over IPv6
00556         IPv6ControlInfo *controlInfo = new IPv6ControlInfo();
00557         controlInfo->setProtocol(IP_PROT_TCP);
00558         controlInfo->setSrcAddr(src.get6());
00559         controlInfo->setDestAddr(dest.get6());
00560         tcpseg->setControlInfo(controlInfo);
00561 
00562         check_and_cast<TCP *>(simulation.getContextModule())->sendDirect(tcpseg, totalDelay, 0, destEntry->getTcpIPv6Gate());
00563     }
00564 }