|
INET Framework for OMNeT++/OMNEST
|
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 }