#include <SCTPAssociation.h>
typedef std::map<IPvXAddress,SCTPPathVariables*> SCTPAssociation::SCTPPathMap [protected] |
typedef std::map<IPvXAddress, uint32> SCTPAssociation::CounterMap [protected] |
typedef struct SCTPAssociation::counter SCTPAssociation::QueueCounter [protected] |
typedef std::map<uint32, SCTPSendStream*> SCTPAssociation::SCTPSendStreamMap [protected] |
typedef std::map<uint32, SCTPReceiveStream*> SCTPAssociation::SCTPReceiveStreamMap [protected] |
typedef struct SCTPAssociation::calcBytesToSend SCTPAssociation::BytesToBeSent [protected] |
typedef struct SCTPAssociation::congestionControlFunctions SCTPAssociation::CCFunctions [protected] |
typedef struct SCTPAssociation::streamSchedulingFunctions SCTPAssociation::SSFunctions [protected] |
SCTPAssociation::SCTPAssociation | ( | SCTP * | mod, | |
int32 | appGateIndex, | |||
int32 | assocId | |||
) |
Constructor.
Referenced by cloneAssociation().
00231 { 00232 sctpMain = _mod; 00233 appGateIndex = _appGateIndex; 00234 assocId = _assocId; 00235 00236 ev<<"SCTPAssociationBase:SCTPAssociation new assocId="<<assocId<<"\n"; 00237 00238 localPort = remotePort = 0; 00239 localVTag = 0; 00240 peerVTag = 0; 00241 numberOfRemoteAddresses=0; 00242 char fsmname[24]; 00243 sprintf(fsmname, "fsm-%d", assocId); 00244 fsm = new cFSM(); 00245 fsm->setName(fsmname); 00246 fsm->setState(SCTP_S_CLOSED); 00247 inboundStreams = SCTP_DEFAULT_INBOUND_STREAMS; 00248 outboundStreams = SCTP_DEFAULT_OUTBOUND_STREAMS; 00249 // queues and algorithm will be created on active or passive open 00250 transmissionQ = NULL; 00251 retransmissionQ = NULL; 00252 sctpAlgorithm = NULL; 00253 state = NULL; 00254 SCTPPathInfo* pinfo = new SCTPPathInfo(); 00255 pinfo->setRemoteAddress(IPvXAddress("0.0.0.0")); 00256 char timername[70]; 00257 sprintf(timername, "T1_INIT of assoc %d", assocId); 00258 T1_InitTimer = new cMessage(timername); 00259 sprintf(timername, "T2_SHUTDOWN of assoc %d", assocId); 00260 T2_ShutdownTimer = new cMessage(timername); 00261 sprintf(timername, "T5_SHUTDOWN_GUARD of assoc %d", assocId); 00262 T5_ShutdownGuardTimer = new cMessage(timername); 00263 sprintf(timername, "SACK_TIMER of assoc %d", assocId); 00264 SackTimer = new cMessage(timername); 00265 00266 if (sctpMain->testTimeout>0) 00267 { 00268 StartTesting = new cMessage("StartTesting"); 00269 StartTesting->setContextPointer(this); 00270 StartTesting->setControlInfo(pinfo->dup()); 00271 scheduleTimeout(StartTesting, sctpMain->testTimeout); 00272 } 00273 sackPeriod = SACK_DELAY; 00274 T1_InitTimer->setContextPointer(this); 00275 T2_ShutdownTimer->setContextPointer(this); 00276 SackTimer->setContextPointer(this); 00277 T5_ShutdownGuardTimer->setContextPointer(this); 00278 00279 T1_InitTimer->setControlInfo(pinfo); 00280 T2_ShutdownTimer->setControlInfo(pinfo->dup()); 00281 SackTimer->setControlInfo(pinfo->dup()); 00282 T5_ShutdownGuardTimer->setControlInfo(pinfo->dup()); 00283 advRwnd = NULL; 00284 quBytes = NULL; 00285 cumTsnAck = NULL; 00286 sendQueue = NULL; 00287 qCounter.roomSumSendStreams = 0; 00288 qCounter.bookedSumSendStreams = 0; 00289 qCounter.roomSumRcvStreams = 0; 00290 bytes.chunk = false; 00291 bytes.packet = false; 00292 bytes.bytesToSend = 0; 00293 advRwnd = new cOutVector(); 00294 sprintf(timername, "Advertised Receiver Window of assoc %d", assocId); 00295 advRwnd->setName(timername); 00296 quBytes = new cOutVector(); 00297 sprintf(timername, "Queued Bytes of assoc %d", assocId); 00298 quBytes->setName(timername); 00299 ssModule = sctpMain->par("ssModule"); 00300 switch (ssModule) 00301 { 00302 case ROUND_ROBIN: 00303 { 00304 ssFunctions.ssInitStreams = &SCTPAssociation::initStreams; 00305 ssFunctions.ssGetNextSid = &SCTPAssociation::streamScheduler; 00306 ssFunctions.ssUsableStreams = &SCTPAssociation::numUsableStreams; 00307 } 00308 } 00309 }
SCTPAssociation::~SCTPAssociation | ( | ) |
Destructor.
00312 { 00313 delete T1_InitTimer; 00314 delete T2_ShutdownTimer; 00315 delete T5_ShutdownGuardTimer; 00316 delete SackTimer; 00317 delete fsm; 00318 delete advRwnd; 00319 delete quBytes; 00320 delete cumTsnAck; 00321 delete sendQueue; 00322 }
void SCTPAssociation::sendAll | ( | IPvXAddress | pathId | ) |
Utility: Send data from sendQueue, at most maxNumBytes (-1 means no limit). If fullSegments is set, don't send segments smaller than MSS (needed for Nagle). Returns true if some data was actually sent.
Referenced by process_ABORT(), process_CLOSE(), process_RCV_Message(), process_TIMEOUT_RTX(), SCTPAlg::sendCommandInvoked(), and sendShutdownAck().
01038 { 01039 SCTPSackChunk* sackChunk=NULL; 01040 uint32 chunksAdded=0,totalChunksSent=0,totalPacketsSent=0; 01041 uint32 nextSsn=0, osb=0; 01042 bool headerCreated=false, forwPresent = false, firstTime=false; 01043 IPvXAddress dpi, newDpi, pd; 01044 int32 dataChunksAdded=0; 01045 SCTPPathVariables* pathVar; 01046 SCTPDataChunk* chunkPtr=NULL; 01047 SCTPMessage* sctpmsg=NULL; 01048 SCTPDataMsg* datMsg; 01049 SCTPDataVariables *chunk=NULL, *datVar=NULL; 01050 bool authAdded = false; 01051 bool sendBeforeRtx = false; 01052 bool rtxActive = false; 01053 bool packetFull = false; 01054 bool probing = false; 01055 bool sendOneMorePacket = false; 01056 int32 tcount = 0, rtcount = 0, scount = 0, bcount = 0, bytesToSend = 0; 01057 sctpEV3<<"sendAll: pathId="<<pathId<<"\n"; 01058 printSctpPathMap(); 01059 if (pathId == IPvXAddress("0.0.0.0")) 01060 pd = state->primaryPathIndex; 01061 else 01062 pd = pathId; 01063 newDpi = pd; 01064 sctpEV3<<"newDpi set to "<<newDpi<<" dpi="<<dpi<<"\n"; 01065 CounterMap::iterator tq=qCounter.roomTransQ.find(pd); 01066 if (tq != qCounter.roomTransQ.end()) 01067 tcount = tq->second; 01068 else 01069 tcount = 0; 01070 CounterMap::iterator rtq=qCounter.roomRetransQ.find(pd); 01071 if (rtq != qCounter.roomRetransQ.end()) 01072 rtcount = rtq->second; 01073 else 01074 rtcount = 0; 01075 scount = qCounter.roomSumSendStreams; 01076 bcount = qCounter.bookedSumSendStreams; 01077 sctpEV3<<"\nsend all on "<<pd<<": tcount="<<tcount<<" scount="<<scount<<" rtcount="<<rtcount<<" nextTsn="<<state->nextTSN<</*" numChunksAllowed="<<state->numChunksAllowed<<*/"\n"; 01078 if (!state->stopSending) //for M3UA 01079 { 01080 if (tcount>0) 01081 { 01082 rtxActive = true; 01083 dpi = pd; 01084 sctpEV3<<"dpi=pd="<<dpi<<"\n"; 01085 } 01086 01087 if (tcount == 0 && scount == 0) 01088 { 01089 01090 sctpEV3<<"No chunk available!\n"; 01091 bytesToSend = 0; 01092 bytes.bytesToSend = 0; 01093 bytes.packet = false; 01094 bytes.chunk = false; 01095 dpi = pathId; 01096 sctpEV3<<"dpi=pathId="<<dpi<<"\n"; 01097 } 01098 else 01099 { 01100 if (tcount==0) 01101 { 01102 dpi = state->primaryPathIndex; 01103 sctpEV3<<"dpi=primary="<<dpi<<"\n"; 01104 firstTime=true; 01105 } 01106 if (!(state->resetPending && firstTime)) 01107 bytesAllowedToSend(dpi); 01108 newDpi = dpi; 01109 sctpEV3<<"newDpi set to "<<newDpi<<" dpi="<<dpi<<"\n"; 01110 } 01111 01112 if (newDpi==IPvXAddress("0.0.0.0")) 01113 opp_error("newDpi unspecified"); 01114 if (bytesToSend < 0) //24.11.2006 01115 bytesToSend=0; 01116 01117 bytesToSend = bytes.bytesToSend; 01118 01119 pathVar=getPath(dpi); 01120 01121 sctpEV3<<"after bytesAllowedToSend: bytesToSend="<<bytesToSend<<", packet="<<bytes.packet<<", chunk="<<bytes.chunk<<"\n"; 01122 if (bytes.chunk && (rtcount==0 || tcount>0)) 01123 probing = true; 01124 /* schedule sending of SACKs at once, when we have fragments to report */ 01125 if ((state->numGaps > 0 || state->dupList.size() > 0) && state->sackAllowed) 01126 { 01127 sctpEV3<<"Gaps present ==> ackState = "<<sackFrequency<<"\n"; 01128 state->ackState = sackFrequency; 01129 } 01130 if (state->ackState < sackFrequency && bytesToSend == 0 && bytes.chunk==false && bytes.packet==false && forwPresent == false) 01131 { 01132 sctpEV3<<"sendAll: nothing to send...chunk pointer is NULL...BYE...\n"; 01133 return; 01134 } 01135 01136 01137 sctpEV3<<"sendAll::bytesToSend="<<bytesToSend<<" osb="<<pathVar->outstandingBytes<<" cwnd="<<pathVar->cwnd<<" arwnd="<<state->peerRwnd<<"\n"; 01138 osb = pathVar->outstandingBytes; 01139 01140 if ((int32)pathVar->outstandingBytes<0) 01141 opp_error("util %d ,tsna=%d",__LINE__, state->cTsnAck); 01142 01143 } 01144 else 01145 dpi = pd; 01146 01147 sctpEV3<<"ackState="<<state->ackState<<" Sacktimer="<<SackTimer->isScheduled()<<"\n"; 01148 if (state->ackState >= sackFrequency || (SackTimer->isScheduled() && (state->alwaysBundleSack == true || pathId == dpi)) ) 01149 { 01150 sctpmsg = new SCTPMessage(); 01151 sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); 01152 01153 sctpEV3<<"SCTPAssociationUtil:sendAll localPort="<<localPort<<" remotePort="<<remotePort<<"\n"; 01154 01155 /*build a SACK chunk....*/ 01156 headerCreated = true; 01157 sackChunk = createSack(); 01158 01159 if (dpi!=remoteAddr) 01160 dpi = remoteAddr; 01161 01162 sctpEV3<<"SACK: dpi="<<dpi<<"\n"; 01163 01164 /* ...and add a SACK to the packet... */ 01165 01166 chunksAdded++; 01167 totalChunksSent++; 01168 sctpmsg->addChunk(sackChunk); 01169 01170 if (tcount==0 && bytesToSend>0 && state->nagleEnabled && state->peerRwnd < pathVar->pmtu && pathVar->outstandingBytes > 0) 01171 { 01172 // Test whether a full packet can be filled 01173 sctpEV3<<" peerRwnd="<<state->peerRwnd<<" bytesToSend="<<bytesToSend<<" nextTSN="<<state->nextTSN<<"\n"; 01174 SCTPDataMsg *datMsg = peekOutboundDataMsg(); 01175 uint32 ums = datMsg->getBooksize(); 01176 uint32 num = (uint32)((pathVar->pmtu-sctpmsg->getByteLength()-20)/(ums+SCTP_DATA_CHUNK_LENGTH)); 01177 if (num*ums>state->peerRwnd) 01178 bytesToSend = 0; 01179 else 01180 bytesToSend = num * ums; 01181 } 01182 sctpEV3<<"sendAll: appended "<<sackChunk->getBitLength()/8<<" bytes SACK chunk, msg length now "<<sctpmsg->getBitLength()/8<<"\n"; 01183 01184 state->ackState = 0; 01185 /* stop SACK timer if it is running... */ 01186 stopTimer(SackTimer); 01187 sctpAlgorithm->sackSent(); 01188 state->sackAllowed = false; 01189 } 01190 else 01191 01192 { 01193 if (tcount==0 && bytesToSend>0 && state->nagleEnabled && state->peerRwnd < pathVar->pmtu && pathVar->outstandingBytes > 0) 01194 { 01195 // Test whether a full packet can be filled 01196 sctpEV3<<" peerRwnd="<<state->peerRwnd<<" bytesToSend="<<bytesToSend<<" nextTSN="<<state->nextTSN<<"\n"; 01197 SCTPDataMsg *datMsg = peekOutboundDataMsg(); 01198 uint32 ums = datMsg->getBooksize(); 01199 uint32 num = (uint32)((pathVar->pmtu-32)/(ums+SCTP_DATA_CHUNK_LENGTH)); 01200 if (num*ums>state->peerRwnd) 01201 bytesToSend = 0; 01202 else 01203 bytesToSend = num * ums; 01204 } 01205 if (bytesToSend > 0 || bytes.chunk || bytes.packet || (bytes.chunk && probing)) 01206 { 01207 if (tcount>0 || scount>0 && (!(state->nagleEnabled && osb>0)||(uint32)scount>=pathVar->pmtu-32 )) 01208 { 01209 sctpmsg = new SCTPMessage(); 01210 headerCreated=true; 01211 sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); 01212 } 01213 } 01214 else 01215 { 01216 sctpEV3<<"Logic Error in sendAll: no header created....???\n"; 01217 01218 } 01219 } 01220 01221 while ((bytesToSend > 0 || bytes.chunk || bytes.packet ) && !(state->resetPending && firstTime) && headerCreated && !state->stopSending) 01222 { 01223 datVar = NULL; 01224 datMsg = NULL; 01225 if (tq->second > 0) //take the chunks out of the transmissionQ first 01226 { 01227 sctpEV3<<tq->second<<" bytes are in the transQ\n"; 01228 datVar=getOutboundDataChunk(dpi, pathVar->pmtu-sctpmsg->getBitLength()/8 -20); 01229 sctpEV3<<"sendAll::sctpmsg->length="<<sctpmsg->getBitLength()/8<<" length datVar="<<pathVar->pmtu-sctpmsg->getBitLength()/8 -20<<"\n"; 01230 if (datVar != NULL) 01231 { 01232 datVar->numberOfRetransmissions++; 01233 if (datVar->hasBeenAcked==false) 01234 { 01235 datVar->countsAsOutstanding = true; 01236 datVar->hasBeenRemoved = false; 01237 getPath(datVar->nextDestination)->outstandingBytes += (datVar->booksize); 01238 sctpEV3<<"osb="<<getPath(datVar->nextDestination)->outstandingBytes<<"\n"; 01239 CounterMap::iterator i=qCounter.roomRetransQ.find(getPath(datVar->lastDestination)->remoteAddress); 01240 i->second += ADD_PADDING(datVar->booksize+SCTP_DATA_CHUNK_LENGTH); 01241 } 01242 } 01243 else 01244 { 01245 sctpEV3<<"datVar=NULL -> packetFull\n"; 01246 packetFull = true; 01247 } 01248 } 01249 else if (scount>0 && dpi==state->primaryPathIndex) 01250 { 01251 sctpEV3<<"scount="<<scount<<", nagle="<<state->nagleEnabled<<", osb="<<osb<<", mtu="<<pathVar->pmtu-32<<"\n"; 01252 if (state->nagleEnabled && osb>0 && (uint32)scount<pathVar->pmtu-32) 01253 { 01254 scount = 0; 01255 break; 01256 } 01257 datMsg=dequeueOutboundDataMsg(pathVar->pmtu-sctpmsg->getBitLength()/8 -20); 01258 sctpEV3<<"sendAll::sctpmsg->length="<<sctpmsg->getBitLength()/8<<" length datMsg="<<pathVar->pmtu-sctpmsg->getBitLength()/8 -20<<"\n"; 01259 if (datMsg) 01260 { 01261 state->queuedMessages--; 01262 if (state->queueLimit>0 && state->queuedMessages < state->queueLimit && state->queueUpdate==false) 01263 { 01264 sendIndicationToApp(SCTP_I_SEND_MSG); 01265 state->queueUpdate = true; 01266 sctpEV3 << "\nQueue has to be filled! Queued Messages = "<<state->queuedMessages<<"\n"; 01267 } 01268 datVar=new SCTPDataVariables(); 01269 datVar->enqueuingTime = datMsg->getEnqueuingTime(); 01270 datVar->expiryTime = datMsg->getExpiryTime(); 01271 datVar->ppid = datMsg->getPpid(); 01272 datMsg->setInitialDestination(state->primaryPathIndex);//I.R.always send on primaryPath 01273 datVar->initialDestination = datMsg->getInitialDestination(); 01274 dpi = datVar->initialDestination; //I.R. 23.10.07 01275 sctpEV3<<"initialDestination="<<datVar->initialDestination<<": data will be sent to "<<dpi<<"\n"; 01276 // datVar->len just data 01277 datVar->len = datMsg->getBitLength(); 01278 datVar->sid = datMsg->getSid(); 01279 datVar->allowedNoRetransmissions = datMsg->getRtx(); 01280 datVar->booksize = datMsg->getBooksize(); 01281 SCTPSendStreamMap::iterator iter=this->sendStreams.find(datMsg->getSid()); 01282 SCTPSendStream* stream=iter->second; 01283 nextSsn = stream->getNextStreamSeqNum(); 01284 datVar->userData = datMsg->decapsulate(); 01285 if (datMsg->getOrdered()) 01286 { 01287 datVar->ssn=nextSsn++; 01288 datVar->ordered = true; 01289 if (nextSsn > 65535) 01290 stream->setNextStreamSeqNum(0); 01291 else 01292 stream->setNextStreamSeqNum(nextSsn); 01293 } 01294 else 01295 { 01296 datVar->ssn=0; 01297 datVar->ordered = false; 01298 } 01299 firstTime=true; 01300 delete datMsg; 01301 01302 sctpEV3<<"chunk "<<datVar<<" dequeued from StreamQ "<<datVar->sid<<" tsn="<<datVar->tsn<<" bytes now "<<qCounter.roomSumSendStreams<<"\n"; 01303 } 01304 else 01305 { 01306 if (headerCreated==true) 01307 { 01308 if (chunksAdded==0) 01309 { 01310 delete sctpmsg; 01311 return; 01312 } 01313 else 01314 { 01315 packetFull = true; 01316 sctpEV3<<"packetFull: msg length = "<<sctpmsg->getBitLength()/8+20<<"\n"; 01317 datVar=NULL; 01318 } 01319 } 01320 } 01321 } 01322 chunk=datVar; 01323 if (chunk!=NULL) 01324 { 01325 if (chunk->tsn == 0) 01326 { 01327 chunk->tsn = state->nextTSN; 01328 sctpEV3<<"Set TSN="<<chunk->tsn<<" sid="<<chunk->sid<<", ssn="<<chunk->ssn<<"\n"; 01329 state->nextTSN++; 01330 } 01331 pathVar->pathTSN->record(chunk->tsn); 01332 SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId); 01333 iter->second.transmittedBytes+=chunk->len/8; 01334 /* only if it is a first time send event, store the chunk also in the retransmission queue */ 01335 chunk->countsAsOutstanding = true; 01336 chunk->hasBeenRemoved = false; 01337 chunk->sendTime = simulation.getSimTime(); //I.R. to send Fast RTX just once a RTT 01338 if (chunk->numberOfTransmissions == 0) 01339 { 01340 chunk->lastDestination = state->primaryPathIndex; 01341 sctpEV3<<simulation.getSimTime()<<" firstTime, TSN "<<chunk->tsn<<": lastDestination set to "<<chunk->lastDestination<<"\n"; 01342 if (chunk->lastDestination==IPvXAddress("0.0.0.0")) 01343 opp_error("primaryPathIndex unspecified"); 01344 if (!state->firstDataSent) 01345 state->firstDataSent=true; 01346 sctpEV3<<"insert in retransmissionQ tsn="<<chunk->tsn<<"\n"; 01347 if(!retransmissionQ->checkAndInsertVar(chunk->tsn, chunk)) 01348 { 01349 sctpEV3<<"Cannot add message/chunk retransmission Q buffer (tsn="<<chunk->tsn<<")...terminating!\n"; 01350 } 01351 else 01352 { 01353 sctpEV3<<"size of retransmissionQ="<<retransmissionQ->getQueueSize()<<"\n"; 01354 chunk->hasBeenAcked = false; 01355 pathVar->outstandingBytes+=chunk->booksize; 01356 sctpEV3<<"osb="<<pathVar->outstandingBytes<<"\n"; 01357 CounterMap::iterator q=qCounter.roomRetransQ.find(dpi); 01358 q->second+= ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH); 01359 } 01360 } 01361 else 01362 sctpEV3<<"numberOfTransmissions="<<chunk->numberOfTransmissions<<"\n"; 01363 01364 /* chunk is already in the retransmissionQ */ 01365 chunk->numberOfTransmissions++; 01366 01367 chunk->gapReports = 0; 01368 chunk->hasBeenFastRetransmitted = false; 01369 sctpEV3<<"sendAll(): adding new outbound data chunk to packet (tsn="<<chunk->tsn<<")...!!!\n"; 01370 01371 chunkPtr = transformDataChunk(chunk); 01372 01373 /* update counters */ 01374 totalChunksSent++; 01375 chunksAdded++; 01376 dataChunksAdded++; 01377 sctpmsg->addChunk(chunkPtr); 01378 01379 if (chunk->booksize > state->peerRwnd) 01380 { 01381 state->peerRwnd = 0; 01382 bytesToSend = 0; 01383 bytes.packet = false; 01384 packetFull = true; 01385 } 01386 else 01387 { 01388 01389 state->peerRwnd-=chunk->booksize; 01390 if (bytes.chunk==false && bytes.packet==false) 01391 bytesToSend -= chunk->booksize; 01392 else if (bytes.chunk) 01393 bytes.chunk = false; 01394 else if (bytes.packet && packetFull) 01395 bytes.packet = false; 01396 } 01397 01398 if (bytesToSend <= 0) 01399 { 01400 if (!packetFull && qCounter.roomSumSendStreams>pathVar->pmtu-32) 01401 { 01402 sendOneMorePacket = true; 01403 bytes.packet = true; 01404 sctpEV3<<"one more packet allowed\n"; 01405 } 01406 else 01407 { 01408 bytesToSend = 0; 01409 packetFull = true; 01410 } 01411 } 01412 else if (qCounter.roomSumSendStreams==0 && tq->second==0) 01413 { 01414 packetFull = true; 01415 sctpEV3<<"no data in send and transQ: packet full\n"; 01416 } 01417 sctpEV3<<"bytesToSend after reduction: "<<bytesToSend<<"\n"; 01418 01419 chunk->lastDestination = newDpi; 01420 sctpEV3<<simulation.getSimTime()<<" TSN "<<chunk->tsn<<": lastDestination set to "<<chunk->lastDestination<<"\n"; 01421 if (chunk->lastDestination==IPvXAddress("0.0.0.0")) 01422 opp_error("newDpi unspecified"); 01423 } 01424 else if (headerCreated) 01425 { 01426 if (chunksAdded==0) 01427 { 01428 delete sctpmsg; 01429 return; 01430 } 01431 else 01432 { 01433 packetFull = true; 01434 sctpEV3<<"packetFull: msg length = "<<sctpmsg->getBitLength()/8+20<<"\n"; 01435 datVar=NULL; 01436 } 01437 } 01438 01439 01440 if (packetFull || (dpi != newDpi) || sendBeforeRtx) 01441 { 01442 01443 sctpEV3<<simulation.getSimTime()<<" packet full: totalLength="<<sctpmsg->getBitLength()/8 + 20<<", dpi="<<dpi<<", newDpi="<<newDpi<<" "<<dataChunksAdded<<" chunks added, osb now "<<getPath(dpi)->outstandingBytes<<"\n"; 01444 01445 if (headerCreated == true && chunksAdded > 0) 01446 { 01447 /* new chunks would exceed MTU, so we send old packet and build a new one */ 01448 /* this implies that at least one data chunk is send here */ 01449 if (dataChunksAdded > 0) 01450 { 01451 if (!pathVar->T3_RtxTimer->isScheduled()) 01452 { 01453 startTimer(pathVar->T3_RtxTimer, pathVar->pathRto); 01454 } 01455 else 01456 sctpEV3<<"RTX Timer already scheduled\n"; 01457 } 01458 if (sendOneMorePacket) 01459 { 01460 sendOneMorePacket = false; 01461 bytesToSend = 0; 01462 bytes.packet = false; 01463 } 01464 sendToIP(sctpmsg, dpi); 01465 pmDataIsSentOn(dpi); 01466 totalPacketsSent++; 01467 headerCreated = false; 01468 authAdded = false; 01469 chunksAdded = 0; 01470 dataChunksAdded = 0; 01471 firstTime = false; 01472 sendBeforeRtx = false; 01473 packetFull = false; 01474 01475 sctpEV3<<"sendAll: Sending Packet to path "<<dpi<<" scount="<<scount<<" tcount="<<tcount<<" bytesToSend="<<bytesToSend<<"\n"; 01476 if (tcount==0 && bytesToSend>0 && state->nagleEnabled && state->peerRwnd < pathVar->pmtu && pathVar->outstandingBytes > 0) 01477 { 01478 // Test whether a full packet can be filled 01479 sctpEV3<<" peerRwnd="<<state->peerRwnd<<" bytesToSend="<<bytesToSend<<" nextTSN="<<state->nextTSN<<"\n"; 01480 SCTPDataMsg *datMsg = peekOutboundDataMsg(); 01481 if (datMsg) 01482 { 01483 uint32 ums = datMsg->getBooksize(); 01484 uint32 num =(uint32)((pathVar->pmtu-32)/(ums+SCTP_DATA_CHUNK_LENGTH)); 01485 if (num*ums>state->peerRwnd) 01486 bytesToSend = 0; 01487 else 01488 bytesToSend = num * ums; 01489 } 01490 else 01491 bytesToSend = 0; 01492 sctpEV3<<"bytesToSend set to "<<bytesToSend<<"\n"; 01493 } 01494 } 01495 else 01496 { 01497 01498 sctpEV3<<"Logic Error: Packet Size + new chunk len exceed path mtu, but chunksAdded==0\n"; 01499 01500 } 01501 01502 } 01503 01504 01505 sctpEV3<<"still "<<bytesToSend<<" bytes to send, headerCreated="<<headerCreated<<"\n"; 01506 /* else { */ /* place left in the MTU, so add chunk to packet...and go on */ 01507 if (!headerCreated && bytesToSend > 0) 01508 { 01509 sctpEV3<<"headerCreated="<<headerCreated<<" bytesToSend="<<bytesToSend<<" sumSendStreams="<<qCounter.roomSumSendStreams<<"\n"; 01510 if ((state->nagleEnabled==false && (qCounter.roomSumSendStreams>0 || tq->second>0)) || (state->nagleEnabled==true && (qCounter.roomSumSendStreams>= (pathVar->pmtu - 32) || tq->second>0))) 01511 { 01512 sctpmsg = new SCTPMessage(); 01513 headerCreated=true; 01514 sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); 01515 tcount = tq->second; 01516 rtcount = rtq->second; 01517 scount = qCounter.roomSumSendStreams; 01518 bcount = qCounter.bookedSumSendStreams; 01519 } 01520 else 01521 bytesToSend=0; 01522 } 01523 01524 } 01525 01526 //sctpEV3<<"end of while\n"; 01527 /* ============================================================= */ 01528 01529 01530 if (chunksAdded > 0 && headerCreated == true) 01531 { 01532 sctpEV3<<"out of while: headerCreated="<<headerCreated<<" chunksAdded="<<chunksAdded<<" dataChunksAdded="<<dataChunksAdded<<"\n"; 01533 if (state->nagleEnabled==false || osb==0 || firstTime == false || (state->nagleEnabled && qCounter.roomSumSendStreams>= (pathVar->pmtu - 32)) || rtxActive == true) 01534 { 01535 /* this destination may have to be changed (e.g. to last fromAddress) */ 01536 if (dpi == IPvXAddress("0.0.0.0")) 01537 dpi = state->primaryPathIndex; 01538 /* start T3 timer, if it is not already running, and turn off probing */ 01539 01540 if (dataChunksAdded > 0) 01541 { 01542 if (!getPath(dpi)->T3_RtxTimer->isScheduled()) 01543 { 01544 01545 startTimer(getPath(dpi)->T3_RtxTimer, getPath(dpi)->pathRto); 01546 } 01547 } 01548 } 01549 sctpEV3<<"send all queued chunks to "<<dpi<<" and get out. osb now "<<getPath(dpi)->outstandingBytes<<"\n"; 01550 sendToIP(sctpmsg, dpi); 01551 authAdded = false; 01552 pmDataIsSentOn(dpi); 01553 totalPacketsSent++; 01554 rtxActive=false; 01555 probing = false; 01556 } 01557 else 01558 { 01559 01560 sctpEV3<<"sendAll: nothing more to send...BYE !\n"; 01561 01562 } 01563 01564 }
const char * SCTPAssociation::indicationName | ( | int32 | code | ) | [static] |
Utility: returns name of SCTP_I_xxx constants
Referenced by sendEstabIndicationToApp(), and sendIndicationToApp().
00114 { 00115 #define CASE(x) case x: s=#x+7; break 00116 const char *s = "unknown"; 00117 switch (code) 00118 { 00119 CASE(SCTP_I_DATA); 00120 CASE(SCTP_I_DATA_NOTIFICATION); 00121 CASE(SCTP_I_ESTABLISHED); 00122 CASE(SCTP_I_PEER_CLOSED); 00123 CASE(SCTP_I_CLOSED); 00124 CASE(SCTP_I_CONNECTION_REFUSED); 00125 CASE(SCTP_I_CONNECTION_RESET); 00126 CASE(SCTP_I_TIMED_OUT); 00127 CASE(SCTP_I_STATUS); 00128 CASE(SCTP_I_ABORT); 00129 CASE(SCTP_I_SHUTDOWN_RECEIVED); 00130 CASE(SCTP_I_SEND_MSG); 00131 CASE(SCTP_I_SENDQUEUE_FULL); 00132 } 00133 return s; 00134 #undef CASE 00135 }
int32 SCTPAssociation::getFsmState | ( | ) | const [inline] |
SCTPStateVariables* SCTPAssociation::getState | ( | ) | [inline] |
SCTPQueue* SCTPAssociation::getTransmissionQueue | ( | ) | [inline] |
SCTPQueue* SCTPAssociation::getRetransmissionQueue | ( | ) | [inline] |
Referenced by SCTP::removeAssociation(), and SCTPAlgorithm::setAssociation().
00494 {return retransmissionQ;};
SCTPAlgorithm* SCTPAssociation::getSctpAlgorithm | ( | ) | [inline] |
SCTP* SCTPAssociation::getSctpMain | ( | ) | [inline] |
cFSM* SCTPAssociation::getFsm | ( | ) | [inline] |
cMessage* SCTPAssociation::getInitTimer | ( | ) | [inline] |
cMessage* SCTPAssociation::getShutdownTimer | ( | ) | [inline] |
cMessage* SCTPAssociation::getSackTimer | ( | ) | [inline] |
const char * SCTPAssociation::stateName | ( | int32 | state | ) | [static] |
Utility: returns name of SCTP_S_xxx constants
Referenced by performStateTransition(), printConnBrief(), process_STATUS(), and process_TIMEOUT_INIT_REXMIT().
00057 { 00058 #define CASE(x) case x: s=#x+7; break 00059 const char *s = "unknown"; 00060 switch (state) 00061 { 00062 CASE(SCTP_S_CLOSED); 00063 CASE(SCTP_S_COOKIE_WAIT); 00064 CASE(SCTP_S_COOKIE_ECHOED); 00065 CASE(SCTP_S_ESTABLISHED); 00066 CASE(SCTP_S_SHUTDOWN_PENDING); 00067 CASE(SCTP_S_SHUTDOWN_SENT); 00068 CASE(SCTP_S_SHUTDOWN_RECEIVED); 00069 CASE(SCTP_S_SHUTDOWN_ACK_SENT); 00070 } 00071 return s; 00072 #undef CASE 00073 }
uint32 SCTPAssociation::chunkToInt | ( | char * | type | ) |
00139 { 00140 if (strcmp(type, "DATA")==0) return 0; 00141 if (strcmp(type, "INIT")==0) return 1; 00142 if (strcmp(type, "INIT_ACK")==0) return 2; 00143 if (strcmp(type, "SACK")==0) return 3; 00144 if (strcmp(type, "HEARTBEAT")==0) return 4; 00145 if (strcmp(type, "HEARTBEAT_ACK")==0) return 5; 00146 if (strcmp(type, "ABORT")==0) return 6; 00147 if (strcmp(type, "SHUTDOWN")==0) return 7; 00148 if (strcmp(type, "SHUTDOWN_ACK")==0) return 8; 00149 if (strcmp(type, "ERRORTYPE")==0) return 9; 00150 if (strcmp(type, "COOKIE_ECHO")==0) return 10; 00151 if (strcmp(type, "COOKIE_ACK")==0) return 11; 00152 if (strcmp(type, "SHUTDOWN_COMPLETE")==0) return 14; 00153 sctpEV3<<"ChunkConversion not successful\n"; 00154 return 0; 00155 }
bool SCTPAssociation::processTimer | ( | cMessage * | msg | ) |
Referenced by SCTP::handleMessage().
00325 { 00326 SCTPPathVariables* path = NULL; 00327 00328 sctpEV3 << msg->getName() << " timer expired at "<<simulation.getSimTime()<<"\n"; 00329 00330 SCTPPathInfo* pinfo = check_and_cast<SCTPPathInfo*>(msg->getControlInfo()); 00331 IPvXAddress addr = pinfo->getRemoteAddress(); 00332 00333 if (addr != IPvXAddress("0.0.0.0")) 00334 path = getPath(addr); 00335 // first do actions 00336 SCTPEventCode event; 00337 event = SCTP_E_IGNORE; 00338 if (msg==T1_InitTimer) 00339 { 00340 process_TIMEOUT_INIT_REXMIT(event); 00341 } 00342 else if (msg==SackTimer) 00343 { 00344 sctpEV3<<simulation.getSimTime()<<" delayed Sack: cTsnAck="<<state->cTsnAck<<" highestTsnReceived="<<state->highestTsnReceived<<" lastTsnReceived="<<state->lastTsnReceived<<" ackState="<<state->ackState<<" numGaps="<<state->numGaps<<"\n"; 00345 sendSack(); 00346 } 00347 else if (msg==T2_ShutdownTimer) 00348 { 00349 stopTimer(T2_ShutdownTimer); 00350 process_TIMEOUT_SHUTDOWN(event); 00351 } 00352 else if (msg==T5_ShutdownGuardTimer) 00353 { 00354 stopTimer(T5_ShutdownGuardTimer); 00355 delete state->shutdownChunk; 00356 sendIndicationToApp(SCTP_I_CONN_LOST); 00357 sendAbort(); 00358 sctpMain->removeAssociation(this); 00359 } 00360 else if (path!=NULL && msg==path->HeartbeatIntervalTimer) 00361 { 00362 process_TIMEOUT_HEARTBEAT_INTERVAL(path, path->forceHb); 00363 } 00364 else if (path!=NULL && msg==path->HeartbeatTimer) 00365 { 00366 process_TIMEOUT_HEARTBEAT(path); 00367 } 00368 else if (path!=NULL && msg==path->T3_RtxTimer) 00369 { 00370 process_TIMEOUT_RTX(path); 00371 } 00372 else if (path!=NULL && msg==path->CwndTimer) 00373 { 00374 (this->*ccFunctions.ccUpdateAfterCwndTimeout)(path); 00375 } 00376 else if (msg==StartTesting) 00377 { 00378 if (sctpMain->testing == false) 00379 { 00380 sctpMain->testing = true; 00381 sctpEV3<<"set testing to true\n"; 00382 } 00383 } 00384 else 00385 { 00386 sctpAlgorithm->processTimer(msg, event); 00387 } 00388 // then state transitions 00389 return performStateTransition(event); 00390 }
bool SCTPAssociation::processSCTPMessage | ( | SCTPMessage * | sctpmsg, | |
IPvXAddress | srcAddr, | |||
IPvXAddress | destAddr | |||
) |
Process incoming SCTP segment. Normally returns true. A return value of false means that the connection structure must be deleted by the caller (SCTP).
Referenced by SCTP::handleMessage().
00393 { 00394 00395 printConnBrief(); 00396 00397 localAddr=msgDestAddr; 00398 localPort=sctpmsg->getDestPort(); 00399 00400 remoteAddr=msgSrcAddr; 00401 remotePort=sctpmsg->getSrcPort(); 00402 00403 return process_RCV_Message(sctpmsg, msgSrcAddr, msgDestAddr); 00404 }
bool SCTPAssociation::processAppCommand | ( | cPacket * | msg | ) |
Process commands from the application. Normally returns true. A return value of false means that the connection structure must be deleted by the caller (SCTP).
Referenced by SCTP::handleMessage().
00429 { 00430 printConnBrief(); 00431 00432 SCTPCommand *sctpCommand = (SCTPCommand *)(msg->removeControlInfo()); 00433 SCTPEventCode event = preanalyseAppCommandEvent(msg->getKind()); 00434 00435 sctpEV3 << "App command: " << eventName(event) << "\n"; 00436 switch (event) 00437 { 00438 case SCTP_E_ASSOCIATE: process_ASSOCIATE(event, sctpCommand, msg); break; 00439 case SCTP_E_OPEN_PASSIVE: process_OPEN_PASSIVE(event, sctpCommand, msg); break; 00440 case SCTP_E_SEND: process_SEND(event, sctpCommand, msg); break; 00441 case SCTP_E_CLOSE: process_CLOSE(event); break; 00442 case SCTP_E_ABORT: process_ABORT(event); break; 00443 case SCTP_E_RECEIVE: process_RECEIVE_REQUEST(event, sctpCommand); break; 00444 case SCTP_E_PRIMARY: process_PRIMARY(event, sctpCommand); break; 00445 case SCTP_E_QUEUE: process_QUEUE(sctpCommand); break; 00446 case SCTP_E_SHUTDOWN: /*sendShutdown*/ break; //I.R. 00447 case SCTP_E_STOP_SENDING: break; 00448 case SCTP_E_SEND_SHUTDOWN_ACK: if (fsm->getState()==SCTP_S_SHUTDOWN_RECEIVED && getOutstandingBytes()==0) sendShutdownAck(state->primaryPathIndex); break; 00449 default: opp_error("wrong event code"); 00450 } 00451 delete sctpCommand; 00452 // then state transitions 00453 return performStateTransition(event); 00454 }
void SCTPAssociation::removePath | ( | ) |
Referenced by SCTP::removeAssociation().
00664 { 00665 SCTPPathMap::iterator j; 00666 while((j=sctpPathMap.begin())!=sctpPathMap.end()) 00667 { 00668 stopTimer(j->second->HeartbeatTimer); 00669 delete j->second->HeartbeatTimer; 00670 stopTimer(j->second->HeartbeatIntervalTimer); 00671 delete j->second->HeartbeatIntervalTimer; 00672 stopTimer(j->second->T3_RtxTimer); 00673 delete j->second->T3_RtxTimer; 00674 stopTimer(j->second->CwndTimer); 00675 delete j->second->CwndTimer; 00676 delete j->second->pathSsthresh; 00677 delete j->second->pathCwnd; 00678 delete j->second->pathTSN; 00679 delete j->second->pathRcvdTSN; 00680 delete j->second->pathRTO; 00681 delete j->second->pathRTT; 00682 delete j->second; 00683 sctpPathMap.erase(j); 00684 } 00685 }
void SCTPAssociation::removePath | ( | IPvXAddress | addr | ) |
01741 { 01742 SCTPPathMap::iterator j = sctpPathMap.find(addr); 01743 if (j!=sctpPathMap.end()) 01744 { 01745 stopTimer(j->second->HeartbeatTimer); 01746 delete j->second->HeartbeatTimer; 01747 stopTimer(j->second->HeartbeatIntervalTimer); 01748 delete j->second->HeartbeatIntervalTimer; 01749 stopTimer(j->second->T3_RtxTimer); 01750 delete j->second->T3_RtxTimer; 01751 stopTimer(j->second->CwndTimer); 01752 delete j->second->CwndTimer; 01753 sctpPathMap.erase(j); 01754 delete j->second; 01755 } 01756 }
void SCTPAssociation::removeLastPath | ( | IPvXAddress | addr | ) |
01772 { 01773 SCTPPathVariables* path = getPath(addr); 01774 stopTimer(path->HeartbeatTimer); 01775 delete path->HeartbeatTimer; 01776 stopTimer(path->HeartbeatIntervalTimer); 01777 delete path->HeartbeatIntervalTimer; 01778 stopTimer(path->T3_RtxTimer); 01779 delete path->T3_RtxTimer; 01780 stopTimer(path->CwndTimer); 01781 delete path->CwndTimer; 01782 }
void SCTPAssociation::deleteStreams | ( | ) |
Referenced by SCTP::removeAssociation().
01759 { 01760 01761 for (SCTPSendStreamMap::iterator it=sendStreams.begin(); it != sendStreams.end(); it++) 01762 { 01763 it->second->deleteQueue(); 01764 } 01765 for (SCTPReceiveStreamMap::iterator it=receiveStreams.begin(); it != receiveStreams.end(); it++) 01766 { 01767 delete it->second; 01768 } 01769 }
void SCTPAssociation::stopTimer | ( | cMessage * | timer | ) |
Referenced by pmDataIsSentOn(), pmStartPathManagement(), process_RCV_Message(), process_TIMEOUT_HEARTBEAT_INTERVAL(), processCookieAckArrived(), processHeartbeatAckArrived(), processInitAckArrived(), processSackArrived(), processTimer(), SCTP::removeAssociation(), removeLastPath(), removePath(), sendAll(), sendSack(), sendShutdown(), sendShutdownAck(), stateEntered(), and stopTimers().
01454 { 01455 01456 ev<<"stopTimer "<<timer->getName()<<"\n"; 01457 01458 if (timer->isScheduled()) 01459 { 01460 cancelEvent(timer); 01461 } 01462 }
void SCTPAssociation::stopTimers | ( | ) |
Referenced by process_RCV_Message().
01445 { 01446 for (SCTPPathMap::iterator j = sctpPathMap.begin(); j!=sctpPathMap.end(); j++) 01447 { 01448 stopTimer(j->second->HeartbeatTimer); 01449 stopTimer(j->second->HeartbeatIntervalTimer); 01450 } 01451 }
SCTPPathVariables * SCTPAssociation::getPath | ( | IPvXAddress | pid | ) |
Referenced by bytesAllowedToSend(), createSack(), cwndUpdateBytesAcked(), dequeueAckedChunks(), fcAdjustCounters(), pmDataIsSentOn(), pmRttMeasurement(), process_STATUS(), process_TIMEOUT_RTX(), processDataArrived(), processSackArrived(), processTimer(), removeLastPath(), and sendAll().
02596 { 02597 SCTPPathMap::iterator i=sctpPathMap.find(pid); 02598 if (i!=sctpPathMap.end()) 02599 { 02600 return i->second; 02601 } 02602 else 02603 { 02604 return NULL; 02605 } 02606 }
void SCTPAssociation::printSctpPathMap | ( | ) |
Referenced by processInitAckArrived(), processInitArrived(), sendAll(), sendInit(), and sendInitAck().
00044 { 00045 SCTPPathVariables* path; 00046 sctpEV3<<"\nSCTP PathMap\n"; 00047 for (SCTPPathMap::iterator i = sctpPathMap.begin(); i!=sctpPathMap.end(); ++i) 00048 { 00049 path = i->second; 00050 00051 sctpEV3<<"address: "<<path->remoteAddress<<" osb: "<<path->outstandingBytes<<" cwnd: "<<path->cwnd<<"\n"; 00052 00053 } 00054 }
SCTPEventCode SCTPAssociation::preanalyseAppCommandEvent | ( | int32 | commandCode | ) | [protected] |
Maps app command codes (msg kind of app command msgs) to SCTP_E_xxx event codes
Referenced by processAppCommand().
00407 { 00408 switch (commandCode) 00409 { 00410 case SCTP_C_ASSOCIATE: return SCTP_E_ASSOCIATE; 00411 case SCTP_C_OPEN_PASSIVE: return SCTP_E_OPEN_PASSIVE; 00412 case SCTP_C_SEND: return SCTP_E_SEND; 00413 case SCTP_C_CLOSE: return SCTP_E_CLOSE; 00414 case SCTP_C_ABORT: return SCTP_E_ABORT; 00415 case SCTP_C_RECEIVE: return SCTP_E_RECEIVE; 00416 case SCTP_C_SEND_UNORDERED: return SCTP_E_SEND; 00417 case SCTP_C_SEND_ORDERED: return SCTP_E_SEND; 00418 case SCTP_C_PRIMARY: return SCTP_E_PRIMARY; 00419 case SCTP_C_QUEUE: return SCTP_E_QUEUE; 00420 case SCTP_C_SHUTDOWN: return SCTP_E_SHUTDOWN; 00421 case SCTP_C_NO_OUTSTANDING: return SCTP_E_SEND_SHUTDOWN_ACK; 00422 default: sctpEV3<<"commandCode="<<commandCode<<"\n"; 00423 opp_error("Unknown message kind in app command"); 00424 return (SCTPEventCode)0; // to satisfy compiler 00425 } 00426 }
bool SCTPAssociation::performStateTransition | ( | const SCTPEventCode & | event | ) | [protected] |
Implemements the pure SCTP state machine
Referenced by process_RCV_Message(), processAppCommand(), processCookieAckArrived(), processCookieEchoArrived(), processInitAckArrived(), processInitArrived(), processTimer(), pushUlp(), and sendShutdownAck().
00458 { 00459 sctpEV3<<"performStateTransition\n"; 00460 if (event==SCTP_E_IGNORE) 00461 { 00462 ev << "Staying in state: " << stateName(fsm->getState()) << " (no FSM event)\n"; 00463 return true; 00464 } 00465 00466 // state machine 00467 int32 oldState = fsm->getState(); 00468 switch (fsm->getState()) 00469 { 00470 case SCTP_S_CLOSED: 00471 switch (event) 00472 { 00473 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00474 case SCTP_E_OPEN_PASSIVE: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00475 case SCTP_E_ASSOCIATE: FSM_Goto((*fsm), SCTP_S_COOKIE_WAIT); break; 00476 case SCTP_E_RCV_INIT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00477 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00478 case SCTP_E_RCV_VALID_COOKIE_ECHO: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break; 00479 case SCTP_E_CLOSE: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00480 default:; 00481 } 00482 break; 00483 00484 case SCTP_S_COOKIE_WAIT: 00485 switch (event) 00486 { 00487 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00488 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00489 case SCTP_E_RCV_INIT_ACK: FSM_Goto((*fsm), SCTP_S_COOKIE_ECHOED); break; 00490 case SCTP_E_RCV_VALID_COOKIE_ECHO: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break; 00491 default:; 00492 } 00493 break; 00494 00495 case SCTP_S_COOKIE_ECHOED: 00496 switch (event) 00497 { 00498 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00499 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00500 case SCTP_E_RCV_COOKIE_ACK:FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break; 00501 default:; 00502 } 00503 break; 00504 case SCTP_S_ESTABLISHED: 00505 switch (event) 00506 { 00507 case SCTP_E_SEND: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break; 00508 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00509 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00510 case SCTP_E_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_PENDING); break; 00511 case SCTP_E_STOP_SENDING: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_PENDING); state->stopSending = true; state->lastTSN = state->nextTSN-1; break; //I.R. 00512 case SCTP_E_RCV_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_RECEIVED); break; 00513 case SCTP_E_CLOSE: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00514 default:; 00515 } 00516 break; 00517 00518 case SCTP_S_SHUTDOWN_PENDING: 00519 switch (event) 00520 { 00521 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00522 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00523 case SCTP_E_NO_MORE_OUTSTANDING: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_SENT); break; 00524 case SCTP_E_RCV_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_RECEIVED); break; 00525 case SCTP_E_RCV_SHUTDOWN_ACK: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00526 default:; 00527 } 00528 break; 00529 00530 case SCTP_S_SHUTDOWN_RECEIVED: 00531 switch (event) 00532 { 00533 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00534 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00535 case SCTP_E_NO_MORE_OUTSTANDING: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT); break; 00536 default:; 00537 } 00538 break; 00539 00540 case SCTP_S_SHUTDOWN_SENT: 00541 switch (event) 00542 { 00543 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00544 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00545 case SCTP_E_RCV_SHUTDOWN_ACK: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00546 case SCTP_E_RCV_SHUTDOWN: sendShutdownAck(remoteAddr); FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT); break; 00547 default:; 00548 } 00549 break; 00550 00551 case SCTP_S_SHUTDOWN_ACK_SENT: 00552 switch (event) 00553 { 00554 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00555 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00556 case SCTP_E_RCV_SHUTDOWN_COMPLETE: FSM_Goto((*fsm), SCTP_S_CLOSED); break; 00557 default:; 00558 } 00559 break; 00560 00561 } 00562 00563 if (oldState!=fsm->getState()) 00564 { 00565 ev << "Transition: " << stateName(oldState) << " --> " << stateName(fsm->getState()) << " (event was: " << eventName(event) << ")\n"; 00566 sctpEV3 << sctpMain->getName() << ": " << stateName(oldState) << " --> " << stateName(fsm->getState()) << " (on " << eventName(event) << ")\n"; 00567 stateEntered(fsm->getState()); 00568 } 00569 else 00570 { 00571 ev<< "Staying in state: " << stateName(fsm->getState()) << " (event was: " << eventName(event) << ")\n"; 00572 } 00573 if (event==SCTP_E_ABORT && oldState==fsm->getState() && fsm->getState()==SCTP_S_CLOSED) 00574 return true; 00575 00576 if (oldState!=fsm->getState() && fsm->getState()==SCTP_S_CLOSED) 00577 { 00578 return false; 00579 } 00580 else 00581 return true; 00582 }
void SCTPAssociation::stateEntered | ( | int32 | state | ) | [protected] |
Referenced by performStateTransition().
00585 { 00586 switch (status) 00587 { 00588 case SCTP_S_COOKIE_WAIT: 00589 00590 break; 00591 case SCTP_S_ESTABLISHED: 00592 { 00593 sctpEV3<<"State ESTABLISHED entered\n"; 00594 char str[70]; 00595 stopTimer(T1_InitTimer); 00596 if (state->initChunk) 00597 delete state->initChunk; 00598 state->nagleEnabled = (bool)sctpMain->par("nagleEnabled"); 00599 state->header = 0; 00600 state->swsLimit = (uint32)sctpMain->par("swsLimit"); 00601 state->reactivatePrimaryPath = (bool)sctpMain->par("reactivatePrimaryPath"); 00602 state->fragment = (bool)sctpMain->par("fragment"); 00603 if (!state->fragment) 00604 state->fragment = false; 00605 sackPeriod = (double)sctpMain->par("sackPeriod"); 00606 sackFrequency = sctpMain->par("sackFrequency"); 00607 SCTP::AssocStat stat; 00608 stat.assocId = assocId; 00609 stat.start = simulation.getSimTime(); 00610 stat.stop = 0; 00611 stat.rcvdBytes=0; 00612 stat.ackedBytes=0; 00613 stat.sentBytes=0; 00614 stat.transmittedBytes=0; 00615 stat.numFastRtx=0; 00616 stat.numT3Rtx=0; 00617 stat.numPathFailures=0; 00618 stat.numForwardTsn=0; 00619 stat.lifeTime=0; 00620 stat.throughput=0; 00621 sctpMain->assocStatMap[stat.assocId] = stat; 00622 ccModule = sctpMain->par("ccModule"); 00623 switch (ccModule) 00624 { 00625 case RFC4960: 00626 { 00627 ccFunctions.ccInitParams = &SCTPAssociation::initCCParameters; 00628 ccFunctions.ccUpdateAfterSack = &SCTPAssociation::cwndUpdateAfterSack; 00629 ccFunctions.ccUpdateAfterCwndTimeout = &SCTPAssociation::cwndUpdateAfterCwndTimeout; 00630 ccFunctions.ccUpdateAfterRtxTimeout = &SCTPAssociation::cwndUpdateAfterRtxTimeout; 00631 ccFunctions.ccUpdateMaxBurst = &SCTPAssociation::cwndUpdateMaxBurst; 00632 ccFunctions.ccUpdateBytesAcked = &SCTPAssociation::cwndUpdateBytesAcked; 00633 break; 00634 } 00635 } 00636 sendEstabIndicationToApp(); 00637 pmStartPathManagement(); 00638 sprintf(str, "Cumulated TSN Ack of assoc %d", assocId); 00639 cumTsnAck = new cOutVector(str); 00640 sprintf(str, "SendQueue of assoc %d", assocId); 00641 sendQueue = new cOutVector(str); 00642 state->sendQueueLimit = (uint32)sctpMain->par("sendQueueLimit"); 00643 SCTP::VTagPair vtagPair; 00644 vtagPair.peerVTag = peerVTag; 00645 vtagPair.localPort = localPort; 00646 vtagPair.remotePort = remotePort; 00647 sctpMain->sctpVTagMap[vtagPair] = this->assocId; 00648 break; 00649 } 00650 case SCTP_S_CLOSED: 00651 { 00652 sendIndicationToApp(SCTP_I_CLOSED); 00653 break; 00654 } 00655 case SCTP_S_SHUTDOWN_PENDING: 00656 { 00657 if (getOutstandingBytes()==0 && transmissionQ->getQueueSize()==0 && qCounter.roomSumSendStreams==0 && fsm->getState() == SCTP_S_SHUTDOWN_PENDING) sendShutdown(); 00658 break; 00659 } 00660 } 00661 }
void SCTPAssociation::process_ASSOCIATE | ( | SCTPEventCode & | event, | |
SCTPCommand * | sctpCommand, | |||
cPacket * | msg | |||
) | [protected] |
Referenced by processAppCommand().
00031 { 00032 IPvXAddress lAddr, rAddr; 00033 00034 SCTPOpenCommand *openCmd = check_and_cast<SCTPOpenCommand *>(sctpCommand); 00035 00036 ev<<"SCTPAssociationEventProc:process_ASSOCIATE\n"; 00037 00038 switch(fsm->getState()) 00039 { 00040 case SCTP_S_CLOSED: 00041 initAssociation(openCmd); 00042 state->active = true; 00043 localAddressList = openCmd->getLocalAddresses(); 00044 lAddr = openCmd->getLocalAddresses().front(); 00045 if (!(openCmd->getRemoteAddresses().empty())) 00046 { 00047 remoteAddressList = openCmd->getRemoteAddresses(); 00048 rAddr = openCmd->getRemoteAddresses().front(); 00049 } 00050 else 00051 rAddr = openCmd->getRemoteAddr(); 00052 localPort = openCmd->getLocalPort(); 00053 remotePort = openCmd->getRemotePort(); 00054 state->numRequests = openCmd->getNumRequests(); 00055 00056 if (rAddr.isUnspecified() || remotePort==0) 00057 opp_error("Error processing command OPEN_ACTIVE: remote address and port must be specified"); 00058 00059 if (localPort==0) 00060 { 00061 localPort = sctpMain->getEphemeralPort(); 00062 } 00063 ev << "OPEN: " << lAddr << ":" << localPort << " --> " << rAddr << ":" << remotePort << "\n"; 00064 00065 sctpMain->updateSockPair(this, lAddr, rAddr, localPort, remotePort); 00066 state->localRwnd = (long)sctpMain->par("arwnd"); 00067 sendInit(); 00068 startTimer(T1_InitTimer,state->initRexmitTimeout); 00069 break; 00070 00071 default: 00072 opp_error("Error processing command OPEN_ACTIVE: connection already exists"); 00073 } 00074 00075 }
void SCTPAssociation::process_OPEN_PASSIVE | ( | SCTPEventCode & | event, | |
SCTPCommand * | sctpCommand, | |||
cPacket * | msg | |||
) | [protected] |
Referenced by processAppCommand().
00078 { 00079 IPvXAddress lAddr; 00080 int16 localPort; 00081 00082 SCTPOpenCommand *openCmd = check_and_cast<SCTPOpenCommand *>(sctpCommand); 00083 00084 sctpEV3<<"SCTPAssociationEventProc:process_OPEN_PASSIVE\n"; 00085 00086 switch(fsm->getState()) 00087 { 00088 case SCTP_S_CLOSED: 00089 initAssociation(openCmd); 00090 state->fork = openCmd->getFork(); 00091 localAddressList = openCmd->getLocalAddresses(); 00092 sctpEV3<<"process_OPEN_PASSIVE: number of local addresses="<<localAddressList.size()<<"\n"; 00093 lAddr = openCmd->getLocalAddresses().front(); 00094 localPort = openCmd->getLocalPort(); 00095 state->localRwnd = (long)sctpMain->par("arwnd"); 00096 state->numRequests = openCmd->getNumRequests(); 00097 state->messagesToPush = openCmd->getMessagesToPush(); 00098 00099 if (localPort==0) 00100 opp_error("Error processing command OPEN_PASSIVE: local port must be specified"); 00101 sctpEV3 << "Assoc "<<assocId<<"::Starting to listen on: " << lAddr << ":" << localPort << "\n"; 00102 00103 sctpMain->updateSockPair(this, lAddr, IPvXAddress(), localPort, 0); 00104 break; 00105 default: 00106 opp_error("Error processing command OPEN_PASSIVE: connection already exists"); 00107 } 00108 }
void SCTPAssociation::process_SEND | ( | SCTPEventCode & | event, | |
SCTPCommand * | sctpCommand, | |||
cPacket * | msg | |||
) | [protected] |
Referenced by processAppCommand().
00111 { 00112 uint32 pkSize=0, streamId, sendUnordered, ppid=0; 00113 SCTPSendStream* stream; 00114 00115 SCTPSendCommand *sendCommand = check_and_cast<SCTPSendCommand *>(sctpCommand); 00116 switch(fsm->getState()) 00117 { 00118 case SCTP_S_ESTABLISHED: 00119 00120 sctpEV3<<"SCTPAssociationEventProc: process_SEND localAddr="<<localAddr<<" remoteAddr="<<remoteAddr<<" appGateIndex="<<appGateIndex<<" assocId="<<assocId<<"\n"; 00121 00122 SCTPSimpleMessage* smsg = check_and_cast<SCTPSimpleMessage*>((msg->decapsulate())); 00123 SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId); 00124 iter->second.sentBytes+=smsg->getBitLength()/8; 00125 pkSize = smsg->getBitLength()+SCTP_DATA_CHUNK_LENGTH*8; 00126 00127 /* check that message is shorter than the MSS, else use segmentation */ 00128 if (pkSize <= SCTP_MAX_PAYLOAD * 8) 00129 { 00130 streamId = sendCommand->getSid(); 00131 sendUnordered = sendCommand->getSendUnordered(); 00132 ppid = sendCommand->getPpid(); 00133 SCTPDataMsg* datMsg = new SCTPDataMsg(); 00134 SCTPSendStreamMap::iterator iter=sendStreams.find(streamId); 00135 if (iter!=sendStreams.end()) 00136 stream=iter->second; 00137 else 00138 opp_error("stream with id %d not found",streamId); 00139 char stri[20]; 00140 sprintf(stri, "SDATA-%d-%d",streamId,state->msgNum); 00141 smsg->setName(stri); 00142 datMsg->encapsulate(smsg); 00143 datMsg->setSid(streamId); 00144 datMsg->setPpid(ppid); 00145 if (sendCommand->getPrimary()) 00146 { 00147 if (sendCommand->getRemoteAddr()==IPvXAddress("0.0.0.0")) 00148 datMsg->setInitialDestination(remoteAddr); 00149 else 00150 datMsg->setInitialDestination(sendCommand->getRemoteAddr()); 00151 } 00152 else 00153 datMsg->setInitialDestination(state->primaryPathIndex); 00154 datMsg->setEnqueuingTime(simulation.getSimTime()); 00155 datMsg->setBooksize(smsg->getBitLength()/8 + state->header); 00156 qCounter.roomSumSendStreams += ADD_PADDING(smsg->getBitLength()/8 + SCTP_DATA_CHUNK_LENGTH); 00157 00158 qCounter.bookedSumSendStreams += datMsg->getBooksize(); 00159 datMsg->setMsgNum(++state->msgNum); 00160 00161 if (sendUnordered==1) 00162 { 00163 datMsg->setOrdered(false); 00164 stream->getUnorderedStreamQ()->insert(datMsg); 00165 } 00166 else 00167 { 00168 datMsg->setOrdered(true); 00169 stream->getStreamQ()->insert(datMsg); 00170 00171 if (stream->getStreamQ()->getLength()==state->sendQueueLimit) 00172 { 00173 sendIndicationToApp(SCTP_I_SENDQUEUE_FULL); 00174 state->appSendAllowed = false; 00175 } 00176 sendQueue->record(stream->getStreamQ()->getLength()); 00177 } 00178 state->queuedMessages++; 00179 if (state->queueLimit>0 && state->queuedMessages>state->queueLimit) 00180 { 00181 state->queueUpdate = false; 00182 } 00183 sctpEV3<<"\nlast="<<sendCommand->getLast()<<", queueLimit="<<state->queueLimit<<"\n"; 00184 if (sendCommand->getLast()==true) 00185 { 00186 if (sendCommand->getPrimary()) 00187 sctpAlgorithm->sendCommandInvoked(IPvXAddress("0.0.0.0")); 00188 else 00189 sctpAlgorithm->sendCommandInvoked(datMsg->getInitialDestination()); 00190 } 00191 } 00192 break; 00193 } 00194 }
void SCTPAssociation::process_CLOSE | ( | SCTPEventCode & | event | ) | [protected] |
Referenced by processAppCommand().
00224 { 00225 00226 sctpEV3<<"SCTPAssociationEventProc:process_CLOSE; assoc="<<assocId<<"\n"; 00227 00228 switch(fsm->getState()) 00229 { 00230 case SCTP_S_ESTABLISHED: 00231 sendAll(state->primaryPathIndex); 00232 00233 if (remoteAddr!=state->primaryPathIndex) 00234 sendAll(remoteAddr); 00235 00236 sendShutdown(); 00237 break; 00238 case SCTP_S_SHUTDOWN_RECEIVED: 00239 if (getOutstandingBytes()==0) 00240 sendShutdownAck(remoteAddr); 00241 break; 00242 } 00243 }
void SCTPAssociation::process_ABORT | ( | SCTPEventCode & | event | ) | [protected] |
Referenced by processAppCommand().
00246 { 00247 sctpEV3<<"SCTPAssociationEventProc:process_ABORT\n"; 00248 switch(fsm->getState()) 00249 { 00250 case SCTP_S_ESTABLISHED: 00251 if (state->ackState < sackFrequency) 00252 { 00253 state->ackState = sackFrequency; 00254 sendAll(state->primaryPathIndex); 00255 if (remoteAddr!=state->primaryPathIndex) 00256 sendAll(remoteAddr); 00257 } 00258 sendAbort(); 00259 break; 00260 } 00261 00262 }
void SCTPAssociation::process_STATUS | ( | SCTPEventCode & | event, | |
SCTPCommand * | sctpCommand, | |||
cPacket * | msg | |||
) | [protected] |
00265 { 00266 SCTPStatusInfo *statusInfo = new SCTPStatusInfo(); 00267 statusInfo->setState(fsm->getState()); 00268 statusInfo->setStateName(stateName(fsm->getState())); 00269 00270 statusInfo->setPathId(remoteAddr); 00271 statusInfo->setActive(getPath(remoteAddr)->activePath); 00272 00273 msg->setControlInfo(statusInfo); 00274 sendToApp(msg); 00275 }
void SCTPAssociation::process_RECEIVE_REQUEST | ( | SCTPEventCode & | event, | |
SCTPCommand * | sctpCommand | |||
) | [protected] |
Referenced by processAppCommand().
00197 { 00198 SCTPSendCommand *sendCommand = check_and_cast<SCTPSendCommand *>(sctpCommand); 00199 if ((uint32)sendCommand->getSid() > inboundStreams || sendCommand->getSid() < 0) 00200 { 00201 00202 sctpEV3<<"Application tries to read from invalid stream id....\n"; 00203 00204 } 00205 00206 state->numMsgsReq[sendCommand->getSid()]+= sendCommand->getNumMsgs(); 00207 pushUlp(); 00208 }
void SCTPAssociation::process_PRIMARY | ( | SCTPEventCode & | event, | |
SCTPCommand * | sctpCommand | |||
) | [protected] |
Referenced by processAppCommand().
00211 { 00212 SCTPPathInfo *pinfo = check_and_cast<SCTPPathInfo *>(sctpCommand); 00213 state->primaryPathIndex = pinfo->getRemoteAddress(); 00214 }
bool SCTPAssociation::process_RCV_Message | ( | SCTPMessage * | sctpseg, | |
IPvXAddress | src, | |||
IPvXAddress | dest | |||
) | [protected] |
Referenced by processSCTPMessage().
00030 { 00031 uint8 type; 00032 bool trans=true, sendAllowed=false, dupReceived=false, dataChunkReceived=false, dataChunkDelivered = false; 00033 bool shutdownCalled=false; 00034 SCTPPathVariables* path; 00035 SCTPChunk* header; 00036 SCTPEventCode event; 00037 int32 srcPort, destPort; 00038 uint32 dataChunkCount = 0; 00039 00040 00041 sctpEV3<<getFullPath()<<" SCTPAssociationRcvMessage:process_RCV_Message\n"; 00042 sctpEV3<<"localAddr="<<localAddr<<" remoteAddr="<<remoteAddr<<"\n"; 00043 uint32 numberOfChunks = sctpmsg->getChunksArraySize(); 00044 sctpEV3<<"numberOfChunks="<<numberOfChunks<<"\n"; 00045 00046 00047 if ((sctpmsg->hasBitError() || !sctpmsg->getChecksumOk())) 00048 { 00049 if (((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType()==INIT_ACK) 00050 { 00051 stopTimer(T1_InitTimer); 00052 sctpEV3<<"InitAck with bit-error. Retransmit Init\n"; 00053 retransmitInit(); 00054 startTimer(T1_InitTimer,state->initRexmitTimeout); 00055 } 00056 if (((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType()==COOKIE_ACK) 00057 { 00058 stopTimer(T1_InitTimer); 00059 sctpEV3<<"CookieAck with bit-error. Retransmit CookieEcho\n"; 00060 retransmitCookieEcho(); 00061 startTimer(T1_InitTimer,state->initRexmitTimeout); 00062 } 00063 } 00064 00065 srcPort = sctpmsg->getDestPort(); 00066 destPort = sctpmsg->getSrcPort(); 00067 00068 SCTPPathMap::iterator it=sctpPathMap.find(src); 00069 if (it!=sctpPathMap.end()) 00070 path=it->second; 00071 else 00072 path=NULL; 00073 state->sctpmsg = (SCTPMessage*)sctpmsg->dup(); 00074 for (uint32 i=0; i<numberOfChunks; i++) 00075 { 00076 header=(SCTPChunk*)(sctpmsg->removeChunk()); 00077 type = header->getChunkType(); 00078 00079 if (type!=INIT && type!=ABORT && sctpmsg->getTag()!= peerVTag) 00080 { 00081 00082 ev<<" VTag "<<sctpmsg->getTag()<<" incorrect. Should be "<<peerVTag<<" localVTag="<<localVTag<<"\n"; 00083 00084 return true; 00085 } 00086 00087 switch (type) 00088 { 00089 case INIT: 00090 00091 sctpEV3<<"SCTPAssociationRcvMessage: INIT received\n"; 00092 00093 SCTPInitChunk* initChunk; 00094 initChunk = check_and_cast<SCTPInitChunk *>(header); 00095 if (initChunk->getNoInStreams()!=0 && initChunk->getNoOutStreams()!=0 && initChunk->getInitTag()!=0) 00096 trans = processInitArrived(initChunk, srcPort, destPort); 00097 i = numberOfChunks-1; 00098 delete initChunk; 00099 break; 00100 case INIT_ACK: 00101 sctpEV3<<"SCTPAssociationRcvMessage: INIT_ACK received\n"; 00102 if (fsm->getState()==SCTP_S_COOKIE_WAIT) 00103 { 00104 SCTPInitAckChunk* initAckChunk; 00105 initAckChunk = check_and_cast<SCTPInitAckChunk *>(header); 00106 if (initAckChunk->getNoInStreams()!=0 && initAckChunk->getNoOutStreams()!=0 && initAckChunk->getInitTag()!=0) 00107 trans = processInitAckArrived(initAckChunk); 00108 else if (initAckChunk->getInitTag()==0) 00109 { 00110 sendAbort(); 00111 sctpMain->removeAssociation(this); 00112 } 00113 i = numberOfChunks-1; 00114 delete initAckChunk; 00115 } 00116 else 00117 sctpEV3<<"INIT_ACK will be ignored\n"; 00118 break; 00119 case COOKIE_ECHO: 00120 sctpEV3<<"SCTPAssociationRcvMessage: COOKIE_ECHO received\n"; 00121 SCTPCookieEchoChunk* cookieEchoChunk; 00122 cookieEchoChunk = check_and_cast<SCTPCookieEchoChunk *>(header); 00123 trans = processCookieEchoArrived(cookieEchoChunk,src); 00124 delete cookieEchoChunk; 00125 break; 00126 case COOKIE_ACK: 00127 00128 sctpEV3<<"SCTPAssociationRcvMessage: COOKIE_ACK received\n"; 00129 if (fsm->getState()==SCTP_S_COOKIE_ECHOED) 00130 { 00131 SCTPCookieAckChunk* cookieAckChunk; 00132 cookieAckChunk = check_and_cast<SCTPCookieAckChunk *>(header); 00133 trans = processCookieAckArrived(); 00134 delete cookieAckChunk; 00135 } 00136 break; 00137 case DATA: 00138 00139 sctpEV3<<"\nSCTPAssociationRcvMessage: DATA received\n"; 00140 if (fsm->getState()==SCTP_S_COOKIE_ECHOED) 00141 trans=performStateTransition(SCTP_E_RCV_COOKIE_ACK); 00142 00143 if (!(fsm->getState()==SCTP_S_SHUTDOWN_RECEIVED || fsm->getState()==SCTP_S_SHUTDOWN_ACK_SENT)) 00144 { 00145 SCTPDataChunk* dataChunk; 00146 dataChunk = check_and_cast<SCTPDataChunk *>(header); 00147 if (dataChunk->getByteLength()-16>0) 00148 { 00149 dataChunkCount++; 00150 event=processDataArrived(dataChunk, dataChunkCount); 00151 if (event == SCTP_E_DELIVERED) 00152 { 00153 dataChunkReceived=true; 00154 dataChunkDelivered = true; 00155 state->sackAllowed = true; 00156 } 00157 else if (event==SCTP_E_SEND || event==SCTP_E_IGNORE) 00158 { 00159 dataChunkReceived=true; 00160 state->sackAllowed = true; 00161 } 00162 else if (event==SCTP_E_DUP_RECEIVED) 00163 { 00164 dupReceived=true; 00165 } 00166 } 00167 else 00168 { 00169 sendAbort(); 00170 sctpMain->removeAssociation(this); 00171 } 00172 00173 delete dataChunk; 00174 } 00175 trans = true; 00176 break; 00177 case SACK: 00178 { 00179 CounterMap::iterator rtq=qCounter.roomRetransQ.find(remoteAddr); 00180 int32 scount; 00181 scount = qCounter.roomSumSendStreams; 00182 sctpEV3<<"SCTPAssociationRcvMessage: SACK received\n"; 00183 00184 SCTPSackChunk* sackChunk; 00185 sackChunk = check_and_cast<SCTPSackChunk *>(header); 00186 processSackArrived(sackChunk); 00187 trans=true; 00188 sendAllowed=true; 00189 delete sackChunk; 00190 sctpEV3<<"state->lastTsnAck="<<state->lastTsnAck<<" state->lastTSN="<<state->lastTSN<<" getOutstandingBytes()="<<getOutstandingBytes()<<" transmissionQ->getQueueSize()="<<transmissionQ->getQueueSize()<<" scount="<<scount<<" fsm->getState()="<<fsm->getState()<<"\n"; 00191 if ((state->lastTsnAck == state->lastTSN || (getOutstandingBytes()==0 && transmissionQ->getQueueSize()==0 && scount==0)) && fsm->getState() == SCTP_S_SHUTDOWN_PENDING) 00192 { 00193 sctpEV3<<"no more packets: send Shutdown\n"; 00194 sendShutdown(); 00195 trans=performStateTransition(SCTP_E_NO_MORE_OUTSTANDING); 00196 shutdownCalled=true; 00197 } 00198 else if (fsm->getState()==SCTP_S_SHUTDOWN_RECEIVED && getOutstandingBytes()==0) 00199 { 00200 sctpEV3<<"no more outstanding\n"; 00201 sendShutdownAck(remoteAddr); 00202 trans=performStateTransition(SCTP_E_NO_MORE_OUTSTANDING); 00203 } 00204 break; 00205 } 00206 case ABORT: 00207 SCTPAbortChunk* abortChunk; 00208 abortChunk = check_and_cast<SCTPAbortChunk *>(header); 00209 sctpEV3<<"SCTPAssociationRcvMessage: ABORT with T-Bit "<<abortChunk->getT_Bit() << " received\n"; 00210 if (sctpmsg->getTag() == localVTag || sctpmsg->getTag() == peerVTag) 00211 { 00212 sendIndicationToApp(SCTP_I_ABORT); 00213 trans=performStateTransition(SCTP_E_ABORT); 00214 } 00215 delete abortChunk; 00216 break; 00217 case HEARTBEAT: 00218 00219 sctpEV3<<"SCTPAssociationRcvMessage: HEARTBEAT received\n"; 00220 00221 SCTPHeartbeatChunk* heartbeatChunk; 00222 heartbeatChunk = check_and_cast<SCTPHeartbeatChunk *>(header); 00223 if (!(fsm->getState()==SCTP_S_CLOSED )) 00224 { 00225 sendHeartbeatAck(heartbeatChunk, dest,src); 00226 } 00227 trans=true; 00228 delete heartbeatChunk; 00229 break; 00230 case HEARTBEAT_ACK: 00231 00232 sctpEV3<<"SCTPAssociationRcvMessage: HEARTBEAT_ACK received\n"; 00233 if (fsm->getState()==SCTP_S_COOKIE_ECHOED) 00234 trans=performStateTransition(SCTP_E_RCV_COOKIE_ACK); 00235 00236 SCTPHeartbeatAckChunk* heartbeatAckChunk; 00237 heartbeatAckChunk = check_and_cast<SCTPHeartbeatAckChunk *>(header); 00238 if (path) 00239 processHeartbeatAckArrived(heartbeatAckChunk, path); 00240 trans=true; 00241 delete heartbeatAckChunk; 00242 break; 00243 case SHUTDOWN: 00244 sctpEV3<<"Shutdown received\n"; 00245 SCTPShutdownChunk* shutdownChunk; 00246 shutdownChunk = check_and_cast<SCTPShutdownChunk *>(header); 00247 if (shutdownChunk->getCumTsnAck()>state->lastTsnAck) 00248 { 00249 simtime_t rttEst=-1.0; 00250 dequeueAckedChunks(shutdownChunk->getCumTsnAck(), remoteAddr, &rttEst); 00251 state->lastTsnAck = shutdownChunk->getCumTsnAck(); 00252 } 00253 trans=performStateTransition(SCTP_E_RCV_SHUTDOWN); 00254 sendIndicationToApp(SCTP_I_SHUTDOWN_RECEIVED); 00255 trans=true; 00256 delete shutdownChunk; 00257 break; 00258 case SHUTDOWN_ACK: 00259 sctpEV3<<"ShutdownAck received\n"; 00260 if (fsm->getState()!=SCTP_S_ESTABLISHED) 00261 { 00262 SCTPShutdownAckChunk* shutdownAckChunk; 00263 shutdownAckChunk = check_and_cast<SCTPShutdownAckChunk *>(header); 00264 sendShutdownComplete(); 00265 stopTimers(); 00266 stopTimer(T2_ShutdownTimer); 00267 stopTimer(T5_ShutdownGuardTimer); 00268 00269 if (fsm->getState()==SCTP_S_SHUTDOWN_SENT || fsm->getState()==SCTP_S_SHUTDOWN_ACK_SENT) 00270 { 00271 trans=performStateTransition(SCTP_E_RCV_SHUTDOWN_ACK); 00272 sendIndicationToApp(SCTP_I_CLOSED); 00273 delete state->shutdownChunk; 00274 } 00275 00276 delete shutdownAckChunk; 00277 } 00278 break; 00279 case SHUTDOWN_COMPLETE: 00280 sctpEV3<<"Shutdown Complete arrived\n"; 00281 SCTPShutdownCompleteChunk* shutdownCompleteChunk; 00282 shutdownCompleteChunk = check_and_cast<SCTPShutdownCompleteChunk *>(header); 00283 trans=performStateTransition(SCTP_E_RCV_SHUTDOWN_COMPLETE); 00284 sendIndicationToApp(SCTP_I_PEER_CLOSED); // necessary for NAT-Rendezvous 00285 if (trans==true) 00286 stopTimers(); 00287 stopTimer(T2_ShutdownTimer); 00288 stopTimer(T5_ShutdownGuardTimer); 00289 delete state->shutdownAckChunk; 00290 delete shutdownCompleteChunk; 00291 break; 00292 default: sctpEV3<<"different type\n"; break; 00293 } 00294 00295 if (i==numberOfChunks-1 && (dataChunkReceived || dupReceived)) 00296 { 00297 sendAllowed=true; 00298 sctpEV3<<"i="<<i<<" sendAllowed=true; scheduleSack\n"; 00299 scheduleSack(); 00300 if (fsm->getState()==SCTP_S_SHUTDOWN_SENT && state->ackState>=sackFrequency) 00301 sendSack(); 00302 } 00303 00304 00305 /* send any new DATA chunks, SACK chunks, HB chunks etc. */ 00306 if ((fsm->getState()==SCTP_S_ESTABLISHED || fsm->getState()==SCTP_S_SHUTDOWN_PENDING) && sendAllowed && !shutdownCalled) 00307 { 00308 sctpEV3<<"SCTPRcvMessage 449:sendAll to primaryPath:"<<state->primaryPathIndex<<"\n"; 00309 sendAll(state->primaryPathIndex); 00310 if (remoteAddr!=state->primaryPathIndex) 00311 { 00312 sctpEV3<<"SCTPRcvMessage 453:sendAll to remoteAddr: "<<remoteAddr<<"\n"; 00313 sendAll(remoteAddr); 00314 } 00315 00316 } 00317 } 00318 disposeOf(state->sctpmsg); 00319 sctpEV3<<"trans="<<trans<<"\n"; 00320 return trans; 00321 }
bool SCTPAssociation::processInitArrived | ( | SCTPInitChunk * | initChunk, | |
int32 | sport, | |||
int32 | dport | |||
) | [protected] |
Process incoming SCTP packets. Invoked from process_RCV_Message
Referenced by process_RCV_Message().
00324 { 00325 SCTPAssociation* assoc; 00326 char timername[70]; 00327 bool trans = false; 00328 InterfaceTableAccess interfaceTableAccess; 00329 AddressVector adv; 00330 sctpEV3<<"processInitArrived\n"; 00331 if (fsm->getState()==SCTP_S_CLOSED) 00332 { 00333 sctpEV3<<"fork="<<state->fork<<" initReceived="<<state->initReceived<<"\n"; 00334 if (state->fork && !state->initReceived) 00335 { 00336 sctpEV3<<"cloneAssociation\n"; 00337 assoc = cloneAssociation(); 00338 sctpEV3<<"addForkedAssociation\n"; 00339 sctpMain->addForkedAssociation(this, assoc, localAddr, remoteAddr, srcPort, destPort); 00340 00341 sctpEV3 << "Connection forked: this connection got new assocId=" << assocId << ", " 00342 "spinoff keeps LISTENing with assocId=" << assoc->assocId << "\n"; 00343 sprintf(timername, "T2_SHUTDOWN of assoc %d", assocId); 00344 T2_ShutdownTimer->setName(timername); 00345 sprintf(timername, "SACK_TIMER of assoc %d", assocId); 00346 SackTimer->setName(timername); 00347 sprintf(timername, "T1_INIT of assoc %d", assocId); 00348 T1_InitTimer->setName(timername); 00349 } 00350 else 00351 { 00352 sctpMain->updateSockPair(this, localAddr, remoteAddr, srcPort, destPort); 00353 00354 } 00355 if (!state->initReceived) 00356 { 00357 state->initReceived = true; 00358 state->initialPrimaryPath = remoteAddr; 00359 state->primaryPathIndex = remoteAddr; 00360 if (initchunk->getAddressesArraySize()==0) 00361 { 00362 SCTPPathVariables* rPath = new SCTPPathVariables(remoteAddr, this); 00363 sctpPathMap[rPath->remoteAddress] = rPath; 00364 qCounter.roomTransQ[rPath->remoteAddress] = 0; 00365 qCounter.roomRetransQ[rPath->remoteAddress] = 0; 00366 qCounter.bookedTransQ[rPath->remoteAddress] = 0; 00367 } 00368 initPeerTsn=initchunk->getInitTSN(); 00369 state->cTsnAck = initPeerTsn - 1; 00370 state->initialPeerRwnd = initchunk->getA_rwnd(); 00371 state->peerRwnd = state->initialPeerRwnd; 00372 localVTag= initchunk->getInitTag(); 00373 numberOfRemoteAddresses =initchunk->getAddressesArraySize(); 00374 IInterfaceTable *ift = interfaceTableAccess.get(); 00375 state->localAddresses.clear(); 00376 if (localAddressList.front() == IPvXAddress("0.0.0.0")) 00377 { 00378 for (int32 i=0; i<ift->getNumInterfaces(); ++i) 00379 { 00380 //if (ift->getInterface(i)->ipv4()!=NULL) 00381 if (ift->getInterface(i)->ipv4Data()!=NULL) 00382 { 00383 //adv.push_back(ift->getInterface(i)->ipv4()->getIPAddress()); 00384 adv.push_back(ift->getInterface(i)->ipv4Data()->getIPAddress()); 00385 } 00386 else if (ift->getInterface(i)->ipv6Data()!=NULL) 00387 { 00388 adv.push_back(ift->getInterface(i)->ipv6Data()->getAddress(0)); 00389 } 00390 } 00391 } 00392 else 00393 { 00394 adv = localAddressList; 00395 } 00396 uint32 rlevel = getLevel(remoteAddr); 00397 if (rlevel>0) 00398 for (AddressVector::iterator i=adv.begin(); i!=adv.end(); ++i) 00399 { 00400 if (getLevel((*i))>=rlevel) 00401 { 00402 sctpMain->addLocalAddress(this, (*i)); 00403 state->localAddresses.push_back((*i)); 00404 } 00405 } 00406 for (uint32 j=0; j<initchunk->getAddressesArraySize(); j++) 00407 { 00408 // skip IPv6 because we can't send to them yet 00409 if (initchunk->getAddresses(j).isIPv6()) 00410 continue; 00411 // set path variables for this pathlocalAddresses 00412 SCTPPathVariables* path = new SCTPPathVariables(initchunk->getAddresses(j), this); 00413 for (AddressVector::iterator k=state->localAddresses.begin(); k!=state->localAddresses.end(); ++k) 00414 { 00415 sctpMain->addRemoteAddress(this,(*k), initchunk->getAddresses(j)); 00416 this->remoteAddressList.push_back(initchunk->getAddresses(j)); 00417 } 00418 sctpPathMap[path->remoteAddress] = path; 00419 qCounter.roomTransQ[path->remoteAddress] = 0; 00420 qCounter.roomRetransQ[path->remoteAddress] = 0; 00421 qCounter.bookedTransQ[path->remoteAddress] = 0; 00422 } 00423 SCTPPathMap::iterator ite=sctpPathMap.find(remoteAddr); 00424 if (ite==sctpPathMap.end()) 00425 { 00426 SCTPPathVariables* path = new SCTPPathVariables(remoteAddr, this); 00427 sctpPathMap[remoteAddr] = path; 00428 qCounter.roomTransQ[remoteAddr] = 0; 00429 qCounter.roomRetransQ[remoteAddr] = 0; 00430 qCounter.bookedTransQ[remoteAddr] = 0; 00431 } 00432 trans=performStateTransition(SCTP_E_RCV_INIT); 00433 if (trans) 00434 { 00435 sendInitAck(initchunk); 00436 } 00437 } 00438 else if (fsm->getState()==SCTP_S_CLOSED) 00439 { 00440 trans=performStateTransition(SCTP_E_RCV_INIT); 00441 if (trans) 00442 sendInitAck(initchunk); 00443 } 00444 else 00445 trans = true; 00446 } 00447 else if (fsm->getState()==SCTP_S_COOKIE_WAIT) //INIT-Collision 00448 { 00449 sctpEV3<<"INIT collision: send Init-Ack\n"; 00450 sendInitAck(initchunk); 00451 trans=true; 00452 } 00453 else if (fsm->getState()==SCTP_S_COOKIE_ECHOED || fsm->getState()==SCTP_S_ESTABLISHED) 00454 { 00455 // check, whether a new address has been added 00456 bool addressPresent = false; 00457 for (uint32 j=0; j<initchunk->getAddressesArraySize(); j++) 00458 { 00459 if (initchunk->getAddresses(j).isIPv6()) 00460 continue; 00461 for (AddressVector::iterator k=remoteAddressList.begin(); k!=remoteAddressList.end(); ++k) 00462 { 00463 if ((*k)==(initchunk->getAddresses(j))) 00464 { 00465 addressPresent = true; 00466 break; 00467 } 00468 } 00469 if (!addressPresent) 00470 { 00471 sendAbort(); 00472 return true; 00473 } 00474 } 00475 sendInitAck(initchunk); 00476 trans=true; 00477 } 00478 else if (fsm->getState()==SCTP_S_SHUTDOWN_ACK_SENT) 00479 trans = true; 00480 printSctpPathMap(); 00481 return trans; 00482 }
bool SCTPAssociation::processInitAckArrived | ( | SCTPInitAckChunk * | initAckChunk | ) | [protected] |
Referenced by process_RCV_Message().
00486 { 00487 bool trans = false; 00488 if (fsm->getState()==SCTP_S_COOKIE_WAIT) 00489 { 00490 sctpEV3<<"State is COOKIE_WAIT, Cookie_Echo has to be sent\n"; 00491 stopTimer(T1_InitTimer); 00492 state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT; 00493 trans=performStateTransition(SCTP_E_RCV_INIT_ACK); 00494 //delete state->initChunk; will be deleted when state ESTABLISHED is entered 00495 if (trans) 00496 { 00497 state->initialPrimaryPath = remoteAddr; 00498 state->primaryPathIndex = remoteAddr; 00499 initPeerTsn=initAckChunk->getInitTSN(); 00500 localVTag= initAckChunk->getInitTag(); 00501 state->cTsnAck = initPeerTsn - 1; 00502 state->initialPeerRwnd = initAckChunk->getA_rwnd(); 00503 state->peerRwnd = state->initialPeerRwnd; 00504 remoteAddressList.clear(); 00505 numberOfRemoteAddresses =initAckChunk->getAddressesArraySize(); 00506 sctpEV3<<"number of remote addresses in initAck="<<numberOfRemoteAddresses<<"\n"; 00507 for (uint32 j=0; j<numberOfRemoteAddresses; j++) 00508 { 00509 if (initAckChunk->getAddresses(j).isIPv6()) 00510 continue; 00511 for (AddressVector::iterator k=state->localAddresses.begin(); k!=state->localAddresses.end(); ++k) 00512 { 00513 if (!((*k).isUnspecified())) 00514 { 00515 sctpEV3<<"addPath "<<initAckChunk->getAddresses(j)<<"\n"; 00516 sctpMain->addRemoteAddress(this,(*k), initAckChunk->getAddresses(j)); 00517 this->remoteAddressList.push_back(initAckChunk->getAddresses(j)); 00518 addPath(initAckChunk->getAddresses(j)); 00519 } 00520 } 00521 } 00522 SCTPPathMap::iterator ite=sctpPathMap.find(remoteAddr); 00523 if (ite==sctpPathMap.end()) 00524 { 00525 SCTPPathVariables* path = new SCTPPathVariables(remoteAddr, this); 00526 sctpPathMap[remoteAddr] = path; 00527 qCounter.roomTransQ[remoteAddr] = 0; 00528 qCounter.roomRetransQ[remoteAddr] = 0; 00529 qCounter.bookedTransQ[remoteAddr] = 0; 00530 } 00531 00532 inboundStreams = ((initAckChunk->getNoOutStreams()<inboundStreams)?initAckChunk->getNoOutStreams():inboundStreams); 00533 outboundStreams = ((initAckChunk->getNoInStreams()<outboundStreams)?initAckChunk->getNoInStreams():outboundStreams); 00534 (this->*ssFunctions.ssInitStreams)(inboundStreams, outboundStreams); 00535 sendCookieEcho(initAckChunk); 00536 } 00537 startTimer(T1_InitTimer, state->initRexmitTimeout); 00538 00539 } 00540 else 00541 sctpEV3<<"State="<<fsm->getState()<<"\n"; 00542 printSctpPathMap(); 00543 return trans; 00544 }
bool SCTPAssociation::processCookieEchoArrived | ( | SCTPCookieEchoChunk * | cookieEcho, | |
IPvXAddress | addr | |||
) | [protected] |
Referenced by process_RCV_Message().
00549 { 00550 bool trans = false; 00551 SCTPCookie* cookie = check_and_cast<SCTPCookie*>(cookieEcho->getStateCookie()); 00552 if (cookie->getCreationTime()+(int32)sctpMain->par("validCookieLifetime")<simulation.getSimTime()) 00553 { 00554 sctpEV3<<"stale Cookie: sendAbort\n"; 00555 sendAbort(); 00556 delete cookie; 00557 return trans; 00558 } 00559 if (fsm->getState()==SCTP_S_CLOSED) 00560 { 00561 if (cookie->getLocalTag()!=localVTag || cookie->getPeerTag() != peerVTag) 00562 { 00563 bool same=true; 00564 for (int32 i=0; i<32; i++) 00565 { 00566 if (cookie->getLocalTieTag(i)!=state->localTieTag[i]) 00567 { 00568 same = false; 00569 break; 00570 } 00571 if (cookie->getPeerTieTag(i)!=state->peerTieTag[i]) 00572 { 00573 same = false; 00574 break; 00575 } 00576 } 00577 if (!same) 00578 { 00579 sendAbort(); 00580 delete cookie; 00581 return trans; 00582 } 00583 } 00584 00585 sctpEV3<<"State is CLOSED, Cookie_Ack has to be sent\n"; 00586 trans=performStateTransition(SCTP_E_RCV_VALID_COOKIE_ECHO); 00587 if (trans) 00588 sendCookieAck(addr);//send to address 00589 } 00590 else if (fsm->getState()==SCTP_S_ESTABLISHED || fsm->getState()==SCTP_S_COOKIE_WAIT || fsm->getState()==SCTP_S_COOKIE_ECHOED) 00591 { 00592 sctpEV3<<"State is not CLOSED, but COOKIE_ECHO received. Compare the Tags\n"; 00593 // case A: Peer restarted, retrieve information from cookie 00594 if (cookie->getLocalTag()!=localVTag && cookie->getPeerTag() != peerVTag ) 00595 { 00596 bool same=true; 00597 for (int32 i=0; i<32; i++) 00598 { 00599 if (cookie->getLocalTieTag(i)!=state->localTieTag[i]) 00600 { 00601 same = false; 00602 break; 00603 } 00604 if (cookie->getPeerTieTag(i)!=state->peerTieTag[i]) 00605 { 00606 same = false; 00607 break; 00608 } 00609 } 00610 if (same) 00611 { 00612 localVTag = cookie->getLocalTag(); 00613 peerVTag = cookie->getPeerTag(); 00614 sendCookieAck(addr); 00615 } 00616 } 00617 // case B: Setup collision, retrieve information from cookie 00618 else if (cookie->getPeerTag()==peerVTag && (cookie->getLocalTag()!=localVTag || cookie->getLocalTag()==0)) 00619 { 00620 localVTag = cookie->getLocalTag(); 00621 peerVTag = cookie->getPeerTag(); 00622 performStateTransition(SCTP_E_RCV_VALID_COOKIE_ECHO); 00623 sendCookieAck(addr); 00624 } 00625 else if (cookie->getPeerTag()==peerVTag && cookie->getLocalTag()==localVTag) 00626 { 00627 sendCookieAck(addr); //send to address src 00628 } 00629 trans=true; 00630 } 00631 else 00632 { 00633 sctpEV3<<"State="<<fsm->getState()<<"\n"; 00634 trans = true; 00635 } 00636 delete cookie; 00637 return trans; 00638 }
bool SCTPAssociation::processCookieAckArrived | ( | ) | [protected] |
Referenced by process_RCV_Message().
00641 { 00642 bool trans=false; 00643 00644 if (fsm->getState()==SCTP_S_COOKIE_ECHOED) 00645 { 00646 stopTimer(T1_InitTimer); 00647 trans=performStateTransition(SCTP_E_RCV_COOKIE_ACK); 00648 if (state->cookieChunk->getCookieArraySize()==0) 00649 { 00650 delete state->cookieChunk->getStateCookie(); 00651 } 00652 delete state->cookieChunk; 00653 return trans; 00654 } 00655 else 00656 sctpEV3<<"State="<<fsm->getState()<<"\n"; 00657 00658 return trans; 00659 }
SCTPEventCode SCTPAssociation::processDataArrived | ( | SCTPDataChunk * | dataChunk, | |
uint32 | count | |||
) | [protected] |
Referenced by process_RCV_Message().
01103 { 01104 SCTPEventCode event; 01105 uint32 tsn; 01106 bool checkCtsnaChange=false; 01107 01108 //recordScalar("delay", simulation.getSimTime()-dataChunk->getEnqueuingTime()); 01109 state->newChunkReceived = false; 01110 state->lastDataSourceAddress = remoteAddr; 01111 SCTPPathVariables* path=getPath(remoteAddr); 01112 tsn=dataChunk->getTsn(); 01113 01114 sctpEV3<<simulation.getSimTime()<<" SCTPAssociation::processDataArrived TSN="<<tsn<<", SID="<<dataChunk->getSid()<<", SSN="<<dataChunk->getSsn()<<"\n"; 01115 sctpEV3<<"localRwnd="<<state->localRwnd<<", queuedRcvBytes="<<state->queuedRcvBytes<<"\n"; 01116 sctpEV3<<"Laenge="<<dataChunk->getBitLength()<<"\n"; 01117 sctpEV3<<simulation.getSimTime()<<" SCTPAssociation::processDataArrived TSN="<<tsn<<"\n"; 01118 path->pathRcvdTSN->record(tsn); 01119 state->lastTsnReceived=tsn; 01120 SCTPSimpleMessage* smsg = check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate()); 01121 dataChunk->setBitLength(SCTP_DATA_CHUNK_LENGTH*8); 01122 dataChunk->encapsulate(smsg); 01123 uint32 payloadLength = dataChunk->getBitLength()/8-SCTP_DATA_CHUNK_LENGTH; 01124 sctpEV3<<"state->bytesRcvd="<<state->bytesRcvd<<"\n"; 01125 state->bytesRcvd+=payloadLength; 01126 sctpEV3<<"state->bytesRcvd now="<<state->bytesRcvd<<"\n"; 01127 SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId); 01128 iter->second.rcvdBytes+=dataChunk->getBitLength()/8-SCTP_DATA_CHUNK_LENGTH; 01129 01130 if (state->numGaps == 0) 01131 state->highestTsnReceived = state->cTsnAck; 01132 else 01133 state->highestTsnReceived = state->gapStopList[state->numGaps-1]; 01134 01135 if (state->stopReceiving) 01136 { 01137 return SCTP_E_IGNORE; 01138 } 01139 01140 if (tsnLe(tsn, state->cTsnAck)) 01141 { 01142 01143 sctpEV3<<"sctp_handle_incoming_data_chunk: old TSN value...inserted to duplist - returning\n tsn="<<tsn<<" lastAcked="<<state->cTsnAck<<"\n"; 01144 01145 state->dupList.push_back(tsn); 01146 state->dupList.unique(); 01147 delete check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate()); 01148 return SCTP_E_DUP_RECEIVED; 01149 } 01150 01151 01152 if ((int32)(state->localRwnd-state->queuedRcvBytes)<=0) 01153 { 01154 if (tsnGt(tsn, state->highestTsnReceived)) 01155 { 01156 sctpEV3<<"sctp_handle_incoming_data_chunk: dropping new chunk due to full receive buffer -- wait for rwnd to open up\n"; 01157 01158 return SCTP_E_IGNORE; 01159 } 01160 // changed 06.07.05 I.R. 01161 else if (!tsnIsDuplicate(tsn) && tsn<state->highestTsnStored) 01162 { 01163 if (!makeRoomForTsn(tsn, dataChunk->getBitLength()-SCTP_DATA_CHUNK_LENGTH*8, dataChunk->getUBit())) 01164 { 01165 delete check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate()); 01166 return SCTP_E_IGNORE; 01167 } 01168 quBytes->record(state->queuedRcvBytes); 01169 } 01170 } 01171 if (tsnGt(tsn, state->highestTsnReceived)) 01172 { 01173 sctpEV3<<"highestTsnReceived="<<state->highestTsnReceived<<"; tsn="<<tsn<<"\n"; 01174 state->highestTsnReceived = state->highestTsnStored = tsn; 01175 if (tsn==initPeerTsn) 01176 { 01177 state->cTsnAck = tsn; 01178 } 01179 else 01180 { 01181 /* UPDATE fragment list */ 01182 sctpEV3<<"update fragment list\n"; 01183 checkCtsnaChange = updateGapList(tsn); 01184 } 01185 state->newChunkReceived = true; 01186 } 01187 else if (tsnIsDuplicate(tsn)) 01188 { 01189 state->dupList.push_back(tsn); 01190 state->dupList.unique(); 01191 01192 sctpEV3<<"sctp_handle_incoming_data_chunk: TSN value is duplicate within a fragment -- returning"; 01193 01194 return SCTP_E_IGNORE; 01195 } 01196 else 01197 { 01198 sctpEV3<<"else: updateGapList\n"; 01199 checkCtsnaChange = updateGapList(tsn); 01200 } 01201 01202 if (state->swsAvoidanceInvoked) 01203 { 01204 /* schedule a SACK to be sent at once in this case */ 01205 sctpEV3<<"swsAvoidanceInvoked\n"; 01206 state->ackState = sackFrequency; 01207 } 01208 01209 if (checkCtsnaChange) 01210 { 01211 advanceCtsna(); 01212 } 01213 event=SCTP_E_SEND; 01214 01215 sctpEV3<<"\ncTsnAck="<<state->cTsnAck<<" highestTsnReceived="<<state->highestTsnReceived<<"\n"; 01216 01217 if (state->newChunkReceived) 01218 { 01219 SCTPReceiveStreamMap::iterator iter=receiveStreams.find(dataChunk->getSid()); 01220 01221 if ((iter->second->enqueueNewDataChunk(makeVarFromMsg(dataChunk)))>0) 01222 { 01223 01224 state->queuedRcvBytes+=payloadLength; 01225 01226 event = SCTP_E_DELIVERED; 01227 sendDataArrivedNotification(dataChunk->getSid()); 01228 putInDeliveryQ(dataChunk->getSid()); 01229 } 01230 state->newChunkReceived=false; 01231 } 01232 01233 01234 return event; 01235 }
SCTPEventCode SCTPAssociation::processSackArrived | ( | SCTPSackChunk * | sackChunk | ) | [protected] |
Referenced by process_RCV_Message().
00664 { 00665 uint32 tsna, ackedBytes=0, osb=0, bufferPosition, osbPathBefore, osbBefore, lo, hi, hiAcked; 00666 uint64 arwnd; 00667 uint16 numGaps, numDups; 00668 bool ctsnaAdvanced = false, rtxNecessary=false, lowestTsnRetransmitted = false; 00669 SCTPDataVariables *datVar; 00670 simtime_t timeDiff, rttEst = -1.0; 00671 SCTPPathVariables* path; 00672 IPvXAddress pathId, pid; 00673 00674 tsna=sackChunk->getCumTsnAck(); 00675 arwnd = sackChunk->getA_rwnd(); 00676 numGaps=sackChunk->getNumGaps(); 00677 numDups=sackChunk->getNumDupTsns(); 00678 hiAcked = tsna; 00679 pathId = remoteAddr; 00680 path=getPath(pathId); 00681 00682 path->pathRcvdTSN->record(tsna); 00683 sctpEV3<<simulation.getSimTime()<<" processSackArrived at "<<localAddr<<": tsna="<<tsna<<" arwnd="<<arwnd<<" numGaps="<<numGaps<<" numDups="<<numDups<<" osb on path "<<pathId<<"="<<path->outstandingBytes<<" highestTsnReceived="<<state->highestTsnReceived<<" highestTsnAcked="<<state->highestTsnAcked<<" lastTsnAcked="<<state->lastTsnAck<<"\n"; 00684 if ((int32)path->outstandingBytes<0) 00685 opp_error("rcv %d ,tsna=%d",__LINE__, tsna); 00686 for (int32 j=0; j<numGaps; j++) 00687 { 00688 sctpEV3<<sackChunk->getGapStart(j)<<" - "<<sackChunk->getGapStop(j)<<"\n"; 00689 } 00690 for(SCTPPathMap::iterator it=sctpPathMap.begin(); it!=sctpPathMap.end(); it++) 00691 { 00692 it->second->requiresRtx = false; 00693 if (it->second->remoteAddress == pathId) 00694 it->second->lastAckTime = simulation.getSimTime(); 00695 } 00696 00697 if (state->zeroWindowProbing && arwnd>0) 00698 state->zeroWindowProbing = false; 00699 00700 osbPathBefore = path->outstandingBytes; 00701 osbBefore = getOutstandingBytes(); 00702 sctpEV3<<"osb="<<osbPathBefore<<", osbPathBefore="<<osbPathBefore<<"\n"; 00703 00704 if (tsnGt(tsna, state->lastTsnAck)) 00705 { 00706 /* we have got new chunks acked, and our cum ack point is advanced... */ 00707 /* depending on the parameter osbWithHeader ackedBytes are with or without the header bytes*/ 00708 ackedBytes = dequeueAckedChunks(tsna, pathId, &rttEst); // chunks with tsn between lastTsnAck and tsna are removed from the transmissionQ and the retransmissionQ; outstandingBytes are decreased 00709 00710 state->lastTsnAck = tsna; 00711 ctsnaAdvanced = true; 00712 } 00713 else if (tsnLt(tsna, state->lastTsnAck)) 00714 { 00715 00716 sctpEV3<<"processSackArrived : stale CTSNA....returning"; 00717 00718 return SCTP_E_IGNORE; 00719 } 00720 00721 if (state->fastRecoveryActive) 00722 { 00723 if (tsnGt(state->lastTsnAck, state->fastRecoveryExitPoint) || (state->lastTsnAck == state->fastRecoveryExitPoint)) 00724 { 00725 00726 sctpEV3<<"===> Leaving FAST RECOVERY !!! CTSNA == "<<state->lastTsnAck<<" <==\n"; 00727 00728 state->fastRecoveryActive = false; 00729 state->fastRecoveryExitPoint = 0; 00730 } 00731 } 00732 00733 if (numGaps == 0 && tsnLt(tsna, state->highestTsnAcked)) 00734 { 00735 sctpEV3<<"numGaps=0 && tsna "<<tsna<<" < highestTsnAcked "<<state->highestTsnAcked<<"\n"; 00736 SCTPQueue::PayloadQueue::iterator pq; 00737 uint32 i=state->highestTsnAcked; 00738 pq=retransmissionQ->payloadQueue.find(i); 00739 while (i>=tsna+1) 00740 { 00741 if (pq!=retransmissionQ->payloadQueue.end()) 00742 { 00743 if (pq->second->hasBeenAcked) 00744 { 00745 pq->second->hasBeenAcked=false; 00746 if (!pq->second->countsAsOutstanding) //12.06.08 00747 { 00748 if (i>tsna+1 && retransmissionQ->payloadQueue.find(i-1)->second->hasBeenAcked) 00749 state->highestTsnAcked = i-1; //I.R. 00750 else 00751 state->highestTsnAcked = tsna; 00752 #ifdef PKT 00753 tsnWasReneged(pq->second); 00754 #else 00755 sctpEV3<<"tsn "<<pq->second->tsn<<" has been removed\n"; 00756 pq->second->hasBeenRemoved = true; 00757 pq->second->gapReports = 1; 00758 if (!getPath(pq->second->lastDestination)->T3_RtxTimer->isScheduled()) 00759 startTimer(getPath(pq->second->lastDestination)->T3_RtxTimer, getPath(pq->second->lastDestination)->pathRto); 00760 sctpEV3<<"highestTsnAcked now "<<state->highestTsnAcked<<"\n"; 00761 #endif 00762 } 00763 } 00764 } 00765 i--; 00766 pq=retransmissionQ->payloadQueue.find(i); 00767 } 00768 } 00769 00770 00771 if (numGaps > 0 && !retransmissionQ->payloadQueue.empty()) 00772 { 00773 00774 sctpEV3<<"We got "<<numGaps<<" GAP reports\n"; 00775 sctpEV3<<"tsna="<<tsna<<" nextTSN="<<state->nextTSN<<"\n"; 00776 00777 /* we got fragment reports...check for newly acked chunks */ 00778 uint32 queuedChunks=retransmissionQ->payloadQueue.size(); 00779 sctpEV3<<"number of chunks in retransmissionQ: "<<queuedChunks<<" highestGapStop: "<<sackChunk->getGapStop(numGaps-1)<<" highestTsnAcked: "<<state->highestTsnAcked<<"\n"; 00780 00781 SCTPQueue::PayloadQueue::iterator pq; 00782 00783 //highest gapStop smaller than highestTsnAcked: there might have been reneging 00784 if (tsnLt(sackChunk->getGapStop(numGaps-1), state->highestTsnAcked)) 00785 { 00786 uint32 i=state->highestTsnAcked; 00787 pq=retransmissionQ->payloadQueue.find(i); 00788 while (i>=sackChunk->getGapStop(numGaps-1)+1) 00789 { 00790 sctpEV3<<"looking for TSN "<<i<<" in retransmissionQ\n"; 00791 if (pq != retransmissionQ->payloadQueue.end()) 00792 { 00793 if (pq->second->hasBeenAcked) 00794 { 00795 pq->second->hasBeenAcked=false; 00796 sctpEV3<<i<<" was found. It has been set to hasBeenAcked=false.\n"; 00797 if (pq->second->countsAsOutstanding) 00798 { 00799 pq->second->countsAsOutstanding = false; //I.R. FIXME: 00800 getPath(pq->second->lastDestination)->outstandingBytes -= (pq->second->booksize); 00801 sctpEV3<<"osb="<<getPath(pq->second->lastDestination)->outstandingBytes<<"\n"; 00802 CounterMap::iterator i=qCounter.roomRetransQ.find(getPath(pq->second->lastDestination)->remoteAddress); 00803 i->second -= ADD_PADDING(pq->second->booksize+SCTP_DATA_CHUNK_LENGTH); 00804 } 00805 00806 if (retransmissionQ->payloadQueue.find(i-1)!=retransmissionQ->payloadQueue.end() && retransmissionQ->payloadQueue.find(i-1)->second->hasBeenAcked) 00807 state->highestTsnAcked = i-1; //I.R. 12.06.08 00808 #ifdef PKT 00809 tsnWasReneged(pq->second); 00810 #else 00811 sctpEV3<<"tsn "<<pq->second->tsn<<" was removed\n"; 00812 pq->second->hasBeenRemoved = true; 00813 pq->second->hasBeenAcked = false; //12.06.08 00814 if (!getPath(pq->second->lastDestination)->T3_RtxTimer->isScheduled()) 00815 startTimer(getPath(pq->second->lastDestination)->T3_RtxTimer, getPath(pq->second->lastDestination)->pathRto); 00816 pq->second->gapReports = 1; 00817 sctpEV3<<"highestTsnAcked now "<<state->highestTsnAcked<<"\n"; 00818 #endif 00819 } 00820 } 00821 else 00822 sctpEV3<<"TSN "<<i<<" not found in retransmissionQ\n"; 00823 i--; 00824 pq=retransmissionQ->payloadQueue.find(i); 00825 } 00826 } 00827 00828 //looking for changes in the gap reports 00829 for (int32 key=0; key<numGaps; key++) 00830 { 00831 lo = sackChunk->getGapStart(key); 00832 hi = sackChunk->getGapStop(key); 00833 sctpEV3<<"examine TSNs between "<<lo<<" and "<<hi<<"\n"; 00834 for (uint32 pos=lo; pos<=hi; pos++) 00835 { 00836 datVar = retransmissionQ->getVar(pos); 00837 if (datVar) 00838 { 00839 /*sctpEV3<<"TSN "<<datVar->tsn<<" found in retransmissionQ\n"; 00840 sctpEV3<<"acked="<<datVar->hasBeenAcked<<", abandoned="<<datVar->hasBeenAbandoned<<", removed="<<datVar->hasBeenRemoved<<"\n";*/ 00841 pmClearPathCounter(datVar->lastDestination); 00842 if (datVar->numberOfTransmissions == 1 && datVar->lastDestination == pathId && datVar->hasBeenAcked == false && datVar->hasBeenRemoved == false) 00843 { 00844 timeDiff = simulation.getSimTime() - datVar->sendTime; 00845 if (timeDiff < rttEst || rttEst == -1.0) 00846 { 00847 rttEst = timeDiff; 00848 } 00849 00850 sctpEV3<<simulation.getSimTime()<<" processSackArrived: computed rtt time diff == "<<timeDiff<<" for TSN "<<datVar->tsn<<"\n"; 00851 00852 } 00853 if (datVar->hasBeenAcked == false && datVar->hasBeenAbandoned == false && datVar->hasBeenRemoved == false) 00854 { 00855 ackedBytes += (datVar->booksize); 00856 sctpEV3<<simulation.getSimTime()<<": "<<datVar->tsn<<" added to newly acked bytes: "<<ackedBytes<<"\n"; 00857 if (datVar->tsn > hiAcked) 00858 hiAcked = datVar->tsn; 00859 datVar->hasBeenAcked = true; 00860 if (datVar->countsAsOutstanding) 00861 { 00862 00863 sctpEV3<<"outstanding\n"; 00864 sctpEV3<<"lastDestination="<<datVar->lastDestination<<"\n"; 00865 sctpEV3<<"booksize="<<datVar->booksize<<"\n"; 00866 sctpEV3<<"outstanding bytes on path="<<getPath(datVar->lastDestination)->outstandingBytes<<"\n"; 00867 00868 getPath(datVar->lastDestination)->outstandingBytes -= datVar->booksize; 00869 datVar->countsAsOutstanding = false; 00870 sctpEV3<<"osb="<<getPath(datVar->lastDestination)->outstandingBytes<<"\n"; 00871 CounterMap::iterator i=qCounter.roomRetransQ.find(getPath(datVar->lastDestination)->remoteAddress); 00872 i->second -= ADD_PADDING(datVar->booksize+SCTP_DATA_CHUNK_LENGTH); 00873 } 00874 if (transmissionQ->getVar(datVar->tsn)) //2.1.07 00875 { 00876 sctpEV3<<"found tsn "<<datVar->tsn<<" in transmissionQ. Remove Message.\n"; 00877 transmissionQ->removeMsg(datVar->tsn); 00878 CounterMap::iterator q = qCounter.roomTransQ.find(datVar->nextDestination); 00879 q->second-=ADD_PADDING(datVar->len/8+SCTP_DATA_CHUNK_LENGTH); 00880 CounterMap::iterator qb=qCounter.bookedTransQ.find(datVar->nextDestination); 00881 qb->second-=datVar->booksize; 00882 00883 00884 } 00885 sctpEV3<<"not outstanding\n"; 00886 00887 00888 datVar->gapReports = 0; 00889 } 00890 } 00891 00892 } 00893 } 00894 lo = tsna; 00895 //examine chunks between the gap reports; they might have to be retransmitted or they could have been removed 00896 for (int32 key=0; key<numGaps; key++) 00897 { 00898 hi = sackChunk->getGapStart(key); 00899 00900 for (uint32 i = lo+1; i<=hi-1; i++) 00901 { 00902 pq=retransmissionQ->payloadQueue.find(i); 00903 if (pq != retransmissionQ->payloadQueue.end()) 00904 { 00905 sctpEV3<<"TSN "<<pq->second->tsn<<"\t"; 00906 if (pq->second->hasBeenAcked) 00907 { 00908 sctpEV3<<" has been acked\n"; 00909 pq->second->hasBeenAcked=false; 00910 if (pq->second->countsAsOutstanding) 00911 { 00912 sctpEV3<<"counts as outstanding\n"; 00913 pq->second->countsAsOutstanding = false; 00914 getPath(pq->second->lastDestination)->outstandingBytes -= (pq->second->booksize); 00915 sctpEV3<<"osb="<<getPath(pq->second->lastDestination)->outstandingBytes<<"\n"; 00916 CounterMap::iterator i=qCounter.roomRetransQ.find(getPath(pq->second->lastDestination)->remoteAddress); 00917 i->second -= ADD_PADDING(pq->second->booksize+SCTP_DATA_CHUNK_LENGTH); 00918 } 00919 #ifdef PKT 00920 tsnWasReneged(pq->second); 00921 #else 00922 sctpEV3<<"not PKT: TSN "<<pq->second->tsn<<"hasBeenRemoved\n"; 00923 pq->second->hasBeenRemoved = true; 00924 pq->second->gapReports = 1; 00925 if (!getPath(pq->second->lastDestination)->T3_RtxTimer->isScheduled()) 00926 startTimer(getPath(pq->second->lastDestination)->T3_RtxTimer, getPath(pq->second->lastDestination)->pathRto); 00927 #endif 00928 } 00929 else 00930 { 00931 sctpEV3<<" has not been acked, hiAcked="<<hiAcked<<" countsAsOutstanding="<<pq->second->countsAsOutstanding<<"\n"; 00932 if (hiAcked > pq->second->tsn) 00933 { 00934 pq->second->gapReports++; 00935 sctpEV3<<"increase gap reports of TSN "<<pq->second->tsn<<" to "<<pq->second->gapReports<<"\n"; 00936 if (pq->second->gapReports >= (uint32) sctpMain->par("numGapReports")) 00937 { 00938 /* chunks are only fast retransmitted once */ 00939 bool fastRtx = false; 00940 fastRtx = ((pq->second->hasBeenFastRetransmitted == false) && (pq->second->numberOfRetransmissions==0)); 00941 if (fastRtx) 00942 { 00943 sctpEV3<<simulation.getSimTime()<<" Got "<<pq->second->gapReports<<" gap_reports, scheduling "<<pq->second->tsn<<" for RTX\n"; 00944 sctpEV3<<"last sendTime for TSN "<<pq->second->tsn<<" was "<<pq->second->sendTime<<". RTT for path "<<pq->second->lastDestination<<" is "<<getPath(pq->second->lastDestination)->srtt<<"\n"; 00945 00946 00947 SCTPQueue::PayloadQueue::iterator it=transmissionQ->payloadQueue.find(pq->second->tsn); 00948 if (it==transmissionQ->payloadQueue.end()) 00949 { 00950 00951 SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId); 00952 iter->second.numFastRtx++; 00953 sctpEV3<<"insert in transmissionQ tsn="<<pq->second->tsn<<"\n"; 00954 pq->second->hasBeenFastRetransmitted = true; 00955 IPvXAddress oldPid=pq->second->lastDestination; 00956 pid = getNextDestination(pq->second); 00957 pq->second->nextDestination = pid; 00958 if (pq->second->countsAsOutstanding) 00959 { 00960 getPath(pq->second->lastDestination)->outstandingBytes -= pq->second->booksize; 00961 pq->second->countsAsOutstanding = false; 00962 CounterMap::iterator i=qCounter.roomRetransQ.find(getPath(pq->second->lastDestination)->remoteAddress); 00963 i->second -= ADD_PADDING(pq->second->booksize+SCTP_DATA_CHUNK_LENGTH); 00964 } 00965 if (!transmissionQ->checkAndInsertVar(pq->second->tsn, pq->second)) 00966 { 00967 00968 ev<<"Fast RTX: cannot add message/chunk (TSN="<<pq->second->tsn<<") to the transmission Q\n"; 00969 00970 } 00971 else 00972 { 00973 CounterMap::iterator q = qCounter.roomTransQ.find(pq->second->nextDestination); 00974 q->second+=ADD_PADDING(pq->second->len/8+SCTP_DATA_CHUNK_LENGTH); 00975 CounterMap::iterator qb=qCounter.bookedTransQ.find(pq->second->nextDestination); 00976 qb->second+=pq->second->booksize; 00977 sctpEV3<<"Fast RTX: "<<transmissionQ->getQueueSize()<<" chunks = "<<q->second<<"bytes. OldPid="<<oldPid<<", newPid="<<pid<<"\n"; 00978 } 00979 path->requiresRtx = true; 00980 rtxNecessary = true; 00981 if(bufferPosition == 0) 00982 lowestTsnRetransmitted = true; 00983 } 00984 } 00985 } 00986 } 00987 else 00988 { 00989 pq->second->hasBeenFastRetransmitted = false; 00990 sctpEV3<<"TSN "<<pq->second->tsn<<" countsAsOutstanding="<<pq->second->countsAsOutstanding<<"\n"; 00991 if (hiAcked > pq->second->tsn) 00992 pq->second->gapReports++; 00993 } 00994 } 00995 } 00996 else 00997 sctpEV3<<"TSN "<<i<<" not found in retransmissionQ\n"; 00998 } 00999 lo = sackChunk->getGapStop(key); 01000 } 01001 01002 state->highestTsnAcked = sackChunk->getGapStop(numGaps-1); 01003 if (state->highestTsnAcked < state->nextTSN-1) 01004 { 01005 SCTPQueue::PayloadQueue::iterator iter; 01006 01007 for (uint32 i=state->highestTsnAcked+1; i< state->nextTSN; i++) 01008 { 01009 iter=retransmissionQ->payloadQueue.find(i); 01010 if (iter!=retransmissionQ->payloadQueue.end()) 01011 { 01012 iter->second->hasBeenAcked=false; 01013 } 01014 } 01015 } 01016 } 01017 /* update RTT measurement for newly acked data chunks */ 01018 sctpEV3<<simulation.getSimTime()<<": SACK: rtt="<<rttEst<<", ackedBytes="<<ackedBytes<<", pathId="<<pathId<<"\n"; 01019 pmRttMeasurement(pathId, rttEst, ackedBytes); 01020 01021 osb = getOutstandingBytes(); 01022 01023 /* compute current receiver window */ 01024 state->peerRwnd = arwnd - osb; 01025 01026 // position of statement changed 20.07.05 I.R. 01027 if ((int32)(state->peerRwnd)< 0) state->peerRwnd= 0; 01028 01029 if (state->peerRwnd > state->initialPeerRwnd) 01030 state->peerRwnd = state->initialPeerRwnd; 01031 01032 sctpEV3<<"rwnd set to "<<state->peerRwnd<<" ("<<arwnd<<"-"<<osb<<")\n"; 01033 sctpEV3<<"pathFlow="<<state->peerRwnd/rttEst<<"="<<state->peerRwnd<<"/"<<rttEst<<"\n"; 01034 sctpEV3<<"state->peerRwnd now "<<state->peerRwnd<<"\n"; 01035 if (arwnd == 1 || state->peerRwnd < state->swsLimit || arwnd == 0) 01036 { 01037 sctpEV3<<"processSackArrived: arwnd="<<arwnd<<" state->peerRwnd="<<state->peerRwnd<<" set peerWindowFull\n"; 01038 state->peerWindowFull = true; 01039 } 01040 else 01041 { 01042 state->peerWindowFull = false; 01043 state->zeroWindowProbing = false; 01044 } 01045 01046 01047 if (ackedBytes > 0) 01048 { 01049 /* adjust congestion control variables for the corresponding path */ 01050 01051 sctpEV3<<"processSackArrived: "<<ackedBytes<<" bytes were acked\n"; 01052 (this->*ccFunctions.ccUpdateBytesAcked)(ackedBytes, osbBefore, ctsnaAdvanced, pathId, osbPathBefore, osb); 01053 } 01054 01055 if (osb == 0) 01056 { 01057 for (SCTPPathMap::iterator iter=sctpPathMap.begin(); iter!=sctpPathMap.end(); iter++) 01058 { 01059 stopTimer(iter->second->T3_RtxTimer); 01060 } 01061 if (arwnd == 0) 01062 state->zeroWindowProbing = true; 01063 01064 } 01065 else 01066 { 01067 sctpEV3<<"outstandingBytes on path "<<pathId<<" = "<<getPath(pathId)->outstandingBytes<<"\n"; 01068 /* there is still something outstanding */ 01069 if (getPath(pathId)->outstandingBytes == 0) 01070 { 01071 /* if all data is acked on **this path** stop T3 timer */ 01072 stopTimer(getPath(pathId)->T3_RtxTimer); 01073 } 01074 else if (ctsnaAdvanced) 01075 { 01076 /* if new data is ACKED, restart T3 timer */ 01077 01078 sctpEV3<<"CTSNA was advanced to "<<state->lastTsnAck<<" by incoming SACK chunk, now restart T3 timer for path id "<<(pathId)<<"\n"; 01079 stopTimer(getPath(pathId)->T3_RtxTimer); 01080 startTimer(getPath(pathId)->T3_RtxTimer,getPath(pathId)->pathRto); 01081 } 01082 else 01083 /* AJ - added next clause - 07.04.2004 - also restart T3 timer, when lowest TSN is rtx'ed */ 01084 if (lowestTsnRetransmitted == true) 01085 { 01086 01087 sctpEV3<<"Lowest tsn "<<state->lastTsnAck<<" was retransmitted, now restart T3 timer for path id "<<(pathId)<<"\n"; 01088 stopTimer(getPath(pathId)->T3_RtxTimer); 01089 startTimer(getPath(pathId)->T3_RtxTimer,getPath(pathId)->pathRto); 01090 } 01091 } 01092 01093 01094 (this->*ccFunctions.ccUpdateAfterSack)(rtxNecessary, path); 01095 01096 01097 return SCTP_E_IGNORE; 01098 }
SCTPEventCode SCTPAssociation::processHeartbeatAckArrived | ( | SCTPHeartbeatAckChunk * | heartbeatack, | |
SCTPPathVariables * | path | |||
) | [protected] |
Referenced by process_RCV_Message().
01239 { 01240 simtime_t rttEstimate = 0.0; 01241 IPvXAddress addr; 01242 simtime_t hbTimeField = 0.0; 01243 01244 /* hb-ack goes to pathmanagement, reset error counters, stop timeout timer */ 01245 addr = hback->getRemoteAddr(); 01246 hbTimeField = hback->getTimeField(); 01247 stopTimer(path->HeartbeatTimer); 01248 /* assume a valid RTT measurement on this path */ 01249 rttEstimate = simulation.getSimTime() - hbTimeField; 01250 pmRttMeasurement(addr, rttEstimate, 1); 01251 path->hbWasAcked = true; 01252 path->confirmed = true; 01253 path->lastAckTime = simulation.getSimTime(); 01254 if (path->primaryPathCandidate == true) 01255 { 01256 state->primaryPathIndex = addr; 01257 path->primaryPathCandidate = false; 01258 if (path->pmtu < state->assocPmtu) 01259 state->assocPmtu = path->pmtu; 01260 path->cwndAdjustmentTime = simulation.getSimTime(); 01261 path->ssthresh = state->peerRwnd; 01262 path->pathSsthresh->record(path->ssthresh); 01263 path->heartbeatTimeout= (double)sctpMain->par("hbInterval")+path->pathRto; 01264 } 01265 01266 if (path->activePath == false) 01267 { 01268 sctpEV3<<"HB-Ack arrived activePath=false. remoteAddress="<<path->remoteAddress<<" initialPP="<<state->initialPrimaryPath<<"\n"; 01269 path->activePath = true; 01270 if (state->reactivatePrimaryPath && path->remoteAddress == state->initialPrimaryPath) 01271 state->primaryPathIndex = path->remoteAddress; 01272 sctpEV3<<"primaryPath now "<<state->primaryPathIndex<<"\n"; 01273 } 01274 path->pathErrorCount = 0; 01275 return SCTP_E_IGNORE; 01276 }
int32 SCTPAssociation::process_TIMEOUT_RTX | ( | SCTPPathVariables * | path | ) | [protected] |
Referenced by processTimer().
01525 { 01526 SCTPDataVariables* chunk = NULL; 01527 bool notifyUlp = false; 01528 01529 /* increase the RTO (by doubling it) */ 01530 path->pathRto = min(2*path->pathRto.dbl(),sctpMain->par("rtoMax")); 01531 path->pathRTO->record(path->pathRto); 01532 01533 sctpEV3<<"Schedule T3 based retransmission for path "<<(path->remoteAddress)<<"\n"; 01534 01535 01536 (this->*ccFunctions.ccUpdateAfterRtxTimeout)(path); 01537 01538 if (!state->zeroWindowProbing) 01539 { 01540 state->errorCount++; 01541 path->pathErrorCount++; 01542 sctpEV3<<"RTX-Timeout: errorCount increased to "<<path->pathErrorCount<<" state->errorCount="<<state->errorCount<<"\n"; 01543 } 01544 if (state->errorCount >= (uint32)sctpMain->par("assocMaxRetrans")) 01545 { 01546 /* error counter exceeded terminate the association -- create an SCTPC_EV_CLOSE event and send it to myself */ 01547 01548 sctpEV3<<"process_TIMEOUT_RTX : ASSOC ERROR COUNTER EXCEEDED, closing ASSOC\n"; 01549 01550 sendIndicationToApp(SCTP_I_CONN_LOST); 01551 sendAbort(); 01552 sctpMain->removeAssociation(this); 01553 return 0; 01554 01555 } 01556 else 01557 { 01558 if (path->pathErrorCount >= (uint32)sctpMain->par("pathMaxRetrans")) 01559 { 01560 sctpEV3<<"pathErrorCount exceeded\n"; 01561 if (path->activePath) 01562 { 01563 /* tell the source */ 01564 notifyUlp = true; 01565 } 01566 path->activePath = false; 01567 if (path->remoteAddress == state->primaryPathIndex) 01568 { 01569 IPvXAddress adr = getNextAddress(path->remoteAddress); 01570 if (adr!=IPvXAddress("0.0.0.0")) 01571 state->primaryPathIndex = adr; 01572 } 01573 sctpEV3<<"process_TIMEOUT_RTX("<<(path->remoteAddress)<<") : PATH ERROR COUNTER EXCEEDED, path status is INACTIVE\n"; 01574 01575 if (allPathsInactive()) 01576 { 01577 01578 sctpEV3<<"process_TIMEOUT_RTX : ALL PATHS INACTIVE --> closing ASSOC\n"; 01579 01580 sendIndicationToApp(SCTP_I_CONN_LOST); 01581 sendAbort(); 01582 sctpMain->removeAssociation(this); 01583 return 0; 01584 01585 } 01586 else if (notifyUlp) 01587 { 01588 /* notify the application */ 01589 pathStatusIndication(path->remoteAddress, false); 01590 } 01591 } 01592 01593 sctpEV3<<"process_TIMEOUT_RTX("<<(path->remoteAddress)<<") : PATH ERROR COUNTER now "<<path->pathErrorCount<<"\n"; 01594 01595 } 01596 01597 /*======================================================================*/ 01598 /* do retransmission */ 01599 /*======================================================================*/ 01600 01601 /* dequeue all chunks not acked so far and put them in the TransmissionQ */ 01602 01603 if (retransmissionQ->payloadQueue.empty()) return 1; 01604 sctpEV3<<"Still "<<retransmissionQ->payloadQueue.size()<<" chunks in retransmissionQ\n"; 01605 for (SCTPQueue::PayloadQueue::iterator iter=retransmissionQ->payloadQueue.begin(); iter!=retransmissionQ->payloadQueue.end(); iter++) 01606 { 01607 chunk = iter->second; 01608 if (chunk == NULL) 01609 { 01610 sctpEV3<<"sctp assoc: chunk pointer is NULL in sctp_handle_t3_timeout()\n"; 01611 } 01612 01613 /*========================================================================*/ 01614 /* only insert chunks that were sent to the path that has timed out */ 01615 /*========================================================================*/ 01616 01617 if ((chunk->hasBeenAcked == false && chunk->countsAsOutstanding || chunk->hasBeenRemoved )&& chunk->lastDestination == path->remoteAddress ) 01618 { 01619 iter->second->hasBeenFastRetransmitted = false; 01620 iter->second->gapReports = 0; 01621 IPvXAddress oldpid = chunk->lastDestination; 01622 iter->second->nextDestination = getNextDestination(chunk); 01623 sctpEV3<<simulation.getSimTime()<<" RTX for TSN "<<iter->second->tsn<<": lastDestination="<<iter->second->lastDestination<<" nextDestination="<<iter->second->nextDestination<<"\n"; 01624 /* check, if chunk_ptr->tsn is already in transmission queue */ 01625 /* this can happen in case multiple timeouts occur in succession */ 01626 if (!transmissionQ->checkAndInsertVar(chunk->tsn, chunk)) 01627 { 01628 sctpEV3<<"TSN "<<chunk->tsn<<" already in transmissionQ\n"; 01629 continue; 01630 } 01631 else 01632 { 01633 sctpEV3<<"insert "<<chunk->tsn<<" in transmissionQ. hasBeenAcked="<<iter->second->hasBeenAcked<<" countsAsOutstanding="<<iter->second->countsAsOutstanding<<"\n"; 01634 CounterMap::iterator q = qCounter.roomTransQ.find(iter->second->nextDestination); 01635 q->second += ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH); 01636 CounterMap::iterator qb = qCounter.bookedTransQ.find(iter->second->nextDestination); 01637 qb->second += chunk->booksize; 01638 sctpEV3<<"RTX-Timeout: "<<transmissionQ->getQueueSize()<<" chunks = "<<q->second<<" bytes. Osb="<<getPath(iter->second->lastDestination)->outstandingBytes<<"\n"; 01639 01640 if (iter->second->countsAsOutstanding) 01641 { 01642 getPath(iter->second->lastDestination)->outstandingBytes -= iter->second->booksize; 01643 sctpEV3<<"osb after substraction="<<getPath(iter->second->lastDestination)->outstandingBytes<<"\n"; 01644 iter->second->countsAsOutstanding = false; 01645 } 01646 CounterMap::iterator i=qCounter.roomRetransQ.find(getPath(iter->second->lastDestination)->remoteAddress); 01647 qb->second += chunk->booksize; 01648 sctpEV3<<"RTX-Timeout: "<<transmissionQ->getQueueSize()<<" chunks = "<<q->second<<" bytes. Osb="<<getPath(iter->second->lastDestination)->outstandingBytes<<"\n"; 01649 01650 if (iter->second->countsAsOutstanding) 01651 { 01652 getPath(iter->second->lastDestination)->outstandingBytes -= iter->second->booksize; 01653 sctpEV3<<"osb after substraction="<<getPath(iter->second->lastDestination)->outstandingBytes<<"\n"; 01654 iter->second->countsAsOutstanding = false; 01655 } 01656 i->second -= ADD_PADDING(iter->second->booksize+SCTP_DATA_CHUNK_LENGTH); 01657 01658 state->peerRwnd += (chunk->booksize); 01659 SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId); 01660 iter->second.numT3Rtx++; 01661 } 01662 if (state->peerRwnd > state->initialPeerRwnd) 01663 state->peerRwnd = state->initialPeerRwnd; 01664 sctpEV3<<"T3 Timeout: Chunk (TSN="<<chunk->tsn<<") has been requeued in transmission Q, rwnd was set to "<<state->peerRwnd<<"\n"; 01665 01666 } 01667 } 01668 01669 IPvXAddress addr=getNextAddress(path->remoteAddress); 01670 sctpEV3<<"TimeoutRTX sendAll to addr: "<<addr<<"\n"; 01671 sendAll(addr); 01672 if (addr != state->primaryPathIndex) 01673 { 01674 sctpEV3<<"TimeoutRTX sendAll to pp: "<<state->primaryPathIndex<<"\n"; 01675 sendAll(state->primaryPathIndex); 01676 } 01677 else 01678 if (addr != path->remoteAddress) 01679 { 01680 sctpEV3<<"TimeoutRTX sendAll to remoteAddr: "<<remoteAddr<<"\n"; 01681 sendAll(path->remoteAddress); 01682 } 01683 01684 01685 01686 sctpEV3<<"process_TIMEOUT_RTX sendAll returned\n"; 01687 01688 return 0; 01689 }
void SCTPAssociation::process_TIMEOUT_HEARTBEAT | ( | SCTPPathVariables * | path | ) | [protected] |
Referenced by processTimer().
01383 { 01384 bool oldState; 01385 01386 /* check if error counters must be increased */ 01387 if (path->hbWasAcked) 01388 { 01389 sctpEV3<<"ERROR : HB Timeout timer expired for a path --> The Timer should already have been stopped !!!\n"; 01390 01391 } 01392 else 01393 { 01394 if (path->activePath) 01395 { 01396 state->errorCount++; 01397 path->pathErrorCount++; 01398 01399 sctpEV3<<"HB timeout timer expired for path "<<path->remoteAddress<<" --> Increase Error Counters (Assoc: "<<state->errorCount<<", Path: "<<path->pathErrorCount<<")\n"; 01400 } 01401 } 01402 01403 /* RTO must be doubled for this path ! */ 01404 path->pathRto = (simtime_t)min(2 * path->pathRto.dbl(), sctpMain->par("rtoMax")); 01405 path->pathRTO->record(path->pathRto); 01406 /* check if any thresholds are exceeded, and if so, check if ULP must be notified */ 01407 if (state->errorCount > (uint32)sctpMain->par("assocMaxRetrans")) 01408 { 01409 sendIndicationToApp(SCTP_I_CONN_LOST); 01410 sendAbort(); 01411 sctpMain->removeAssociation(this); 01412 return; 01413 01414 } 01415 else 01416 { 01417 /* set path state to INACTIVE, if the path error counter is exceeded */ 01418 if (path->pathErrorCount > (uint32)sctpMain->par("pathMaxRetrans")) 01419 { 01420 oldState = path->activePath; 01421 path->activePath = false; 01422 if (path->remoteAddress == state->primaryPathIndex) 01423 state->primaryPathIndex = getNextAddress(path->remoteAddress); 01424 sctpEV3<<"pathErrorCount now "<<path->pathErrorCount<<" PP now "<<state->primaryPathIndex<<"\n"; 01425 } 01426 /* then: we can check, if all paths are INACTIVE ! */ 01427 if (allPathsInactive()) 01428 { 01429 01430 sctpEV3<<"sctp_do_hb_to_timer() : ALL PATHS INACTIVE --> closing ASSOC\n"; 01431 01432 sendIndicationToApp(SCTP_I_CONN_LOST); 01433 return; 01434 01435 } else if (path->activePath == false && oldState == true) 01436 { 01437 /* notify the application, in case the PATH STATE has changed from ACTIVE to INACTIVE */ 01438 pathStatusIndication(path->remoteAddress, false); 01439 } 01440 01441 } 01442 }
void SCTPAssociation::process_TIMEOUT_HEARTBEAT_INTERVAL | ( | SCTPPathVariables * | path, | |
bool | force | |||
) | [protected] |
Referenced by processTimer().
01356 { 01357 01358 01359 sctpEV3<<"HB Interval timer expired -- sending new HB REQ on path "<<path->remoteAddress<<"\n"; 01360 01361 /* restart hb_send_timer on this path */ 01362 01363 stopTimer(path->HeartbeatIntervalTimer); 01364 stopTimer(path->HeartbeatTimer); 01365 01366 path->heartbeatIntervalTimeout = (double)sctpMain->par("hbInterval") + path->pathRto; 01367 path->heartbeatTimeout = path->pathRto; 01368 01369 startTimer(path->HeartbeatIntervalTimer, path->heartbeatIntervalTimeout); 01370 01371 if (simulation.getSimTime() - path->lastAckTime > path->heartbeatIntervalTimeout/2 || path->forceHb) 01372 { 01373 sendHeartbeat(path, false); 01374 startTimer(path->HeartbeatTimer, path->heartbeatTimeout); 01375 01376 path->forceHb = false; 01377 } 01378 01379 }
void SCTPAssociation::process_TIMEOUT_INIT_REXMIT | ( | SCTPEventCode & | event | ) | [protected] |
Referenced by processTimer().
01281 { 01282 01283 if (++state->initRetransCounter > (int32)sctpMain->par("maxInitRetrans")) 01284 { 01285 sctpEV3 << "Retransmission count during connection setup exceeds " << (int32)sctpMain->par("maxInitRetrans") << ", giving up\n"; 01286 sendIndicationToApp(SCTP_I_CLOSED); 01287 sendAbort(); 01288 sctpMain->removeAssociation(this); 01289 return; 01290 } 01291 01292 sctpEV3<< "Performing retransmission #" << state->initRetransCounter << "\n"; 01293 01294 switch(fsm->getState()) 01295 { 01296 case SCTP_S_COOKIE_WAIT: retransmitInit(); break; 01297 case SCTP_S_COOKIE_ECHOED: retransmitCookieEcho(); break; 01298 default: opp_error("Internal error: INIT-REXMIT timer expired while in state %s", stateName(fsm->getState())); 01299 } 01300 01301 state->initRexmitTimeout *= 2; 01302 01303 if (state->initRexmitTimeout > SCTP_TIMEOUT_INIT_REXMIT_MAX) 01304 state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT_MAX; 01305 01306 startTimer(T1_InitTimer,state->initRexmitTimeout); 01307 }
void SCTPAssociation::process_TIMEOUT_CWND | ( | SCTPPathVariables * | path | ) | [protected] |
01341 { 01342 /* 01343 * When the association does not transmit data on a given transport address 01344 * within an RTO, the cwnd of the transport address SHOULD be adjusted to 2*MTU. 01345 */ 01346 01347 path->cwnd = (int32)min(4 * path->pmtu, max(2 * path->pmtu, 4380)); 01348 path->pathCwnd->record(path->cwnd); 01349 01350 sctpEV3<<"CWND timer run off: readjusting CWND(path=="<<path->remoteAddress<<") = "<<path->cwnd<<"\n"; 01351 01352 path->cwndAdjustmentTime = simulation.getSimTime(); 01353 }
void SCTPAssociation::process_TIMEOUT_PROBING | ( | ) | [protected] |
void SCTPAssociation::process_TIMEOUT_SHUTDOWN | ( | SCTPEventCode & | event | ) | [protected] |
Referenced by processTimer().
01310 { 01311 01312 if (++state->errorCount > (uint32)sctpMain->par("assocMaxRetrans")) 01313 { 01314 sendIndicationToApp(SCTP_I_CONN_LOST); 01315 sendAbort(); 01316 sctpMain->removeAssociation(this); 01317 return; 01318 01319 } 01320 01321 sctpEV3 << "Performing shutdown retransmission. Assoc error count now "<<state->errorCount<<" \n"; 01322 01323 if(fsm->getState()==SCTP_S_SHUTDOWN_SENT) 01324 { 01325 retransmitShutdown(); 01326 } 01327 else if (fsm->getState()==SCTP_S_SHUTDOWN_ACK_SENT) 01328 retransmitShutdownAck(); 01329 01330 state->initRexmitTimeout *= 2; 01331 01332 if (state->initRexmitTimeout > SCTP_TIMEOUT_INIT_REXMIT_MAX) 01333 state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT_MAX; 01334 01335 startTimer(T2_ShutdownTimer,state->initRexmitTimeout); 01336 }
int32 SCTPAssociation::updateCounters | ( | SCTPPathVariables * | path | ) | [protected] |
01475 { 01476 bool notifyUlp = false; 01477 01478 if (++state->errorCount >= (uint32)sctpMain->par("assocMaxRetrans")) 01479 { 01480 sctpEV3 << "Retransmission count during connection setup exceeds " << (int32)sctpMain->par("assocMaxRetrans") << ", giving up\n"; 01481 sendIndicationToApp(SCTP_I_CLOSED); 01482 sendAbort(); 01483 sctpMain->removeAssociation(this); 01484 return 0; 01485 } 01486 else if (++path->pathErrorCount >= (uint32)sctpMain->par("pathMaxRetrans")) 01487 { 01488 if (path->activePath) 01489 { 01490 /* tell the source */ 01491 notifyUlp = true; 01492 } 01493 01494 path->activePath = false; 01495 if (path->remoteAddress == state->primaryPathIndex) 01496 state->primaryPathIndex = getNextAddress(path->remoteAddress); 01497 sctpEV3<<"process_TIMEOUT_RESET("<<(path->remoteAddress)<<") : PATH ERROR COUNTER EXCEEDED, path status is INACTIVE\n"; 01498 01499 if (allPathsInactive()) 01500 { 01501 01502 sctpEV3<<"process_TIMEOUT_RESET : ALL PATHS INACTIVE --> closing ASSOC\n"; 01503 01504 sendIndicationToApp(SCTP_I_CONN_LOST); 01505 sendAbort(); 01506 sctpMain->removeAssociation(this); 01507 return 0; 01508 01509 } 01510 else if (notifyUlp) 01511 { 01512 /* notify the application */ 01513 pathStatusIndication(path->remoteAddress, false); 01514 } 01515 sctpEV3<<"process_TIMEOUT_RESET("<<(path->remoteAddress)<<") : PATH ERROR COUNTER now "<<path->pathErrorCount<<"\n"; 01516 return 2; 01517 } 01518 return 1; 01519 }
void SCTPAssociation::startTimer | ( | cMessage * | timer, | |
simtime_t | timeout | |||
) | [protected] |
Referenced by pmDataIsSentOn(), pmStartPathManagement(), process_ASSOCIATE(), process_RCV_Message(), process_TIMEOUT_HEARTBEAT_INTERVAL(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_SHUTDOWN(), processInitAckArrived(), processSackArrived(), scheduleSack(), sendAll(), sendShutdown(), and sendShutdownAck().
01465 { 01466 01467 sctpEV3<<"startTimer "<<timer->getName()<<" with timeout "<<timeout<<" to expire at "<<simulation.getSimTime()+timeout<<"\n"; 01468 01469 scheduleTimeout(timer, timeout); 01470 }
SCTPAssociation * SCTPAssociation::cloneAssociation | ( | ) | [protected] |
Utility: clone a listening association. Used for forking.
Referenced by processInitArrived().
00180 { 00181 SCTPAssociation *assoc = new SCTPAssociation(sctpMain,appGateIndex,assocId); 00182 const char *queueClass = transmissionQ->getClassName(); 00183 assoc->transmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass)); 00184 assoc->retransmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass)); 00185 00186 const char *sctpAlgorithmClass = sctpAlgorithm->getClassName(); 00187 assoc->sctpAlgorithm = check_and_cast<SCTPAlgorithm *>(createOne(sctpAlgorithmClass)); 00188 assoc->sctpAlgorithm->setAssociation(assoc); 00189 assoc->sctpAlgorithm->initialize(); 00190 assoc->state = assoc->sctpAlgorithm->createStateVariables(); 00191 00192 assoc->state->active = false; 00193 assoc->state->fork = true; 00194 assoc->localAddr = localAddr; 00195 assoc->localPort = localPort; 00196 assoc->localAddressList = localAddressList; 00197 00198 FSM_Goto((*assoc->fsm), SCTP_S_CLOSED); 00199 sctpMain->printInfoConnMap(); 00200 return assoc; 00201 }
void SCTPAssociation::initAssociation | ( | SCTPOpenCommand * | openCmd | ) | [protected] |
Utility: creates send/receive queues and sctpAlgorithm
Referenced by process_ASSOCIATE(), and process_OPEN_PASSIVE().
00357 { 00358 sctpEV3<<"SCTPAssociationUtil:initAssociation\n"; 00359 // create send/receive queues 00360 const char *queueClass = openCmd->getQueueClass(); 00361 transmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass)); 00362 00363 retransmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass)); 00364 outboundStreams = openCmd->getOutboundStreams(); 00365 // create algorithm 00366 const char *sctpAlgorithmClass = openCmd->getSctpAlgorithmClass(); 00367 if (!sctpAlgorithmClass || !sctpAlgorithmClass[0]) 00368 sctpAlgorithmClass = sctpMain->par("sctpAlgorithmClass"); 00369 sctpAlgorithm = check_and_cast<SCTPAlgorithm *>(createOne(sctpAlgorithmClass)); 00370 sctpAlgorithm->setAssociation(this); 00371 sctpAlgorithm->initialize(); 00372 // create state block 00373 state = sctpAlgorithm->createStateVariables(); 00374 }
bool SCTPAssociation::tsnIsDuplicate | ( | uint32 | tsn | ) | [protected] |
Methods dealing with the handling of TSNs
Referenced by processDataArrived().
01856 { 01857 for (std::list<uint32>::iterator it=state->dupList.begin(); it!=state->dupList.end(); it++) 01858 { 01859 if ((*it)==tsn) 01860 return true; 01861 } 01862 for (uint32 i=0; i<state->numGaps; i++) 01863 if (tsnBetween(state->gapStartList[i], tsn, state->gapStopList[i])) 01864 return true; 01865 return false; 01866 }
bool SCTPAssociation::advanceCtsna | ( | void | ) | [protected] |
Referenced by processDataArrived().
02111 { 02112 int32 listLength, counter; 02113 02114 ev<<"Entering advanceCtsna(ctsna now =="<< state->cTsnAck<<"\n";; 02115 02116 listLength = state->numGaps; 02117 02118 /* if there are no fragments, we cannot advance the ctsna */ 02119 if (listLength == 0) return false; 02120 counter = 0; 02121 02122 while(counter < listLength) 02123 { 02124 /* if we take out a fragment here, we need to modify either counter or list_length */ 02125 02126 if (state->cTsnAck + 1 == state->gapStartList[0]) 02127 { 02128 /* BINGO ! */ 02129 state->cTsnAck = state->gapStopList[0]; 02130 /* we can take out a maximum of list_length fragments */ 02131 counter++; 02132 for (uint32 i=1; i<state->numGaps; i++) 02133 { 02134 state->gapStartList[i-1] = state->gapStartList[i]; 02135 state->gapStopList[i-1] = state->gapStopList[i]; 02136 } 02137 02138 } 02139 else 02140 { 02141 ev<<"Entering advanceCtsna(when leaving: ctsna=="<<state->cTsnAck<<"\n"; 02142 return false; 02143 } 02144 02145 } /* end while */ 02146 02147 ev<<"Entering advanceCtsna(when leaving: ctsna=="<< state->cTsnAck<<"\n"; 02148 return true; 02149 }
bool SCTPAssociation::updateGapList | ( | uint32 | tsn | ) | [protected] |
TSN either sits at the end of one gap, and thus changes gap boundaries, or it is in between two gaps, and becomes a new gap
Referenced by processDataArrived().
01932 { 01933 uint32 lo, hi, gapsize; 01934 01935 01936 sctpEV3<<"Entering updateGapList(tsn=="<< receivedTsn<<" cTsnAck="<<state->cTsnAck<<" Number of Gaps="<<state->numGaps<<"\n"; 01937 01938 lo = state->cTsnAck + 1; 01939 if ((int32)(state->localRwnd-state->queuedRcvBytes)<=0) 01940 { 01941 sctpEV3<<"window full\n"; 01942 //only check if cumTsnAck can be advanced 01943 if (receivedTsn == lo) 01944 { 01945 sctpEV3<<"Window full, but cumTsnAck can be advanced:"<<lo<<"\n"; 01946 01947 } 01948 else 01949 return false; 01950 } 01951 01952 if (tsnGt(receivedTsn, state->highestTsnStored)) //17.06.08 01953 state->highestTsnStored = receivedTsn; 01954 01955 for (uint32 i=0; i<state->numGaps; i++) 01956 { 01957 if (state->gapStartList[i]>0) 01958 { 01959 hi = state->gapStartList[i] - 1; 01960 if (tsnBetween(lo, receivedTsn, hi)) 01961 { 01962 gapsize = hi - lo + 1; 01963 if (gapsize > 1) 01964 { 01969 if (receivedTsn == hi) 01970 { 01971 01972 sctpEV3<<"receivedTsn==hi...."; 01973 01974 state->gapStartList[i] = receivedTsn; 01975 state->newChunkReceived = true; 01976 return true; 01977 } 01978 else if (receivedTsn == lo) 01979 { 01980 01981 sctpEV3<<"receivedTsn==lo=="<<lo<<"....."<< lo<<"\n"; 01982 01983 if (receivedTsn == (state->cTsnAck + 1)) 01984 { 01985 state->cTsnAck++; 01986 state->newChunkReceived = true; 01987 return true; 01988 } 01989 /* some gap must increase its upper bound */ 01990 state->gapStopList[i-1] = receivedTsn; 01991 state->newChunkReceived = true; 01992 return true; 01993 } 01994 else 01995 { /* a gap in between */ 01996 state->numGaps++; 01997 01998 sctpEV3<<"Inserting new gap (start==stop=="<<receivedTsn<<"\n"; 01999 02000 for (uint32 j=state->numGaps; j>i; j--) 02001 { 02002 state->gapStartList[j] = state->gapStartList[j-1]; 02003 state->gapStopList[j] = state->gapStopList[j-1]; 02004 } 02005 state->gapStartList[i]=receivedTsn; 02006 state->gapStopList[i]=receivedTsn; 02007 state->newChunkReceived = true; 02008 for (uint32 k=0; k<state->numGaps; k++) 02009 02010 sctpEV3<<"Gap "<<k<<": "<<state->gapStartList[k]<<" - "<<state->gapStopList[k]<<"\n"; 02011 02012 return true; 02013 } 02014 } 02015 else 02016 { /* alright: gapsize is 1: our received tsn may close gap between fragments */ 02017 02018 sctpEV3<<"gapsize="<<gapsize<<"\n"; 02019 02020 if (lo == state->cTsnAck + 1) 02021 { 02022 state->cTsnAck = state->gapStopList[i]; 02023 if (i==state->numGaps-1) 02024 { 02025 state->gapStartList[i] = 0; 02026 state->gapStopList[i] = 0; 02027 } 02028 else 02029 for (uint32 j=i; j<state->numGaps; j++) 02030 { 02031 state->gapStartList[j] = state->gapStartList[j+1]; 02032 state->gapStopList[j] = state->gapStopList[j+1]; 02033 } 02034 state->numGaps--; 02035 02036 sctpEV3<<"state->numGaps="<<state->numGaps<<"\n"; 02037 02038 state->newChunkReceived = true; 02039 return true; 02040 } 02041 else 02042 { 02043 state->gapStopList[i-1] = state->gapStopList[i]; 02044 if (i==state->numGaps-1) 02045 { 02046 state->gapStartList[i] = 0; 02047 state->gapStopList[i] = 0; 02048 } 02049 else 02050 for (uint32 j=i; j<=state->numGaps; j++) 02051 { 02052 state->gapStartList[j] = state->gapStartList[j+1]; 02053 state->gapStopList[j] = state->gapStopList[j+1]; 02054 } 02055 state->numGaps--; 02056 state->newChunkReceived = true; 02057 return true; 02058 } 02059 02060 } 02061 02062 } 02063 else 02064 { /* receivedTsn is not in the gap between these fragments... */ 02065 lo = state->gapStopList[i] + 1; 02066 } 02067 } /* end: for */ 02068 }/* end: for */ 02069 02070 /* (NULL LIST) OR (End of Gap List passed) */ 02071 if (receivedTsn == lo) 02072 { 02073 /* just increase ctsna, handle further update of ctsna later */ 02074 if (receivedTsn == state->cTsnAck + 1) 02075 { 02076 02077 sctpEV3<<"Updating cTsnAck....now cTsnAck=="<<receivedTsn<<"\n"; 02078 02079 state->cTsnAck = receivedTsn; 02080 state->newChunkReceived = true; 02081 return true; 02082 } 02083 /* Update last fragment....increase stop_tsn by one */ 02084 state->gapStopList[state->numGaps-1]++; 02085 02086 state->newChunkReceived = true; 02087 return true; 02088 02089 } 02090 else 02091 { /* a new fragment altogether, past the end of the list */ 02092 02093 sctpEV3<<"Inserting new fragment after the end of the list (start==stop=="<<receivedTsn<<"\n"; 02094 02095 state->gapStartList[state->numGaps] = receivedTsn; 02096 state->gapStopList[state->numGaps] = receivedTsn; 02097 state->numGaps++; 02098 state->newChunkReceived = true; 02099 for (uint32 k=0; k<state->numGaps; k++) 02100 02101 sctpEV3<<"Gap "<<k<<": "<<state->gapStartList[k]<<" - "<<state->gapStopList[k]<<"\n"; 02102 02103 return true; 02104 } 02105 02106 return false; 02107 02108 }
void SCTPAssociation::removeFromGapList | ( | uint32 | removedTsn | ) | [protected] |
Referenced by makeRoomForTsn().
01869 { 01870 int32 gapsize, numgaps; 01871 01872 numgaps = state->numGaps; 01873 sctpEV3<<"remove TSN "<<removedTsn<<" from GapList. "<<numgaps<<" gaps present, cumTsnAck="<<state->cTsnAck<<"\n"; 01874 for (int32 j=0; j<numgaps; j++) 01875 sctpEV3<<state->gapStartList[j]<<" - "<<state->gapStopList[j]<<"\n"; 01876 for (int32 i=numgaps-1; i>=0; i--) 01877 { 01878 sctpEV3<<"gapStartList["<<i<<"]="<<state->gapStartList[i]<<", state->gapStopList["<<i<<"]="<<state->gapStopList[i]<<"\n"; 01879 if (tsnBetween(state->gapStartList[i], removedTsn, state->gapStopList[i])) 01880 { 01881 gapsize = (int32)(state->gapStopList[i] - state->gapStartList[i]+1); 01882 if (gapsize>1) 01883 { 01884 if (state->gapStopList[i]==removedTsn) 01885 { 01886 state->gapStopList[i]--; 01887 } 01888 else if (state->gapStartList[i]==removedTsn) 01889 { 01890 state->gapStartList[i]++; 01891 } 01892 else //gap is split in two 01893 { 01894 for (int32 j=numgaps-1; j>=i; j--) 01895 { 01896 state->gapStopList[j+1] = state->gapStopList[j]; 01897 state->gapStartList[j+1] = state->gapStartList[j]; 01898 } 01899 state->gapStopList[i] = removedTsn-1; 01900 state->gapStartList[i+1] = removedTsn+1; 01901 state->numGaps++; 01902 } 01903 } 01904 else 01905 { 01906 01907 for (int32 j=i; j<=numgaps-1; j++) 01908 { 01909 state->gapStopList[j] = state->gapStopList[j+1]; 01910 state->gapStartList[j] = state->gapStartList[j+1]; 01911 } 01912 state->gapStartList[numgaps-1]=0; 01913 state->gapStopList[numgaps-1]=0; 01914 state->numGaps--; 01915 if (state->numGaps == 0) 01916 { 01917 if (removedTsn == state->lastTsnAck+1) 01918 { 01919 state->lastTsnAck = removedTsn; 01920 } 01921 } 01922 } 01923 } 01924 } 01925 if (state->numGaps>0) 01926 state->highestTsnReceived = state->gapStopList[state->numGaps-1]; 01927 else 01928 state->highestTsnReceived = state->cTsnAck; 01929 }
bool SCTPAssociation::makeRoomForTsn | ( | uint32 | tsn, | |
uint32 | length, | |||
bool | uBit | |||
) | [protected] |
Referenced by processDataArrived().
01785 { 01786 SCTPDataVariables* datVar=NULL; 01787 SCTPQueue* stream, dStream; 01788 uint32 sum=0, comp=0; 01789 bool delQ = false; 01790 uint32 high = state->highestTsnStored; 01791 sctpEV3<<simulation.getSimTime()<<": makeRoomForTsn: tsn="<<tsn<<", length="<<length<<" high="<<high<<"\n"; 01792 while (sum<length && state->highestTsnReceived>state->lastTsnAck) 01793 { 01794 comp = sum; 01795 for (SCTPReceiveStreamMap::iterator iter=receiveStreams.begin();iter!=receiveStreams.end(); iter++) 01796 { 01797 if (tsn > high) 01798 return false; 01799 if (uBit) 01800 stream = iter->second->getUnorderedQ(); 01801 else 01802 stream = iter->second->getOrderedQ(); 01803 datVar = stream->getVar(high); 01804 if (datVar==NULL) //12.06.08 01805 { 01806 sctpEV3<<high<<" not found in orderedQ. Try deliveryQ\n"; 01807 stream = iter->second->getDeliveryQ(); 01808 datVar = stream->getVar(high); 01809 delQ = true; 01810 } 01811 if (datVar!=NULL) 01812 { 01813 01814 sum+=datVar->len; 01815 if (stream->deleteMsg(high)) 01816 { 01817 sctpEV3<<high<<" found and deleted\n"; 01818 01819 state->queuedRcvBytes-=datVar->len/8; //12.06.08 01820 if (ssnGt(iter->second->getExpectedStreamSeqNum(),datVar->ssn)) 01821 iter->second->setExpectedStreamSeqNum(datVar->ssn); 01822 } 01823 qCounter.roomSumRcvStreams -= ADD_PADDING(datVar->len/8 + SCTP_DATA_CHUNK_LENGTH); 01824 if (high == state->highestTsnReceived) 01825 state->highestTsnReceived--; 01826 removeFromGapList(high); 01827 01828 if (tsn > state->highestTsnReceived) 01829 state->highestTsnReceived=tsn; 01830 high--; 01831 break; 01832 } 01833 else 01834 { 01835 01836 sctpEV3<<"TSN "<<high<<" not found in stream "<<iter->second->getStreamId()<<"\n"; 01837 01838 } 01839 } 01840 01841 if (comp == sum) 01842 { 01843 //removeFromGapList(high); 01844 sctpEV3<<high<<" not found in any stream\n"; 01845 high--; 01846 } 01847 state->highestTsnStored = high; 01848 01849 if (tsn > state->highestTsnReceived) 01850 return false; 01851 } 01852 return true; 01853 }
void SCTPAssociation::sendInit | ( | ) | [protected] |
Methods for creating and sending chunks
Referenced by process_ASSOCIATE().
00378 { 00379 //RoutingTableAccess routingTableAccess; 00380 InterfaceTableAccess interfaceTableAccess; 00381 AddressVector adv; 00382 uint32 length = SCTP_INIT_CHUNK_LENGTH; 00383 00384 if (remoteAddr.isUnspecified() || remotePort==0) 00385 opp_error("Error processing command ASSOCIATE: foreign socket unspecified"); 00386 if (localPort==0) 00387 opp_error("Error processing command ASSOCIATE: local port unspecified"); 00388 state->primaryPathIndex = remoteAddr; 00389 // create message consisting of INIT chunk 00390 SCTPMessage *sctpmsg = new SCTPMessage(); 00391 sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); 00392 SCTPInitChunk *initChunk = new SCTPInitChunk("INIT"); 00393 initChunk->setChunkType(INIT); 00394 00395 initChunk->setInitTag(uint32rand()); 00396 00397 peerVTag = initChunk->getInitTag(); 00398 sctpEV3<<"INIT from "<<localAddr<<":InitTag="<<peerVTag<<"\n"; 00399 initChunk->setA_rwnd(sctpMain->par("arwnd")); 00400 initChunk->setNoOutStreams(outboundStreams); 00401 initChunk->setNoInStreams(SCTP_DEFAULT_INBOUND_STREAMS); 00402 initChunk->setInitTSN(1000); 00403 state->nextTSN=initChunk->getInitTSN(); 00404 state->lastTSN = initChunk->getInitTSN() + state->numRequests - 1; 00405 initTsn=initChunk->getInitTSN(); 00406 IInterfaceTable *ift = interfaceTableAccess.get(); 00407 sctpEV3<<"add local address\n"; 00408 if (localAddressList.front() == IPvXAddress("0.0.0.0")) 00409 { 00410 for (int32 i=0; i<ift->getNumInterfaces(); ++i) 00411 { 00412 if (ift->getInterface(i)->ipv4Data()!=NULL) 00413 { 00414 sctpEV3<<"save address "<<ift->getInterfaceById(i)->ipv4Data()->getIPAddress()<<"\n"; 00415 adv.push_back(ift->getInterface(i)->ipv4Data()->getIPAddress()); 00416 } 00417 else if (ift->getInterface(i)->ipv6Data()!=NULL) 00418 { 00419 for (int32 j=0; j<ift->getInterface(i)->ipv6Data()->getNumAddresses(); j++) 00420 { 00421 sctpEV3<<"add address "<<ift->getInterface(i)->ipv6Data()->getAddress(j)<<"\n"; 00422 adv.push_back(ift->getInterface(i)->ipv6Data()->getAddress(j)); 00423 } 00424 } 00425 } 00426 } 00427 else 00428 { 00429 adv = localAddressList; 00430 sctpEV3<<"gebundene Adresse "<<localAddr<<" wird hinzugefuegt\n"; 00431 } 00432 uint32 addrNum=0; 00433 bool friendly = false; 00434 if (remoteAddr.isIPv6()) 00435 { 00436 for (AddressVector::iterator i=adv.begin(); i!=adv.end(); ++i) 00437 { 00438 if (!friendly) 00439 { 00440 initChunk->setAddressesArraySize(addrNum+1); 00441 initChunk->setAddresses(addrNum++,(*i)); 00442 length+=20; 00443 } 00444 sctpMain->addLocalAddress(this, (*i)); 00445 state->localAddresses.push_back((*i)); 00446 if (localAddr.isUnspecified()) 00447 localAddr=(*i); 00448 } 00449 } 00450 else 00451 { 00452 uint32 rlevel = getLevel(remoteAddr); 00453 sctpEV3<<"level of remote address="<<rlevel<<"\n"; 00454 for (AddressVector::iterator i=adv.begin(); i!=adv.end(); ++i) 00455 { 00456 sctpEV3<<"level of address "<<(*i)<<" = "<<getLevel((*i))<<"\n"; 00457 if (getLevel((*i))>=rlevel) 00458 { 00459 initChunk->setAddressesArraySize(addrNum+1); 00460 initChunk->setAddresses(addrNum++,(*i)); 00461 length+=8; 00462 sctpMain->addLocalAddress(this, (*i)); 00463 state->localAddresses.push_back((*i)); 00464 if (localAddr.get4().getInt()==0) 00465 localAddr=(*i); 00466 } 00467 else if (rlevel==4 && getLevel((*i))==3 && friendly) 00468 { 00469 sctpMain->addLocalAddress(this, (*i)); 00470 state->localAddresses.push_back((*i)); 00471 if (localAddr.get4().getInt()==0) 00472 localAddr=(*i); 00473 } 00474 } 00475 } 00476 sctpMain->printInfoConnMap(); 00477 initChunk->setBitLength(length*8); 00478 sctpmsg->addChunk(initChunk); 00479 // set path variables 00480 if (remoteAddressList.size()>0) 00481 { 00482 for (AddressVector::iterator it=remoteAddressList.begin(); it!=remoteAddressList.end(); it++) 00483 { 00484 SCTPPathVariables* path = new SCTPPathVariables((*it), this); 00485 sctpPathMap[(*it)] = path; 00486 qCounter.roomTransQ[(*it)] = 0; 00487 qCounter.roomRetransQ[(*it)] = 0; 00488 qCounter.bookedTransQ[(*it)] = 0; 00489 } 00490 } 00491 else 00492 { 00493 SCTPPathVariables* path = new SCTPPathVariables(remoteAddr, this); 00494 sctpPathMap[remoteAddr] = path; 00495 qCounter.roomTransQ[remoteAddr] = 0; 00496 qCounter.roomRetransQ[remoteAddr] = 0; 00497 qCounter.bookedTransQ[remoteAddr] = 0; 00498 } 00499 // send it 00500 state->initChunk=check_and_cast<SCTPInitChunk *>(initChunk->dup()); 00501 state->initChunk->setName("StateInitChunk"); 00502 printSctpPathMap(); 00503 sctpEV3<<getFullPath()<<" sendInit: localVTag="<<localVTag<<" peerVTag="<<peerVTag<<"\n"; 00504 sendToIP(sctpmsg); 00505 }
void SCTPAssociation::sendInitAck | ( | SCTPInitChunk * | initchunk | ) | [protected] |
Referenced by processInitArrived().
00526 { 00527 uint32 length = SCTP_INIT_CHUNK_LENGTH; 00528 00529 state->primaryPathIndex = remoteAddr; 00530 // create segment 00531 SCTPMessage *sctpinitack = new SCTPMessage(); 00532 sctpinitack->setBitLength(SCTP_COMMON_HEADER*8); 00533 00534 sctpinitack->setSrcPort(localPort); 00535 sctpinitack->setDestPort(remotePort); 00536 SCTPInitAckChunk *initAckChunk = new SCTPInitAckChunk("INIT_ACK"); 00537 initAckChunk->setChunkType(INIT_ACK); 00538 SCTPCookie *cookie = new SCTPCookie("CookieUtil"); 00539 cookie->setCreationTime(simulation.getSimTime()); 00540 cookie->setLocalTieTagArraySize(32); 00541 cookie->setPeerTieTagArraySize(32); 00542 if (fsm->getState()==SCTP_S_CLOSED) 00543 { 00544 do 00545 { 00546 peerVTag = uint32rand(); 00547 } while (peerVTag==0); 00548 initAckChunk->setInitTag(peerVTag); 00549 initAckChunk->setInitTSN(2000); 00550 state->nextTSN=initAckChunk->getInitTSN(); 00551 state->lastTSN = initAckChunk->getInitTSN() + state->numRequests - 1; 00552 cookie->setLocalTag(localVTag); 00553 cookie->setPeerTag(peerVTag); 00554 for (int32 i=0; i<32; i++) 00555 { 00556 cookie->setLocalTieTag(i,0); 00557 cookie->setPeerTieTag(i,0); 00558 } 00559 sctpinitack->setTag(localVTag); 00560 sctpEV3<<"state=closed: localVTag="<<localVTag<<" peerVTag="<<peerVTag<<"\n"; 00561 } 00562 else if (fsm->getState()==SCTP_S_COOKIE_WAIT || fsm->getState()==SCTP_S_COOKIE_ECHOED) 00563 { 00564 initAckChunk->setInitTag(peerVTag); 00565 sctpEV3<<"different state:set InitTag in InitAck: "<<initAckChunk->getInitTag()<<"\n"; 00566 initAckChunk->setInitTSN(state->nextTSN); 00567 initPeerTsn=initChunk->getInitTSN(); 00568 state->cTsnAck = initPeerTsn - 1; 00569 cookie->setLocalTag(initChunk->getInitTag()); 00570 cookie->setPeerTag(peerVTag); 00571 for (int32 i=0; i<32; i++) 00572 { 00573 cookie->setPeerTieTag(i,(uint8)intrand(256)); 00574 state->peerTieTag[i] = cookie->getPeerTieTag(i); 00575 if (fsm->getState()==SCTP_S_COOKIE_ECHOED) 00576 { 00577 cookie->setLocalTieTag(i,(uint8)intrand(256)); 00578 state->localTieTag[i] = cookie->getLocalTieTag(i); 00579 } 00580 else 00581 cookie->setLocalTieTag(i,0); 00582 } 00583 sctpinitack->setTag(initChunk->getInitTag()); 00584 sctpEV3<<"VTag in InitAck: "<<sctpinitack->getTag()<<"\n"; 00585 } 00586 else 00587 { 00588 sctpEV3<<"other state\n"; 00589 uint32 tag; 00590 do 00591 { 00592 tag = uint32rand(); 00593 } while (tag==0); 00594 initAckChunk->setInitTag(tag); 00595 initAckChunk->setInitTSN(state->nextTSN); 00596 cookie->setLocalTag(localVTag); 00597 cookie->setPeerTag(peerVTag); 00598 for (int32 i=0; i<32; i++) 00599 { 00600 cookie->setPeerTieTag(i,state->peerTieTag[i]); 00601 cookie->setLocalTieTag(i,state->localTieTag[i]); 00602 } 00603 sctpinitack->setTag(initChunk->getInitTag()); 00604 } 00605 cookie->setBitLength(SCTP_COOKIE_LENGTH*8); 00606 initAckChunk->setStateCookie(cookie); 00607 initAckChunk->setCookieArraySize(0); 00608 initAckChunk->setA_rwnd(sctpMain->par("arwnd")); 00609 initAckChunk->setNoOutStreams((unsigned int)min(outboundStreams,initChunk->getNoInStreams())); 00610 initAckChunk->setNoInStreams(SCTP_DEFAULT_INBOUND_STREAMS); 00611 00612 initTsn=initAckChunk->getInitTSN(); 00613 uint32 addrNum=0; 00614 bool friendly = false; 00615 if (!friendly) 00616 for (AddressVector::iterator k=state->localAddresses.begin(); k!=state->localAddresses.end(); ++k) 00617 { 00618 initAckChunk->setAddressesArraySize(addrNum+1); 00619 initAckChunk->setAddresses(addrNum++,(*k)); 00620 length+=8; 00621 } 00622 uint32 unknownLen = initChunk->getUnrecognizedParametersArraySize(); 00623 if (unknownLen>0) 00624 { 00625 sctpEV3<<"Found unrecognized Parameters in INIT chunk with a length of "<<unknownLen<<" bytes.\n"; 00626 initAckChunk->setUnrecognizedParametersArraySize(unknownLen); 00627 for (uint32 i=0; i<unknownLen; i++) 00628 initAckChunk->setUnrecognizedParameters(i,initChunk->getUnrecognizedParameters(i)); 00629 length+=unknownLen; 00630 } 00631 else 00632 initAckChunk->setUnrecognizedParametersArraySize(0); 00633 00634 initAckChunk->setBitLength((length+initAckChunk->getCookieArraySize())*8 + cookie->getBitLength()); 00635 inboundStreams = ((initChunk->getNoOutStreams()<initAckChunk->getNoInStreams())?initChunk->getNoOutStreams():initAckChunk->getNoInStreams()); 00636 outboundStreams = ((initChunk->getNoInStreams()<initAckChunk->getNoOutStreams())?initChunk->getNoInStreams():initAckChunk->getNoOutStreams()); 00637 (this->*ssFunctions.ssInitStreams)(inboundStreams, outboundStreams); 00638 sctpinitack->addChunk(initAckChunk); 00639 if (fsm->getState()==SCTP_S_CLOSED) 00640 { 00641 sendToIP(sctpinitack, state->initialPrimaryPath); 00642 } 00643 else 00644 { 00645 sendToIP(sctpinitack); 00646 00647 } 00648 printSctpPathMap(); 00649 }
void SCTPAssociation::sendCookieEcho | ( | SCTPInitAckChunk * | initackchunk | ) | [protected] |
Referenced by processInitAckArrived().
00652 { 00653 SCTPMessage *sctpcookieecho = new SCTPMessage(); 00654 sctpcookieecho->setBitLength(SCTP_COMMON_HEADER*8); 00655 00656 sctpEV3<<"SCTPAssociationUtil:sendCookieEcho\n"; 00657 00658 sctpcookieecho->setSrcPort(localPort); 00659 sctpcookieecho->setDestPort(remotePort); 00660 SCTPCookieEchoChunk* cookieEchoChunk=new SCTPCookieEchoChunk("COOKIE_ECHO"); 00661 cookieEchoChunk->setChunkType(COOKIE_ECHO); 00662 int32 len = initAckChunk->getCookieArraySize(); 00663 cookieEchoChunk->setCookieArraySize(len); 00664 if (len>0) 00665 { 00666 for (int32 i=0; i<len; i++) 00667 cookieEchoChunk->setCookie(i, initAckChunk->getCookie(i)); 00668 cookieEchoChunk->setBitLength((SCTP_COOKIE_ACK_LENGTH+len)*8); 00669 } 00670 else 00671 { 00672 SCTPCookie* cookie = check_and_cast <SCTPCookie*> (initAckChunk->getStateCookie()); 00673 cookieEchoChunk->setStateCookie(cookie); 00674 cookieEchoChunk->setBitLength(SCTP_COOKIE_ACK_LENGTH*8 + cookie->getBitLength()); 00675 } 00676 uint32 unknownLen = initAckChunk->getUnrecognizedParametersArraySize(); 00677 if (unknownLen>0) 00678 { 00679 sctpEV3<<"Found unrecognized Parameters in INIT-ACK chunk with a length of "<<unknownLen<<" bytes.\n"; 00680 cookieEchoChunk->setUnrecognizedParametersArraySize(unknownLen); 00681 for (uint32 i=0; i<unknownLen; i++) 00682 cookieEchoChunk->setUnrecognizedParameters(i,initAckChunk->getUnrecognizedParameters(i)); 00683 } 00684 else 00685 cookieEchoChunk->setUnrecognizedParametersArraySize(0); 00686 state->cookieChunk=check_and_cast<SCTPCookieEchoChunk*>(cookieEchoChunk->dup()); 00687 if (len==0) 00688 { 00689 state->cookieChunk->setStateCookie(initAckChunk->getStateCookie()->dup()); 00690 } 00691 sctpcookieecho->addChunk(cookieEchoChunk); 00692 sendToIP(sctpcookieecho); 00693 }
void SCTPAssociation::sendCookieAck | ( | IPvXAddress | dest | ) | [protected] |
Referenced by processCookieEchoArrived().
00767 { 00768 SCTPMessage *sctpcookieack = new SCTPMessage(); 00769 sctpcookieack->setBitLength(SCTP_COMMON_HEADER*8); 00770 00771 sctpEV3<<"SCTPAssociationUtil:sendCookieACK\n"; 00772 00773 sctpcookieack->setSrcPort(localPort); 00774 sctpcookieack->setDestPort(remotePort); 00775 SCTPCookieAckChunk* cookieAckChunk=new SCTPCookieAckChunk("COOKIE_ACK"); 00776 cookieAckChunk->setChunkType(COOKIE_ACK); 00777 cookieAckChunk->setBitLength(SCTP_COOKIE_ACK_LENGTH*8); 00778 sctpcookieack->addChunk(cookieAckChunk); 00779 sendToIP(sctpcookieack, dest); 00780 }
void SCTPAssociation::sendAbort | ( | ) | [protected] |
Referenced by process_ABORT(), process_RCV_Message(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_RTX(), process_TIMEOUT_SHUTDOWN(), processCookieEchoArrived(), processInitArrived(), processTimer(), and updateCounters().
00831 { 00832 SCTPMessage *msg = new SCTPMessage(); 00833 msg->setBitLength(SCTP_COMMON_HEADER*8); 00834 00835 sctpEV3<<"SCTPAssociationUtil:sendABORT localPort="<<localPort<<" remotePort="<<remotePort<<"\n"; 00836 00837 msg->setSrcPort(localPort); 00838 msg->setDestPort(remotePort); 00839 SCTPAbortChunk* abortChunk = new SCTPAbortChunk("ABORT"); 00840 abortChunk->setChunkType(ABORT); 00841 abortChunk->setT_Bit(0); 00842 abortChunk->setBitLength(SCTP_ABORT_CHUNK_LENGTH*8); 00843 msg->addChunk(abortChunk); 00844 sendToIP(msg, remoteAddr); 00845 }
void SCTPAssociation::sendHeartbeat | ( | SCTPPathVariables * | path, | |
bool | local | |||
) | [protected] |
Referenced by pmStartPathManagement(), and process_TIMEOUT_HEARTBEAT_INTERVAL().
00714 { 00715 SCTPMessage *sctpheartbeat = new SCTPMessage(); 00716 sctpheartbeat->setBitLength(SCTP_COMMON_HEADER*8); 00717 00718 sctpheartbeat->setSrcPort(localPort); 00719 sctpheartbeat->setDestPort(remotePort); 00720 SCTPHeartbeatChunk* heartbeatChunk=new SCTPHeartbeatChunk("HEARTBEAT"); 00721 heartbeatChunk->setChunkType(HEARTBEAT); 00722 heartbeatChunk->setRemoteAddr(path->remoteAddress); 00723 heartbeatChunk->setTimeField(simulation.getSimTime()); 00724 heartbeatChunk->setBitLength((SCTP_HEARTBEAT_CHUNK_LENGTH+12)*8); 00725 //heartbeatChunk->setBitLength((SCTP_HEARTBEAT_CHUNK_LENGTH+12+1000)*8); 00726 sctpheartbeat->addChunk(heartbeatChunk); 00727 if (local) 00728 { 00729 sctpEV3<<"sendHeartbeat: sendToIP from "<<localAddr<<" to "<<path->remoteAddress<<"\n"; 00730 sendToIP(sctpheartbeat, localAddr, path->remoteAddress); 00731 } 00732 else 00733 { 00734 sctpEV3<<"sendHeartbeat: sendToIP to "<<path->remoteAddress<<"\n"; 00735 sendToIP(sctpheartbeat, path->remoteAddress); 00736 } 00737 path->hbWasAcked=false; 00738 }
void SCTPAssociation::sendHeartbeatAck | ( | SCTPHeartbeatChunk * | heartbeatChunk, | |
IPvXAddress | src, | |||
IPvXAddress | dest | |||
) | [protected] |
Referenced by process_RCV_Message().
00741 { 00742 SCTPMessage *sctpheartbeatack = new SCTPMessage(); 00743 sctpheartbeatack->setBitLength(SCTP_COMMON_HEADER*8); 00744 00745 sctpheartbeatack->setSrcPort(localPort); 00746 sctpheartbeatack->setDestPort(remotePort); 00747 SCTPHeartbeatAckChunk* heartbeatAckChunk=new SCTPHeartbeatAckChunk("HEARTBEAT_ACK"); 00748 heartbeatAckChunk->setChunkType(HEARTBEAT_ACK); 00749 heartbeatAckChunk->setRemoteAddr(heartbeatChunk->getRemoteAddr()); 00750 heartbeatAckChunk->setTimeField(heartbeatChunk->getTimeField()); 00751 int32 len=heartbeatChunk->getInfoArraySize(); 00752 if (len>0) 00753 { 00754 heartbeatAckChunk->setInfoArraySize(len); 00755 for (int32 i=0; i<len; i++) 00756 heartbeatAckChunk->setInfo(i,heartbeatChunk->getInfo(i)); 00757 } 00758 00759 heartbeatAckChunk->setBitLength(heartbeatChunk->getBitLength()); 00760 sctpheartbeatack->addChunk(heartbeatAckChunk); 00761 sctpEV3<<"try to get path for "<<dest<<"\n"; 00762 sctpEV3<<"send heartBeatAck from "<<src<<" to "<<dest<<"\n"; 00763 sendToIP(sctpheartbeatack, src, dest); 00764 }
void SCTPAssociation::sendSack | ( | void | ) | [protected] |
Referenced by process_RCV_Message(), processTimer(), and pushUlp().
01018 { 01019 sctpEV3<<"sendSack\n"; 01020 SCTPSackChunk* sackChunk; 01021 IPvXAddress dpi; /* destination path index that will actually be used/was used on last send */ 01022 /* sack timer has expired, reset flag, and send SACK */ 01023 stopTimer(SackTimer); 01024 state->ackState = 0; 01025 sackChunk = createSack(); 01026 01027 /* return the SACK to the address where we last got a data chunk from */ 01028 dpi = state->lastDataSourceAddress; 01029 SCTPMessage* sctpmsg = new SCTPMessage(); 01030 sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); 01031 sctpmsg->addChunk(sackChunk); 01032 sendToIP(sctpmsg, dpi); 01033 }
void SCTPAssociation::sendShutdown | ( | ) | [protected] |
Referenced by process_CLOSE(), process_RCV_Message(), and stateEntered().
00848 { 00849 SCTPMessage *msg = new SCTPMessage(); 00850 msg->setBitLength(SCTP_COMMON_HEADER*8); 00851 00852 sctpEV3<<"SCTPAssociationUtil:sendShutdown localPort="<<localPort<<" remotePort="<<remotePort<<"\n"; 00853 00854 msg->setSrcPort(localPort); 00855 msg->setDestPort(remotePort); 00856 SCTPShutdownChunk* shutdownChunk = new SCTPShutdownChunk("Shutdown"); 00857 shutdownChunk->setChunkType(SHUTDOWN); 00858 //shutdownChunk->setCumTsnAck(state->lastTsnAck); 00859 shutdownChunk->setCumTsnAck(state->cTsnAck); 00860 shutdownChunk->setBitLength(SCTP_SHUTDOWN_CHUNK_LENGTH*8); 00861 state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT; 00862 state->initRetransCounter = 0; 00863 stopTimer(T5_ShutdownGuardTimer); 00864 startTimer(T5_ShutdownGuardTimer,SHUTDOWN_GUARD_TIMEOUT); 00865 stopTimer(T2_ShutdownTimer); 00866 startTimer(T2_ShutdownTimer,state->initRexmitTimeout); 00867 state->shutdownChunk=check_and_cast<SCTPShutdownChunk*>(shutdownChunk->dup()); 00868 msg->addChunk(shutdownChunk); 00869 sendToIP(msg, remoteAddr); 00870 }
void SCTPAssociation::sendShutdownAck | ( | IPvXAddress | dest | ) | [protected] |
Referenced by performStateTransition(), process_CLOSE(), process_RCV_Message(), and processAppCommand().
00783 { 00784 sendAll(dest); 00785 if (dest!=state->primaryPathIndex) 00786 sendAll(state->primaryPathIndex); 00787 if (getOutstandingBytes()==0) 00788 { 00789 performStateTransition(SCTP_E_NO_MORE_OUTSTANDING); 00790 SCTPMessage *sctpshutdownack = new SCTPMessage(); 00791 sctpshutdownack->setBitLength(SCTP_COMMON_HEADER*8); 00792 00793 sctpEV3<<"SCTPAssociationUtil:sendShutdownACK\n"; 00794 00795 sctpshutdownack->setSrcPort(localPort); 00796 sctpshutdownack->setDestPort(remotePort); 00797 SCTPShutdownAckChunk* shutdownAckChunk=new SCTPShutdownAckChunk("SHUTDOWN_ACK"); 00798 shutdownAckChunk->setChunkType(SHUTDOWN_ACK); 00799 shutdownAckChunk->setBitLength(SCTP_COOKIE_ACK_LENGTH*8); 00800 sctpshutdownack->addChunk(shutdownAckChunk); 00801 state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT; 00802 state->initRetransCounter = 0; 00803 stopTimer(T2_ShutdownTimer); 00804 startTimer(T2_ShutdownTimer,state->initRexmitTimeout); 00805 stopTimer(T5_ShutdownGuardTimer); 00806 startTimer(T5_ShutdownGuardTimer,SHUTDOWN_GUARD_TIMEOUT); 00807 state->shutdownAckChunk=check_and_cast<SCTPShutdownAckChunk*>(shutdownAckChunk->dup()); 00808 sendToIP(sctpshutdownack, dest); 00809 } 00810 }
void SCTPAssociation::sendShutdownComplete | ( | ) | [protected] |
Referenced by process_RCV_Message().
00813 { 00814 SCTPMessage *sctpshutdowncomplete = new SCTPMessage(); 00815 sctpshutdowncomplete->setBitLength(SCTP_COMMON_HEADER*8); 00816 00817 sctpEV3<<"SCTPAssociationUtil:sendShutdownComplete\n"; 00818 00819 sctpshutdowncomplete->setSrcPort(localPort); 00820 sctpshutdowncomplete->setDestPort(remotePort); 00821 SCTPShutdownCompleteChunk* shutdownCompleteChunk=new SCTPShutdownCompleteChunk("SHUTDOWN_COMPLETE"); 00822 shutdownCompleteChunk->setChunkType(SHUTDOWN_COMPLETE); 00823 shutdownCompleteChunk->setTBit(0); 00824 shutdownCompleteChunk->setBitLength(SCTP_SHUTDOWN_ACK_LENGTH*8); 00825 sctpshutdowncomplete->addChunk(shutdownCompleteChunk); 00826 sendToIP(sctpshutdowncomplete); 00827 }
SCTPSackChunk * SCTPAssociation::createSack | ( | ) | [protected] |
Referenced by sendAll(), and sendSack().
00932 { 00933 uint32 key=0, arwnd=0; 00934 00935 sctpEV3<<"SCTPAssociationUtil:createSACK localPort="<<localPort<<" remotePort="<<remotePort<<"\n"; 00936 00937 sctpEV3<<" localRwnd="<<state->localRwnd<<" queuedBytes="<<state->queuedRcvBytes<<"\n"; 00938 if ((int32)(state->localRwnd - state->queuedRcvBytes) <= 0) 00939 { 00940 arwnd = 0; 00941 if (state->swsLimit > 0) 00942 state->swsAvoidanceInvoked = true; 00943 } 00944 else if (state->localRwnd - state->queuedRcvBytes < state->swsLimit || state->swsAvoidanceInvoked == true) 00945 { 00946 arwnd = 1; 00947 if (state->swsLimit > 0) 00948 state->swsAvoidanceInvoked = true; 00949 // SWS Avoidance ACTIVE !!! 00950 } 00951 else 00952 { 00953 arwnd = state->localRwnd - state->queuedRcvBytes; 00954 sctpEV3<<simulation.getSimTime()<<" arwnd = "<<state->localRwnd<<" - "<<state->queuedRcvBytes<<" = "<<arwnd<<"\n"; 00955 } 00956 advRwnd->record(arwnd); 00957 quBytes->record(state->queuedRcvBytes); 00958 SCTPSackChunk* sackChunk=new SCTPSackChunk("SACK"); 00959 sackChunk->setChunkType(SACK); 00960 sackChunk->setCumTsnAck(state->cTsnAck); 00961 sackChunk->setA_rwnd(arwnd); 00962 uint32 numGaps=state->numGaps; 00963 uint32 numDups=state->dupList.size(); 00964 uint16 sackLength=SCTP_SACK_CHUNK_LENGTH + numGaps*4 + numDups*4; 00965 uint32 mtu = getPath(remoteAddr)->pmtu; 00966 00967 if (sackLength > mtu-32) // FIXME 00968 { 00969 if (SCTP_SACK_CHUNK_LENGTH + numGaps*4 > mtu-32) 00970 { 00971 numDups = 0; 00972 numGaps = (uint32)((mtu-32-SCTP_SACK_CHUNK_LENGTH)/4); 00973 } 00974 else 00975 { 00976 numDups = (uint32)((mtu-32-SCTP_SACK_CHUNK_LENGTH - numGaps*4)/4); 00977 } 00978 sackLength=SCTP_SACK_CHUNK_LENGTH + numGaps*4 + numDups*4; 00979 } 00980 sackChunk->setNumGaps(numGaps); 00981 sackChunk->setNumDupTsns(numDups); 00982 sackChunk->setBitLength(sackLength*8); 00983 00984 sctpEV3<<"Sack arwnd="<<sackChunk->getA_rwnd()<<" ctsnAck="<<state->cTsnAck<<" numGaps="<<numGaps<<" numDups="<<numDups<<"\n"; 00985 00986 if (numGaps > 0) 00987 { 00988 sackChunk->setGapStartArraySize(numGaps); 00989 sackChunk->setGapStopArraySize(numGaps); 00990 for (key=0; key<numGaps; key++) 00991 { 00992 sackChunk->setGapStart(key, state->gapStartList[key]); 00993 sackChunk->setGapStop(key, state->gapStopList[key]); 00994 } 00995 } 00996 if (numDups > 0) 00997 { 00998 sackChunk->setDupTsnsArraySize(numDups); 00999 key=0; 01000 for(std::list<uint32>::iterator iter=state->dupList.begin(); iter!=state->dupList.end(); iter++) 01001 { 01002 sackChunk->setDupTsns(key, (*iter)); 01003 key++; 01004 if (key == numDups) 01005 break; 01006 } 01007 state->dupList.clear(); 01008 } 01009 sctpEV3<<endl; 01010 for (uint32 i=0; i<numGaps; i++) 01011 sctpEV3<<sackChunk->getGapStart(i)<<" - "<<sackChunk->getGapStop(i)<<"\n"; 01012 01013 sctpEV3<<"send "<<sackChunk->getName()<<" from "<<localAddr<<" to "<<state->lastDataSourceAddress<<"\n"; 01014 return sackChunk; 01015 }
void SCTPAssociation::retransmitInit | ( | ) | [protected] |
Retransmitting chunks
Referenced by process_RCV_Message(), and process_TIMEOUT_INIT_REXMIT().
00508 { 00509 SCTPMessage *sctpmsg = new SCTPMessage(); 00510 sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); 00511 SCTPInitChunk *sctpinit;// = new SCTPInitChunk("INIT"); 00512 00513 sctpEV3<<"Retransmit InitChunk="<<&sctpinit<<"\n"; 00514 00515 sctpinit=check_and_cast<SCTPInitChunk *>(state->initChunk->dup()); 00516 sctpinit->setChunkType(INIT); 00517 sctpmsg->addChunk(sctpinit); 00518 00519 sendToIP(sctpmsg); 00520 00521 }
void SCTPAssociation::retransmitCookieEcho | ( | ) | [protected] |
Referenced by process_RCV_Message(), and process_TIMEOUT_INIT_REXMIT().
00698 { 00699 SCTPMessage *sctpmsg = new SCTPMessage(); 00700 sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); 00701 SCTPCookieEchoChunk* cookieEchoChunk=check_and_cast<SCTPCookieEchoChunk*>(state->cookieChunk->dup()); 00702 if (cookieEchoChunk->getCookieArraySize()==0) 00703 { 00704 cookieEchoChunk->setStateCookie(state->cookieChunk->getStateCookie()->dup()); 00705 } 00706 sctpmsg->addChunk(cookieEchoChunk); 00707 00708 sctpEV3<<"retransmitCookieEcho localAddr="<<localAddr<<" remoteAddr"<<remoteAddr<<"\n"; 00709 00710 sendToIP(sctpmsg); 00711 }
void SCTPAssociation::retransmitShutdown | ( | ) | [protected] |
Referenced by process_TIMEOUT_SHUTDOWN().
00874 { 00875 SCTPMessage *sctpmsg = new SCTPMessage(); 00876 sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); 00877 SCTPShutdownChunk* shutdownChunk; 00878 shutdownChunk=check_and_cast<SCTPShutdownChunk*>(state->shutdownChunk->dup()); 00879 00880 sctpmsg->addChunk(shutdownChunk); 00881 00882 sctpEV3<<"retransmitShutdown localAddr="<<localAddr<<" remoteAddr"<<remoteAddr<<"\n"; 00883 00884 sendToIP(sctpmsg); 00885 }
void SCTPAssociation::retransmitShutdownAck | ( | ) | [protected] |
Referenced by process_TIMEOUT_SHUTDOWN().
00888 { 00889 SCTPMessage *sctpmsg = new SCTPMessage(); 00890 sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); 00891 SCTPShutdownAckChunk* shutdownAckChunk; 00892 shutdownAckChunk=check_and_cast<SCTPShutdownAckChunk*>(state->shutdownAckChunk->dup()); 00893 sctpmsg->addChunk(shutdownAckChunk); 00894 00895 sctpEV3<<"retransmitShutdownAck localAddr="<<localAddr<<" remoteAddr"<<remoteAddr<<"\n"; 00896 00897 sendToIP(sctpmsg); 00898 }
void SCTPAssociation::sendToIP | ( | SCTPMessage * | sctpmsg | ) | [protected] |
Utility: adds control info to message and sends it to IP
Referenced by retransmitCookieEcho(), retransmitInit(), retransmitShutdown(), retransmitShutdownAck(), sendAbort(), sendAll(), sendCookieAck(), sendCookieEcho(), sendHeartbeat(), sendHeartbeatAck(), sendInit(), sendInitAck(), sendSack(), sendShutdown(), sendShutdownAck(), and sendShutdownComplete().
00204 { 00205 // final touches on the segment before sending 00206 sctpmsg->setSrcPort(localPort); 00207 sctpmsg->setDestPort(remotePort); 00208 if (sctpmsg->getTag()==0) 00209 sctpmsg->setTag(localVTag); 00210 sctpmsg->setChecksumOk(true); 00211 if (remoteAddr.isIPv6()) 00212 { 00213 IPv6ControlInfo *controlInfo = new IPv6ControlInfo(); 00214 controlInfo->setProtocol(IP_PROT_SCTP); 00215 controlInfo->setSrcAddr(IPv6Address()); 00216 controlInfo->setDestAddr(remoteAddr.get6()); 00217 sctpmsg->setControlInfo(controlInfo); 00218 sctpMain->send(sctpmsg,"to_ipv6"); 00219 } 00220 else 00221 { 00222 IPControlInfo *controlInfo = new IPControlInfo(); 00223 controlInfo->setProtocol(IP_PROT_SCTP); 00224 controlInfo->setSrcAddr(IPAddress("0.0.0.0")); 00225 controlInfo->setDestAddr(remoteAddr.get4()); 00226 sctpmsg->setControlInfo(controlInfo); 00227 sctpMain->send(sctpmsg,"to_ip"); 00228 } 00229 }
void SCTPAssociation::sendToIP | ( | SCTPMessage * | sctpmsg, | |
IPvXAddress | dest | |||
) | [protected] |
00232 { 00233 00234 sctpmsg->setSrcPort(localPort); 00235 sctpmsg->setDestPort(remotePort); 00236 sctpmsg->setChecksumOk(true); 00237 SCTPChunk* chunk = (SCTPChunk*)(sctpmsg->peekFirstChunk()); 00238 if (chunk->getChunkType() == ABORT) 00239 { 00240 SCTPAbortChunk* abortChunk; 00241 abortChunk = check_and_cast<SCTPAbortChunk *>(chunk); 00242 if (abortChunk->getT_Bit()==1) 00243 sctpmsg->setTag(peerVTag); 00244 else 00245 sctpmsg->setTag(localVTag); 00246 } 00247 else if (sctpmsg->getTag()==0) 00248 sctpmsg->setTag(localVTag); 00249 00250 if (dest.isIPv6()) 00251 { 00252 IPv6ControlInfo *controlInfo = new IPv6ControlInfo(); 00253 controlInfo->setProtocol(IP_PROT_SCTP); 00254 controlInfo->setSrcAddr(IPv6Address()); 00255 controlInfo->setDestAddr(dest.get6()); 00256 sctpmsg->setControlInfo(controlInfo); 00257 sctpMain->send(sctpmsg,"to_ipv6"); 00258 } 00259 else 00260 { 00261 IPControlInfo *controlInfo = new IPControlInfo(); 00262 controlInfo->setProtocol(IP_PROT_SCTP); 00263 controlInfo->setSrcAddr(IPAddress("0.0.0.0")); 00264 controlInfo->setDestAddr(dest.get4()); 00265 sctpmsg->setControlInfo(controlInfo); 00266 sctpMain->send(sctpmsg,"to_ip"); 00267 } 00268 00269 sctpEV3 << "Sent to "<<dest<<"\n "; 00270 00271 }
void SCTPAssociation::sendToIP | ( | SCTPMessage * | sctpmsg, | |
IPvXAddress | src, | |||
IPvXAddress | dest | |||
) | [protected] |
00274 { 00275 00276 sctpmsg->setSrcPort(localPort); 00277 sctpmsg->setDestPort(remotePort); 00278 sctpmsg->setChecksumOk(true); 00279 SCTPChunk* chunk = (SCTPChunk*)(sctpmsg->peekFirstChunk()); 00280 if (chunk->getChunkType() == ABORT) 00281 { 00282 SCTPAbortChunk* abortChunk; 00283 abortChunk = check_and_cast<SCTPAbortChunk *>(chunk); 00284 if (abortChunk->getT_Bit()==1) 00285 sctpmsg->setTag(peerVTag); 00286 else 00287 sctpmsg->setTag(localVTag); 00288 } 00289 else if (sctpmsg->getTag()==0) 00290 sctpmsg->setTag(localVTag); 00291 00292 if (dest.isIPv6()) 00293 { 00294 IPv6ControlInfo *controlInfo = new IPv6ControlInfo(); 00295 controlInfo->setProtocol(IP_PROT_SCTP); 00296 controlInfo->setSrcAddr(src.get6()); 00297 controlInfo->setDestAddr(dest.get6()); 00298 sctpmsg->setControlInfo(controlInfo); 00299 sctpMain->send(sctpmsg,"to_ipv6"); 00300 } 00301 else 00302 { 00303 IPControlInfo *controlInfo = new IPControlInfo(); 00304 controlInfo->setProtocol(IP_PROT_SCTP); 00305 controlInfo->setSrcAddr(src.get4()); 00306 controlInfo->setDestAddr(dest.get4()); 00307 sctpmsg->setControlInfo(controlInfo); 00308 sctpMain->send(sctpmsg,"to_ip"); 00309 } 00310 00311 sctpEV3 << "Sent to "<<dest<<"\n "; 00312 00313 }
void SCTPAssociation::scheduleSack | ( | void | ) | [protected] |
Referenced by process_RCV_Message().
00902 { 00903 /* increase SACK counter, we received another data PACKET */ 00904 if (state->firstChunkReceived) 00905 state->ackState++; 00906 else 00907 { 00908 state->ackState = sackFrequency; 00909 state->firstChunkReceived = true; 00910 } 00911 00912 sctpEV3<<"scheduleSack() : ackState is now: "<<state->ackState<<"\n"; 00913 00914 if (state->ackState <= sackFrequency - 1) 00915 { 00916 /* start a SACK timer if none is running, to expire 200 ms (or parameter) from now */ 00917 if (!SackTimer->isScheduled()) 00918 { 00919 startTimer(SackTimer, sackPeriod); 00920 } 00921 /* else: leave timer running, and do nothing... */ else { 00922 /* is this possible at all ? Check this... */ 00923 00924 sctpEV3<<"SACK timer running, but scheduleSack() called\n"; 00925 00926 } 00927 } 00928 }
void SCTPAssociation::signalConnectionTimeout | ( | ) | [protected] |
Utility: signal to user that connection timed out
00316 { 00317 sendIndicationToApp(SCTP_I_TIMED_OUT); 00318 }
void SCTPAssociation::scheduleTimeout | ( | cMessage * | msg, | |
simtime_t | timeout | |||
) | [inline, protected] |
Utility: start a timer
Referenced by SCTPAssociation(), and startTimer().
00641 {sctpMain->scheduleAt(simulation.getSimTime()+timeout, msg);}
cMessage* SCTPAssociation::cancelEvent | ( | cMessage * | msg | ) | [inline, protected] |
void SCTPAssociation::sendToApp | ( | cPacket * | msg | ) | [protected] |
Utility: sends packet to application
Referenced by pathStatusIndication(), process_STATUS(), pushUlp(), and sendDataArrivedNotification().
00351 { 00352 00353 sctpMain->send(msg, "to_appl", appGateIndex); 00354 }
void SCTPAssociation::sendIndicationToApp | ( | int32 | code | ) | [protected] |
Utility: sends status indication (SCTP_I_xxx) to application
Referenced by dequeueOutboundDataMsg(), process_RCV_Message(), process_SEND(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_RTX(), process_TIMEOUT_SHUTDOWN(), processTimer(), sendAll(), signalConnectionTimeout(), stateEntered(), and updateCounters().
00321 { 00322 cPacket *msg = new cPacket(indicationName(code)); 00323 msg->setKind(code); 00324 SCTPCommand *ind = new SCTPCommand(indicationName(code)); 00325 ind->setAssocId(assocId); 00326 ind->setLocalAddr(localAddr); 00327 ind->setRemoteAddr(remoteAddr); 00328 msg->setControlInfo(ind); 00329 sctpMain->send(msg, "to_appl", appGateIndex); 00330 }
void SCTPAssociation::sendEstabIndicationToApp | ( | ) | [protected] |
Utility: sends SCTP_I_ESTABLISHED indication with SCTPConnectInfo to application
Referenced by stateEntered().
00333 { 00334 cPacket *msg = new cPacket(indicationName(SCTP_I_ESTABLISHED)); 00335 msg->setKind(SCTP_I_ESTABLISHED); 00336 00337 SCTPConnectInfo *ind = new SCTPConnectInfo("CI"); 00338 ind->setAssocId(assocId); 00339 ind->setLocalAddr(localAddr); 00340 ind->setRemoteAddr(remoteAddr); 00341 ind->setLocalPort(localPort); 00342 ind->setRemotePort(remotePort); 00343 ind->setRemoteAddresses(remoteAddressList); 00344 ind->setInboundStreams(inboundStreams); 00345 ind->setOutboundStreams(outboundStreams); 00346 msg->setControlInfo(ind); 00347 sctpMain->send(msg, "to_appl", appGateIndex); 00348 }
void SCTPAssociation::pushUlp | ( | ) | [protected] |
Referenced by process_RECEIVE_REQUEST().
01624 { 01625 int32 count=0; 01626 SCTPReceiveStream* rStream; 01627 SCTPDataVariables* chunk; 01628 for (unsigned i=0; i<inboundStreams; i++) //12.06.08 01629 putInDeliveryQ(i); 01630 if (state->pushMessagesLeft <=0) 01631 state->pushMessagesLeft = state->messagesToPush; 01632 bool restrict = false; 01633 01634 if (state->pushMessagesLeft > 0) 01635 restrict = true; 01636 01637 quBytes->record(state->queuedRcvBytes); 01638 01639 sctpEV3<<simulation.getSimTime()<<" Calling PUSH_ULP ("<<state->queuedRcvBytes<<" bytes queued)...\n"; 01640 uint32 i=state->nextRSid; 01641 do 01642 { 01643 SCTPReceiveStreamMap::iterator iter=receiveStreams.find(i); 01644 rStream=iter->second; 01645 sctpEV3<<"Size of stream "<<iter->first<<": "<<rStream->getDeliveryQ()->getQueueSize()<<"\n"; 01646 01647 while (!rStream->getDeliveryQ()->payloadQueue.empty() && (!restrict || (restrict && state->pushMessagesLeft>0))) 01648 { 01649 chunk = rStream->getDeliveryQ()->extractMessage(); 01650 qCounter.roomSumRcvStreams -= ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH); 01651 01652 if (state->pushMessagesLeft >0) 01653 state->pushMessagesLeft--; 01654 01655 state->queuedRcvBytes-=chunk->len/8; 01656 01657 if (state->swsAvoidanceInvoked) 01658 { 01659 quBytes->record(state->queuedRcvBytes); 01660 if ((int32)(state->localRwnd - state->queuedRcvBytes) >= (int32)(state->swsLimit) && (int32)(state->localRwnd - state->queuedRcvBytes) <= (int32)(state->swsLimit+state->assocPmtu)) 01661 01662 { 01663 /* only if the window has opened up more than one MTU we will send a SACK */ 01664 state->swsAvoidanceInvoked = false; 01665 sctpEV3<<"pushUlp: Window opens up to "<<(int32)state->localRwnd-state->queuedRcvBytes<<" bytes: sending a SACK. SWS Avoidance INACTIVE\n"; 01666 01667 sendSack(); 01668 } 01669 } 01670 sctpEV3<<"Push TSN "<<chunk->tsn<<": sid="<<chunk->sid<<" ssn="<<chunk->ssn<<"\n"; 01671 cPacket* msg= (cPacket *)chunk->userData; 01672 msg->setKind(SCTP_I_DATA); 01673 SCTPCommand *cmd = new SCTPCommand("push"); 01674 cmd->setAssocId(assocId); 01675 cmd->setGate(appGateIndex); 01676 cmd->setSid(chunk->sid); 01677 cmd->setLocalAddr(localAddr); 01678 cmd->setRemoteAddr(remoteAddr); 01679 msg->setControlInfo(cmd); 01680 state->numMsgsReq[count]--; 01681 delete chunk; 01682 sendToApp(msg); 01683 } 01684 01685 i = (i+1)%inboundStreams; 01686 01687 count++; 01688 } while (i!=state->nextRSid); 01689 01690 state->nextRSid = (state->nextRSid+1)%inboundStreams; 01691 01692 if (state->queuedRcvBytes==0 && fsm->getState()==SCTP_S_SHUTDOWN_ACK_SENT) 01693 { 01694 sctpEV3<<"SCTP_E_CLOSE\n"; 01695 performStateTransition(SCTP_E_CLOSE); 01696 } 01697 }
void SCTPAssociation::sendDataArrivedNotification | ( | uint16 | sid | ) | [protected] |
Referenced by processDataArrived(), and putInDeliveryQ().
01568 { 01569 01570 sctpEV3<<"SendDataArrivedNotification\n"; 01571 01572 cPacket* cmsg = new cPacket("DataArrivedNotification"); 01573 cmsg->setKind(SCTP_I_DATA_NOTIFICATION); 01574 SCTPCommand *cmd = new SCTPCommand("notification"); 01575 cmd->setAssocId(assocId); 01576 cmd->setSid(sid); 01577 cmd->setNumMsgs(1); 01578 cmsg->setControlInfo(cmd); 01579 01580 sendToApp(cmsg); 01581 }
void SCTPAssociation::putInDeliveryQ | ( | uint16 | sid | ) | [protected] |
Referenced by processDataArrived(), and pushUlp().
01585 { 01586 SCTPReceiveStream* rStream; 01587 SCTPDataVariables* chunk; 01588 SCTPReceiveStreamMap::iterator iter=receiveStreams.find(sid); 01589 rStream = iter->second; 01590 sctpEV3<<"putInDeliveryQ: first look for SSN "<<rStream->getExpectedStreamSeqNum()<<" of SID "<<sid<<" in orderedQ of size "<<rStream->getOrderedQ()->getQueueSize()<<"\n"; 01591 while (rStream->getOrderedQ()->getQueueSize()>0) 01592 { 01593 /* dequeue first from reassembly Q */ 01594 chunk = rStream->getOrderedQ()-> dequeueVarBySsn(rStream->getExpectedStreamSeqNum()); 01595 if (chunk) 01596 { 01597 sctpEV3<<"putInDeliveryQ::chunk "<<chunk->tsn<<" , sid "<<chunk->sid<<" and ssn "<<chunk->ssn<<" dequeued from ordered queue. queuedRcvBytes="<<state->queuedRcvBytes<<" will be reduced by "<<chunk->len/8<<"\n"; 01598 state->queuedRcvBytes-=chunk->len/8; 01599 01600 01601 qCounter.roomSumRcvStreams -= ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH); 01602 if (rStream->getDeliveryQ()->checkAndInsertVar(chunk->tsn, chunk)) 01603 { 01604 01605 state->queuedRcvBytes+=chunk->len/8; 01606 01607 sctpEV3<<"data put in deliveryQ; queuedBytes now "<<state->queuedRcvBytes<<"\n"; 01608 qCounter.roomSumRcvStreams += ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH); 01609 int32 seqnum=rStream->getExpectedStreamSeqNum(); 01610 rStream->setExpectedStreamSeqNum(++seqnum); 01611 if (rStream->getExpectedStreamSeqNum() > 65535) 01612 rStream->setExpectedStreamSeqNum(0); 01613 sendDataArrivedNotification(sid); 01614 } 01615 } 01616 else 01617 { 01618 break; 01619 } 01620 } 01621 }
void SCTPAssociation::printConnBrief | ( | ) | [protected] |
Utility: prints local/remote addr/port and app gate index/assocId
Referenced by processAppCommand(), and processSCTPMessage().
00161 { 00162 sctpEV3 << "Connection " << this << " "; 00163 sctpEV3 << localAddr << ":" << localPort << " to " << remoteAddr << ":" << remotePort; 00164 sctpEV3 << " on app[" << appGateIndex << "],assocId=" << assocId; 00165 sctpEV3 << " in " << stateName(fsm->getState()) << "\n"; 00166 00167 }
void SCTPAssociation::printSegmentBrief | ( | SCTPMessage * | sctpmsg | ) | [static, protected] |
const char * SCTPAssociation::eventName | ( | int32 | event | ) | [static, protected] |
Utility: returns name of SCTP_E_xxx constants
Referenced by performStateTransition(), and processAppCommand().
00076 { 00077 #define CASE(x) case x: s=#x+7; break 00078 const char *s = "unknown"; 00079 switch (event) 00080 { 00081 CASE(SCTP_E_OPEN_PASSIVE); 00082 CASE(SCTP_E_ASSOCIATE); 00083 CASE(SCTP_E_SHUTDOWN); 00084 CASE(SCTP_E_CLOSE); 00085 CASE(SCTP_E_ABORT); 00086 CASE(SCTP_E_SEND); 00087 CASE(SCTP_E_RCV_INIT); 00088 CASE(SCTP_E_RCV_ABORT); 00089 CASE(SCTP_E_RCV_VALID_COOKIE_ECHO); 00090 CASE(SCTP_E_RCV_INIT_ACK); 00091 CASE(SCTP_E_RCV_COOKIE_ACK); 00092 CASE(SCTP_E_RCV_SHUTDOWN); 00093 CASE(SCTP_E_RCV_SHUTDOWN_ACK); 00094 CASE(SCTP_E_RCV_SHUTDOWN_COMPLETE); 00095 CASE(SCTP_E_TIMEOUT_INIT_TIMER); 00096 CASE(SCTP_E_TIMEOUT_SHUTDOWN_TIMER); 00097 CASE(SCTP_E_TIMEOUT_RTX_TIMER); 00098 CASE(SCTP_E_TIMEOUT_HEARTBEAT_TIMER); 00099 CASE(SCTP_E_RECEIVE); 00100 CASE(SCTP_E_DUP_RECEIVED); 00101 CASE(SCTP_E_PRIMARY); 00102 CASE(SCTP_E_QUEUE); 00103 CASE(SCTP_E_NO_MORE_OUTSTANDING); 00104 CASE(SCTP_E_IGNORE); 00105 CASE(SCTP_E_DELIVERED); 00106 CASE(SCTP_E_SEND_SHUTDOWN_ACK); 00107 CASE(SCTP_E_STOP_SENDING); 00108 } 00109 return s; 00110 #undef CASE 00111 }
void SCTPAssociation::addPath | ( | IPvXAddress | addr | ) | [protected] |
Referenced by processInitAckArrived().
01725 { 01726 01727 sctpEV3<<"Add Path remote address: "<<addr<<"\n"; 01728 01729 SCTPPathMap::iterator i = sctpPathMap.find(addr); 01730 if (i==sctpPathMap.end()) 01731 { 01732 SCTPPathVariables* path = new SCTPPathVariables(addr, this); 01733 sctpPathMap[addr] = path; 01734 qCounter.roomTransQ[addr] = 0; 01735 qCounter.roomRetransQ[addr] = 0; 01736 qCounter.bookedTransQ[addr] = 0; 01737 } 01738 }
IPvXAddress SCTPAssociation::getNextDestination | ( | SCTPDataVariables * | chk | ) | [protected] |
Referenced by process_TIMEOUT_RTX(), and processSackArrived().
02380 { 02381 IPvXAddress dpi, last; 02382 02383 02384 sctpEV3<<"getNextDestination\n"; 02385 02386 if (chk->numberOfTransmissions == 0) 02387 { 02388 if (chk->initialDestination == IPvXAddress("0.0.0.0")) 02389 { 02390 dpi = state->primaryPathIndex; 02391 } 02392 else 02393 { 02394 dpi = chk->initialDestination; 02395 } 02396 } 02397 else 02398 { 02399 if (chk->hasBeenFastRetransmitted) 02400 { 02401 02402 sctpEV3<<"Chunk is scheduled for FastRetransmission. Next destination = "<<chk->lastDestination<<"\n"; 02403 02404 //chk->hasBeenFastRetransmitted=false; 02405 return chk->lastDestination; 02406 } 02407 dpi = last = chk->lastDestination; 02408 /* if this is a retransmission, we should choose another, active path */ 02409 SCTPPathMap::iterator iter=sctpPathMap.find(dpi); 02410 do 02411 { 02412 02413 sctpEV3<<"old dpi="<<iter->first<<"\n"; 02414 02415 iter++; 02416 if (iter==sctpPathMap.end()) 02417 iter=sctpPathMap.begin(); 02418 dpi=iter->first; 02419 02420 } while (iter->first != last && iter->second->activePath == false || iter->second->confirmed==false); 02421 } 02422 02423 02424 sctpEV3<<"sctp_get_next_destination: chunk was last sent to "<<last<<", will next be sent to path "<<dpi<<"\n"; 02425 02426 sctpEV3<<"new dpi="<<dpi<<"\n"; 02427 return (dpi); 02428 }
IPvXAddress SCTPAssociation::getNextAddress | ( | IPvXAddress | dpi | ) | [protected] |
Referenced by process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_RTX(), and updateCounters().
02357 { 02358 02359 int32 hit=0; 02360 02361 if (sctpPathMap.size()>1) 02362 { 02363 for (SCTPPathMap::iterator iter=sctpPathMap.begin(); iter!=sctpPathMap.end(); iter++) 02364 { 02365 if (iter->first==pid) 02366 { 02367 if (++hit==1) 02368 continue; 02369 else 02370 break; 02371 } 02372 if (iter->second->activePath) 02373 return iter->first; 02374 } 02375 } 02376 return IPvXAddress("0.0.0.0"); 02377 }
void SCTPAssociation::bytesAllowedToSend | ( | IPvXAddress | dpi | ) | [protected] |
Referenced by sendAll().
02431 { 02432 uint32 osb = 0; 02433 int32 diff = 0; 02434 SCTPPathMap::iterator iter; 02435 bytes.chunk = false; 02436 bytes.packet = false; 02437 bytes.bytesToSend = 0; 02438 02439 iter=sctpPathMap.find(dpi); 02440 osb = getPath(dpi)->outstandingBytes; 02441 sctpEV3<<"bytesAllowedToSend: osb="<<osb<<" cwnd="<<iter->second->cwnd<<"\n"; 02442 if (!state->firstDataSent) 02443 { 02444 bytes.chunk = true; 02445 return; 02446 } 02447 if (state->peerWindowFull) 02448 { 02449 if (osb==0) 02450 { 02451 sctpEV3<<"probingIsAllowed\n"; 02452 state->zeroWindowProbing=true; 02453 bytes.chunk = true; 02454 } 02455 return; 02456 } 02457 else 02458 { 02459 02460 02461 sctpEV3<<"bytesAllowedToSend: osb="<<osb<<" cwnd="<<iter->second->cwnd<<"\n"; 02462 CounterMap::iterator it = qCounter.roomTransQ.find(dpi); 02463 sctpEV3<<"bytes in transQ="<<it->second<<"\n"; 02464 if (it->second>0) 02465 { 02466 diff = iter->second->cwnd - osb; 02467 sctpEV3<<"cwnd-osb="<<diff<<"\n"; 02468 if (state->peerRwnd<iter->second->pmtu) 02469 { 02470 bytes.bytesToSend = state->peerRwnd; 02471 return; 02472 } 02473 if (diff > 0) 02474 { 02475 CounterMap::iterator bit = qCounter.bookedTransQ.find(dpi); 02476 if (bit->second > (uint32)diff) 02477 { 02478 bytes.bytesToSend = diff; 02479 sctpEV3<<"cwnd does not allow all RTX\n"; 02480 return; 02481 } 02482 else 02483 { 02484 bytes.bytesToSend = bit->second; 02485 sctpEV3<<"cwnd allows more than those "<<bytes.bytesToSend<<" bytes for retransmission\n"; 02486 } 02487 } 02488 else // You may transmit one packet 02489 { 02490 bytes.packet = true; 02491 sctpEV3<<"diff<=0: retransmit one packet\n"; 02492 return; 02493 } 02494 } 02495 02496 if (!bytes.chunk && !bytes.packet) 02497 { 02498 if (osb < iter->second->cwnd && !state->peerWindowFull ) 02499 { 02500 sctpEV3<<"bookedSumSendStreams="<<qCounter.bookedSumSendStreams<<" bytes.bytesToSend="<<bytes.bytesToSend<<"\n"; 02501 diff = iter->second->cwnd - osb - bytes.bytesToSend; 02502 if (diff>0) 02503 if (qCounter.bookedSumSendStreams > (uint32)diff) 02504 { 02505 bytes.bytesToSend = iter->second->cwnd - osb ; 02506 sctpEV3<<"bytesToSend are limited by cwnd: "<<bytes.bytesToSend<<"\n"; 02507 } 02508 else 02509 { 02510 bytes.bytesToSend += qCounter.bookedSumSendStreams; 02511 sctpEV3<<"send all stored bytes: "<<bytes.bytesToSend<<"\n"; 02512 } 02513 } 02514 } 02515 } 02516 02517 }
void SCTPAssociation::pathStatusIndication | ( | IPvXAddress | pid, | |
bool | status | |||
) | [protected] |
Referenced by pmClearPathCounter(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_RTX(), and updateCounters().
02817 { 02818 cPacket* msg=new cPacket("StatusInfo"); 02819 msg->setKind(SCTP_I_STATUS); 02820 SCTPStatusInfo *cmd = new SCTPStatusInfo(); 02821 cmd->setPathId(pid); 02822 cmd->setAssocId(assocId); 02823 cmd->setActive(status); 02824 msg->setControlInfo(cmd); 02825 if (!status) 02826 { 02827 SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId); 02828 iter->second.numPathFailures++; 02829 } 02830 sendToApp(msg); 02831 }
bool SCTPAssociation::allPathsInactive | ( | void | ) | [protected] |
Referenced by process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_RTX(), and updateCounters().
02947 { 02948 for(SCTPPathMap::iterator i=sctpPathMap.begin(); i!=sctpPathMap.end(); i++) 02949 { 02950 if (i->second->activePath) 02951 return false; 02952 } 02953 02954 return true; 02955 }
uint32 SCTPAssociation::getLevel | ( | IPvXAddress | addr | ) | [protected] |
Referenced by processInitArrived(), and sendInit().
02958 { 02959 if (addr.isIPv6()) 02960 { 02961 if (addr.get6().getScope()==IPv6Address::UNSPECIFIED || addr.get6().getScope()==IPv6Address::MULTICAST) 02962 return 0; 02963 if (addr.get6().getScope()==IPv6Address::LOOPBACK) 02964 return 1; 02965 if (addr.get6().getScope()==IPv6Address::LINK) 02966 return 2; 02967 if (addr.get6().getScope()==IPv6Address::SITE) 02968 return 3; 02969 } 02970 else 02971 { 02972 //Addresses usable with SCTP, but not as destination or source address 02973 if (addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("0.0.0.0"), IPAddress("255.0.0.0")) || 02974 addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("224.0.0.0"), IPAddress("240.0.0.0")) || 02975 addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("198.18.0.0"), IPAddress("255.255.255.0")) || 02976 addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("192.88.99.0"), IPAddress("255.255.255.0"))) 02977 return 0; 02978 02979 //Loopback 02980 if (addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("127.0.0.0"), IPAddress("255.0.0.0"))) 02981 return 1; 02982 02983 //Link-local 02984 if (addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("169.254.0.0"), IPAddress("255.255.0.0"))) 02985 return 2; 02986 02987 //Private 02988 if (addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("10.0.0.0"), IPAddress("255.0.0.0")) || 02989 addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("172.16.0.0"), IPAddress("255.240.0.0")) || 02990 addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("192.168.0.0"), IPAddress("255.255.0.0"))) 02991 return 3; 02992 } 02993 //Global 02994 return 4; 02995 }
SCTPDataChunk * SCTPAssociation::transformDataChunk | ( | SCTPDataVariables * | datVar | ) | [protected] |
Manipulating chunks
Referenced by sendAll().
01700 { 01701 01702 SCTPDataChunk* dataChunk=new SCTPDataChunk("DATA"); 01703 SCTPSimpleMessage* msg=check_and_cast<SCTPSimpleMessage*>(datVar->userData->dup()); 01704 dataChunk->setChunkType(DATA); 01705 // no fragmentation implemented yet 01706 dataChunk->setBBit(1); 01707 dataChunk->setEBit(1); 01708 if (datVar->ordered) 01709 dataChunk->setUBit(0); 01710 else 01711 dataChunk->setUBit(1); 01712 dataChunk->setTsn(datVar->tsn); 01713 dataChunk->setSid(datVar->sid); 01714 dataChunk->setSsn(datVar->ssn); 01715 dataChunk->setPpid(datVar->ppid); 01716 dataChunk->setEnqueuingTime(datVar->enqueuingTime); 01717 dataChunk->setBitLength(SCTP_DATA_CHUNK_LENGTH*8); 01718 msg->setBitLength(datVar->len); 01719 dataChunk->encapsulate(msg); 01720 return dataChunk; 01721 }
SCTPDataVariables * SCTPAssociation::makeVarFromMsg | ( | SCTPDataChunk * | datachunk | ) | [protected] |
Referenced by processDataArrived().
02152 { 02153 SCTPDataVariables* datVar=new SCTPDataVariables(); 02154 02155 datVar->sid = dataChunk->getSid(); 02156 datVar->ssn = dataChunk->getSsn(); 02157 datVar->ppid = dataChunk->getPpid(); 02158 datVar->tsn = dataChunk->getTsn(); 02159 if (!dataChunk->getUBit()) 02160 datVar->ordered = true; 02161 else 02162 datVar->ordered = false; 02163 SCTPSimpleMessage* smsg=check_and_cast<SCTPSimpleMessage*>(dataChunk->decapsulate()); 02164 02165 datVar->userData = smsg; 02166 datVar->len = smsg->getDataLen()*8; 02167 sctpEV3<<"Datenlaenge="<<datVar->len/8<<"\n"; 02168 02169 02170 sctpEV3<<"makeVarFromMsg::queuedBytes have been increased to "<<state->queuedRcvBytes<<"\n"; 02171 return datVar; 02172 }
int32 SCTPAssociation::streamScheduler | ( | bool | peek | ) | [protected] |
Dealing with streams
Referenced by SCTPAssociation().
00063 { 00064 00065 uint32 sid = 0; 00066 int32 num = 0; 00067 00068 //num = numUsableStreams(); 00069 num = (this->*ssFunctions.ssUsableStreams)(); 00070 00071 if (num > 1) 00072 { 00073 sid = (state->lastStreamScheduled + 1) % outboundStreams; 00074 00075 sctpEV3<<"streamScheduler sid="<<sid<<" lastStream="<<state->lastStreamScheduled<<" outboundStreams="<<outboundStreams<<"\n"; 00076 00077 num = (this->*ssFunctions.ssUsableStreams)(); 00078 while (sid!=state->lastStreamScheduled) 00079 { 00080 SCTPSendStreamMap::iterator iter=sendStreams.find(sid); 00081 SCTPSendStream* stream=iter->second; 00082 cQueue* strQ=stream->getUnorderedStreamQ(); 00083 00084 sctpEV3<<"Laenge unordered StreamQueue Nr "<<sid<<" = "<<strQ->length()<<"\n"; 00085 00086 if (strQ && strQ->length()>0) 00087 { 00088 sid =(iter->first); 00089 00090 if (!peek) 00091 state->lastStreamScheduled = sid; 00092 return sid; 00093 } 00094 strQ=stream->getStreamQ(); 00095 00096 sctpEV3<<"Laenge StreamQueue Nr "<<sid<<" = "<<strQ->length()<<"\n"; 00097 00098 if (strQ && strQ->length()>0) 00099 { 00100 sid =(iter->first); 00101 00102 if (!peek) 00103 state->lastStreamScheduled = sid; 00104 return sid; 00105 } 00106 else 00107 { 00108 sid = (sid+1)%outboundStreams; 00109 00110 sctpEV3<<"new sid="<<sid<<"\n"; 00111 00112 } 00113 } 00114 } 00115 else if (num == 1) 00116 { 00117 for (SCTPSendStreamMap::iterator iter=sendStreams.begin(); iter!=sendStreams.end(); ++iter) 00118 { 00119 if (iter->second->getUnorderedStreamQ()->length()>0) 00120 { 00121 sid = iter->first; 00122 if (!peek) 00123 state->lastStreamScheduled = sid; 00124 return sid; 00125 } 00126 if (iter->second->getStreamQ()->length()>0) 00127 { 00128 sid = iter->first; 00129 if (!peek) 00130 state->lastStreamScheduled = sid; 00131 return sid; 00132 } 00133 } 00134 } 00135 00136 00137 00138 sctpEV3<<"Stream Scheduler: found no stream with data queued !\n"; 00139 00140 return (-1); 00141 }
void SCTPAssociation::initStreams | ( | uint32 | inStreams, | |
uint32 | outStreams | |||
) | [protected] |
Referenced by SCTPAssociation().
00037 { 00038 uint32 i; 00039 00040 sctpEV3<<"initStreams instreams="<<inStreams<<" outstream="<<outStreams<<"\n"; 00041 if (receiveStreams.size()==0 && sendStreams.size()==0) 00042 { 00043 for (i=0; i<inStreams; i++) 00044 { 00045 SCTPReceiveStream* rcvStream = new SCTPReceiveStream(); 00046 00047 this->receiveStreams[i]=rcvStream; 00048 rcvStream->setStreamId(i); 00049 00050 this->state->numMsgsReq[i]=0; 00051 } 00052 for (i=0; i<outStreams; i++) 00053 { 00054 SCTPSendStream* sendStream = new SCTPSendStream(i); 00055 this->sendStreams[i]=sendStream; 00056 sendStream->setStreamId(i); 00057 } 00058 } 00059 }
int32 SCTPAssociation::numUsableStreams | ( | void | ) | [protected] |
Referenced by SCTPAssociation().
00145 { 00146 int32 count=0; 00147 00148 00149 for (SCTPSendStreamMap::iterator iter=sendStreams.begin(); iter!=sendStreams.end(); iter++) 00150 if (iter->second->getStreamQ()->length()>0 || iter->second->getUnorderedStreamQ()->length()>0) 00151 { 00152 count++; 00153 } 00154 return count; 00155 }
int32 SCTPAssociation::getQueuedBytes | ( | void | ) | [protected] |
Queue Management
02684 { 02685 int32 qb = 0; 02686 SCTPReceiveStream* rStream; 02687 SCTPQueue* sq; 02688 02689 for (SCTPReceiveStreamMap::iterator iter=receiveStreams.begin(); iter!=receiveStreams.end(); iter++) 02690 { 02691 rStream = iter->second; 02692 sq = rStream->getOrderedQ(); 02693 if (sq) 02694 { 02695 qb+=sq->getNumBytes(); 02696 } 02697 sq = rStream->getUnorderedQ(); 02698 if (sq) 02699 { 02700 qb+=sq->getNumBytes(); 02701 } 02702 sq = rStream->getDeliveryQ(); 02703 if (sq) 02704 { 02705 qb+=sq->getNumBytes(); 02706 } 02707 } 02708 02709 02710 sctpEV3<<"getQueuedBytes : currently "<<qb<<" bytes buffered\n"; 02711 02712 return (qb); 02713 }
int32 SCTPAssociation::getOutstandingBytes | ( | void | ) | [protected] |
Referenced by process_CLOSE(), process_RCV_Message(), processAppCommand(), processSackArrived(), sendShutdownAck(), and stateEntered().
02716 { 02717 int32 osb = 0; 02718 for (SCTPPathMap::iterator pm=sctpPathMap.begin(); pm != sctpPathMap.end(); pm++) 02719 osb += pm->second->outstandingBytes; 02720 return osb; 02721 }
int32 SCTPAssociation::dequeueAckedChunks | ( | uint32 | tsna, | |
IPvXAddress | pathId, | |||
simtime_t * | rttEstimation | |||
) | [protected] |
Referenced by process_RCV_Message(), and processSackArrived().
02724 { 02725 int32 newlyAckedBytes = 0; 02726 SCTPDataVariables* chunk = NULL; 02727 simtime_t timeDiff = 0.0; 02728 02729 /* set it ridiculously high */ 02730 *rttEstimation = -1.0; 02731 02732 /* are there chunks in the retransmission queue ? If Yes -> check for dequeue */ 02733 while (!retransmissionQ->payloadQueue.empty()) 02734 { 02735 02736 SCTPQueue::PayloadQueue::iterator iter=retransmissionQ->payloadQueue.begin(); 02737 chunk = iter->second; 02738 02739 sctpEV3<<"dequeueAckedChunks() found chunk tsn "<<chunk->tsn<<" in the retransmissionQ\n"; 02740 02741 02742 if (tsnGe(tsna,chunk->tsn)) 02743 { 02744 /* dequeue chunk, cause it has been acked */ 02745 if (transmissionQ->getVar(chunk->tsn)) 02746 { 02747 sctpEV3<<"Chunk was found in transmissionQ. Remove it\n"; 02748 transmissionQ->removeMsg(chunk->tsn); 02749 CounterMap::iterator q = qCounter.roomTransQ.find(chunk->nextDestination); 02750 q->second -= ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH); 02751 CounterMap::iterator qb = qCounter.bookedTransQ.find(chunk->nextDestination); 02752 qb->second -= chunk->booksize; 02753 } 02754 chunk = retransmissionQ->getAndExtractMessage(chunk->tsn); 02755 sctpEV3<<"dequeueAckedChunks(): dequeue chunk tsn="<<chunk->tsn<<", tsna="<<tsna<<", "<<retransmissionQ->getQueueSize()<<" chunks still in queue \n"; 02756 02757 if (!chunk->hasBeenAcked) 02758 newlyAckedBytes += (chunk->booksize); 02759 SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId); 02760 iter->second.ackedBytes+=chunk->len/8; 02761 02762 if (chunk->hasBeenAcked == false && chunk->countsAsOutstanding) 02763 { 02764 chunk->hasBeenAcked = true; 02765 chunk->countsAsOutstanding = false; 02766 if (chunk->numberOfTransmissions == 1 && chunk->lastDestination == pathId) 02767 { 02768 timeDiff = simulation.getSimTime() - chunk->sendTime; 02769 02770 if (timeDiff < *rttEstimation || *rttEstimation == -1.0) 02771 *rttEstimation = timeDiff; 02772 02773 sctpEV3<<"dequeueAckedChunks(): computed rtt time diff == "<<timeDiff<<" for TSN"<<chunk->tsn<<"\n"; 02774 } 02775 getPath(chunk->lastDestination)->outstandingBytes -= chunk->booksize; 02776 sctpEV3<<"osb="<<getPath(chunk->lastDestination)->outstandingBytes<<"\n"; 02777 CounterMap::iterator i=qCounter.roomRetransQ.find(getPath(chunk->lastDestination)->remoteAddress); 02778 i->second -= ADD_PADDING(chunk->booksize+SCTP_DATA_CHUNK_LENGTH); 02779 } 02780 pmClearPathCounter(chunk->lastDestination); 02781 if (chunk->userData != NULL) 02782 { 02783 delete chunk->userData; 02784 } 02785 delete chunk; 02786 } 02787 else 02788 break; 02789 } 02790 02791 02792 sctpEV3<<"dequeueAckedChunks(): newly_acked_bytes== "<<newlyAckedBytes<<", rtt estimation == "<<*rttEstimation<<"\n"; 02793 02794 02795 return (newlyAckedBytes); 02796 }
uint32 SCTPAssociation::getOutstandingBytesOnPath | ( | IPvXAddress | pathId | ) | [protected] |
02552 { 02553 uint32 osb = 0, queueLength = 0, first=0, second = 0; 02554 02555 02556 if (retransmissionQ->payloadQueue.empty()) return 0; 02557 02558 queueLength = retransmissionQ->getQueueSize(); 02559 sctpEV3<<"queueLength of retransmissionQ="<<queueLength<<"\n"; 02560 sctpEV3<<"outstanding TSNs\n"; 02561 for(SCTPQueue::PayloadQueue::iterator pl=retransmissionQ->payloadQueue.begin();pl!=retransmissionQ->payloadQueue.end();pl++) 02562 { 02563 if (pl->second->lastDestination == pathId) 02564 { 02565 if (pl->second->hasBeenAcked == false && pl->second->countsAsOutstanding == true) 02566 { 02567 //osb += pl->second->len/8; 02568 if (pl->second->tsn > second+1) 02569 { 02570 if (second != 0) 02571 { 02572 sctpEV3<<" - "<<second<<"\t";; 02573 02574 } 02575 first = second = pl->second->tsn; 02576 sctpEV3<<pl->second->tsn; 02577 } 02578 else if (pl->second->tsn == second+1) 02579 { 02580 second = pl->second->tsn; 02581 } 02582 first = pl->second->tsn; 02583 osb += pl->second->booksize; 02584 } 02585 } 02586 } 02587 sctpEV3<<" - "<<second<<"\n"; 02588 02589 sctpEV3<<"getOutstandingBytesOnPath("<<(pathId)<<") : currently "<<osb<<" bytes outstanding\n"; 02590 02591 02592 return (osb); 02593 }
SCTPDataVariables * SCTPAssociation::peekOutboundDataChunk | ( | IPvXAddress | pid | ) | [protected] |
02213 { 02214 SCTPDataVariables* chunk = NULL; 02215 02216 /* are there chunks in the transmission queue ? If Yes -> dequeue and return it */ 02217 if (!transmissionQ->payloadQueue.empty()) 02218 { 02219 for(SCTPQueue::PayloadQueue::iterator it=transmissionQ->payloadQueue.begin(); it!=transmissionQ->payloadQueue.end(); it++) 02220 { 02221 chunk = it->second; 02222 if (chunk->nextDestination == pid) 02223 { 02224 sctpEV3<<"peekOutboundDataChunk() found chunk "<<chunk->tsn<<" in the transmission queue\n"; 02225 if (chunk->hasBeenAcked) 02226 { 02227 transmissionQ->payloadQueue.erase(it); 02228 CounterMap::iterator i=qCounter.roomTransQ.find(pid); 02229 i->second-= ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH); 02230 CounterMap::iterator ib=qCounter.bookedTransQ.find(pid); 02231 ib->second-= chunk->booksize; 02232 } 02233 else 02234 { 02235 return chunk; 02236 } 02237 } 02238 } 02239 } 02240 02241 return NULL; 02242 }
SCTPDataMsg * SCTPAssociation::peekOutboundDataMsg | ( | void | ) | [protected] |
Referenced by sendAll().
02268 { 02269 SCTPDataMsg* datMsg=NULL; 02270 int32 nextStream = -1; 02271 nextStream = (this->*ssFunctions.ssGetNextSid)(true); 02272 02273 if (nextStream == -1) 02274 { 02275 02276 sctpEV3<<"peekOutboundDataMsg(): no valid stream found -> returning NULL !\n"; 02277 02278 return NULL; 02279 } 02280 02281 02282 for (SCTPSendStreamMap::iterator iter=sendStreams.begin(); iter!=sendStreams.end(); ++iter) 02283 { 02284 if ((int32)iter->first==nextStream) 02285 { 02286 SCTPSendStream* stream=iter->second; 02287 if (!stream->getUnorderedStreamQ()->empty()) 02288 { 02289 return (datMsg); 02290 02291 } 02292 if (!stream->getStreamQ()->empty()) 02293 { 02294 return (datMsg); 02295 02296 } 02297 } 02298 } 02299 return NULL; 02300 02301 }
SCTPDataVariables * SCTPAssociation::peekAbandonedChunk | ( | IPvXAddress | pid | ) | [protected] |
02245 { 02246 SCTPDataVariables* chunk = NULL; 02247 02248 /* are there chunks in the retransmission queue ? If Yes -> dequeue and return it */ 02249 if (!retransmissionQ->payloadQueue.empty()) 02250 { 02251 for(SCTPQueue::PayloadQueue::iterator it=retransmissionQ->payloadQueue.begin(); it!=retransmissionQ->payloadQueue.end(); it++) 02252 { 02253 chunk=it->second; 02254 sctpEV3<<"peek Chunk "<<chunk->tsn<<"\n"; 02255 if (chunk->lastDestination == pid && chunk->hasBeenAbandoned) 02256 { 02257 sctpEV3<<"peekAbandonedChunk() found chunk in the retransmission queue\n"; 02258 return chunk; 02259 } 02260 } 02261 } 02262 02263 return NULL; 02264 }
SCTPDataVariables * SCTPAssociation::getOutboundDataChunk | ( | IPvXAddress | pid, | |
int32 | bytes | |||
) | [protected] |
Referenced by sendAll().
02178 { 02179 int32 len; 02180 /* are there chunks in the transmission queue ? If Yes -> dequeue and return it */ 02181 sctpEV3<<"getOutboundDataChunk: pid="<<pid<<" bytes="<<bytes<<"\n"; 02182 sctpEV3<<"chunks in transmissionQ="<<transmissionQ->getQueueSize()<<"\n"; 02183 if (!transmissionQ->payloadQueue.empty()) 02184 { 02185 sctpEV3<<"transmissionQ not empty\n"; 02186 for(SCTPQueue::PayloadQueue::iterator it=transmissionQ->payloadQueue.begin(); it!=transmissionQ->payloadQueue.end(); it++) 02187 { 02188 SCTPDataVariables* chunk=it->second; 02189 sctpEV3<<"chunk->nextDestination="<<chunk->nextDestination<<"\n"; 02190 if (chunk->nextDestination == pid) 02191 { 02192 len = ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH); 02193 sctpEV3<<"getOutboundDataChunk() found chunk "<<chunk->tsn<<" in the transmission queue, length="<<len<<"\n"; 02194 if (len<=bytes) 02195 { 02196 transmissionQ->payloadQueue.erase(it); 02197 CounterMap::iterator i=qCounter.roomTransQ.find(pid); 02198 i->second-= ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH); 02199 CounterMap::iterator ib=qCounter.bookedTransQ.find(pid); 02200 ib->second-= chunk->booksize; 02201 if (chunk->hasBeenAcked==false) 02202 return chunk; 02203 } 02204 } 02205 } 02206 } 02207 else 02208 sctpEV3<<"transmissionQ empty!\n"; 02209 return NULL; 02210 }
SCTPDataMsg * SCTPAssociation::dequeueOutboundDataMsg | ( | int32 | bytes | ) | [protected] |
Referenced by sendAll().
02304 { 02305 SCTPDataMsg* datMsg=NULL; 02306 int32 nextStream = -1; 02307 02308 sctpEV3<<"dequeueOutboundDataMsg: "<<bytes<<" bytes left to be sent\n"; 02309 nextStream = (this->*ssFunctions.ssGetNextSid)(false); 02310 02311 if (nextStream == -1) 02312 return NULL; 02313 02314 for (SCTPSendStreamMap::iterator iter=sendStreams.begin(); iter!=sendStreams.end(); ++iter) 02315 { 02316 if ((int32)iter->first==nextStream) 02317 { 02318 SCTPSendStream* stream=iter->second; 02319 if (!stream->getUnorderedStreamQ()->empty()) 02320 { 02321 datMsg = (SCTPDataMsg*)stream->getUnorderedStreamQ()->pop(); 02322 02323 sctpEV3<<"DequeueOutboundDataMsg() found chunk ("<<&datMsg<<") in the unordered stream queue "<<&iter->first<<"("<<stream->getUnorderedStreamQ()<<") queue size="<<stream->getUnorderedStreamQ()->getLength()<<"\n"; 02324 } 02325 else if (!stream->getStreamQ()->empty()) 02326 { 02327 02328 int32 b=ADD_PADDING( (check_and_cast<SCTPSimpleMessage*>(((SCTPDataMsg*)stream->getStreamQ()->back())->getEncapsulatedMsg())->getBitLength()/8+SCTP_DATA_CHUNK_LENGTH)); 02329 if (b<=bytes) 02330 { 02331 datMsg = (SCTPDataMsg*)stream->getStreamQ()->pop(); 02332 if (!state->appSendAllowed && stream->getStreamQ()->getLength()<=state->sendQueueLimit) 02333 { 02334 state->appSendAllowed = true; 02335 sendIndicationToApp(SCTP_I_SENDQUEUE_ABATED); 02336 } 02337 sendQueue->record(stream->getStreamQ()->getLength()); 02338 sctpEV3<<"DequeueOutboundDataMsg() found chunk ("<<&datMsg<<") in the stream queue "<<&iter->first<<"("<<stream->getStreamQ()<<") queue size="<<stream->getStreamQ()->getLength()<<"\n"; 02339 } 02340 else 02341 sctpEV3<<"chunk too long\n"; 02342 } 02343 break; 02344 } 02345 } 02346 if (datMsg != NULL) 02347 { 02348 qCounter.roomSumSendStreams -= ADD_PADDING( (check_and_cast<SCTPSimpleMessage*>(datMsg->getEncapsulatedMsg())->getBitLength()/8+SCTP_DATA_CHUNK_LENGTH)); 02349 qCounter.bookedSumSendStreams -= datMsg->getBooksize(); 02350 } 02351 return (datMsg); 02352 }
void SCTPAssociation::process_QUEUE | ( | SCTPCommand * | sctpCommand | ) | [protected] |
Referenced by processAppCommand().
00218 { 00219 SCTPInfo* qinfo = check_and_cast<SCTPInfo*>(sctpCommand); 00220 state->queueLimit = qinfo->getText(); 00221 }
void SCTPAssociation::pmDataIsSentOn | ( | IPvXAddress | pathId | ) | [protected] |
Flow control
Referenced by sendAll().
02609 { 02610 SCTPPathVariables* path; 02611 02612 /* restart hb_timer on this path */ 02613 path=getPath(pathId); 02614 path->heartbeatTimeout = path->pathRto+ (double)sctpMain->par("hbInterval"); 02615 stopTimer(path->HeartbeatTimer); 02616 startTimer(path->HeartbeatTimer, path->heartbeatTimeout); 02617 path->cwndTimeout = path->pathRto; 02618 stopTimer(path->CwndTimer); 02619 startTimer(path->CwndTimer, path->cwndTimeout); 02620 02621 02622 sctpEV3<<"Restarting HB timer on path "<<(pathId)<<" to expire at time "<<path->heartbeatTimeout<<"\n"; 02623 sctpEV3<<"Restarting CWND timer on path "<<(pathId)<<" to expire at time "<<path->cwndTimeout<<"\n"; 02624 02625 02626 /* AJ - 02-04-2004 - added for fullfilling section 8.2 */ 02627 state->lastUsedDataPath = pathId; 02628 }
void SCTPAssociation::pmStartPathManagement | ( | void | ) | [protected] |
Referenced by stateEntered().
02631 { 02632 RoutingTableAccess routingTableAccess; 02633 SCTPPathVariables* path; 02634 int32 i=0; 02635 /* populate path structures !!! */ 02636 /* set a high start value...this is appropriately decreased later (below) */ 02637 state->assocPmtu = state->localRwnd; 02638 for(SCTPPathMap::iterator piter=sctpPathMap.begin(); piter!=sctpPathMap.end(); piter++) 02639 { 02640 path=piter->second; 02641 path->pathErrorCount = 0; 02642 InterfaceEntry *rtie = routingTableAccess.get()->getInterfaceForDestAddr(path->remoteAddress.get4()); 02643 path->pmtu = rtie->getMTU(); 02644 if (path->pmtu < state->assocPmtu) 02645 { 02646 state->assocPmtu = path->pmtu; 02647 } 02648 initCCParameters(path); 02649 path->pathRto = (double)sctpMain->par("rtoInitial"); 02650 path->srtt = path->pathRto; 02651 path->rttvar = 0.0; 02652 /* from now on we may have one update per RTO/SRTT */ 02653 path->updateTime = 0.0; 02654 02655 02656 path->partialBytesAcked = 0; 02657 path->outstandingBytes = 0; 02658 path->activePath = true; 02659 path->hbWasAcked = true; 02660 // Timer probably not running, but stop it anyway I.R. 02661 stopTimer(path->T3_RtxTimer); 02662 02663 path->heartbeatTimeout= (double)sctpMain->par("hbInterval")+i*path->pathRto; 02664 stopTimer(path->HeartbeatTimer); 02665 if (path->remoteAddress == state->initialPrimaryPath && !path->confirmed) 02666 { 02667 path->confirmed = true; 02668 02669 } 02670 sctpEV3<<getFullPath()<<" numberOfLocalAddresses="<<state->localAddresses.size()<<"\n"; 02671 if (state->localAddresses.size()>1) 02672 sendHeartbeat(path, false); 02673 else 02674 sendHeartbeat(path, true); 02675 startTimer(path->HeartbeatTimer, path->heartbeatTimeout); 02676 startTimer(path->HeartbeatIntervalTimer, path->heartbeatIntervalTimeout); 02677 path->pathRTO->record(path->pathRto); 02678 i++; 02679 } 02680 }
void SCTPAssociation::pmClearPathCounter | ( | IPvXAddress | pid | ) | [protected] |
Referenced by dequeueAckedChunks(), pmRttMeasurement(), and processSackArrived().
02799 { 02800 SCTPPathMap::iterator pm=sctpPathMap.find(pathId); 02801 if (pm!=sctpPathMap.end()) 02802 { 02803 pm->second->pathErrorCount = 0; 02804 02805 if (pm->second->activePath==false) 02806 { 02807 /* notify the application */ 02808 pathStatusIndication(pathId, true); 02809 02810 sctpEV3<<"Path "<<pathId<<" state changes from INACTIVE to ACTIVE !!!!\n"; 02811 02812 } 02813 } 02814 }
void SCTPAssociation::pmRttMeasurement | ( | IPvXAddress | pathId, | |
simtime_t | rttEstimate, | |||
int32 | acknowledgedBytes | |||
) | [protected] |
Referenced by processHeartbeatAckArrived(), and processSackArrived().
02834 { 02835 02836 if (rttEstimate != -1.0) 02837 { 02838 /* we have a valid estimation */ 02839 SCTPPathVariables* path=getPath(pathId); 02840 02841 if (simulation.getSimTime() > path->updateTime) 02842 { 02843 02844 if (path->updateTime == 0.0) 02845 { 02846 path->rttvar = rttEstimate / 2; 02847 path->srtt = rttEstimate; 02848 path->pathRto = 3 * rttEstimate; 02849 path->pathRto = max(min(path->pathRto.dbl(), sctpMain->par("rtoMax")), (double)sctpMain->par("rtoMin")); 02850 02851 } 02852 else 02853 { 02854 02855 path->rttvar = (1.0 - (double)sctpMain->par("rtoBeta")) * path->rttvar + (double)sctpMain->par("rtoBeta") * fabs(path->srtt - rttEstimate); 02856 02857 path->srtt = (1.0 - (double)sctpMain->par("rtoAlpha")) * path->srtt + (double)sctpMain->par("rtoAlpha") * rttEstimate; 02858 02859 path->pathRto = path->srtt + 4 * path->rttvar; 02860 02861 path->pathRto = max(min(path->pathRto.dbl(), sctpMain->par("rtoMax")), (double)sctpMain->par("rtoMin")); 02862 } 02863 02864 sctpEV3<<simulation.getSimTime()<<": Updating timer values for path "<<pathId<<"...RTO == "<<path->pathRto<<"\n"; 02865 sctpEV3<<" rttEstimat="<<rttEstimate<<" SRTT == "<<path->srtt<<" ------> RTTVAR == "<<path->rttvar<<"\n"; 02866 02867 /* RFC2960, sect.6.3.1: new RTT measurements SHOULD be made no more than once per round-trip */ 02868 path->updateTime = simulation.getSimTime() + path->srtt; 02869 } 02870 path->pathRTO->record(path->pathRto); 02871 path->pathRTT->record(rttEstimate); 02872 } 02873 02874 if (acknowledgedBytes > 0) 02875 { 02876 /* we received a (new) SACK/HB ACK from our peer -- reset the error counters for this path */ 02877 state->errorCount = 0; 02878 pmClearPathCounter(pathId); 02879 } 02880 02881 }
void SCTPAssociation::fcAdjustCounters | ( | uint32 | ackedBytes, | |
uint32 | osb, | |||
bool | ctsnaAdvanced, | |||
IPvXAddress | pathId, | |||
uint32 | pathOsb, | |||
uint32 | newOsb | |||
) | [protected] |
From the implementers guide: increase cwnd only if
02884 { 02885 SCTPPathVariables* path=getPath(pathId); 02886 02887 02888 sctpEV3<<"fcAdjustCounters: cwnd="<<path->cwnd<<" ssthresh="<<path->ssthresh<<" pathOsbBefore="<<pathOsb<<" osbBefore="<<osb<<" ackedBytes="<<ackedBytes<<"\n"; 02889 02890 02891 if (path->cwnd <=path->ssthresh) 02892 { 02893 for (SCTPPathMap::iterator iter=sctpPathMap.begin(); iter!=sctpPathMap.end(); iter++) 02894 { 02895 iter->second->partialBytesAcked = 0; 02896 } 02897 02905 sctpEV3<<"ctsnaAdvanced="<<ctsnaAdvanced<<" fastRecoveryActive="<<state->fastRecoveryActive<<"\n"; 02906 02907 if (ctsnaAdvanced == true && pathOsb >= path->cwnd ) 02908 { 02909 path->cwndAdjustmentTime = simulation.getSimTime(); 02910 02911 path->cwnd += (int32)min(path->pmtu, ackedBytes); 02912 path->pathCwnd->record(path->cwnd); 02913 02914 sctpEV3<<"SLOW START: Setting CWND of path "<<pathId<<" to "<<path->cwnd<<" bytes\n"; 02915 02916 } 02917 02918 } 02919 else 02920 { 02921 path->partialBytesAcked += ackedBytes; 02922 sctpEV3<<"partialBytesAcked="<<path->partialBytesAcked<<" cwnd="<<path->cwnd<<" osb="<<osb<<" advanced="<<ctsnaAdvanced<<"\n"; 02923 if ((path->partialBytesAcked >= path->cwnd) && 02924 (osb >= path->cwnd) && (ctsnaAdvanced == true)) 02925 { 02926 path->cwnd += path->pmtu; 02927 path->pathCwnd->record(path->cwnd); 02928 // I.R. make the term easier 02929 path->partialBytesAcked = 02930 ((path->cwnd < path->partialBytesAcked) ? 02931 (path->partialBytesAcked - path->cwnd) : 0); 02932 02933 /* get and store the time when CWND was adjusted here */ 02934 path->cwndAdjustmentTime = simulation.getSimTime(); 02935 02936 02937 sctpEV3<<"CONG.AVOID.: Setting CWND of path "<<pathId<<" to "<<path->cwnd<<" bytes\n"; 02938 02939 } 02940 } 02941 02942 02943 if (newOsb == 0) path->partialBytesAcked = 0; 02944 }
int32 SCTPAssociation::tsnLt | ( | uint32 | tsn1, | |
uint32 | tsn2 | |||
) | [inline, protected] |
int32 SCTPAssociation::tsnLe | ( | uint32 | tsn1, | |
uint32 | tsn2 | |||
) | [inline, protected] |
int32 SCTPAssociation::tsnGe | ( | uint32 | tsn1, | |
uint32 | tsn2 | |||
) | [inline, protected] |
int32 SCTPAssociation::tsnGt | ( | uint32 | tsn1, | |
uint32 | tsn2 | |||
) | [inline, protected] |
Referenced by cwndUpdateAfterSack(), processDataArrived(), processSackArrived(), and updateGapList().
int32 SCTPAssociation::tsnBetween | ( | uint32 | tsn1, | |
uint32 | midtsn, | |||
uint32 | tsn2 | |||
) | [inline, protected] |
int16 SCTPAssociation::ssnGt | ( | uint16 | ssn1, | |
uint16 | ssn2 | |||
) | [inline, protected] |
uint32 SCTPAssociation::subBytes | ( | uint32 | osb, | |
uint32 | bytes | |||
) | [inline, protected] |
void SCTPAssociation::disposeOf | ( | SCTPMessage * | sctpmsg | ) | [protected] |
Referenced by process_RCV_Message().
02998 { 02999 SCTPChunk* chunk; 03000 uint32 numberOfChunks = sctpmsg->getChunksArraySize(); 03001 if (numberOfChunks>0) 03002 for (uint32 i=0; i<numberOfChunks; i++) 03003 { 03004 chunk = (SCTPChunk*)(sctpmsg->removeChunk()); 03005 if (chunk->getChunkType()==DATA) 03006 delete (SCTPSimpleMessage*)chunk->decapsulate(); 03007 delete chunk; 03008 } 03009 delete sctpmsg; 03010 }
void SCTPAssociation::printOutstandingTsns | ( | ) | [protected] |
02520 { 02521 uint32 first=0, second = 0; 02522 02523 if (retransmissionQ->payloadQueue.empty()) 02524 { 02525 return; 02526 } 02527 for(SCTPQueue::PayloadQueue::iterator pl=retransmissionQ->payloadQueue.begin();pl!=retransmissionQ->payloadQueue.end();pl++) 02528 { 02529 if (pl->second->hasBeenAcked == false && pl->second->countsAsOutstanding == true) 02530 { 02531 if (pl->second->tsn > second+1) 02532 { 02533 if (second != 0) 02534 { 02535 sctpEV3<<" - "<<second<<"\t";; 02536 02537 } 02538 first = second = pl->second->tsn; 02539 sctpEV3<<pl->second->tsn; 02540 } 02541 else if (pl->second->tsn == second+1) 02542 { 02543 second = pl->second->tsn; 02544 } 02545 first = pl->second->tsn; 02546 } 02547 } 02548 sctpEV3<<" - "<<second<<"\n"; 02549 }
void SCTPAssociation::initCCParameters | ( | SCTPPathVariables * | path | ) | [protected] |
SCTPCCFunctions
Referenced by pmStartPathManagement(), and stateEntered().
00022 { 00023 path->cwnd = (int32)min(4 * path->pmtu, max(2 * path->pmtu, 4380)); 00024 path->pathCwnd->record(path->cwnd); 00025 path->cwndAdjustmentTime = simulation.getSimTime(); 00026 path->ssthresh = state->peerRwnd; 00027 path->pathSsthresh->record(path->ssthresh); 00028 }
void SCTPAssociation::cwndUpdateAfterSack | ( | bool | rtxNecessary, | |
SCTPPathVariables * | path | |||
) | [protected] |
Referenced by stateEntered().
00033 { 00034 if (rtxNecessary == true && state->fastRecoveryActive == false) 00035 { 00036 for (SCTPPathMap::iterator iter=sctpPathMap.begin(); iter!=sctpPathMap.end(); iter++) 00037 { 00038 path=iter->second; 00039 if (path->requiresRtx) 00040 { 00041 path->ssthresh = (int32)max(path->cwnd / 2, 4 * path->pmtu); 00042 path->pathSsthresh->record(path->ssthresh);; 00043 path->cwnd = path->ssthresh; 00044 path->pathCwnd->record(path->cwnd); 00045 path->partialBytesAcked = 0; 00046 /* get and store the time when CWND was adjusted here */ 00047 path->cwndAdjustmentTime = simulation.getSimTime(); 00048 00049 if (state->fastRecoverySupported) 00050 { 00051 state->highestTsnAcked = state->lastTsnAck; 00052 for (SCTPQueue::PayloadQueue::iterator pq=retransmissionQ->payloadQueue.begin(); pq!=retransmissionQ->payloadQueue.end(); pq++) 00053 { 00054 if (pq->second->hasBeenAcked == true && tsnGt(pq->second->tsn, state->highestTsnAcked)) 00055 { 00056 state->highestTsnAcked = pq->second->tsn; 00057 } 00058 } 00059 /* this can ONLY become TRUE, when Fast Recovery IS supported */ 00060 state->fastRecoveryActive = true; 00061 state->fastRecoveryExitPoint = state->highestTsnAcked; 00062 00063 sctpEV3<<"===> ENTERING FAST RECOVERY.....Exit Point == "<< state->fastRecoveryExitPoint<<"\n"; 00064 00065 00066 } /* end: if (fast_recovery_supported */ 00067 } /* end: if (path_requires_rtx... */ 00068 } /* end: for (counter... */ 00069 } /* end: if (rtx_necessary */ 00070 00071 }
void SCTPAssociation::cwndUpdateAfterCwndTimeout | ( | SCTPPathVariables * | path | ) | [protected] |
Referenced by stateEntered().
00074 { 00075 /* 00076 * When the association does not transmit data on a given transport address 00077 * within an RTO, the cwnd of the transport address SHOULD be adjusted to 2*MTU. 00078 */ 00079 00080 path->cwnd = (int32)min(4 * path->pmtu, max(2 * path->pmtu, 4380)); 00081 path->pathCwnd->record(path->cwnd); 00082 00083 sctpEV3<<"CWND timer run off: readjusting CWND(path=="<<path->remoteAddress<<") = "<<path->cwnd<<"\n"; 00084 00085 path->cwndAdjustmentTime = simulation.getSimTime(); 00086 }
void SCTPAssociation::cwndUpdateAfterRtxTimeout | ( | SCTPPathVariables * | path | ) | [protected] |
Referenced by stateEntered().
00089 { 00090 /* implement optional FAST RECOVERY */ 00091 if (state->fastRecoveryActive == false) 00092 { 00093 path->ssthresh = (int32)max(path->cwnd / 2, 4 * path->pmtu); 00094 00095 path->pathSsthresh->record(path->ssthresh); 00096 path->cwnd = path->pmtu; 00097 path->pathCwnd->record(path->cwnd); 00098 path->partialBytesAcked = 0; 00099 00100 path->cwndAdjustmentTime = simulation.getSimTime(); 00101 00102 } 00103 }
void SCTPAssociation::cwndUpdateMaxBurst | ( | SCTPPathVariables * | path | ) | [protected] |
Referenced by stateEntered().
00107 { 00108 if(path->cwnd > ((path->outstandingBytes + (uint32)sctpMain->par("maxBurst") * path->pmtu))) 00109 { 00110 path->cwnd = path->outstandingBytes + ((uint32)sctpMain->par("maxBurst") * path->pmtu); 00111 path->pathCwnd->record(path->cwnd); 00112 path->cwndAdjustmentTime = simulation.getSimTime(); 00113 } 00114 }
void SCTPAssociation::cwndUpdateBytesAcked | ( | uint32 | ackedBytes, | |
uint32 | osb, | |||
bool | ctsnaAdvanced, | |||
IPvXAddress | pathId, | |||
uint32 | pathOsb, | |||
uint32 | newOsb | |||
) | [protected] |
Referenced by stateEntered().
00118 { 00119 SCTPPathVariables* path=getPath(pathId); 00120 00121 00122 sctpEV3<<simulation.getSimTime()<<" fcAdjustCounters: path="<<pathId<<" cwnd="<<path->cwnd<<" ssthresh="<<path->ssthresh<<" pathOsbBefore="<<pathOsb<<" osbBefore="<<osb<<" ackedBytes="<<ackedBytes<<"\n"; 00123 00124 00125 if (path->cwnd <=path->ssthresh) 00126 { 00127 // SLOW START 00128 for (SCTPPathMap::iterator iter=sctpPathMap.begin(); iter!=sctpPathMap.end(); iter++) 00129 { 00130 iter->second->partialBytesAcked = 0; 00131 } 00132 00133 00134 sctpEV3<<"ctsnaAdvanced="<<ctsnaAdvanced<<" fastRecoveryActive="<<state->fastRecoveryActive<<"\n"; 00135 sctpEV3<<simulation.getSimTime()<<" primaryPath="<<state->primaryPathIndex<<", pathOsb="<<pathOsb<<", cwnd="<<path->cwnd<<"\n"; 00136 if ((ctsnaAdvanced == true && pathOsb >= path->cwnd)) 00137 { 00138 path->cwndAdjustmentTime = simulation.getSimTime(); 00139 00140 path->cwnd += (int32)min(path->pmtu, ackedBytes); 00141 path->pathCwnd->record(path->cwnd); 00142 00143 sctpEV3<<simulation.getSimTime()<<" SLOW START: Setting CWND of path "<<pathId<<" to "<<path->cwnd<<" bytes. Osb = "<<pathOsb<<"\n"; 00144 00145 } 00146 00147 } 00148 else 00149 { 00150 // CONGESTION AVOIDANCE 00151 path->partialBytesAcked += ackedBytes; 00152 sctpEV3<<"partialBytesAcked="<<path->partialBytesAcked<<" cwnd="<<path->cwnd<<" osb="<<osb<<" advanced="<<ctsnaAdvanced<<" fastRecoveryActive="<<state->fastRecoveryActive<<"\n"; 00153 if ((path->partialBytesAcked >= path->cwnd) && 00154 (osb >= path->cwnd) && (ctsnaAdvanced == true)) 00155 { 00156 path->cwnd += path->pmtu; 00157 path->pathCwnd->record(path->cwnd); 00158 path->partialBytesAcked = 00159 ((path->cwnd < path->partialBytesAcked) ? 00160 (path->partialBytesAcked - path->cwnd) : 0); 00161 00162 /* get and store the time when CWND was adjusted here */ 00163 path->cwndAdjustmentTime = simulation.getSimTime(); 00164 00165 00166 sctpEV3<<"CONG.AVOID.: Setting CWND of path "<<pathId<<" to "<<path->cwnd<<" bytes\n"; 00167 00168 } 00169 } 00170 00171 00172 if (newOsb == 0) path->partialBytesAcked = 0; 00173 }
int32 SCTPAssociation::assocId |
Referenced by SCTP::addForkedAssociation(), cloneAssociation(), dequeueAckedChunks(), pathStatusIndication(), printConnBrief(), SCTP::printInfoConnMap(), process_CLOSE(), process_OPEN_PASSIVE(), process_SEND(), process_TIMEOUT_RTX(), processDataArrived(), processInitArrived(), processSackArrived(), pushUlp(), SCTP::removeAssociation(), SCTPAssociation(), SCTPPathVariables::SCTPPathVariables(), sendAll(), sendDataArrivedNotification(), sendEstabIndicationToApp(), sendIndicationToApp(), and stateEntered().
Referenced by SCTP::addLocalAddress(), createSack(), performStateTransition(), printConnBrief(), process_ABORT(), process_CLOSE(), process_RCV_Message(), process_SEND(), process_STATUS(), process_TIMEOUT_RTX(), processDataArrived(), processInitAckArrived(), processInitArrived(), processSackArrived(), processSCTPMessage(), pushUlp(), retransmitCookieEcho(), retransmitShutdown(), retransmitShutdownAck(), sendAbort(), sendAll(), sendEstabIndicationToApp(), sendIndicationToApp(), sendInit(), sendInitAck(), sendShutdown(), sendToIP(), and SCTP::updateSockPair().
Referenced by SCTP::addLocalAddress(), SCTP::addLocalAddressToAllRemoteAddresses(), cloneAssociation(), createSack(), printConnBrief(), process_RCV_Message(), process_SEND(), processInitArrived(), processSackArrived(), processSCTPMessage(), pushUlp(), retransmitCookieEcho(), retransmitShutdown(), retransmitShutdownAck(), sendEstabIndicationToApp(), sendHeartbeat(), sendIndicationToApp(), sendInit(), and SCTP::updateSockPair().
uint16 SCTPAssociation::localPort |
Referenced by SCTP::addLocalAddress(), SCTP::addLocalAddressToAllRemoteAddresses(), SCTP::addRemoteAddress(), cloneAssociation(), createSack(), printConnBrief(), process_ASSOCIATE(), process_OPEN_PASSIVE(), processSCTPMessage(), SCTP::removeLocalAddressFromAllRemoteAddresses(), SCTP::removeRemoteAddressFromAllConnections(), SCTPAssociation(), sendAbort(), sendAll(), sendCookieAck(), sendCookieEcho(), sendEstabIndicationToApp(), sendHeartbeat(), sendHeartbeatAck(), sendInit(), sendInitAck(), sendShutdown(), sendShutdownAck(), sendShutdownComplete(), sendToIP(), stateEntered(), and SCTP::updateSockPair().
uint16 SCTPAssociation::remotePort |
Referenced by SCTP::addLocalAddress(), SCTP::addLocalAddressToAllRemoteAddresses(), SCTP::addRemoteAddress(), createSack(), printConnBrief(), process_ASSOCIATE(), processSCTPMessage(), SCTP::removeLocalAddressFromAllRemoteAddresses(), SCTP::removeRemoteAddressFromAllConnections(), SCTPAssociation(), sendAbort(), sendAll(), sendCookieAck(), sendCookieEcho(), sendEstabIndicationToApp(), sendHeartbeat(), sendHeartbeatAck(), sendInit(), sendInitAck(), sendShutdown(), sendShutdownAck(), sendShutdownComplete(), sendToIP(), stateEntered(), and SCTP::updateSockPair().
uint32 SCTPAssociation::localVTag |
uint32 SCTPAssociation::peerVTag |
Referenced by process_RCV_Message(), processCookieEchoArrived(), SCTPAssociation(), sendInit(), sendInitAck(), sendToIP(), and stateEntered().
cMessage* SCTPAssociation::T1_InitTimer |
cMessage* SCTPAssociation::T2_ShutdownTimer |
cMessage* SCTPAssociation::T5_ShutdownGuardTimer |
cMessage* SCTPAssociation::SackTimer |
cMessage* SCTPAssociation::StartTesting |
Referenced by processTimer(), and SCTPAssociation().
AddressVector SCTPAssociation::localAddressList [protected] |
Referenced by cloneAssociation(), process_ASSOCIATE(), process_OPEN_PASSIVE(), processInitArrived(), and sendInit().
AddressVector SCTPAssociation::remoteAddressList [protected] |
Referenced by process_ASSOCIATE(), processInitAckArrived(), processInitArrived(), sendEstabIndicationToApp(), and sendInit().
int32 SCTPAssociation::status [protected] |
uint32 SCTPAssociation::numberOfRemoteAddresses [protected] |
Referenced by processInitAckArrived(), processInitArrived(), and SCTPAssociation().
uint32 SCTPAssociation::initTsn [protected] |
Referenced by sendInit(), and sendInitAck().
uint32 SCTPAssociation::initPeerTsn [protected] |
Referenced by processDataArrived(), processInitAckArrived(), processInitArrived(), and sendInitAck().
uint32 SCTPAssociation::inboundStreams [protected] |
Referenced by process_RECEIVE_REQUEST(), processInitAckArrived(), pushUlp(), SCTPAssociation(), sendEstabIndicationToApp(), and sendInitAck().
uint32 SCTPAssociation::outboundStreams [protected] |
Referenced by initAssociation(), processInitAckArrived(), SCTPAssociation(), sendEstabIndicationToApp(), sendInit(), sendInitAck(), and streamScheduler().
uint32 SCTPAssociation::sackFrequency [protected] |
Referenced by process_ABORT(), process_RCV_Message(), processDataArrived(), scheduleSack(), sendAll(), and stateEntered().
double SCTPAssociation::sackPeriod [protected] |
Referenced by scheduleSack(), SCTPAssociation(), and stateEntered().
SCTPStateVariables* SCTPAssociation::state [protected] |
Referenced by advanceCtsna(), bytesAllowedToSend(), cloneAssociation(), createSack(), cwndUpdateAfterRtxTimeout(), cwndUpdateAfterSack(), cwndUpdateBytesAcked(), dequeueOutboundDataMsg(), fcAdjustCounters(), getNextDestination(), getState(), initAssociation(), initCCParameters(), initStreams(), makeRoomForTsn(), makeVarFromMsg(), performStateTransition(), pmDataIsSentOn(), pmRttMeasurement(), pmStartPathManagement(), process_ABORT(), process_ASSOCIATE(), process_CLOSE(), process_OPEN_PASSIVE(), process_PRIMARY(), process_QUEUE(), process_RCV_Message(), process_RECEIVE_REQUEST(), process_SEND(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_RTX(), process_TIMEOUT_SHUTDOWN(), processAppCommand(), processCookieAckArrived(), processCookieEchoArrived(), processDataArrived(), processHeartbeatAckArrived(), processInitAckArrived(), processInitArrived(), processSackArrived(), processTimer(), pushUlp(), putInDeliveryQ(), removeFromGapList(), retransmitCookieEcho(), retransmitInit(), retransmitShutdown(), retransmitShutdownAck(), scheduleSack(), SCTPAssociation(), sendAll(), sendCookieEcho(), sendInit(), sendInitAck(), sendSack(), sendShutdown(), sendShutdownAck(), stateEntered(), streamScheduler(), tsnIsDuplicate(), updateCounters(), and updateGapList().
cOutVector* SCTPAssociation::advRwnd [protected] |
Referenced by createSack(), SCTPAssociation(), and ~SCTPAssociation().
cOutVector* SCTPAssociation::quBytes [protected] |
Referenced by createSack(), processDataArrived(), pushUlp(), SCTPAssociation(), and ~SCTPAssociation().
cOutVector* SCTPAssociation::cumTsnAck [protected] |
Referenced by SCTPAssociation(), stateEntered(), and ~SCTPAssociation().
cOutVector* SCTPAssociation::sendQueue [protected] |
Referenced by dequeueOutboundDataMsg(), process_SEND(), SCTPAssociation(), stateEntered(), and ~SCTPAssociation().
SCTP* SCTPAssociation::sctpMain [protected] |
Referenced by cancelEvent(), cloneAssociation(), cwndUpdateMaxBurst(), dequeueAckedChunks(), getSctpMain(), initAssociation(), pathStatusIndication(), performStateTransition(), pmDataIsSentOn(), pmRttMeasurement(), pmStartPathManagement(), process_ASSOCIATE(), process_OPEN_PASSIVE(), process_RCV_Message(), process_SEND(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_HEARTBEAT_INTERVAL(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_RTX(), process_TIMEOUT_SHUTDOWN(), processCookieEchoArrived(), processDataArrived(), processHeartbeatAckArrived(), processInitAckArrived(), processInitArrived(), processSackArrived(), processTimer(), scheduleTimeout(), SCTPAssociation(), sendAll(), sendEstabIndicationToApp(), sendIndicationToApp(), sendInit(), sendInitAck(), sendToApp(), sendToIP(), stateEntered(), and updateCounters().
cFSM* SCTPAssociation::fsm [protected] |
Referenced by cloneAssociation(), getFsm(), getFsmState(), performStateTransition(), printConnBrief(), process_ABORT(), process_ASSOCIATE(), process_CLOSE(), process_OPEN_PASSIVE(), process_RCV_Message(), process_SEND(), process_STATUS(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_SHUTDOWN(), processAppCommand(), processCookieAckArrived(), processCookieEchoArrived(), processInitAckArrived(), processInitArrived(), pushUlp(), SCTPAssociation(), sendInitAck(), stateEntered(), and ~SCTPAssociation().
SCTPPathMap SCTPAssociation::sctpPathMap [protected] |
Referenced by addPath(), allPathsInactive(), bytesAllowedToSend(), cwndUpdateAfterSack(), cwndUpdateBytesAcked(), fcAdjustCounters(), getNextAddress(), getNextDestination(), getOutstandingBytes(), getPath(), pmClearPathCounter(), pmStartPathManagement(), printSctpPathMap(), process_RCV_Message(), processInitAckArrived(), processInitArrived(), processSackArrived(), removePath(), sendInit(), and stopTimers().
QueueCounter SCTPAssociation::qCounter [protected] |
Referenced by addPath(), bytesAllowedToSend(), dequeueAckedChunks(), dequeueOutboundDataMsg(), getOutboundDataChunk(), makeRoomForTsn(), peekOutboundDataChunk(), process_RCV_Message(), process_SEND(), process_TIMEOUT_RTX(), processInitAckArrived(), processInitArrived(), processSackArrived(), pushUlp(), putInDeliveryQ(), SCTPAssociation(), sendAll(), sendInit(), and stateEntered().
SCTPQueue* SCTPAssociation::transmissionQ [protected] |
SCTPQueue* SCTPAssociation::retransmissionQ [protected] |
SCTPSendStreamMap SCTPAssociation::sendStreams [protected] |
Referenced by deleteStreams(), dequeueOutboundDataMsg(), initStreams(), numUsableStreams(), peekOutboundDataMsg(), process_SEND(), sendAll(), and streamScheduler().
SCTPReceiveStreamMap SCTPAssociation::receiveStreams [protected] |
Referenced by deleteStreams(), getQueuedBytes(), initStreams(), makeRoomForTsn(), processDataArrived(), pushUlp(), and putInDeliveryQ().
SCTPAlgorithm* SCTPAssociation::sctpAlgorithm [protected] |
Referenced by cloneAssociation(), getSctpAlgorithm(), initAssociation(), process_SEND(), processTimer(), SCTPAssociation(), and sendAll().
BytesToBeSent SCTPAssociation::bytes [protected] |
Referenced by bytesAllowedToSend(), SCTPAssociation(), and sendAll().
CCFunctions SCTPAssociation::ccFunctions [protected] |
Referenced by process_TIMEOUT_RTX(), processSackArrived(), processTimer(), and stateEntered().
uint16 SCTPAssociation::ccModule [protected] |
Referenced by stateEntered().
SSFunctions SCTPAssociation::ssFunctions [protected] |
Referenced by dequeueOutboundDataMsg(), peekOutboundDataMsg(), processInitAckArrived(), SCTPAssociation(), sendInitAck(), and streamScheduler().
uint16 SCTPAssociation::ssModule [protected] |
Referenced by SCTPAssociation().