SCTPAssociationBase.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2005-2010 Irene Ruengeler
00003 // Copyright (C) 2009-2010 Thomas Dreibholz
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, see <http://www.gnu.org/licenses/>.
00017 //
00018 
00019 
00020 #include <string.h>
00021 #include <assert.h>
00022 #include "SCTP.h"
00023 #include "SCTPAssociation.h"
00024 #include "SCTPCommand_m.h"
00025 #include "IPControlInfo_m.h"
00026 #include "SCTPQueue.h"
00027 #include "SCTPAlgorithm.h"
00028 #include "IPv4InterfaceData.h"
00029 
00030 #include <sstream>
00031 
00032 
00033 SCTPPathVariables::SCTPPathVariables(const IPvXAddress& addr, SCTPAssociation* assoc)
00034 {
00035     InterfaceTableAccess interfaceTableAccess;
00036 
00037     association                  = assoc;
00038     remoteAddress                = addr;
00039     activePath                   = true;
00040     confirmed                    = false;
00041     primaryPathCandidate         = false;
00042     pathErrorCount               = 0;
00043     pathErrorThreshold       = assoc->getSctpMain()->par("pathMaxRetrans");
00044     if (!pathErrorThreshold) {
00045         pathErrorThreshold = PATH_MAX_RETRANS;
00046     }
00047     pathRto                      = assoc->getSctpMain()->par("rtoInitial");
00048     heartbeatTimeout             = pathRto;
00049     double interval              = (double)assoc->getSctpMain()->par("hbInterval");
00050     if (!interval) {
00051         interval = HB_INTERVAL;
00052     }
00053     heartbeatIntervalTimeout = pathRto+interval;
00054     srtt                         = pathRto;
00055     lastAckTime                  = 0;
00056     forceHb                      = false;
00057     partialBytesAcked            = 0;
00058     queuedBytes                  = 0;
00059     outstandingBytes             = 0;
00060 
00061     RoutingTableAccess routingTableAccess;
00062     const InterfaceEntry* rtie = routingTableAccess.get()->getInterfaceForDestAddr(remoteAddress.get4());
00063     if(rtie == NULL) {
00064         opp_error("No interface for remote address %s found!", remoteAddress.get4().str().c_str());
00065     }
00066     pmtu                         = rtie->getMTU();
00067     rttvar                       = 0.0;
00068 
00069     cwndTimeout                  = pathRto;
00070     cwnd                         = 0;
00071     ssthresh                     = 0;
00072     updateTime                   = 0.0;
00073     fastRecoveryExitPoint        = 0;
00074     fastRecoveryActive           = false;
00075 
00076     numberOfFastRetransmissions      = 0;
00077     numberOfTimerBasedRetransmissions = 0;
00078     numberOfHeartbeatsSent = 0;
00079     numberOfHeartbeatsRcvd = 0;
00080     numberOfHeartbeatAcksSent = 0;
00081     numberOfHeartbeatAcksRcvd = 0;
00082 
00083     char str[128];
00084     snprintf(str, sizeof(str), "HB_TIMER %d:%s",assoc->assocId,addr.str().c_str());
00085     HeartbeatTimer = new cMessage(str);
00086     snprintf(str, sizeof(str), "HB_INT_TIMER %d:%s",assoc->assocId,addr.str().c_str());
00087     HeartbeatIntervalTimer = new cMessage(str);
00088     snprintf(str, sizeof(str), "CWND_TIMER %d:%s",assoc->assocId,addr.str().c_str());
00089     CwndTimer = new cMessage(str);
00090     snprintf(str, sizeof(str), "RTX_TIMER %d:%s",assoc->assocId,addr.str().c_str());
00091     T3_RtxTimer = new cMessage(str);
00092     HeartbeatTimer->setContextPointer(association);
00093     HeartbeatIntervalTimer->setContextPointer(association);
00094     CwndTimer->setContextPointer(association);
00095     T3_RtxTimer->setContextPointer(association);
00096 
00097     snprintf(str, sizeof(str), "RTO %d:%s",assoc->assocId,addr.str().c_str());
00098     statisticsPathRTO = new cOutVector(str);
00099     snprintf(str, sizeof(str), "RTT %d:%s",assoc->assocId,addr.str().c_str());
00100     statisticsPathRTT = new cOutVector(str);
00101 
00102     snprintf(str, sizeof(str), "Slow Start Threshold %d:%s",assoc->assocId,addr.str().c_str());
00103     statisticsPathSSthresh = new cOutVector(str);
00104     snprintf(str, sizeof(str), "Congestion Window %d:%s",assoc->assocId,addr.str().c_str());
00105     statisticsPathCwnd = new cOutVector(str);
00106 
00107     snprintf(str, sizeof(str), "TSN Sent %d:%s",assoc->assocId,addr.str().c_str());
00108     pathTSN = new cOutVector(str);
00109     snprintf(str, sizeof(str), "TSN Received %d:%s",assoc->assocId,addr.str().c_str());
00110     pathRcvdTSN = new cOutVector(str);
00111 
00112     snprintf(str, sizeof(str), "HB Sent %d:%s",assoc->assocId,addr.str().c_str());
00113     pathHb = new cOutVector(str);
00114     snprintf(str, sizeof(str), "HB ACK Sent %d:%s",assoc->assocId,addr.str().c_str());
00115     pathHbAck = new cOutVector(str);
00116     snprintf(str, sizeof(str), "HB Received %d:%s",assoc->assocId,addr.str().c_str());
00117     pathRcvdHb = new cOutVector(str);
00118     snprintf(str, sizeof(str), "HB ACK Received %d:%s",assoc->assocId,addr.str().c_str());
00119     pathRcvdHbAck = new cOutVector(str);
00120 
00121 
00122 
00123     SCTPPathInfo* pinfo = new SCTPPathInfo("pinfo");
00124     pinfo->setRemoteAddress(addr);
00125     T3_RtxTimer->setControlInfo(pinfo);
00126     HeartbeatTimer->setControlInfo(pinfo->dup());
00127     HeartbeatIntervalTimer->setControlInfo(pinfo->dup());
00128     CwndTimer->setControlInfo(pinfo->dup());
00129 
00130 }
00131 
00132 SCTPPathVariables::~SCTPPathVariables()
00133 {
00134     statisticsPathSSthresh->record(0);
00135     statisticsPathCwnd->record(0);
00136     delete statisticsPathSSthresh;
00137     delete statisticsPathCwnd;
00138     statisticsPathRTO->record(0);
00139     statisticsPathRTT->record(0);
00140     delete statisticsPathRTO;
00141     delete statisticsPathRTT;
00142 
00143     delete pathTSN;
00144     delete pathRcvdTSN;
00145     delete pathHb;
00146     delete pathRcvdHb;
00147     delete pathHbAck;
00148     delete pathRcvdHbAck;
00149 
00150 }
00151 
00152 
00153 const IPvXAddress SCTPDataVariables::zeroAddress = IPvXAddress("0.0.0.0");
00154 
00155 SCTPDataVariables::SCTPDataVariables()
00156 {
00157     userData                     = NULL;
00158     ordered                      = true;
00159     len                          = 0;
00160     tsn                          = 0;
00161     sid                          = 0;
00162     ssn                          = 0;
00163     ppid                         = 0;
00164     gapReports                   = 0;
00165     enqueuingTime                = 0;
00166     sendTime                     = 0;
00167     ackTime                      = 0;
00168     expiryTime                   = 0;
00169     enqueuedInTransmissionQ      = false;
00170     hasBeenAcked                 = false;
00171     hasBeenReneged               = false;
00172     hasBeenAbandoned             = false;
00173     hasBeenFastRetransmitted     = false;
00174     countsAsOutstanding          = false;
00175     lastDestination              = NULL;
00176     nextDestination              = NULL;
00177     initialDestination           = NULL;
00178     numberOfTransmissions        = 0;
00179     numberOfRetransmissions      = 0;
00180     booksize                     = 0;
00181 }
00182 
00183 SCTPDataVariables::~SCTPDataVariables()
00184 {
00185 }
00186 
00187 SCTPStateVariables::SCTPStateVariables()
00188 {
00189     active                    = false;
00190     fork                          = false;
00191     initReceived              = false;
00192     cookieEchoReceived    = false;
00193     ackPointAdvanced          = false;
00194     swsAvoidanceInvoked   = false;
00195     firstChunkReceived    = false;
00196     probingIsAllowed          = false;
00197     zeroWindowProbing         = true;
00198     alwaysBundleSack          = true;
00199     fastRecoverySupported  = true;
00200     reactivatePrimaryPath  = false;
00201     newChunkReceived          = false;
00202     dataChunkReceived         = false;
00203     sackAllowed               = false;
00204     resetPending              = false;
00205     stopReceiving             = false;
00206     stopOldData               = false;
00207     stopSending               = false;
00208     inOut                         = false;
00209     queueUpdate               = false;
00210     firstDataSent             = false;
00211     peerWindowFull            = false;
00212     zeroWindow                = false;
00213     appSendAllowed            = true;
00214     noMoreOutstanding         = false;
00215     primaryPath               = NULL;
00216     lastDataSourceAddress  = IPvXAddress("0.0.0.0");
00217     shutdownChunk             = NULL;
00218     initChunk                 = NULL;
00219     cookieChunk               = NULL;
00220     sctpmsg                   = NULL;
00221     sctpMsg                   = NULL;
00222     bytesToRetransmit         = 0;
00223     initRexmitTimeout         = SCTP_TIMEOUT_INIT_REXMIT;
00224     localRwnd                 = SCTP_DEFAULT_ARWND;
00225     errorCount                = 0;
00226     initRetransCounter    = 0;
00227     nextTSN                   = 0;
00228     cTsnAck                   = 0;
00229     lastTsnAck                = 0;
00230     highestTsnReceived    = 0;
00231     highestTsnAcked       = 0;
00232     highestTsnStored          = 0;
00233     nextRSid                      = 0;
00234     ackState                      = 0;
00235     lastStreamScheduled   = 0;
00236     peerRwnd                      = 0;
00237     initialPeerRwnd       = 0;
00238     assocPmtu                 = 0;
00239     outstandingBytes          = 0;
00240     messagesToPush            = 0;
00241     pushMessagesLeft          = 0;
00242     numGaps                   = 0;
00243     msgNum                    = 0;
00244     bytesRcvd                 = 0;
00245     sendBuffer                = 0;
00246     queuedReceivedBytes   = 0;
00247     lastSendQueueAbated   = simTime();
00248     queuedMessages            = 0;
00249     queueLimit                = 0;
00250     probingTimeout            = 1;
00251     numRequests               = 0;
00252     numMsgsReq.resize(65536);
00253     for (unsigned int i = 0; i < 65536; i++) {
00254         numMsgsReq[i] = 0;
00255     }
00256     for (unsigned int i = 0; i < MAX_GAP_COUNT; i++) {
00257         gapStartList[i] = 0;
00258         gapStopList[i]   = 0;
00259     }
00260     for (unsigned int i = 0; i < 32; i++) {
00261         localTieTag[i] = 0;
00262         peerTieTag[i]   = 0;
00263     }
00264     count = 0;
00265 }
00266 
00267 SCTPStateVariables::~SCTPStateVariables()
00268 {
00269 }
00270 
00271 
00272 //
00273 // FSM framework, SCTP FSM
00274 //
00275 
00276 SCTPAssociation::SCTPAssociation(SCTP* _module, int32 _appGateIndex, int32 _assocId)
00277 {
00278     // ====== Initialize variables ===========================================
00279     sctpMain                            = _module;
00280     appGateIndex                        = _appGateIndex;
00281     assocId                             = _assocId;
00282     localPort                           = 0;
00283     remotePort                          = 0;
00284     localVTag                           = 0;
00285     peerVTag                            = 0;
00286     numberOfRemoteAddresses             = 0;
00287     inboundStreams                      = SCTP_DEFAULT_INBOUND_STREAMS;
00288     outboundStreams                     = SCTP_DEFAULT_OUTBOUND_STREAMS;
00289     // queues and algorithm will be created on active or passive open
00290     transmissionQ                       = NULL;
00291     retransmissionQ                     = NULL;
00292     sctpAlgorithm                       = NULL;
00293     state                               = NULL;
00294     sackPeriod                          = SACK_DELAY;
00295 /*
00296     totalCwndAdjustmentTime         = simTime();
00297     lastTotalSSthresh                   = ~0;
00298     lastTotalCwnd                       = ~0;*/
00299 
00300     cumTsnAck                           = NULL;
00301     sendQueue                           = NULL;
00302     numGapBlocks                        = NULL;
00303 
00304     qCounter.roomSumSendStreams = 0;
00305     qCounter.bookedSumSendStreams = 0;
00306     qCounter.roomSumRcvStreams      = 0;
00307     bytes.chunk                         = false;
00308     bytes.packet                        = false;
00309     bytes.bytesToSend                   = 0;
00310 
00311     sctpEV3 << "SCTPAssociationBase::SCTPAssociation(): new assocId="
00312               << assocId << endl;
00313 
00314     // ====== FSM ============================================================
00315     char fsmName[64];
00316     snprintf(fsmName, sizeof(fsmName), "fsm-%d", assocId);
00317     fsm = new cFSM();
00318     fsm->setName(fsmName);
00319     fsm->setState(SCTP_S_CLOSED);
00320 
00321 
00322     // ====== Path Info ======================================================
00323     SCTPPathInfo* pinfo = new SCTPPathInfo("pathInfo");
00324     pinfo->setRemoteAddress(IPvXAddress("0.0.0.0"));
00325 
00326     // ====== Timers =========================================================
00327     char timerName[128];
00328     snprintf(timerName, sizeof(timerName), "T1_INIT of Association %d", assocId);
00329     T1_InitTimer = new cMessage(timerName);
00330     snprintf(timerName, sizeof(timerName), "T2_SHUTDOWN of Association %d", assocId);
00331     T2_ShutdownTimer = new cMessage(timerName);
00332     snprintf(timerName, sizeof(timerName), "T5_SHUTDOWN_GUARD of Association %d", assocId);
00333     T5_ShutdownGuardTimer = new cMessage(timerName);
00334     snprintf(timerName, sizeof(timerName), "SACK_TIMER of Association %d", assocId);
00335     SackTimer = new cMessage(timerName);
00336 
00337     if (sctpMain->testTimeout > 0){
00338         StartTesting = new cMessage("StartTesting");
00339         StartTesting->setContextPointer(this);
00340         StartTesting->setControlInfo(pinfo->dup());
00341         scheduleTimeout(StartTesting, sctpMain->testTimeout);
00342     }
00343     T1_InitTimer->setContextPointer(this);
00344     T2_ShutdownTimer->setContextPointer(this);
00345     SackTimer->setContextPointer(this);
00346     T5_ShutdownGuardTimer->setContextPointer(this);
00347 
00348     T1_InitTimer->setControlInfo(pinfo);
00349     T2_ShutdownTimer->setControlInfo(pinfo->dup());
00350     SackTimer->setControlInfo(pinfo->dup());
00351     T5_ShutdownGuardTimer->setControlInfo(pinfo->dup());
00352 
00353     // ====== Output vectors =================================================
00354     char vectorName[128];
00355     snprintf(vectorName, sizeof(vectorName), "Advertised Receiver Window %d", assocId);
00356     advRwnd = new cOutVector(vectorName);
00357 
00358     // ====== Stream scheduling ==============================================
00359     ssModule = sctpMain->par("ssModule");
00360     switch (ssModule)
00361     {
00362         case ROUND_ROBIN:
00363             ssFunctions.ssInitStreams    = &SCTPAssociation::initStreams;
00364             ssFunctions.ssGetNextSid     = &SCTPAssociation::streamScheduler;
00365             ssFunctions.ssUsableStreams  = &SCTPAssociation::numUsableStreams;
00366             break;
00367     }
00368 }
00369 
00370 SCTPAssociation::~SCTPAssociation()
00371 {
00372     sctpEV3 << "Destructor SCTPAssociation" << endl;
00373 
00374     delete T1_InitTimer;
00375     delete T2_ShutdownTimer;
00376     delete T5_ShutdownGuardTimer;
00377     delete SackTimer;
00378 
00379     delete advRwnd;
00380     delete cumTsnAck;
00381     delete numGapBlocks;
00382     delete sendQueue;
00383 
00384 
00385     delete fsm;
00386     delete state;
00387     delete sctpAlgorithm;
00388 }
00389 
00390 bool SCTPAssociation::processTimer(cMessage *msg)
00391 {
00392     SCTPPathVariables* path = NULL;
00393 
00394     sctpEV3 << msg->getName() << " timer expired at "<<simulation.getSimTime()<<"\n";
00395 
00396     SCTPPathInfo* pinfo = check_and_cast<SCTPPathInfo*>(msg->getControlInfo());
00397     IPvXAddress addr = pinfo->getRemoteAddress();
00398 
00399     if (addr != IPvXAddress("0.0.0.0"))
00400         path = getPath(addr);
00401      // first do actions
00402     SCTPEventCode event;
00403     event = SCTP_E_IGNORE;
00404     if (msg==T1_InitTimer)
00405     {
00406         process_TIMEOUT_INIT_REXMIT(event);
00407     }
00408     else if (msg==SackTimer)
00409     {
00410     sctpEV3<<simulation.getSimTime()<<" delayed Sack: cTsnAck="<<state->cTsnAck<<" highestTsnReceived="<<state->highestTsnReceived<<" lastTsnReceived="<<state->lastTsnReceived<<" ackState="<<state->ackState<<" numGaps="<<state->numGaps<<"\n";
00411         sendSack();
00412     }
00413     else if (msg==T2_ShutdownTimer)
00414     {
00415         stopTimer(T2_ShutdownTimer);
00416         process_TIMEOUT_SHUTDOWN(event);
00417     }
00418     else if (msg==T5_ShutdownGuardTimer)
00419     {
00420         stopTimer(T5_ShutdownGuardTimer);
00421         delete state->shutdownChunk;
00422         sendIndicationToApp(SCTP_I_CONN_LOST);
00423         sendAbort();
00424         sctpMain->removeAssociation(this);
00425     }
00426     else if (path!=NULL && msg==path->HeartbeatIntervalTimer)
00427     {
00428         process_TIMEOUT_HEARTBEAT_INTERVAL(path, path->forceHb);
00429     }
00430     else if (path!=NULL && msg==path->HeartbeatTimer)
00431     {
00432         process_TIMEOUT_HEARTBEAT(path);
00433     }
00434     else if (path!=NULL && msg==path->T3_RtxTimer)
00435     {
00436         process_TIMEOUT_RTX(path);
00437     }
00438     else if (path!=NULL && msg==path->CwndTimer)
00439     {
00440         (this->*ccFunctions.ccUpdateAfterCwndTimeout)(path);
00441     }
00442     else if (strcmp(msg->getName(), "StartTesting")==0)
00443     {
00444         if (sctpMain->testing == false)
00445         {
00446             sctpMain->testing = true;
00447             sctpEV3<<"set testing to true\n";
00448         }
00449     }
00450     else
00451     {
00452         sctpAlgorithm->processTimer(msg, event);
00453     }
00454      // then state transitions
00455      return performStateTransition(event);
00456 }
00457 
00458 bool SCTPAssociation::processSCTPMessage(SCTPMessage*           sctpmsg,
00459                                                       const IPvXAddress& msgSrcAddr,
00460                                                       const IPvXAddress& msgDestAddr)
00461 {
00462     printConnBrief();
00463 
00464     localAddr  = msgDestAddr;
00465     localPort  = sctpmsg->getDestPort();
00466     remoteAddr = msgSrcAddr;
00467     remotePort = sctpmsg->getSrcPort();
00468 
00469     return process_RCV_Message(sctpmsg, msgSrcAddr, msgDestAddr);
00470 }
00471 
00472 SCTPEventCode SCTPAssociation::preanalyseAppCommandEvent(int32 commandCode)
00473 {
00474     switch (commandCode) {
00475     case SCTP_C_ASSOCIATE:           return SCTP_E_ASSOCIATE;
00476     case SCTP_C_OPEN_PASSIVE:        return SCTP_E_OPEN_PASSIVE;
00477     case SCTP_C_SEND:                return SCTP_E_SEND;
00478     case SCTP_C_CLOSE:               return SCTP_E_CLOSE;
00479     case SCTP_C_ABORT:               return SCTP_E_ABORT;
00480     case SCTP_C_RECEIVE:             return SCTP_E_RECEIVE;
00481     case SCTP_C_SEND_UNORDERED:      return SCTP_E_SEND;
00482     case SCTP_C_SEND_ORDERED:        return SCTP_E_SEND;
00483     case SCTP_C_PRIMARY:             return SCTP_E_PRIMARY;
00484     case SCTP_C_QUEUE_MSGS_LIMIT:    return SCTP_E_QUEUE_MSGS_LIMIT;
00485     case SCTP_C_QUEUE_BYTES_LIMIT:   return SCTP_E_QUEUE_BYTES_LIMIT;
00486     case SCTP_C_SHUTDOWN:            return SCTP_E_SHUTDOWN;
00487     case SCTP_C_NO_OUTSTANDING:      return SCTP_E_SEND_SHUTDOWN_ACK;
00488     default:
00489         sctpEV3<<"commandCode="<<commandCode<<"\n";
00490         opp_error("Unknown message kind in app command");
00491                       return (SCTPEventCode)0; // to satisfy compiler
00492     }
00493 }
00494 
00495 bool SCTPAssociation::processAppCommand(cPacket *msg)
00496 {
00497     printConnBrief();
00498 
00499     // first do actions
00500     SCTPCommand *sctpCommand = (SCTPCommand *)(msg->removeControlInfo());
00501     SCTPEventCode event = preanalyseAppCommandEvent(msg->getKind());
00502 
00503     sctpEV3 << "App command: " << eventName(event) << "\n";
00504     switch (event)
00505     {
00506         case SCTP_E_ASSOCIATE: process_ASSOCIATE(event, sctpCommand, msg); break;
00507         case SCTP_E_OPEN_PASSIVE: process_OPEN_PASSIVE(event, sctpCommand, msg); break;
00508         case SCTP_E_SEND: process_SEND(event, sctpCommand, msg); break;
00509         case SCTP_E_CLOSE: process_CLOSE(event); break;
00510         case SCTP_E_ABORT: process_ABORT(event); break;
00511         case SCTP_E_RECEIVE: process_RECEIVE_REQUEST(event, sctpCommand); break;
00512         case SCTP_E_PRIMARY: process_PRIMARY(event, sctpCommand); break;
00513         case SCTP_E_QUEUE_BYTES_LIMIT: process_QUEUE_BYTES_LIMIT(sctpCommand); break;
00514         case SCTP_E_QUEUE_MSGS_LIMIT:    process_QUEUE_MSGS_LIMIT(sctpCommand); break;
00515         case SCTP_E_SHUTDOWN: /*sendShutdown*/
00516         sctpEV3<<"SCTP_E_SHUTDOWN in state "<<stateName(fsm->getState())<<"\n";
00517             if (fsm->getState()==SCTP_S_SHUTDOWN_RECEIVED) {
00518             sctpEV3<<"send shutdown ack\n";
00519                 sendShutdownAck(remoteAddr);
00520                 }
00521             break;  //I.R.
00522         case SCTP_E_STOP_SENDING: break;
00523         case SCTP_E_SEND_SHUTDOWN_ACK:
00524                 /*if (fsm->getState()==SCTP_S_SHUTDOWN_RECEIVED && getOutstandingBytes()==0
00525                     && qCounter.roomSumSendStreams==0 && transmissionQ->getQueueSize()==0)
00526                 {
00527                     sendShutdownAck(state->primaryPathIndex);
00528                 }*/
00529                 break;
00530         default: opp_error("wrong event code");
00531     }
00532     delete sctpCommand;
00533     // then state transitions
00534     return performStateTransition(event);
00535 }
00536 
00537 
00538 bool SCTPAssociation::performStateTransition(const SCTPEventCode& event)
00539 {
00540     sctpEV3<<"performStateTransition\n";
00541     if (event==SCTP_E_IGNORE)   // e.g. discarded segment
00542     {
00543         ev << "Staying in state: " << stateName(fsm->getState()) << " (no FSM event)\n";
00544         return true;
00545     }
00546 
00547     // state machine
00548     int32 oldState = fsm->getState();
00549     switch (fsm->getState())
00550     {
00551         case SCTP_S_CLOSED:
00552             switch (event)
00553             {
00554                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00555                 case SCTP_E_OPEN_PASSIVE: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00556                 case SCTP_E_ASSOCIATE: FSM_Goto((*fsm), SCTP_S_COOKIE_WAIT); break;
00557                 case SCTP_E_RCV_INIT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00558                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00559                 case SCTP_E_RCV_VALID_COOKIE_ECHO: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break;
00560                     case SCTP_E_CLOSE: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00561                 default:;
00562             }
00563             break;
00564 
00565         case SCTP_S_COOKIE_WAIT:
00566             switch (event)
00567             {
00568                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00569                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00570                 case SCTP_E_RCV_INIT_ACK: FSM_Goto((*fsm), SCTP_S_COOKIE_ECHOED); break;
00571                 case SCTP_E_RCV_VALID_COOKIE_ECHO: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break;
00572                 default:;
00573             }
00574             break;
00575 
00576         case SCTP_S_COOKIE_ECHOED:
00577             switch (event)
00578             {
00579                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00580                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00581                 case SCTP_E_RCV_COOKIE_ACK:FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break;
00582                 default:;
00583             }
00584             break;
00585         case SCTP_S_ESTABLISHED:
00586             switch (event)
00587             {
00588                 case SCTP_E_SEND: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break;
00589                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00590                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00591                 case SCTP_E_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_PENDING);    break;
00592                 case SCTP_E_STOP_SENDING: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_PENDING); state->stopSending = true; state->lastTSN = state->nextTSN-1; break;    //I.R.
00593                 case SCTP_E_RCV_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_RECEIVED); break;
00594                 case SCTP_E_CLOSE: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00595                 default:;
00596             }
00597             break;
00598 
00599         case SCTP_S_SHUTDOWN_PENDING:
00600             switch (event)
00601             {
00602                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00603                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00604                 case SCTP_E_NO_MORE_OUTSTANDING: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_SENT); break;
00605                 case SCTP_E_RCV_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_RECEIVED); break;
00606                 case SCTP_E_RCV_SHUTDOWN_ACK: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00607                 default:;
00608             }
00609             break;
00610 
00611         case SCTP_S_SHUTDOWN_RECEIVED:
00612             switch (event)
00613             {
00614                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00615                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00616                 case SCTP_E_NO_MORE_OUTSTANDING:
00617                             FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT);
00618                     break;
00619                 case SCTP_E_SHUTDOWN: sendShutdownAck(remoteAddr); /*FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT);*/ break;
00620                 default:;
00621             }
00622             break;
00623 
00624         case SCTP_S_SHUTDOWN_SENT:
00625             switch (event)
00626             {
00627                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00628                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00629                 case SCTP_E_RCV_SHUTDOWN_ACK: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00630                 case SCTP_E_RCV_SHUTDOWN: sendShutdownAck(remoteAddr); FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT); break;
00631                 default:;
00632             }
00633             break;
00634 
00635         case SCTP_S_SHUTDOWN_ACK_SENT:
00636             switch (event)
00637             {
00638                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00639                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00640                 case SCTP_E_RCV_SHUTDOWN_COMPLETE:      FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00641                 default:;
00642             }
00643             break;
00644 
00645     }
00646 
00647     if (oldState!=fsm->getState())
00648     {
00649         ev << "Transition: " << stateName(oldState) << " --> " << stateName(fsm->getState()) << "    (event was: " << eventName(event) << ")\n";
00650         sctpEV3 << sctpMain->getName() << ": " << stateName(oldState) << " --> " << stateName(fsm->getState()) << "  (on " << eventName(event) << ")\n";
00651         stateEntered(fsm->getState());
00652     }
00653     else
00654     {
00655         ev<< "Staying in state: " << stateName(fsm->getState()) << " (event was: " << eventName(event) << ")\n";
00656     }
00657     if (event==SCTP_E_ABORT && oldState==fsm->getState() && fsm->getState()==SCTP_S_CLOSED)
00658         return true;
00659 
00660     if (oldState!=fsm->getState() && fsm->getState()==SCTP_S_CLOSED)
00661     {
00662         sctpEV3<<"return false because oldState="<<oldState<<" and new state is closed\n";
00663         return false;
00664     }
00665     else
00666         return true;
00667 }
00668 
00669 void SCTPAssociation::stateEntered(int32 status)
00670 {
00671     switch (status)
00672     {
00673         case SCTP_S_COOKIE_WAIT:
00674             break;
00675         case SCTP_S_ESTABLISHED:
00676         {
00677             sctpEV3 << "State ESTABLISHED entered" << endl;
00678             stopTimer(T1_InitTimer);
00679             if (state->initChunk) {
00680                 delete state->initChunk;
00681             }
00682             state->nagleEnabled                   = (bool)sctpMain->par("nagleEnabled");
00683             state->enableHeartbeats               = (bool)sctpMain->par("enableHeartbeats");
00684             state->numGapReports                  = sctpMain->par("numGapReports");
00685             state->maxBurst                       = (uint32)sctpMain->par("maxBurst");
00686                 state->header = 0;
00687             state->swsLimit                      = (uint32)sctpMain->par("swsLimit");
00688             state->fastRecoverySupported         = (bool)sctpMain->par("fastRecoverySupported");
00689             state->reactivatePrimaryPath         = (bool)sctpMain->par("reactivatePrimaryPath");
00690             sackPeriod                           = (double)sctpMain->par("sackPeriod");
00691             sackFrequency                        = sctpMain->par("sackFrequency");
00692             SCTP::AssocStat stat;
00693             stat.assocId                         = assocId;
00694             stat.start                           = simulation.getSimTime();
00695             stat.stop                            = 0;
00696             stat.rcvdBytes                       = 0;
00697             stat.ackedBytes                      = 0;
00698             stat.sentBytes                       = 0;
00699             stat.transmittedBytes                = 0;
00700             stat.numFastRtx                      = 0;
00701             stat.numT3Rtx                        = 0;
00702             stat.numDups                         = 0;
00703             stat.numPathFailures                 = 0;
00704             stat.numForwardTsn                   = 0;
00705             stat.lifeTime                        = 0;
00706             stat.throughput                      = 0;
00707             sctpMain->assocStatMap[stat.assocId] = stat;
00708             ccModule = sctpMain->par("ccModule");
00709             switch (ccModule)
00710             {
00711                 case RFC4960:
00712                 {
00713                     ccFunctions.ccInitParams                 = &SCTPAssociation::initCCParameters;
00714                     ccFunctions.ccUpdateAfterSack            = &SCTPAssociation::cwndUpdateAfterSack;
00715                     ccFunctions.ccUpdateAfterCwndTimeout     = &SCTPAssociation::cwndUpdateAfterCwndTimeout;
00716                     ccFunctions.ccUpdateAfterRtxTimeout      = &SCTPAssociation::cwndUpdateAfterRtxTimeout;
00717                     ccFunctions.ccUpdateMaxBurst             = &SCTPAssociation::cwndUpdateMaxBurst;
00718                     ccFunctions.ccUpdateBytesAcked           = &SCTPAssociation::cwndUpdateBytesAcked;
00719                     break;
00720                 }
00721             }
00722             pmStartPathManagement();
00723             state->sendQueueLimit = (uint32)sctpMain->par("sendQueueLimit");
00724             sendEstabIndicationToApp();
00725             char str[128];
00726             snprintf(str, sizeof(str), "Cumulated TSN Ack of Association %d", assocId);
00727             cumTsnAck = new cOutVector(str);
00728             snprintf(str, sizeof(str), "Number of Gap Blocks in Last SACK of Association %d", assocId);
00729             numGapBlocks = new cOutVector(str);
00730             snprintf(str, sizeof(str), "SendQueue of Association %d", assocId);
00731             sendQueue = new cOutVector(str);
00732             state->sendQueueLimit = (uint32)sctpMain->par("sendQueueLimit");
00733             SCTP::VTagPair vtagPair;
00734             vtagPair.peerVTag     = peerVTag;
00735             vtagPair.localVTag  = localVTag;
00736             vtagPair.localPort  = localPort;
00737             vtagPair.remotePort = remotePort;
00738             sctpMain->sctpVTagMap[assocId] = vtagPair;
00739             break;
00740         }
00741         case SCTP_S_CLOSED:
00742         {
00743             sendIndicationToApp(SCTP_I_CLOSED);
00744             break;
00745         }
00746         case SCTP_S_SHUTDOWN_PENDING:
00747         {
00748             if (getOutstandingBytes()==0 && transmissionQ->getQueueSize()==0 && qCounter.roomSumSendStreams==0)
00749                 sendShutdown();
00750             break;
00751         }
00752         case SCTP_S_SHUTDOWN_RECEIVED:
00753         {
00754             sctpEV3 << "Entered state SHUTDOWN_RECEIVED, osb=" << getOutstandingBytes()
00755                       << ", transQ=" << transmissionQ->getQueueSize()
00756                       << ", scount=" << qCounter.roomSumSendStreams << endl;
00757             if (getOutstandingBytes()==0 && transmissionQ->getQueueSize()==0 && qCounter.roomSumSendStreams==0) {
00758                 sendShutdownAck(remoteAddr);
00759             }
00760             else {
00761                 sendOnAllPaths(state->getPrimaryPath());
00762             }
00763             break;
00764         }
00765     }
00766 }
00767 
00768 void SCTPAssociation::removePath()
00769 {
00770     SCTPPathMap::iterator pathIterator;
00771     while((pathIterator = sctpPathMap.begin()) != sctpPathMap.end())
00772     {
00773         SCTPPathVariables* path = pathIterator->second;
00774         sctpEV3 << getFullPath() << " remove path " << path->remoteAddress << endl;
00775         stopTimer(path->HeartbeatTimer);
00776         delete path->HeartbeatTimer;
00777         stopTimer(path->HeartbeatIntervalTimer);
00778         sctpEV3 << "delete timer " << path->HeartbeatIntervalTimer->getName() << endl;
00779         delete path->HeartbeatIntervalTimer;
00780         stopTimer(path->T3_RtxTimer);
00781         delete path->T3_RtxTimer;
00782         stopTimer(path->CwndTimer);
00783         delete path->CwndTimer;
00784         delete path;
00785         sctpPathMap.erase(pathIterator);
00786     }
00787 }