#include <SCTPAssociation.h>
Classes | |
struct | calcBytesToSend |
struct | congestionControlFunctions |
struct | counter |
struct | streamSchedulingFunctions |
Public Member Functions | |
SCTPAssociation (SCTP *mod, int32 appGateIndex, int32 assocId) | |
~SCTPAssociation () | |
void | sendOnPath (SCTPPathVariables *pathId, const bool firstPass=true) |
void | sendOnAllPaths (SCTPPathVariables *firstPath) |
Static Public Member Functions | |
static const char * | indicationName (const int32 code) |
Public Attributes | |
int32 | appGateIndex |
int32 | assocId |
IPvXAddress | remoteAddr |
IPvXAddress | localAddr |
uint16 | localPort |
uint16 | remotePort |
uint32 | localVTag |
uint32 | peerVTag |
bool | listen |
cMessage * | T1_InitTimer |
cMessage * | T2_ShutdownTimer |
cMessage * | T5_ShutdownGuardTimer |
cMessage * | SackTimer |
cMessage * | StartTesting |
Protected Types | |
typedef struct SCTPAssociation::streamSchedulingFunctions | SSFunctions |
Protected Member Functions | |
void | startTimer (cMessage *timer, const simtime_t &timeout) |
SCTPAssociation * | cloneAssociation () |
void | initAssociation (SCTPOpenCommand *openCmd) |
bool | tsnIsDuplicate (const uint32 tsn) const |
bool | advanceCtsna () |
bool | updateGapList (const uint32 tsn) |
void | removeFromGapList (const uint32 removedTsn) |
bool | makeRoomForTsn (const uint32 tsn, const uint32 length, const bool uBit) |
void | sendInit () |
void | sendInitAck (SCTPInitChunk *initchunk) |
void | sendCookieEcho (SCTPInitAckChunk *initackchunk) |
void | sendCookieAck (const IPvXAddress &dest) |
void | sendAbort () |
void | sendHeartbeat (const SCTPPathVariables *path) |
void | sendHeartbeatAck (const SCTPHeartbeatChunk *heartbeatChunk, const IPvXAddress &src, const IPvXAddress &dest) |
void | sendSack () |
void | sendShutdown () |
void | sendShutdownAck (const IPvXAddress &dest) |
void | sendShutdownComplete () |
SCTPSackChunk * | createSack () |
void | retransmitInit () |
void | retransmitCookieEcho () |
void | retransmitShutdown () |
void | retransmitShutdownAck () |
void | sendToIP (SCTPMessage *sctpmsg, const IPvXAddress &dest, const bool qs=false) |
void | sendToIP (SCTPMessage *sctpmsg, const bool qs=false) |
void | recordInPathVectors (SCTPMessage *pMsg, const IPvXAddress &rDest) |
void | scheduleSack () |
void | signalConnectionTimeout () |
void | scheduleTimeout (cMessage *msg, const simtime_t &timeout) |
cMessage * | cancelEvent (cMessage *msg) |
void | sendToApp (cPacket *msg) |
void | sendIndicationToApp (const int32 code, const int32 value=0) |
void | sendEstabIndicationToApp () |
void | pushUlp () |
void | sendDataArrivedNotification (uint16 sid) |
void | putInDeliveryQ (uint16 sid) |
void | printConnBrief () |
void | addPath (const IPvXAddress &addr) |
SCTPPathVariables * | getNextPath (const SCTPPathVariables *oldPath) const |
const IPvXAddress & | getNextAddress (const SCTPPathVariables *oldPath) const |
SCTPPathVariables * | getNextDestination (SCTPDataVariables *chunk) const |
void | bytesAllowedToSend (SCTPPathVariables *path, const bool firstPass) |
void | pathStatusIndication (const SCTPPathVariables *path, const bool status) |
bool | allPathsInactive () const |
SCTPDataChunk * | transformDataChunk (SCTPDataVariables *chunk) |
SCTPDataVariables * | makeVarFromMsg (SCTPDataChunk *datachunk) |
int32 | streamScheduler (bool peek) |
void | initStreams (uint32 inStreams, uint32 outStreams) |
int32 | numUsableStreams () |
void | process_QUEUE_MSGS_LIMIT (const SCTPCommand *sctpCommand) |
void | process_QUEUE_BYTES_LIMIT (const SCTPCommand *sctpCommand) |
int32 | getOutstandingBytes () const |
uint32 | dequeueAckedChunks (const uint32 tsna, SCTPPathVariables *path, simtime_t &rttEstimation) |
SCTPDataMsg * | peekOutboundDataMsg () |
SCTPDataVariables * | peekAbandonedChunk (const SCTPPathVariables *path) |
SCTPDataVariables * | getOutboundDataChunk (const SCTPPathVariables *path, const int32 availableSpace, const int32 availableCwnd) |
SCTPDataMsg * | dequeueOutboundDataMsg (const int32 availableSpace, const int32 availableCwnd) |
bool | nextChunkFitsIntoPacket (int32 bytes) |
void | putInTransmissionQ (uint32 tsn, SCTPDataVariables *chunk) |
void | pmStartPathManagement () |
void | pmDataIsSentOn (SCTPPathVariables *path) |
void | pmClearPathCounter (SCTPPathVariables *path) |
void | pmRttMeasurement (SCTPPathVariables *path, const simtime_t &rttEstimation) |
void | disposeOf (SCTPMessage *sctpmsg) |
void | tsnWasReneged (SCTPDataVariables *chunk, const int type) |
void | printOutstandingTsns () |
void | initCCParameters (SCTPPathVariables *path) |
void | updateFastRecoveryStatus (const uint32 lastTsnAck) |
void | cwndUpdateAfterSack () |
void | cwndUpdateAfterCwndTimeout (SCTPPathVariables *path) |
void | cwndUpdateAfterRtxTimeout (SCTPPathVariables *path) |
void | cwndUpdateMaxBurst (SCTPPathVariables *path) |
void | cwndUpdateBytesAcked (SCTPPathVariables *path, const uint32 ackedBytes, const bool ctsnaAdvanced) |
FSM transitions: analysing events and executing state transitions | |
SCTPEventCode | preanalyseAppCommandEvent (int32 commandCode) |
bool | performStateTransition (const SCTPEventCode &event) |
void | stateEntered (int32 state) |
Processing app commands. Invoked from processAppCommand(). | |
void | process_ASSOCIATE (SCTPEventCode &event, SCTPCommand *sctpCommand, cPacket *msg) |
void | process_OPEN_PASSIVE (SCTPEventCode &event, SCTPCommand *sctpCommand, cPacket *msg) |
void | process_SEND (SCTPEventCode &event, SCTPCommand *sctpCommand, cPacket *msg) |
void | process_CLOSE (SCTPEventCode &event) |
void | process_ABORT (SCTPEventCode &event) |
void | process_STATUS (SCTPEventCode &event, SCTPCommand *sctpCommand, cPacket *msg) |
void | process_RECEIVE_REQUEST (SCTPEventCode &event, SCTPCommand *sctpCommand) |
void | process_PRIMARY (SCTPEventCode &event, SCTPCommand *sctpCommand) |
Processing SCTP message arrivals. Invoked from processSCTPMessage(). | |
bool | process_RCV_Message (SCTPMessage *sctpseg, const IPvXAddress &src, const IPvXAddress &dest) |
bool | processInitArrived (SCTPInitChunk *initChunk, int32 sport, int32 dport) |
bool | processInitAckArrived (SCTPInitAckChunk *initAckChunk) |
bool | processCookieEchoArrived (SCTPCookieEchoChunk *cookieEcho, IPvXAddress addr) |
bool | processCookieAckArrived () |
SCTPEventCode | processDataArrived (SCTPDataChunk *dataChunk) |
SCTPEventCode | processSackArrived (SCTPSackChunk *sackChunk) |
SCTPEventCode | processHeartbeatAckArrived (SCTPHeartbeatAckChunk *heartbeatack, SCTPPathVariables *path) |
Processing timeouts. Invoked from processTimer(). | |
int32 | process_TIMEOUT_RTX (SCTPPathVariables *path) |
void | process_TIMEOUT_HEARTBEAT (SCTPPathVariables *path) |
void | process_TIMEOUT_HEARTBEAT_INTERVAL (SCTPPathVariables *path, bool force) |
void | process_TIMEOUT_INIT_REXMIT (SCTPEventCode &event) |
void | process_TIMEOUT_PROBING () |
void | process_TIMEOUT_SHUTDOWN (SCTPEventCode &event) |
int32 | updateCounters (SCTPPathVariables *path) |
Static Protected Member Functions | |
static void | printSegmentBrief (SCTPMessage *sctpmsg) |
static const char * | eventName (const int32 event) |
static int32 | tsnLt (const uint32 tsn1, const uint32 tsn2) |
static int32 | tsnLe (const uint32 tsn1, const uint32 tsn2) |
static int32 | tsnGe (const uint32 tsn1, const uint32 tsn2) |
static int32 | tsnGt (const uint32 tsn1, const uint32 tsn2) |
static int32 | tsnBetween (const uint32 tsn1, const uint32 midtsn, const uint32 tsn2) |
static int16 | ssnGt (const uint16 ssn1, const uint16 ssn2) |
Protected Attributes | |
AddressVector | localAddressList |
AddressVector | remoteAddressList |
uint32 | numberOfRemoteAddresses |
uint32 | inboundStreams |
uint32 | outboundStreams |
int32 | status |
uint32 | initTsn |
uint32 | initPeerTsn |
uint32 | sackFrequency |
double | sackPeriod |
CCFunctions | ccFunctions |
uint16 | ccModule |
cOutVector * | advRwnd |
cOutVector * | cumTsnAck |
cOutVector * | sendQueue |
cOutVector * | numGapBlocks |
SCTPStateVariables * | state |
BytesToBeSent | bytes |
SCTP * | sctpMain |
cFSM * | fsm |
SCTPPathMap | sctpPathMap |
QueueCounter | qCounter |
SCTPQueue * | transmissionQ |
SCTPQueue * | retransmissionQ |
SCTPSendStreamMap | sendStreams |
SCTPReceiveStreamMap | receiveStreams |
SCTPAlgorithm * | sctpAlgorithm |
SSFunctions | ssFunctions |
uint16 | ssModule |
Private Types | |
typedef std::map< IPvXAddress, SCTPPathVariables * > | SCTPPathMap |
typedef std::map< IPvXAddress, uint32 > | CounterMap |
typedef struct SCTPAssociation::counter | QueueCounter |
typedef struct SCTPAssociation::calcBytesToSend | BytesToBeSent |
typedef struct SCTPAssociation::congestionControlFunctions | CCFunctions |
typedef std::map< uint32, SCTPSendStream * > | SCTPSendStreamMap |
typedef std::map< uint32, SCTPReceiveStream * > | SCTPReceiveStreamMap |
Private Member Functions | |
SCTPDataVariables * | makeDataVarFromDataMsg (SCTPDataMsg *datMsg, SCTPPathVariables *path) |
SCTPPathVariables * | choosePathForRetransmission () |
void | timeForSack (bool &sackOnly, bool &sackWithData) |
void | recordCwndUpdate (SCTPPathVariables *path) |
void | handleChunkReportedAsAcked (uint32 &highestNewAck, simtime_t &rttEstimation, SCTPDataVariables *myChunk, SCTPPathVariables *sackPath) |
void | handleChunkReportedAsMissing (const SCTPSackChunk *sackChunk, const uint32 highestNewAck, SCTPDataVariables *myChunk, const SCTPPathVariables *sackPath) |
void | moveChunkToOtherPath (SCTPDataVariables *chunk, SCTPPathVariables *newPath) |
void | decreaseOutstandingBytes (SCTPDataVariables *chunk) |
void | increaseOutstandingBytes (SCTPDataVariables *chunk, SCTPPathVariables *path) |
int32 | calculateBytesToSendOnPath (const SCTPPathVariables *pathVar) |
void | storePacket (SCTPPathVariables *pathVar, SCTPMessage *sctpMsg, const uint16 chunksAdded, const uint16 dataChunksAdded, const uint32 packetBytes, const bool authAdded) |
void | loadPacket (SCTPPathVariables *pathVar, SCTPMessage **sctpMsg, uint16 *chunksAdded, uint16 *dataChunksAdded, uint32 *packetBytes, bool *authAdded) |
void | ackChunk (SCTPDataVariables *chunk) |
void | unackChunk (SCTPDataVariables *chunk) |
bool | chunkHasBeenAcked (const SCTPDataVariables *chunk) const |
bool | chunkHasBeenAcked (const uint32 tsn) const |
Friends | |
class | SCTP |
class | SCTPPathVariables |
| |
int32 | getFsmState () const |
SCTPStateVariables * | getState () const |
SCTPQueue * | getTransmissionQueue () const |
SCTPQueue * | getRetransmissionQueue () const |
SCTPAlgorithm * | getSctpAlgorithm () const |
SCTP * | getSctpMain () const |
cFSM * | getFsm () const |
cMessage * | getInitTimer () const |
cMessage * | getShutdownTimer () const |
cMessage * | getSackTimer () const |
bool | processTimer (cMessage *msg) |
bool | processSCTPMessage (SCTPMessage *sctpmsg, const IPvXAddress &srcAddr, const IPvXAddress &destAddr) |
bool | processAppCommand (cPacket *msg) |
void | removePath () |
void | removePath (const IPvXAddress &addr) |
void | deleteStreams () |
void | stopTimer (cMessage *timer) |
void | stopTimers () |
SCTPPathVariables * | getPath (const IPvXAddress &pathId) const |
void | printSctpPathMap () const |
static const char * | stateName (const int32 state) |
static uint32 | chunkToInt (const char *type) |
Definition at line 488 of file SCTPAssociation.h.
typedef struct SCTPAssociation::calcBytesToSend SCTPAssociation::BytesToBeSent [private] |
typedef struct SCTPAssociation::congestionControlFunctions SCTPAssociation::CCFunctions [private] |
typedef std::map<IPvXAddress, uint32> SCTPAssociation::CounterMap [private] |
Definition at line 496 of file SCTPAssociation.h.
typedef struct SCTPAssociation::counter SCTPAssociation::QueueCounter [private] |
typedef std::map<IPvXAddress,SCTPPathVariables*> SCTPAssociation::SCTPPathMap [private] |
Definition at line 494 of file SCTPAssociation.h.
typedef std::map<uint32, SCTPReceiveStream*> SCTPAssociation::SCTPReceiveStreamMap [private] |
Definition at line 519 of file SCTPAssociation.h.
typedef std::map<uint32, SCTPSendStream*> SCTPAssociation::SCTPSendStreamMap [private] |
Definition at line 518 of file SCTPAssociation.h.
typedef struct SCTPAssociation::streamSchedulingFunctions SCTPAssociation::SSFunctions [protected] |
SCTPAssociation::SCTPAssociation | ( | SCTP * | mod, | |
int32 | appGateIndex, | |||
int32 | assocId | |||
) |
Constructor.
Definition at line 276 of file SCTPAssociationBase.cc.
Referenced by cloneAssociation().
{ // ====== Initialize variables =========================================== sctpMain = _module; appGateIndex = _appGateIndex; assocId = _assocId; localPort = 0; remotePort = 0; localVTag = 0; peerVTag = 0; numberOfRemoteAddresses = 0; inboundStreams = SCTP_DEFAULT_INBOUND_STREAMS; outboundStreams = SCTP_DEFAULT_OUTBOUND_STREAMS; // queues and algorithm will be created on active or passive open transmissionQ = NULL; retransmissionQ = NULL; sctpAlgorithm = NULL; state = NULL; sackPeriod = SACK_DELAY; /* totalCwndAdjustmentTime = simTime(); lastTotalSSthresh = ~0; lastTotalCwnd = ~0;*/ cumTsnAck = NULL; sendQueue = NULL; numGapBlocks = NULL; qCounter.roomSumSendStreams = 0; qCounter.bookedSumSendStreams = 0; qCounter.roomSumRcvStreams = 0; bytes.chunk = false; bytes.packet = false; bytes.bytesToSend = 0; sctpEV3 << "SCTPAssociationBase::SCTPAssociation(): new assocId=" << assocId << endl; // ====== FSM ============================================================ char fsmName[64]; snprintf(fsmName, sizeof(fsmName), "fsm-%d", assocId); fsm = new cFSM(); fsm->setName(fsmName); fsm->setState(SCTP_S_CLOSED); // ====== Path Info ====================================================== SCTPPathInfo* pinfo = new SCTPPathInfo("pathInfo"); pinfo->setRemoteAddress(IPvXAddress("0.0.0.0")); // ====== Timers ========================================================= char timerName[128]; snprintf(timerName, sizeof(timerName), "T1_INIT of Association %d", assocId); T1_InitTimer = new cMessage(timerName); snprintf(timerName, sizeof(timerName), "T2_SHUTDOWN of Association %d", assocId); T2_ShutdownTimer = new cMessage(timerName); snprintf(timerName, sizeof(timerName), "T5_SHUTDOWN_GUARD of Association %d", assocId); T5_ShutdownGuardTimer = new cMessage(timerName); snprintf(timerName, sizeof(timerName), "SACK_TIMER of Association %d", assocId); SackTimer = new cMessage(timerName); if (sctpMain->testTimeout > 0){ StartTesting = new cMessage("StartTesting"); StartTesting->setContextPointer(this); StartTesting->setControlInfo(pinfo->dup()); scheduleTimeout(StartTesting, sctpMain->testTimeout); } T1_InitTimer->setContextPointer(this); T2_ShutdownTimer->setContextPointer(this); SackTimer->setContextPointer(this); T5_ShutdownGuardTimer->setContextPointer(this); T1_InitTimer->setControlInfo(pinfo); T2_ShutdownTimer->setControlInfo(pinfo->dup()); SackTimer->setControlInfo(pinfo->dup()); T5_ShutdownGuardTimer->setControlInfo(pinfo->dup()); // ====== Output vectors ================================================= char vectorName[128]; snprintf(vectorName, sizeof(vectorName), "Advertised Receiver Window %d", assocId); advRwnd = new cOutVector(vectorName); // ====== Stream scheduling ============================================== ssModule = sctpMain->par("ssModule"); switch (ssModule) { case ROUND_ROBIN: ssFunctions.ssInitStreams = &SCTPAssociation::initStreams; ssFunctions.ssGetNextSid = &SCTPAssociation::streamScheduler; ssFunctions.ssUsableStreams = &SCTPAssociation::numUsableStreams; break; } }
SCTPAssociation::~SCTPAssociation | ( | ) |
Destructor.
Definition at line 370 of file SCTPAssociationBase.cc.
{ sctpEV3 << "Destructor SCTPAssociation" << endl; delete T1_InitTimer; delete T2_ShutdownTimer; delete T5_ShutdownGuardTimer; delete SackTimer; delete advRwnd; delete cumTsnAck; delete numGapBlocks; delete sendQueue; delete fsm; delete state; delete sctpAlgorithm; }
void SCTPAssociation::ackChunk | ( | SCTPDataVariables * | chunk | ) | [inline, private] |
Definition at line 887 of file SCTPAssociation.h.
Referenced by dequeueAckedChunks(), and handleChunkReportedAsAcked().
{ chunk->hasBeenAcked = true; }
void SCTPAssociation::addPath | ( | const IPvXAddress & | addr | ) | [protected] |
Definition at line 1153 of file SCTPAssociationUtil.cc.
Referenced by processInitAckArrived().
{ sctpEV3<<"Add Path remote address: "<<addr<<"\n"; SCTPPathMap::iterator i = sctpPathMap.find(addr); if (i==sctpPathMap.end()) { sctpEV3<<__LINE__<<" get new path for "<<addr<<"\n"; SCTPPathVariables* path = new SCTPPathVariables(addr, this); sctpPathMap[addr] = path; qCounter.roomTransQ[addr] = 0; qCounter.bookedTransQ[addr] = 0; qCounter.roomRetransQ[addr] = 0; } sctpEV3<<"path added\n"; }
bool SCTPAssociation::advanceCtsna | ( | ) | [protected] |
Definition at line 1483 of file SCTPAssociationUtil.cc.
Referenced by processDataArrived().
{ int32 listLength, counter; ev<<"Entering advanceCtsna(ctsna now =="<< state->cTsnAck<<"\n";; listLength = state->numGaps; /* if there are no fragments, we cannot advance the ctsna */ if (listLength == 0) return false; counter = 0; while(counter < listLength) { /* if we take out a fragment here, we need to modify either counter or list_length */ if (state->cTsnAck + 1 == state->gapStartList[0]) { /* BINGO ! */ state->cTsnAck = state->gapStopList[0]; /* we can take out a maximum of list_length fragments */ counter++; for (uint32 i=1; i<state->numGaps; i++) { state->gapStartList[i-1] = state->gapStartList[i]; state->gapStopList[i-1] = state->gapStopList[i]; } } else { ev<<"Entering advanceCtsna(when leaving: ctsna=="<<state->cTsnAck<<"\n"; return false; } } /* end while */ ev<<"Entering advanceCtsna(when leaving: ctsna=="<< state->cTsnAck<<"\n"; return true; }
bool SCTPAssociation::allPathsInactive | ( | ) | const [protected] |
Definition at line 2074 of file SCTPAssociationUtil.cc.
Referenced by process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_RTX(), and updateCounters().
{ for(SCTPPathMap::const_iterator it = sctpPathMap.begin(); it != sctpPathMap.end(); it++) { if (it->second->activePath) { return false; } } return true; }
void SCTPAssociation::bytesAllowedToSend | ( | SCTPPathVariables * | path, | |
const bool | firstPass | |||
) | [protected] |
Definition at line 213 of file SCTPAssociationSendAll.cc.
Referenced by sendOnPath().
{ assert(path != NULL); bytes.chunk = false; bytes.packet = false; bytes.bytesToSend = 0; sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "):" << " osb=" << path->outstandingBytes << " cwnd=" << path->cwnd << endl; // ====== First transmission ============================================= if (!state->firstDataSent) { bytes.chunk = true; } // ====== Transmission allowed by peer's receiver window? ================ else if (state->peerWindowFull) { if (path->outstandingBytes == 0) { // Zero Window Probing sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): zeroWindowProbing" << endl; state->zeroWindowProbing = true; bytes.chunk = true; } } // ====== Retransmissions ================================================ else { CounterMap::const_iterator it = qCounter.roomTransQ.find(path->remoteAddress); sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): bytes in transQ=" << it->second << endl; if (it->second > 0) { const int32 allowance = path->cwnd - path->outstandingBytes; sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): cwnd-osb=" << allowance << endl; if (state->peerRwnd < path->pmtu) { bytes.bytesToSend = state->peerRwnd; sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): rwnd<pmtu" << endl; return; } else if (allowance > 0) { CounterMap::const_iterator bit = qCounter.bookedTransQ.find(path->remoteAddress); if (bit->second > (uint32)allowance) { bytes.bytesToSend = allowance; sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): cwnd does not allow all RTX" << endl; return; // More bytes available than allowed -> just return what is allowed. } else { bytes.bytesToSend = bit->second; sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): cwnd allows more than those " << bytes.bytesToSend << " bytes for retransmission" << endl; } } else { // You may retransmit one packet bytes.packet = true; sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): allowance<=0: retransmit one packet" << endl; } } // ====== New transmissions =========================================== if (!bytes.chunk && !bytes.packet) { if ((path->outstandingBytes < path->cwnd) && (!state->peerWindowFull)) { sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "):" << " bookedSumSendStreams=" << qCounter.bookedSumSendStreams << " bytes.bytesToSend=" << bytes.bytesToSend << endl; const int32 allowance = path->cwnd - path->outstandingBytes - bytes.bytesToSend; if (allowance > 0) { if (qCounter.bookedSumSendStreams > (uint32)allowance) { bytes.bytesToSend = path->cwnd - path->outstandingBytes; sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): bytesToSend are limited by cwnd: " << bytes.bytesToSend << endl; } else { bytes.bytesToSend += qCounter.bookedSumSendStreams; sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): send all stored bytes: " << bytes.bytesToSend << endl; } } } } } sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "):" << " osb=" << path->outstandingBytes << " cwnd=" << path->cwnd << " bytes.packet=" << (bytes.packet ? "YES!" : "no") << " bytes.chunk=" << (bytes.chunk ? "YES!" : "no") << " bytes.bytesToSend=" << bytes.bytesToSend << endl; }
int32 SCTPAssociation::calculateBytesToSendOnPath | ( | const SCTPPathVariables * | pathVar | ) | [private] |
Definition at line 38 of file SCTPAssociationSendAll.cc.
{ int32 bytesToSend; const SCTPDataMsg* datMsg = peekOutboundDataMsg(); if(datMsg != NULL) { const uint32 ums = datMsg->getBooksize(); // Get user message size const uint32 num = (uint32)floor((double)(pathVar->pmtu - 32) / (ums + SCTP_DATA_CHUNK_LENGTH)); if (num * ums > state->peerRwnd) { // Receiver cannot handle data yet bytesToSend = 0; } else { // Receiver will accept data bytesToSend = num * ums; } } else { bytesToSend = 0; } return(bytesToSend); }
cMessage* SCTPAssociation::cancelEvent | ( | cMessage * | msg | ) | [inline, protected] |
Utility: cancel a timer
Definition at line 740 of file SCTPAssociation.h.
Referenced by stopTimer().
{ return sctpMain->cancelEvent(msg); }
SCTPPathVariables * SCTPAssociation::choosePathForRetransmission | ( | ) | [private] |
Definition at line 158 of file SCTPAssociationSendAll.cc.
Referenced by sendOnPath().
{ uint32 max = 0; SCTPPathVariables* temp = NULL; for (SCTPPathMap::iterator iterator = sctpPathMap.begin(); iterator != sctpPathMap.end(); ++iterator) { SCTPPathVariables* path = iterator->second; CounterMap::const_iterator tq = qCounter.roomTransQ.find(path->remoteAddress); if ((tq != qCounter.roomTransQ.end()) && (tq->second > max)) { max = tq->second; temp = path; } } return temp; }
bool SCTPAssociation::chunkHasBeenAcked | ( | const SCTPDataVariables * | chunk | ) | const [inline, private] |
Definition at line 893 of file SCTPAssociation.h.
Referenced by cwndUpdateAfterSack(), dequeueAckedChunks(), getOutboundDataChunk(), handleChunkReportedAsMissing(), process_TIMEOUT_RTX(), processSackArrived(), and sendOnPath().
{ return(chunk->hasBeenAcked); }
bool SCTPAssociation::chunkHasBeenAcked | ( | const uint32 | tsn | ) | const [inline, private] |
Definition at line 896 of file SCTPAssociation.h.
{ const SCTPDataVariables* chunk = retransmissionQ->getChunk(tsn); if(chunk) { return(chunkHasBeenAcked(chunk)); } return(false); }
uint32 SCTPAssociation::chunkToInt | ( | const char * | type | ) | [static] |
Definition at line 132 of file SCTPAssociationUtil.cc.
{ if (strcmp(type, "DATA")==0) return 0; if (strcmp(type, "INIT")==0) return 1; if (strcmp(type, "INIT_ACK")==0) return 2; if (strcmp(type, "SACK")==0) return 3; if (strcmp(type, "HEARTBEAT")==0) return 4; if (strcmp(type, "HEARTBEAT_ACK")==0) return 5; if (strcmp(type, "ABORT")==0) return 6; if (strcmp(type, "SHUTDOWN")==0) return 7; if (strcmp(type, "SHUTDOWN_ACK")==0) return 8; if (strcmp(type, "ERRORTYPE")==0) return 9; if (strcmp(type, "COOKIE_ECHO")==0) return 10; if (strcmp(type, "COOKIE_ACK")==0) return 11; if (strcmp(type, "SHUTDOWN_COMPLETE")==0) return 14; sctpEV3<<"ChunkConversion not successful\n"; return 0; }
SCTPAssociation * SCTPAssociation::cloneAssociation | ( | ) | [protected] |
Utility: clone a listening association. Used for forking.
Definition at line 166 of file SCTPAssociationUtil.cc.
Referenced by processInitArrived().
{ SCTPAssociation* assoc = new SCTPAssociation(sctpMain,appGateIndex,assocId); const char* queueClass = transmissionQ->getClassName(); assoc->transmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass)); assoc->retransmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass)); const char* sctpAlgorithmClass = sctpAlgorithm->getClassName(); assoc->sctpAlgorithm = check_and_cast<SCTPAlgorithm *>(createOne(sctpAlgorithmClass)); assoc->sctpAlgorithm->setAssociation(assoc); assoc->sctpAlgorithm->initialize(); assoc->state = assoc->sctpAlgorithm->createStateVariables(); assoc->state->active = false; assoc->state->fork = true; assoc->localAddr = localAddr; assoc->localPort = localPort; assoc->localAddressList = localAddressList; FSM_Goto((*assoc->fsm), SCTP_S_CLOSED); sctpMain->printInfoConnMap(); return assoc; }
SCTPSackChunk * SCTPAssociation::createSack | ( | ) | [protected] |
Definition at line 881 of file SCTPAssociationUtil.cc.
Referenced by sendOnPath(), and sendSack().
{ uint32 key=0, arwnd=0; sctpEV3<<"SCTPAssociationUtil:createSACK localAddress="<<localAddr<<" remoteAddress="<<remoteAddr<<"\n"; sctpEV3<<" localRwnd="<<state->localRwnd<<" queuedBytes="<<state->queuedReceivedBytes<<"\n"; if ((int32)(state->localRwnd - state->queuedReceivedBytes) <= 0) { arwnd = 0; if (state->swsLimit > 0) state->swsAvoidanceInvoked = true; } else if (state->localRwnd - state->queuedReceivedBytes < state->swsLimit || state->swsAvoidanceInvoked == true) { arwnd = 1; if (state->swsLimit > 0) state->swsAvoidanceInvoked = true; sctpEV3<<"arwnd=1; createSack : SWS Avoidance ACTIVE !!!\n"; } else { arwnd = state->localRwnd - state->queuedReceivedBytes; sctpEV3<<simTime()<<" arwnd = "<<state->localRwnd<<" - "<<state->queuedReceivedBytes<<" = "<<arwnd<<"\n"; } advRwnd->record(arwnd); SCTPSackChunk* sackChunk=new SCTPSackChunk("SACK"); sackChunk->setChunkType(SACK); sackChunk->setCumTsnAck(state->cTsnAck); sackChunk->setA_rwnd(arwnd); uint32 numGaps=state->numGaps; uint32 numDups=state->dupList.size(); uint16 sackLength=SCTP_SACK_CHUNK_LENGTH + numGaps*4 + numDups*4; uint32 mtu = getPath(remoteAddr)->pmtu; if (sackLength > mtu-32) // FIXME { if (SCTP_SACK_CHUNK_LENGTH + numGaps*4 > mtu-32) { numDups = 0; numGaps = (uint32)((mtu-32-SCTP_SACK_CHUNK_LENGTH)/4); } else { numDups = (uint32)((mtu-32-SCTP_SACK_CHUNK_LENGTH - numGaps*4)/4); } sackLength=SCTP_SACK_CHUNK_LENGTH + numGaps*4 + numDups*4; } sackChunk->setNumGaps(numGaps); sackChunk->setNumDupTsns(numDups); sackChunk->setBitLength(sackLength*8); sctpEV3<<"Sack arwnd="<<sackChunk->getA_rwnd()<<" ctsnAck="<<state->cTsnAck<<" numGaps="<<numGaps<<" numDups="<<numDups<<"\n"; if (numGaps > 0) { sackChunk->setGapStartArraySize(numGaps); sackChunk->setGapStopArraySize(numGaps); uint32 last = state->cTsnAck; for (key=0; key<numGaps; key++) { // ====== Validity check =========================================== assert(tsnGt(state->gapStartList[key], last + 1)); assert(tsnGe(state->gapStopList[key], state->gapStartList[key])); last = state->gapStopList[key]; sackChunk->setGapStart(key, state->gapStartList[key]); sackChunk->setGapStop(key, state->gapStopList[key]); } } if (numDups > 0) { sackChunk->setDupTsnsArraySize(numDups); key=0; for(std::list<uint32>::iterator iter=state->dupList.begin(); iter!=state->dupList.end(); iter++) { sackChunk->setDupTsns(key, (*iter)); key++; if (key == numDups) break; } state->dupList.clear(); } sctpEV3<<endl; for (uint32 i=0; i<numGaps; i++) sctpEV3<<sackChunk->getGapStart(i)<<" - "<<sackChunk->getGapStop(i)<<"\n"; sctpEV3<<"send "<<sackChunk->getName()<<" from "<<localAddr<<" to "<<state->lastDataSourceAddress<<"\n"; return sackChunk; }
void SCTPAssociation::cwndUpdateAfterCwndTimeout | ( | SCTPPathVariables * | path | ) | [protected] |
Definition at line 272 of file SCTPCCFunctions.cc.
{ // When the association does not transmit data on a given transport address // within an RTO, the cwnd of the transport address SHOULD be adjusted to 2*MTU. sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterCwndTimeout]\t" << path->remoteAddress << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd; path->cwnd = (int32)min(4 * path->pmtu, max(2 * path->pmtu, 4380)); sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl; recordCwndUpdate(path); }
void SCTPAssociation::cwndUpdateAfterRtxTimeout | ( | SCTPPathVariables * | path | ) | [protected] |
Definition at line 236 of file SCTPCCFunctions.cc.
{ sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterRtxTimeout]\t" << path->remoteAddress << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd; path->ssthresh = (int32)max(path->cwnd / 2, 4 * path->pmtu); path->cwnd = path->pmtu; sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl; path->partialBytesAcked = 0; recordCwndUpdate(path); // Leave Fast Recovery mode if (path->fastRecoveryActive == true) { path->fastRecoveryActive = false; path->fastRecoveryExitPoint = 0; } }
void SCTPAssociation::cwndUpdateAfterSack | ( | ) | [protected] |
Definition at line 50 of file SCTPCCFunctions.cc.
{ for (SCTPPathMap::iterator iter = sctpPathMap.begin(); iter != sctpPathMap.end(); iter++) { SCTPPathVariables* path = iter->second; if(path->fastRecoveryActive == false) { // ====== Retransmission required -> reduce congestion window ====== if(path->requiresRtx) { double decreaseFactor = 0.5; sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterSack]\t" << path->remoteAddress << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd; path->ssthresh = max((int32)path->cwnd - (int32)rint(decreaseFactor * (double)path->cwnd), 4 * (int32)path->pmtu); path->cwnd = path->ssthresh; sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl; recordCwndUpdate(path); path->partialBytesAcked = 0; // ====== Fast Recovery ======================================== if(state->fastRecoverySupported) { uint32 highestAckOnPath = state->lastTsnAck; for(SCTPQueue::PayloadQueue::iterator pq = retransmissionQ->payloadQueue.begin(); pq != retransmissionQ->payloadQueue.end(); pq++) { if( (chunkHasBeenAcked(pq->second) == true) && (tsnGt(pq->second->tsn, highestAckOnPath)) && (pq->second->getLastDestinationPath() == path) ) { // T.D. 21.11.09: Only take care of TSNs on the same path! highestAckOnPath = pq->second->tsn; } } /* this can ONLY become TRUE, when Fast Recovery IS supported */ path->fastRecoveryActive = true; path->fastRecoveryExitPoint = highestAckOnPath; path->fastRecoveryEnteringTime = simTime(); sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterSack] Entering Fast Recovery on path " << path->remoteAddress << ", exit point is " << path->fastRecoveryExitPoint << endl; } } } else { for (SCTPPathMap::iterator iter = sctpPathMap.begin(); iter != sctpPathMap.end(); iter++) { SCTPPathVariables* path = iter->second; if(path->fastRecoveryActive) { sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterSack] Still in Fast Recovery on path " << path->remoteAddress << ", exit point is " << path->fastRecoveryExitPoint << endl; } } } } }
void SCTPAssociation::cwndUpdateBytesAcked | ( | SCTPPathVariables * | path, | |
const uint32 | ackedBytes, | |||
const bool | ctsnaAdvanced | |||
) | [protected] |
Definition at line 130 of file SCTPCCFunctions.cc.
{ sctpEV3 << simulation.getSimTime() << "====> cwndUpdateBytesAcked:" << " path=" << path->remoteAddress << " ackedBytes=" << ackedBytes << " ctsnaAdvanced=" << ((ctsnaAdvanced == true) ? "yes" : "no") << " cwnd=" << path->cwnd << " ssthresh=" << path->ssthresh << " ackedBytes=" << ackedBytes << " pathOsbBeforeUpdate=" << path->outstandingBytesBeforeUpdate << " pathOsb=" << path->outstandingBytes << endl; if (path->fastRecoveryActive == false) { // T.D. 21.11.09: Increasing cwnd is only allowed when not being in // Fast Recovery mode! // ====== Slow Start ================================================== if (path->cwnd <= path->ssthresh) { // ------ Clear PartialBytesAcked counter -------------------------- path->partialBytesAcked = 0; // ------ Increase Congestion Window ------------------------------- if ((ctsnaAdvanced == true) && (path->outstandingBytesBeforeUpdate >= path->cwnd)) { sctpEV3 << simTime() << ":\tCC [cwndUpdateBytesAcked-SlowStart]\t" << path->remoteAddress << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << " acked=" << ackedBytes; path->cwnd += (int32)min(path->pmtu, ackedBytes); sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl; recordCwndUpdate(path); } // ------ No need to increase Congestion Window -------------------- else { sctpEV3 << simTime() << ":\tCC " << "Not increasing cwnd of path " << path->remoteAddress << " in slow start:\t" << "ctsnaAdvanced=" << ((ctsnaAdvanced == true) ? "yes" : "no") << "\t" << "cwnd=" << path->cwnd << "\t" << "ssthresh=" << path->ssthresh << "\t" << "ackedBytes=" << ackedBytes << "\t" << "pathOsbBeforeUpdate=" << path->outstandingBytesBeforeUpdate << "\t" << "pathOsb=" << path->outstandingBytes << "\t" << "(pathOsbBeforeUpdate >= path->cwnd)=" << (path->outstandingBytesBeforeUpdate >= path->cwnd) << endl; } } // ====== Congestion Avoidance ======================================== else { // ------ Increase PartialBytesAcked counter ----------------------- path->partialBytesAcked += ackedBytes; double increaseFactor = 1.0; // ------ Increase Congestion Window ------------------------------- if ( (path->partialBytesAcked >= path->cwnd) && (ctsnaAdvanced == true) && (path->outstandingBytesBeforeUpdate >= path->cwnd) ) { sctpEV3 << simTime() << ":\tCC [cwndUpdateBytesAcked-CgAvoidance]\t" << path->remoteAddress << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << " acked=" << ackedBytes; path->cwnd += (int32)rint(increaseFactor * path->pmtu); sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl; recordCwndUpdate(path); path->partialBytesAcked = ((path->cwnd < path->partialBytesAcked) ? (path->partialBytesAcked - path->cwnd) : 0); } // ------ No need to increase Congestion Window ------------------- else { sctpEV3 << simTime() << ":\tCC " << "Not increasing cwnd of path " << path->remoteAddress << " in congestion avoidance: " << "ctsnaAdvanced=" << ((ctsnaAdvanced == true) ? "yes" : "no") << "\t" << "cwnd=" << path->cwnd << "\t" << "ssthresh=" << path->ssthresh << "\t" << "ackedBytes=" << ackedBytes << "\t" << "pathOsbBeforeUpdate=" << path->outstandingBytesBeforeUpdate << "\t" << "pathOsb=" << path->outstandingBytes << "\t" << "(pathOsbBeforeUpdate >= path->cwnd)=" << (path->outstandingBytesBeforeUpdate >= path->cwnd) << "\t" << "partialBytesAcked=" << path->partialBytesAcked << "\t" << "(path->partialBytesAcked >= path->cwnd)=" << (path->partialBytesAcked >= path->cwnd) << endl; } } // ====== Reset PartialBytesAcked counter if no more outstanding bytes if(path->outstandingBytes == 0) { path->partialBytesAcked = 0; } } else { sctpEV3 << simTime() << ":\tCC " << "Not increasing cwnd of path " << path->remoteAddress << " during Fast Recovery" << endl; } }
void SCTPAssociation::cwndUpdateMaxBurst | ( | SCTPPathVariables * | path | ) | [protected] |
Definition at line 256 of file SCTPCCFunctions.cc.
{ if(path->cwnd > ((path->outstandingBytes + state->maxBurst * path->pmtu))) { sctpEV3 << simTime() << ":\tCC [cwndUpdateMaxBurst]\t" << path->remoteAddress << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << "\tosb=" << path->outstandingBytes << "\tmaxBurst=" << state->maxBurst * path->pmtu << endl; path->cwnd = path->outstandingBytes + (state->maxBurst * path->pmtu); recordCwndUpdate(path); sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl; } }
void SCTPAssociation::decreaseOutstandingBytes | ( | SCTPDataVariables * | chunk | ) | [private] |
Definition at line 32 of file SCTPAssociationRcvMessage.cc.
Referenced by dequeueAckedChunks(), handleChunkReportedAsAcked(), handleChunkReportedAsMissing(), moveChunkToOtherPath(), and tsnWasReneged().
{ SCTPPathVariables* lastPath = chunk->getLastDestinationPath(); assert(lastPath->outstandingBytes >= chunk->booksize); lastPath->outstandingBytes -= chunk->booksize; state->outstandingBytes -= chunk->booksize; assert((int64)state->outstandingBytes >= 0); chunk->countsAsOutstanding = false; CounterMap::iterator iterator = qCounter.roomRetransQ.find(lastPath->remoteAddress); iterator->second -= ADD_PADDING(chunk->booksize + SCTP_DATA_CHUNK_LENGTH); }
void SCTPAssociation::deleteStreams | ( | ) |
Definition at line 1193 of file SCTPAssociationUtil.cc.
Referenced by SCTP::removeAssociation().
{ for (SCTPSendStreamMap::iterator it=sendStreams.begin(); it != sendStreams.end(); it++) { it->second->deleteQueue(); } for (SCTPReceiveStreamMap::iterator it=receiveStreams.begin(); it != receiveStreams.end(); it++) { delete it->second; } }
uint32 SCTPAssociation::dequeueAckedChunks | ( | const uint32 | tsna, | |
SCTPPathVariables * | path, | |||
simtime_t & | rttEstimation | |||
) | [protected] |
Definition at line 1151 of file SCTPAssociationRcvMessage.cc.
Referenced by process_RCV_Message(), and processSackArrived().
{ SCTP::AssocStat* assocStat = sctpMain->getAssocStat(assocId); uint32 newlyAckedBytes = 0; uint64 sendBufferBeforeUpdate = state->sendBuffer; // Set it ridiculously high rttEstimation = MAXTIME; // Are there chunks in the retransmission queue ? If Yes -> check for dequeue. SCTPQueue::PayloadQueue::iterator iterator = retransmissionQ->payloadQueue.begin(); while (iterator != retransmissionQ->payloadQueue.end()) { SCTPDataVariables* chunk = iterator->second; if (tsnGe(tsna, chunk->tsn)) { // Dequeue chunk, cause it has been acked if (transmissionQ->getChunk(chunk->tsn)) { transmissionQ->removeMsg(chunk->tsn); chunk->enqueuedInTransmissionQ = false; CounterMap::iterator q = qCounter.roomTransQ.find(chunk->getNextDestination()); q->second -= ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH); CounterMap::iterator qb = qCounter.bookedTransQ.find(chunk->getNextDestination()); qb->second -= chunk->booksize; } chunk = retransmissionQ->getAndExtractChunk(chunk->tsn); state->sendBuffer -= chunk->len/8; SCTPPathVariables* lastPath = chunk->getLastDestinationPath(); assert(lastPath != NULL); if (!chunkHasBeenAcked(chunk)) { newlyAckedBytes += (chunk->booksize); sctpEV3 << simTime() << ": CumAcked TSN " << chunk->tsn << " on path " << chunk->getLastDestination() << endl; lastPath->newlyAckedBytes += (chunk->booksize); // T.D. 05.12.09: CumAck affects lastPath -> reset its T3 timer later. lastPath->newCumAck = true; } if(assocStat) { assocStat->ackedBytes += chunk->len/8; } if ((chunkHasBeenAcked(chunk) == false) && (chunk->countsAsOutstanding)) { ackChunk(chunk); if ((chunk->numberOfTransmissions == 1) && (chunk->getLastDestinationPath() == sackPath)) { const simtime_t timeDifference = simTime() - chunk->sendTime; if ((timeDifference < rttEstimation) || (rttEstimation == MAXTIME)) { rttEstimation = timeDifference; } } decreaseOutstandingBytes(chunk); } if (chunk->userData != NULL) { delete chunk->userData; } delete chunk; } else { break; } iterator = retransmissionQ->payloadQueue.begin(); } if(sendBufferBeforeUpdate != state->sendBuffer && state->sendBuffer < state->sendQueueLimit) { // T.D. 06.02.2010: Just send SCTP_I_SENDQUEUE_ABATED once, after all newly acked // chunks have been dequeued. // I.R. only send indication if the sendBuffer size has dropped below the sendQueueLimit assert(state->lastSendQueueAbated < simTime()); state->appSendAllowed = true; sctpEV3 << simTime() << ":\tSCTP_I_SENDQUEUE_ABATED(" << sendBufferBeforeUpdate - state->sendBuffer << ") to refill buffer " << state->sendBuffer << "/" << state->sendQueueLimit << endl; sendIndicationToApp(SCTP_I_SENDQUEUE_ABATED, sendBufferBeforeUpdate - state->sendBuffer); state->lastSendQueueAbated = simTime(); } sctpEV3 << "dequeueAckedChunks(): newlyAckedBytes=" << newlyAckedBytes << ", rttEstimation=" << rttEstimation << endl; return (newlyAckedBytes); }
SCTPDataMsg * SCTPAssociation::dequeueOutboundDataMsg | ( | const int32 | availableSpace, | |
const int32 | availableCwnd | |||
) | [protected] |
Definition at line 1646 of file SCTPAssociationUtil.cc.
Referenced by sendOnPath().
{ SCTPDataMsg* datMsg=NULL; int32 nextStream = -1; sctpEV3<<"dequeueOutboundDataMsg: " << availableSpace <<" bytes left to be sent" << endl; /* Only change stream if we don't have to finish a fragmented message */ if (state->lastMsgWasFragment) nextStream = state->lastStreamScheduled; else nextStream = (this->*ssFunctions.ssGetNextSid)(false); if (nextStream == -1) return NULL; sctpEV3<<"dequeueOutboundDataMsg: now stream "<< nextStream << endl; for (SCTPSendStreamMap::iterator iter=sendStreams.begin(); iter!=sendStreams.end(); ++iter) { if ((int32)iter->first==nextStream) { SCTPSendStream* stream=iter->second; cQueue* streamQ = NULL; if (!stream->getUnorderedStreamQ()->empty()) { streamQ = stream->getUnorderedStreamQ(); sctpEV3<<"DequeueOutboundDataMsg() found chunks in stream "<<iter->first<<" unordered queue, queue size="<<stream->getUnorderedStreamQ()->getLength()<<"\n"; } else if (!stream->getStreamQ()->empty()) { streamQ = stream->getStreamQ(); sctpEV3<<"DequeueOutboundDataMsg() found chunks in stream "<<iter->first<<" ordered queue, queue size="<<stream->getStreamQ()->getLength()<<"\n"; } if (streamQ) { int32 b=ADD_PADDING( (check_and_cast<SCTPSimpleMessage*>(((SCTPDataMsg*)streamQ->front())->getEncapsulatedMsg())->getByteLength()+SCTP_DATA_CHUNK_LENGTH)); /* check if chunk found in queue has to be fragmented */ if (b > (int32)state->assocPmtu - IP_HEADER_LENGTH - SCTP_COMMON_HEADER) { /* START FRAGMENTATION */ SCTPDataMsg* datMsgQueued = (SCTPDataMsg*)streamQ->pop(); SCTPSimpleMessage *datMsgQueuedSimple = check_and_cast<SCTPSimpleMessage*>(datMsgQueued->getEncapsulatedMsg()); SCTPDataMsg* datMsgLastFragment = NULL; uint32 offset = 0; sctpEV3<<"Fragmentation: chunk " << &datMsgQueued << ", size = " << datMsgQueued->getByteLength() << endl; while (datMsgQueued) { /* detemine size of fragment, either max payload or what's left */ uint32 msgbytes = state->assocPmtu - IP_HEADER_LENGTH - SCTP_COMMON_HEADER - SCTP_DATA_CHUNK_LENGTH; if (msgbytes > datMsgQueuedSimple->getDataLen() - offset) msgbytes = datMsgQueuedSimple->getDataLen() - offset; /* new DATA msg */ SCTPDataMsg* datMsgFragment = new SCTPDataMsg(); datMsgFragment->setSid(datMsgQueued->getSid()); datMsgFragment->setPpid(datMsgQueued->getPpid()); datMsgFragment->setInitialDestination(datMsgQueued->getInitialDestination()); datMsgFragment->setEnqueuingTime(datMsgQueued->getEnqueuingTime()); datMsgFragment->setMsgNum(datMsgQueued->getMsgNum()); datMsgFragment->setOrdered(datMsgQueued->getOrdered()); datMsgFragment->setExpiryTime(datMsgQueued->getExpiryTime()); datMsgFragment->setRtx(datMsgQueued->getRtx()); datMsgFragment->setFragment(true); datMsgFragment->setBooksize(msgbytes + state->header); /* is this the first fragment? */ if (offset == 0) datMsgFragment->setBBit(true); /* new msg */ SCTPSimpleMessage *datMsgFragmentSimple = new SCTPSimpleMessage(); datMsgFragmentSimple->setName(datMsgQueuedSimple->getName()); datMsgFragmentSimple->setCreationTime(datMsgQueuedSimple->getCreationTime()); datMsgFragmentSimple->setDataArraySize(msgbytes); datMsgFragmentSimple->setDataLen(msgbytes); datMsgFragmentSimple->setByteLength(msgbytes); /* copy data */ for (uint32 i = offset; i < offset + msgbytes; i++) datMsgFragmentSimple->setData(i - offset, datMsgQueuedSimple->getData(i)); offset += msgbytes; datMsgFragment->encapsulate(datMsgFragmentSimple); /* insert fragment into queue */ if (!streamQ->empty()) { if (!datMsgLastFragment) { /* insert first fragment at the begining of the queue*/ streamQ->insertBefore((SCTPDataMsg*)streamQ->front(), datMsgFragment); } else { /* insert fragment after last inserted */ streamQ->insertAfter(datMsgLastFragment, datMsgFragment); } } else streamQ->insert(datMsgFragment); state->queuedMessages++; qCounter.roomSumSendStreams += ADD_PADDING(datMsgFragment->getByteLength() + SCTP_DATA_CHUNK_LENGTH); qCounter.bookedSumSendStreams += datMsgFragment->getBooksize(); sctpEV3<<"Fragmentation: fragment " << &datMsgFragment << " created, length = " << datMsgFragmentSimple->getByteLength() << ", queue size = " << streamQ->getLength() << endl; datMsgLastFragment = datMsgFragment; /* all fragments done? */ if (datMsgQueuedSimple->getDataLen() == offset) { datMsgFragment->setEBit(true); /* remove original element */ sctpEV3<<"Fragmentation: delete " << &datMsgQueued << endl; //streamQ->pop(); qCounter.roomSumSendStreams -= ADD_PADDING(datMsgQueued->getByteLength() + SCTP_DATA_CHUNK_LENGTH); qCounter.bookedSumSendStreams -= datMsgQueued->getBooksize(); delete datMsgQueued; datMsgQueued = NULL; state->queuedMessages--; } } /* the next chunk returned will always be a fragment */ state->lastMsgWasFragment = true; b=ADD_PADDING( (check_and_cast<SCTPSimpleMessage*>(((SCTPDataMsg*)streamQ->front())->getEncapsulatedMsg())->getBitLength()/8+SCTP_DATA_CHUNK_LENGTH)); /* FRAGMENTATION DONE */ } if ((b <= availableSpace) && ( (int32)((SCTPDataMsg*)streamQ->front())->getBooksize() <= availableCwnd)) { datMsg = (SCTPDataMsg*)streamQ->pop(); /*if (!state->appSendAllowed && streamQ->getLength()<=state->sendQueueLimit) { state->appSendAllowed = true; sendIndicationToApp(SCTP_I_SENDQUEUE_ABATED); }*/ sendQueue->record(streamQ->getLength()); if (!datMsg->getFragment()) { datMsg->setBBit(true); datMsg->setEBit(true); state->lastMsgWasFragment = false; } else { if (datMsg->getEBit()) state->lastMsgWasFragment = false; else state->lastMsgWasFragment = true; } sctpEV3<<"DequeueOutboundDataMsg() found chunk ("<<&datMsg<<") in the stream queue "<<&iter->first<<"("<<streamQ<<") queue size="<<streamQ->getLength()<<"\n"; } } break; } } if (datMsg != NULL) { qCounter.roomSumSendStreams -= ADD_PADDING( (check_and_cast<SCTPSimpleMessage*>(datMsg->getEncapsulatedMsg())->getBitLength()/8+SCTP_DATA_CHUNK_LENGTH)); qCounter.bookedSumSendStreams -= datMsg->getBooksize(); } return (datMsg); }
void SCTPAssociation::disposeOf | ( | SCTPMessage * | sctpmsg | ) | [protected] |
Definition at line 2085 of file SCTPAssociationUtil.cc.
Referenced by process_RCV_Message().
{ SCTPChunk* chunk; uint32 numberOfChunks = sctpmsg->getChunksArraySize(); if (numberOfChunks>0) for (uint32 i=0; i<numberOfChunks; i++) { chunk = (SCTPChunk*)(sctpmsg->removeChunk()); if (chunk->getChunkType()==DATA) delete (SCTPSimpleMessage*)chunk->decapsulate(); delete chunk; } delete sctpmsg; }
const char * SCTPAssociation::eventName | ( | const int32 | event | ) | [static, protected] |
Utility: returns name of SCTP_E_xxx constants
Definition at line 69 of file SCTPAssociationUtil.cc.
Referenced by performStateTransition(), and processAppCommand().
{ #define CASE(x) case x: s=#x+7; break const char* s = "unknown"; switch (event) { CASE(SCTP_E_OPEN_PASSIVE); CASE(SCTP_E_ASSOCIATE); CASE(SCTP_E_SHUTDOWN); CASE(SCTP_E_CLOSE); CASE(SCTP_E_ABORT); CASE(SCTP_E_SEND); CASE(SCTP_E_RCV_INIT); CASE(SCTP_E_RCV_ABORT); CASE(SCTP_E_RCV_VALID_COOKIE_ECHO); CASE(SCTP_E_RCV_INIT_ACK); CASE(SCTP_E_RCV_COOKIE_ACK); CASE(SCTP_E_RCV_SHUTDOWN); CASE(SCTP_E_RCV_SHUTDOWN_ACK); CASE(SCTP_E_RCV_SHUTDOWN_COMPLETE); CASE(SCTP_E_TIMEOUT_INIT_TIMER); CASE(SCTP_E_TIMEOUT_SHUTDOWN_TIMER); CASE(SCTP_E_TIMEOUT_RTX_TIMER); CASE(SCTP_E_TIMEOUT_HEARTBEAT_TIMER); CASE(SCTP_E_RECEIVE); CASE(SCTP_E_DUP_RECEIVED); CASE(SCTP_E_PRIMARY); CASE(SCTP_E_QUEUE_MSGS_LIMIT); CASE(SCTP_E_QUEUE_BYTES_LIMIT); CASE(SCTP_E_NO_MORE_OUTSTANDING); CASE(SCTP_E_IGNORE); CASE(SCTP_E_DELIVERED); CASE(SCTP_E_SEND_SHUTDOWN_ACK); CASE(SCTP_E_STOP_SENDING); } return s; #undef CASE }
cFSM* SCTPAssociation::getFsm | ( | ) | const [inline] |
Definition at line 599 of file SCTPAssociation.h.
{ return fsm; };
int32 SCTPAssociation::getFsmState | ( | ) | const [inline] |
Definition at line 593 of file SCTPAssociation.h.
{ return fsm->getState(); };
cMessage* SCTPAssociation::getInitTimer | ( | ) | const [inline] |
Definition at line 600 of file SCTPAssociation.h.
{ return T1_InitTimer; };
const IPvXAddress& SCTPAssociation::getNextAddress | ( | const SCTPPathVariables * | oldPath | ) | const [inline, protected] |
Definition at line 766 of file SCTPAssociation.h.
{ const SCTPPathVariables* nextPath = getNextPath(oldPath); if(nextPath != NULL) { return(nextPath->remoteAddress); } return(SCTPDataVariables::zeroAddress); }
SCTPPathVariables * SCTPAssociation::getNextDestination | ( | SCTPDataVariables * | chunk | ) | const [protected] |
Definition at line 1898 of file SCTPAssociationUtil.cc.
Referenced by handleChunkReportedAsMissing(), and process_TIMEOUT_RTX().
{ SCTPPathVariables* next; SCTPPathVariables* last; sctpEV3 << "Running getNextDestination()" << endl; if (chunk->numberOfTransmissions == 0) { if (chunk->getInitialDestinationPath() == NULL) { next = state->getPrimaryPath(); } else { next = chunk->getInitialDestinationPath(); } } else { if (chunk->hasBeenFastRetransmitted) { sctpEV3 << "Chunk is scheduled for FastRetransmission. Next destination = " << chunk->getLastDestination() << endl; return(chunk->getLastDestinationPath()); } // If this is a retransmission, we should choose another, active path. last = chunk->getLastDestinationPath(); next = getNextPath(last); if( (next == NULL) || (next->confirmed == false) ) { next = last; } } sctpEV3 << "getNextDestination(): chunk was last sent to " << last->remoteAddress << ", will next be sent to path " << next->remoteAddress << endl; return (next); }
SCTPPathVariables * SCTPAssociation::getNextPath | ( | const SCTPPathVariables * | oldPath | ) | const [protected] |
Definition at line 1876 of file SCTPAssociationUtil.cc.
Referenced by getNextDestination(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_RTX(), and updateCounters().
{ int32 hit = 0; if (sctpPathMap.size() > 1) { for (SCTPPathMap::const_iterator iterator = sctpPathMap.begin(); iterator != sctpPathMap.end(); iterator++) { if (iterator->second == oldPath) { if (++hit == 1) { continue; } else { break; } } if (iterator->second->activePath) { return iterator->second; } } } return(NULL); }
SCTPDataVariables * SCTPAssociation::getOutboundDataChunk | ( | const SCTPPathVariables * | path, | |
const int32 | availableSpace, | |||
const int32 | availableCwnd | |||
) | [protected] |
Definition at line 1552 of file SCTPAssociationUtil.cc.
Referenced by sendOnPath().
{ /* are there chunks in the transmission queue ? If Yes -> dequeue and return it */ sctpEV3 << "getOutboundDataChunk(" << path->remoteAddress << "):" << " availableSpace=" << availableSpace << " availableCwnd=" << availableCwnd << endl; if (!transmissionQ->payloadQueue.empty()) { for(SCTPQueue::PayloadQueue::iterator it = transmissionQ->payloadQueue.begin(); it != transmissionQ->payloadQueue.end(); it++) { SCTPDataVariables* chunk = it->second; if( (chunkHasBeenAcked(chunk) == false) && (chunk->getNextDestinationPath() == path) ) { const int32 len = ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH); sctpEV3 << "getOutboundDataChunk() found chunk " << chunk->tsn <<" in the transmission queue, length=" << len << endl; if ((len <= availableSpace) && ((int32)chunk->booksize <= availableCwnd)) { // T.D. 05.01.2010: The bookkeeping counters may only be decreased when // this chunk is actually dequeued. Therefore, the check // for "chunkHasBeenAcked==false" has been moved into the // "if" statement above! transmissionQ->payloadQueue.erase(it); chunk->enqueuedInTransmissionQ = false; CounterMap::iterator i = qCounter.roomTransQ.find(path->remoteAddress); i->second -= ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH); CounterMap::iterator ib = qCounter.bookedTransQ.find(path->remoteAddress); ib->second -= chunk->booksize; return chunk; } } } } return NULL; }
int32 SCTPAssociation::getOutstandingBytes | ( | ) | const [protected] |
Definition at line 2000 of file SCTPAssociationUtil.cc.
Referenced by process_CLOSE(), process_RCV_Message(), processSackArrived(), sendShutdownAck(), and stateEntered().
{ int32 osb = 0; for (SCTPPathMap::const_iterator pm = sctpPathMap.begin(); pm != sctpPathMap.end(); pm++) { osb += pm->second->outstandingBytes; } return osb; }
SCTPPathVariables* SCTPAssociation::getPath | ( | const IPvXAddress & | pathId | ) | const [inline] |
Definition at line 631 of file SCTPAssociation.h.
Referenced by createSack(), process_PRIMARY(), process_RCV_Message(), process_SEND(), process_STATUS(), processDataArrived(), processHeartbeatAckArrived(), processInitAckArrived(), processInitArrived(), processSackArrived(), processTimer(), recordInPathVectors(), sendInit(), sendInitAck(), and sendShutdownAck().
{ SCTPPathMap::const_iterator iterator = sctpPathMap.find(pathId); if (iterator !=sctpPathMap.end()) { return iterator->second; } return NULL; }
SCTPQueue* SCTPAssociation::getRetransmissionQueue | ( | ) | const [inline] |
Definition at line 596 of file SCTPAssociation.h.
Referenced by SCTP::removeAssociation().
{ return retransmissionQ; };
cMessage* SCTPAssociation::getSackTimer | ( | ) | const [inline] |
Definition at line 602 of file SCTPAssociation.h.
{ return SackTimer; };
SCTPAlgorithm* SCTPAssociation::getSctpAlgorithm | ( | ) | const [inline] |
Definition at line 597 of file SCTPAssociation.h.
{ return sctpAlgorithm; };
SCTP* SCTPAssociation::getSctpMain | ( | ) | const [inline] |
Definition at line 598 of file SCTPAssociation.h.
Referenced by SCTPPathVariables::SCTPPathVariables().
{ return sctpMain; };
cMessage* SCTPAssociation::getShutdownTimer | ( | ) | const [inline] |
Definition at line 601 of file SCTPAssociation.h.
{ return T2_ShutdownTimer; };
SCTPStateVariables* SCTPAssociation::getState | ( | ) | const [inline] |
Definition at line 594 of file SCTPAssociation.h.
{ return state; };
SCTPQueue* SCTPAssociation::getTransmissionQueue | ( | ) | const [inline] |
Definition at line 595 of file SCTPAssociation.h.
Referenced by SCTP::removeAssociation(), and SCTPAlgorithm::setAssociation().
{ return transmissionQ; };
void SCTPAssociation::handleChunkReportedAsAcked | ( | uint32 & | highestNewAck, | |
simtime_t & | rttEstimation, | |||
SCTPDataVariables * | myChunk, | |||
SCTPPathVariables * | sackPath | |||
) | [private] |
Definition at line 1011 of file SCTPAssociationRcvMessage.cc.
Referenced by processSackArrived().
{ SCTPPathVariables* myChunkLastPath = myChunk->getLastDestinationPath(); if ( (myChunk->numberOfTransmissions == 1) && (myChunk->hasBeenReneged == false) ) { if (myChunkLastPath == sackPath) { const simtime_t timeDifference = simTime() - myChunk->sendTime; if((timeDifference < rttEstimation) || (rttEstimation == -1.0)) { rttEstimation = timeDifference; } sctpEV3 << simTime() << " processSackArrived: computed rtt time diff == " << timeDifference << " for TSN "<< myChunk->tsn << endl; } } if ( (myChunk->hasBeenAbandoned == false) && (myChunk->hasBeenReneged == false) ) { myChunkLastPath->newlyAckedBytes += (myChunk->booksize); sctpEV3 << simTime() << ": GapAcked TSN " << myChunk->tsn << " on path " << myChunkLastPath->remoteAddress << endl; if (myChunk->tsn > highestNewAck) { highestNewAck = myChunk->tsn; } ackChunk(myChunk); if (myChunk->countsAsOutstanding) { decreaseOutstandingBytes(myChunk); } if (transmissionQ->getChunk(myChunk->tsn)) { // I.R. 02.01.07 sctpEV3 << "Found TSN " << myChunk->tsn << " in transmissionQ -> remote it" << endl; transmissionQ->removeMsg(myChunk->tsn); myChunk->enqueuedInTransmissionQ = false; CounterMap::iterator q = qCounter.roomTransQ.find(myChunk->getNextDestination()); q->second -= ADD_PADDING(myChunk->len/8+SCTP_DATA_CHUNK_LENGTH); CounterMap::iterator qb = qCounter.bookedTransQ.find(myChunk->getNextDestination()); qb->second -= myChunk->booksize; } myChunk->gapReports = 0; } }
void SCTPAssociation::handleChunkReportedAsMissing | ( | const SCTPSackChunk * | sackChunk, | |
const uint32 | highestNewAck, | |||
SCTPDataVariables * | myChunk, | |||
const SCTPPathVariables * | sackPath | |||
) | [private] |
Definition at line 1056 of file SCTPAssociationRcvMessage.cc.
Referenced by processSackArrived().
{ SCTPPathVariables* myChunkLastPath = myChunk->getLastDestinationPath(); sctpEV3 << "TSN " << myChunk->tsn << " is missing in gap reports (last " << myChunkLastPath->remoteAddress << ") "; if (!chunkHasBeenAcked(myChunk)) { sctpEV3 << "has not been acked, highestNewAck=" << highestNewAck << " countsAsOutstanding=" << myChunk->countsAsOutstanding << endl; const uint32 chunkReportedAsMissing = (highestNewAck > myChunk->tsn) ? 1 : 0; if (chunkReportedAsMissing > 0) { // T.D. 15.04.09: Increase gapReports by chunkReportedAsMissing. // Fixed bug here: gapReports += chunkReportedAsMissing instead of gapReports = chunkReportedAsMissing. /* printf("GapReports for TSN %u [ret=%d,fast=%s] at t=%s: %d --> %d by %d\n", myChunk->tsn, myChunk->numberOfRetransmissions, (myChunk->hasBeenFastRetransmitted == true) ? "YES" : "no", simTime().str().c_str(), myChunk->gapReports, myChunk->gapReports + chunkReportedAsMissing, chunkReportedAsMissing); */ myChunk->gapReports += chunkReportedAsMissing; myChunkLastPath->gapNAcksInLastSACK++; if (myChunk->gapReports >= state->numGapReports) { bool fastRtx = false; fastRtx = ((myChunk->hasBeenFastRetransmitted == false) && (myChunk->numberOfRetransmissions == 0)); if (fastRtx) { // ====== Add chunk to transmission queue ======== SCTPQueue::PayloadQueue::iterator it = transmissionQ->payloadQueue.find(myChunk->tsn); if (transmissionQ->getChunk(myChunk->tsn) == NULL) { SCTP::AssocStat* assocStat = sctpMain->getAssocStat(assocId); if(assocStat) { assocStat->numFastRtx++; } myChunk->hasBeenFastRetransmitted = true; sctpEV3 << simTime() << ": Fast RTX for TSN " << myChunk->tsn << " on path " << myChunk->getLastDestination() << endl; myChunkLastPath->numberOfFastRetransmissions++; myChunk->setNextDestination(getNextDestination(myChunk)); SCTPPathVariables* myChunkNextPath = myChunk->getNextDestinationPath(); assert(myChunkNextPath != NULL); if (myChunk->countsAsOutstanding) { decreaseOutstandingBytes(myChunk); } if (!transmissionQ->checkAndInsertChunk(myChunk->tsn, myChunk)) { sctpEV3 << "Fast RTX: cannot add message/chunk (TSN=" << myChunk->tsn << ") to the transmissionQ" << endl; } else { myChunk->enqueuedInTransmissionQ = true; CounterMap::iterator q = qCounter.roomTransQ.find(myChunk->getNextDestination()); q->second += ADD_PADDING(myChunk->len/8+SCTP_DATA_CHUNK_LENGTH); CounterMap::iterator qb = qCounter.bookedTransQ.find(myChunk->getNextDestination()); qb->second += myChunk->booksize; } myChunkNextPath->requiresRtx = true; if(myChunkNextPath->findLowestTSN == true) { // TD 08.12.09: fixed detection of lowest TSN retransmitted myChunkNextPath->lowestTSNRetransmitted = true; } } } } } else { myChunk->hasBeenFastRetransmitted = false; sctpEV3 << "TSN " << myChunk->tsn << " countsAsOutstanding=" << myChunk->countsAsOutstanding << endl; if (highestNewAck > myChunk->tsn) { myChunk->gapReports++; } myChunkLastPath->gapAcksInLastSACK++; } myChunkLastPath->findLowestTSN = false; } else { // Reneging, type 1: // A chunk in the gap blocks has been un-acked => reneg it. tsnWasReneged(myChunk, 1); } }
void SCTPAssociation::increaseOutstandingBytes | ( | SCTPDataVariables * | chunk, | |
SCTPPathVariables * | path | |||
) | [private] |
Definition at line 28 of file SCTPAssociationSendAll.cc.
Referenced by sendOnPath().
{ path->outstandingBytes += chunk->booksize; state->outstandingBytes += chunk->booksize; CounterMap::iterator iterator = qCounter.roomRetransQ.find(path->remoteAddress); iterator->second += ADD_PADDING(chunk->booksize + SCTP_DATA_CHUNK_LENGTH); }
const char * SCTPAssociation::indicationName | ( | const int32 | code | ) | [static] |
Utility: returns name of SCTP_I_xxx constants
Definition at line 107 of file SCTPAssociationUtil.cc.
Referenced by sendEstabIndicationToApp(), and sendIndicationToApp().
{ #define CASE(x) case x: s=#x+7; break const char* s = "unknown"; switch (code) { CASE(SCTP_I_DATA); CASE(SCTP_I_DATA_NOTIFICATION); CASE(SCTP_I_ESTABLISHED); CASE(SCTP_I_PEER_CLOSED); CASE(SCTP_I_CLOSED); CASE(SCTP_I_CONNECTION_REFUSED); CASE(SCTP_I_CONNECTION_RESET); CASE(SCTP_I_TIMED_OUT); CASE(SCTP_I_STATUS); CASE(SCTP_I_ABORT); CASE(SCTP_I_SHUTDOWN_RECEIVED); CASE(SCTP_I_SEND_MSG); CASE(SCTP_I_SENDQUEUE_FULL); CASE(SCTP_I_SENDQUEUE_ABATED); } return s; #undef CASE }
void SCTPAssociation::initAssociation | ( | SCTPOpenCommand * | openCmd | ) | [protected] |
Utility: creates send/receive queues and sctpAlgorithm
Definition at line 318 of file SCTPAssociationUtil.cc.
Referenced by process_ASSOCIATE(), and process_OPEN_PASSIVE().
{ sctpEV3<<"SCTPAssociationUtil:initAssociation\n"; // create send/receive queues const char *queueClass = openCmd->getQueueClass(); transmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass)); retransmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass)); outboundStreams = openCmd->getOutboundStreams(); // create algorithm const char *sctpAlgorithmClass = openCmd->getSctpAlgorithmClass(); if (!sctpAlgorithmClass || !sctpAlgorithmClass[0]) sctpAlgorithmClass = sctpMain->par("sctpAlgorithmClass"); sctpAlgorithm = check_and_cast<SCTPAlgorithm *>(createOne(sctpAlgorithmClass)); sctpAlgorithm->setAssociation(this); sctpAlgorithm->initialize(); // create state block state = sctpAlgorithm->createStateVariables(); }
void SCTPAssociation::initCCParameters | ( | SCTPPathVariables * | path | ) | [protected] |
SCTPCCFunctions
Definition at line 39 of file SCTPCCFunctions.cc.
Referenced by pmStartPathManagement().
void SCTPAssociation::initStreams | ( | uint32 | inStreams, | |
uint32 | outStreams | |||
) | [protected] |
Definition at line 37 of file SCTPSSFunctions.cc.
{ uint32 i; sctpEV3<<"initStreams instreams="<<inStreams<<" outstream="<<outStreams<<"\n"; if (receiveStreams.size()==0 && sendStreams.size()==0) { for (i=0; i<inStreams; i++) { SCTPReceiveStream* rcvStream = new SCTPReceiveStream(); this->receiveStreams[i]=rcvStream; rcvStream->setStreamId(i); this->state->numMsgsReq[i]=0; } for (i=0; i<outStreams; i++) { SCTPSendStream* sendStream = new SCTPSendStream(i); this->sendStreams[i]=sendStream; sendStream->setStreamId(i); } } }
void SCTPAssociation::loadPacket | ( | SCTPPathVariables * | pathVar, | |
SCTPMessage ** | sctpMsg, | |||
uint16 * | chunksAdded, | |||
uint16 * | dataChunksAdded, | |||
uint32 * | packetBytes, | |||
bool * | authAdded | |||
) | [private] |
Definition at line 84 of file SCTPAssociationSendAll.cc.
Referenced by sendOnPath().
{ *sctpMsg = state->sctpMsg; *chunksAdded = state->chunksAdded; *dataChunksAdded = state->dataChunksAdded; *packetBytes = state->packetBytes; sctpEV3 << "loadPacket: path=" << pathVar->remoteAddress << " osb=" << pathVar->outstandingBytes << " -> " << pathVar->outstandingBytes + state->packetBytes << endl; pathVar->outstandingBytes += state->packetBytes; qCounter.bookedSumSendStreams -= state->packetBytes; for (uint16 i = 0; i < (*sctpMsg)->getChunksArraySize(); i++) retransmissionQ->payloadQueue.find(((SCTPDataChunk*)(*sctpMsg)->getChunks(i))->getTsn())->second->countsAsOutstanding = true; }
SCTPDataVariables * SCTPAssociation::makeDataVarFromDataMsg | ( | SCTPDataMsg * | datMsg, | |
SCTPPathVariables * | path | |||
) | [private] |
Definition at line 106 of file SCTPAssociationSendAll.cc.
Referenced by sendOnPath().
{ SCTPDataVariables* datVar = new SCTPDataVariables(); datMsg->setInitialDestination(path->remoteAddress); datVar->setInitialDestination(path); datVar->bbit = datMsg->getBBit(); datVar->ebit = datMsg->getEBit(); datVar->enqueuingTime = datMsg->getEnqueuingTime(); datVar->expiryTime = datMsg->getExpiryTime(); datVar->ppid = datMsg->getPpid(); datVar->len = datMsg->getBitLength(); datVar->sid = datMsg->getSid(); datVar->allowedNoRetransmissions = datMsg->getRtx(); datVar->booksize = datMsg->getBooksize(); // ------ Stream handling --------------------------------------- SCTPSendStreamMap::iterator iterator = sendStreams.find(datMsg->getSid()); SCTPSendStream* stream = iterator->second; uint32 nextSSN = stream->getNextStreamSeqNum(); datVar->userData = datMsg->decapsulate(); if (datMsg->getOrdered()) { // ------ Ordered mode: assign SSN --------- if (datMsg->getEBit()) { datVar->ssn = nextSSN++; } else { datVar->ssn = nextSSN; } datVar->ordered = true; if (nextSSN > 65535) { stream->setNextStreamSeqNum(0); } else { stream->setNextStreamSeqNum(nextSSN); } } else { // ------ Ordered mode: no SSN needed ------ datVar->ssn = 0; datVar->ordered = false; } return(datVar); }
bool SCTPAssociation::makeRoomForTsn | ( | const uint32 | tsn, | |
const uint32 | length, | |||
const bool | uBit | |||
) | [protected] |
Definition at line 1205 of file SCTPAssociationUtil.cc.
Referenced by processDataArrived().
{ SCTPQueue* stream, dStream; uint32 sum = 0; uint32 comp = 0; bool delQ = false; uint32 high = state->highestTsnStored; sctpEV3 << "makeRoomForTsn: tsn=" << tsn << ", length=" << length << " high=" << high << endl; while ((sum < length) && (state->highestTsnReceived>state->lastTsnAck)) { comp = sum; for (SCTPReceiveStreamMap::iterator iter = receiveStreams.begin(); iter!=receiveStreams.end(); iter++) { if (tsn > high) { return false; } if (uBit) { stream = iter->second->getUnorderedQ(); } else { stream = iter->second->getOrderedQ(); } SCTPDataVariables* chunk = stream->getChunk(high); if (chunk == NULL) { //12.06.08 sctpEV3 << high << " not found in orderedQ. Try deliveryQ" << endl; stream = iter->second->getDeliveryQ(); chunk = stream->getChunk(high); delQ = true; } if (chunk != NULL) { sum+=chunk->len; if (stream->deleteMsg(high)) { sctpEV3 << high << " found and deleted" << endl; state->queuedReceivedBytes-=chunk->len/8; //12.06.08 if (ssnGt(iter->second->getExpectedStreamSeqNum(),chunk->ssn)) { iter->second->setExpectedStreamSeqNum(chunk->ssn); } } qCounter.roomSumRcvStreams -= ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH); if (high == state->highestTsnReceived) { state->highestTsnReceived--; } removeFromGapList(high); if (tsn > state->highestTsnReceived) { state->highestTsnReceived = tsn; } high--; break; } else { sctpEV3 << "TSN " << high << " not found in stream " << iter->second->getStreamId() << endl; } } if (comp == sum) { sctpEV3 << high << " not found in any stream" << endl; high--; } state->highestTsnStored = high; if (tsn > state->highestTsnReceived) { return false; } } return true; }
SCTPDataVariables * SCTPAssociation::makeVarFromMsg | ( | SCTPDataChunk * | datachunk | ) | [protected] |
Definition at line 1524 of file SCTPAssociationUtil.cc.
Referenced by processDataArrived().
{ SCTPDataVariables* chunk = new SCTPDataVariables(); chunk->bbit = dataChunk->getBBit(); chunk->ebit = dataChunk->getEBit(); chunk->sid = dataChunk->getSid(); chunk->ssn = dataChunk->getSsn(); chunk->ppid = dataChunk->getPpid(); chunk->tsn = dataChunk->getTsn(); if (!dataChunk->getUBit()) { chunk->ordered = true; } else { chunk->ordered = false; } SCTPSimpleMessage* smsg=check_and_cast<SCTPSimpleMessage*>(dataChunk->decapsulate()); chunk->userData = smsg; chunk->len = smsg->getDataLen()*8; sctpEV3 << "makeVarFromMsg: queuedBytes has been increased to " << state->queuedReceivedBytes << endl; return chunk; }
void SCTPAssociation::moveChunkToOtherPath | ( | SCTPDataVariables * | chunk, | |
SCTPPathVariables * | newPath | |||
) | [private] |
Definition at line 1687 of file SCTPAssociationRcvMessage.cc.
Referenced by process_TIMEOUT_RTX().
{ // ====== Prepare next destination ======================================= SCTPPathVariables* lastPath = chunk->getLastDestinationPath(); chunk->hasBeenFastRetransmitted = false; chunk->gapReports = 0; chunk->setNextDestination(newPath); sctpEV3 << simTime() << ": Timer-Based RTX for TSN " << chunk->tsn << ": lastDestination=" << chunk->getLastDestination() << " nextDestination=" << chunk->getNextDestination() << endl; // ======= Remove chunk's booksize from outstanding bytes ================ // T.D. 12.02.2010: This case may happen when using sender queue control! if(chunk->countsAsOutstanding) { assert(lastPath->outstandingBytes >= chunk->booksize); lastPath->outstandingBytes -= chunk->booksize; assert((int32)lastPath->outstandingBytes >= 0); state->outstandingBytes -= chunk->booksize; assert((int64)state->outstandingBytes >= 0); chunk->countsAsOutstanding = false; // T.D. 12.02.2010: No Timer-Based RTX is necessary any more when there // are no outstanding bytes! if(lastPath->outstandingBytes == 0) { stopTimer(lastPath->T3_RtxTimer); } } // ====== Perform bookkeeping ============================================ // Check, if chunk_ptr->tsn is already in transmission queue. // This can happen in case multiple timeouts occur in succession. if (!transmissionQ->checkAndInsertChunk(chunk->tsn, chunk)) { sctpEV3 << "TSN " << chunk->tsn << " already in transmissionQ" << endl; return; } else { chunk->enqueuedInTransmissionQ = true; sctpEV3 << "Inserting TSN " << chunk->tsn << " into transmissionQ" << endl; CounterMap::iterator q = qCounter.roomTransQ.find(chunk->getNextDestination()); q->second += ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH); CounterMap::iterator qb = qCounter.bookedTransQ.find(chunk->getNextDestination()); qb->second += chunk->booksize; if (chunk->countsAsOutstanding) { decreaseOutstandingBytes(chunk); } state->peerRwnd += (chunk->booksize); } if (state->peerRwnd > state->initialPeerRwnd) { state->peerRwnd = state->initialPeerRwnd; } sctpEV3 << "T3 Timeout: Chunk (TSN=" << chunk->tsn << ") has been requeued in transmissionQ, rwnd was set to " << state->peerRwnd << endl; }
bool SCTPAssociation::nextChunkFitsIntoPacket | ( | int32 | bytes | ) | [protected] |
Definition at line 1825 of file SCTPAssociationUtil.cc.
Referenced by sendOnPath().
{ int32 nextStream = -1; SCTPSendStream* stream; /* Only change stream if we don't have to finish a fragmented message */ if (state->lastMsgWasFragment) nextStream = state->lastStreamScheduled; else nextStream = (this->*ssFunctions.ssGetNextSid)(true); if (nextStream == -1) return false; stream = sendStreams.find(nextStream)->second; if (stream) { cQueue* streamQ = NULL; if (!stream->getUnorderedStreamQ()->empty()) streamQ = stream->getUnorderedStreamQ(); else if (!stream->getStreamQ()->empty()) streamQ = stream->getStreamQ(); if (streamQ) { int32 b=ADD_PADDING( (check_and_cast<SCTPSimpleMessage*>(((SCTPDataMsg*)streamQ->front())->getEncapsulatedMsg())->getByteLength()+SCTP_DATA_CHUNK_LENGTH)); /* Check if next message would be fragmented */ if (b > (int32) state->assocPmtu - IP_HEADER_LENGTH - SCTP_COMMON_HEADER) { /* Test if fragment fits */ if (bytes >= (int32) state->assocPmtu - IP_HEADER_LENGTH - SCTP_COMMON_HEADER - SCTP_DATA_CHUNK_LENGTH) return true; else return false; } /* Message doesn't need to be fragmented, just try if it fits */ if (b <= bytes) return true; else return false; } } return false; }
int32 SCTPAssociation::numUsableStreams | ( | void | ) | [protected] |
Definition at line 106 of file SCTPSSFunctions.cc.
{ int32 count=0; for (SCTPSendStreamMap::iterator iter=sendStreams.begin(); iter!=sendStreams.end(); iter++) if (iter->second->getStreamQ()->length()>0 || iter->second->getUnorderedStreamQ()->length()>0) { count++; } return count; }
void SCTPAssociation::pathStatusIndication | ( | const SCTPPathVariables * | path, | |
const bool | status | |||
) | [protected] |
Definition at line 2020 of file SCTPAssociationUtil.cc.
Referenced by pmClearPathCounter(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_RTX(), and updateCounters().
{ cPacket* msg = new cPacket("StatusInfo"); msg->setKind(SCTP_I_STATUS); SCTPStatusInfo* cmd = new SCTPStatusInfo(); cmd->setPathId(path->remoteAddress); cmd->setAssocId(assocId); cmd->setActive(status); msg->setControlInfo(cmd); if (!status) { SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId); iter->second.numPathFailures++; } sendToApp(msg); }
SCTPDataVariables * SCTPAssociation::peekAbandonedChunk | ( | const SCTPPathVariables * | path | ) | [protected] |
Definition at line 1591 of file SCTPAssociationUtil.cc.
{ // Are there chunks in the retransmission queue? If Yes -> dequeue and return it. if (!retransmissionQ->payloadQueue.empty()) { for(SCTPQueue::PayloadQueue::iterator it = retransmissionQ->payloadQueue.begin(); it != retransmissionQ->payloadQueue.end(); it++) { SCTPDataVariables* chunk = it->second; sctpEV3<<"peek Chunk "<<chunk->tsn<<"\n"; if (chunk->getLastDestinationPath() == path && chunk->hasBeenAbandoned) { sctpEV3<<"peekAbandonedChunk() found chunk in the retransmission queue\n"; return chunk; } } } return NULL; }
SCTPDataMsg * SCTPAssociation::peekOutboundDataMsg | ( | ) | [protected] |
Definition at line 1610 of file SCTPAssociationUtil.cc.
Referenced by calculateBytesToSendOnPath().
{ SCTPDataMsg* datMsg=NULL; int32 nextStream = -1; nextStream = (this->*ssFunctions.ssGetNextSid)(true); if (nextStream == -1) { sctpEV3<<"peekOutboundDataMsg(): no valid stream found -> returning NULL !\n"; return NULL; } for (SCTPSendStreamMap::iterator iter=sendStreams.begin(); iter!=sendStreams.end(); ++iter) { if ((int32)iter->first==nextStream) { SCTPSendStream* stream=iter->second; if (!stream->getUnorderedStreamQ()->empty()) { return (datMsg); } if (!stream->getStreamQ()->empty()) { return (datMsg); } } } return NULL; }
bool SCTPAssociation::performStateTransition | ( | const SCTPEventCode & | event | ) | [protected] |
Implemements the pure SCTP state machine
Definition at line 538 of file SCTPAssociationBase.cc.
Referenced by process_RCV_Message(), processAppCommand(), processCookieAckArrived(), processCookieEchoArrived(), processInitAckArrived(), processInitArrived(), processTimer(), pushUlp(), sendShutdown(), and sendShutdownAck().
{ sctpEV3<<"performStateTransition\n"; if (event==SCTP_E_IGNORE) // e.g. discarded segment { ev << "Staying in state: " << stateName(fsm->getState()) << " (no FSM event)\n"; return true; } // state machine int32 oldState = fsm->getState(); switch (fsm->getState()) { case SCTP_S_CLOSED: switch (event) { case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_OPEN_PASSIVE: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_ASSOCIATE: FSM_Goto((*fsm), SCTP_S_COOKIE_WAIT); break; case SCTP_E_RCV_INIT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_RCV_VALID_COOKIE_ECHO: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break; case SCTP_E_CLOSE: FSM_Goto((*fsm), SCTP_S_CLOSED); break; default:; } break; case SCTP_S_COOKIE_WAIT: switch (event) { case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_RCV_INIT_ACK: FSM_Goto((*fsm), SCTP_S_COOKIE_ECHOED); break; case SCTP_E_RCV_VALID_COOKIE_ECHO: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break; default:; } break; case SCTP_S_COOKIE_ECHOED: switch (event) { case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_RCV_COOKIE_ACK:FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break; default:; } break; case SCTP_S_ESTABLISHED: switch (event) { case SCTP_E_SEND: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break; case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_PENDING); break; case SCTP_E_STOP_SENDING: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_PENDING); state->stopSending = true; state->lastTSN = state->nextTSN-1; break; //I.R. case SCTP_E_RCV_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_RECEIVED); break; case SCTP_E_CLOSE: FSM_Goto((*fsm), SCTP_S_CLOSED); break; default:; } break; case SCTP_S_SHUTDOWN_PENDING: switch (event) { case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_NO_MORE_OUTSTANDING: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_SENT); break; case SCTP_E_RCV_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_RECEIVED); break; case SCTP_E_RCV_SHUTDOWN_ACK: FSM_Goto((*fsm), SCTP_S_CLOSED); break; default:; } break; case SCTP_S_SHUTDOWN_RECEIVED: switch (event) { case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_NO_MORE_OUTSTANDING: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT); break; case SCTP_E_SHUTDOWN: sendShutdownAck(remoteAddr); /*FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT);*/ break; default:; } break; case SCTP_S_SHUTDOWN_SENT: switch (event) { case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_RCV_SHUTDOWN_ACK: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_RCV_SHUTDOWN: sendShutdownAck(remoteAddr); FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT); break; default:; } break; case SCTP_S_SHUTDOWN_ACK_SENT: switch (event) { case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break; case SCTP_E_RCV_SHUTDOWN_COMPLETE: FSM_Goto((*fsm), SCTP_S_CLOSED); break; default:; } break; } if (oldState!=fsm->getState()) { ev << "Transition: " << stateName(oldState) << " --> " << stateName(fsm->getState()) << " (event was: " << eventName(event) << ")\n"; sctpEV3 << sctpMain->getName() << ": " << stateName(oldState) << " --> " << stateName(fsm->getState()) << " (on " << eventName(event) << ")\n"; stateEntered(fsm->getState()); } else { ev<< "Staying in state: " << stateName(fsm->getState()) << " (event was: " << eventName(event) << ")\n"; } if (event==SCTP_E_ABORT && oldState==fsm->getState() && fsm->getState()==SCTP_S_CLOSED) return true; if (oldState!=fsm->getState() && fsm->getState()==SCTP_S_CLOSED) { sctpEV3<<"return false because oldState="<<oldState<<" and new state is closed\n"; return false; } else return true; }
void SCTPAssociation::pmClearPathCounter | ( | SCTPPathVariables * | path | ) | [protected] |
Definition at line 2009 of file SCTPAssociationUtil.cc.
Referenced by processHeartbeatAckArrived(), and processSackArrived().
{ path->pathErrorCount = 0; if (path->activePath == false) { /* notify the application */ pathStatusIndication(path, true); sctpEV3 << "Path " << path->remoteAddress << " state changes from INACTIVE to ACTIVE !!!" << endl; } }
void SCTPAssociation::pmDataIsSentOn | ( | SCTPPathVariables * | path | ) | [protected] |
Definition at line 1932 of file SCTPAssociationUtil.cc.
Referenced by sendOnPath().
{ /* restart hb_timer on this path */ stopTimer(path->HeartbeatTimer); if (state->enableHeartbeats) { path->heartbeatTimeout = path->pathRto + (double)sctpMain->par("hbInterval"); startTimer(path->HeartbeatTimer, path->heartbeatTimeout); sctpEV3 << "Restarting HB timer on path "<< path->remoteAddress << " to expire at time " << path->heartbeatTimeout << endl; } path->cwndTimeout = path->pathRto; stopTimer(path->CwndTimer); startTimer(path->CwndTimer, path->cwndTimeout); sctpEV3 << "Restarting CWND timer on path "<< path->remoteAddress << " to expire at time " << path->cwndTimeout << endl; }
void SCTPAssociation::pmRttMeasurement | ( | SCTPPathVariables * | path, | |
const simtime_t & | rttEstimation | |||
) | [protected] |
Definition at line 2037 of file SCTPAssociationUtil.cc.
Referenced by processHeartbeatAckArrived(), and processSackArrived().
{ if (rttEstimation < MAXTIME) { if (simTime() > path->updateTime) { if (path->updateTime == SIMTIME_ZERO) { path->rttvar = rttEstimation.dbl() / 2; path->srtt = rttEstimation; path->pathRto = 3.0 * rttEstimation.dbl(); path->pathRto = max(min(path->pathRto.dbl(), (double)sctpMain->par("rtoMax")), (double)sctpMain->par("rtoMin")); } else { path->rttvar = (1.0 - (double)sctpMain->par("rtoBeta")) * path->rttvar.dbl() + (double)sctpMain->par("rtoBeta") * fabs(path->srtt.dbl() - rttEstimation.dbl()); path->srtt = (1.0 - (double)sctpMain->par("rtoAlpha")) * path->srtt.dbl() + (double)sctpMain->par("rtoAlpha") * rttEstimation.dbl(); path->pathRto = path->srtt.dbl() + 4.0 * path->rttvar.dbl(); path->pathRto = max(min(path->pathRto.dbl(), (double)sctpMain->par("rtoMax")), (double)sctpMain->par("rtoMin")); } /* std::cout << simTime() << ": Updating timer values for path " << path->remoteAddress << ":" << " RTO=" << path->pathRto << " rttEstimation=" << rttEstimation << " SRTT=" << path->srtt << " --> RTTVAR=" << path->rttvar << endl; */ // RFC 2960, sect. 6.3.1: new RTT measurements SHOULD be made no more // than once per round-trip. path->updateTime = simTime() + path->srtt; path->statisticsPathRTO->record(path->pathRto); path->statisticsPathRTT->record(rttEstimation); } } }
void SCTPAssociation::pmStartPathManagement | ( | ) | [protected] |
Flow control
Definition at line 1952 of file SCTPAssociationUtil.cc.
Referenced by stateEntered().
{ RoutingTableAccess routingTableAccess; SCTPPathVariables* path; int32 i=0; /* populate path structures !!! */ /* set a high start value...this is appropriately decreased later (below) */ state->assocPmtu = state->localRwnd; for(SCTPPathMap::iterator piter=sctpPathMap.begin(); piter!=sctpPathMap.end(); piter++) { path=piter->second; path->pathErrorCount = 0; InterfaceEntry *rtie = routingTableAccess.get()->getInterfaceForDestAddr(path->remoteAddress.get4()); path->pmtu = rtie->getMTU(); sctpEV3 << "Path MTU of Interface "<< i << " = " << path->pmtu <<"\n"; if (path->pmtu < state->assocPmtu) { state->assocPmtu = path->pmtu; } initCCParameters(path); path->pathRto = (double)sctpMain->par("rtoInitial"); path->srtt = path->pathRto; path->rttvar = SIMTIME_ZERO; /* from now on we may have one update per RTO/SRTT */ path->updateTime = SIMTIME_ZERO; path->partialBytesAcked = 0; path->outstandingBytes = 0; path->activePath = true; // Timer probably not running, but stop it anyway I.R. stopTimer(path->T3_RtxTimer); if (path->remoteAddress == state->initialPrimaryPath && !path->confirmed) { path->confirmed = true; } sctpEV3<<getFullPath()<<" numberOfLocalAddresses="<<state->localAddresses.size()<<"\n"; path->heartbeatTimeout= (double)sctpMain->par("hbInterval")+i*path->pathRto; stopTimer(path->HeartbeatTimer); sendHeartbeat(path); startTimer(path->HeartbeatTimer, path->heartbeatTimeout); startTimer(path->HeartbeatIntervalTimer, path->heartbeatIntervalTimeout); path->statisticsPathRTO->record(path->pathRto); i++; } }
SCTPEventCode SCTPAssociation::preanalyseAppCommandEvent | ( | int32 | commandCode | ) | [protected] |
Maps app command codes (msg kind of app command msgs) to SCTP_E_xxx event codes
Definition at line 472 of file SCTPAssociationBase.cc.
Referenced by processAppCommand().
{ switch (commandCode) { case SCTP_C_ASSOCIATE: return SCTP_E_ASSOCIATE; case SCTP_C_OPEN_PASSIVE: return SCTP_E_OPEN_PASSIVE; case SCTP_C_SEND: return SCTP_E_SEND; case SCTP_C_CLOSE: return SCTP_E_CLOSE; case SCTP_C_ABORT: return SCTP_E_ABORT; case SCTP_C_RECEIVE: return SCTP_E_RECEIVE; case SCTP_C_SEND_UNORDERED: return SCTP_E_SEND; case SCTP_C_SEND_ORDERED: return SCTP_E_SEND; case SCTP_C_PRIMARY: return SCTP_E_PRIMARY; case SCTP_C_QUEUE_MSGS_LIMIT: return SCTP_E_QUEUE_MSGS_LIMIT; case SCTP_C_QUEUE_BYTES_LIMIT: return SCTP_E_QUEUE_BYTES_LIMIT; case SCTP_C_SHUTDOWN: return SCTP_E_SHUTDOWN; case SCTP_C_NO_OUTSTANDING: return SCTP_E_SEND_SHUTDOWN_ACK; default: sctpEV3<<"commandCode="<<commandCode<<"\n"; opp_error("Unknown message kind in app command"); return (SCTPEventCode)0; // to satisfy compiler } }
void SCTPAssociation::printConnBrief | ( | ) | [protected] |
Utility: prints local/remote addr/port and app gate index/assocId
Definition at line 151 of file SCTPAssociationUtil.cc.
Referenced by processAppCommand(), and processSCTPMessage().
{ sctpEV3 << "Connection " << this << " "; sctpEV3 << localAddr << ":" << localPort << " to " << remoteAddr << ":" << remotePort; sctpEV3 << " on app[" << appGateIndex << "],assocId=" << assocId; sctpEV3 << " in " << stateName(fsm->getState()) << "\n"; }
void SCTPAssociation::printOutstandingTsns | ( | ) | [protected] |
void SCTPAssociation::printSctpPathMap | ( | ) | const |
Definition at line 40 of file SCTPAssociationUtil.cc.
Referenced by processInitAckArrived(), processInitArrived(), sendInit(), and sendInitAck().
{ sctpEV3 <<"SCTP PathMap:" << endl; for (SCTPPathMap::const_iterator iterator = sctpPathMap.begin(); iterator != sctpPathMap.end(); ++iterator) { const SCTPPathVariables* path = iterator->second; sctpEV3 << " - " << path->remoteAddress << ": osb=" << path->outstandingBytes << " cwnd=" << path->cwnd << endl; } }
void SCTPAssociation::printSegmentBrief | ( | SCTPMessage * | sctpmsg | ) | [static, protected] |
Utility: prints important header fields
Definition at line 159 of file SCTPAssociationUtil.cc.
void SCTPAssociation::process_ABORT | ( | SCTPEventCode & | event | ) | [protected] |
Definition at line 265 of file SCTPAssociationEventProc.cc.
Referenced by processAppCommand().
{ sctpEV3 << "SCTPAssociationEventProc:process_ABORT; assoc=" << assocId << endl; switch(fsm->getState()) { case SCTP_S_ESTABLISHED: sendOnAllPaths(state->getPrimaryPath()); sendAbort(); break; } }
void SCTPAssociation::process_ASSOCIATE | ( | SCTPEventCode & | event, | |
SCTPCommand * | sctpCommand, | |||
cPacket * | msg | |||
) | [protected] |
Definition at line 31 of file SCTPAssociationEventProc.cc.
Referenced by processAppCommand().
{ IPvXAddress lAddr, rAddr; SCTPOpenCommand *openCmd = check_and_cast<SCTPOpenCommand *>(sctpCommand); ev<<"SCTPAssociationEventProc:process_ASSOCIATE\n"; switch(fsm->getState()) { case SCTP_S_CLOSED: initAssociation(openCmd); state->active = true; localAddressList = openCmd->getLocalAddresses(); lAddr = openCmd->getLocalAddresses().front(); if (!(openCmd->getRemoteAddresses().empty())) { remoteAddressList = openCmd->getRemoteAddresses(); rAddr = openCmd->getRemoteAddresses().front(); } else rAddr = openCmd->getRemoteAddr(); localPort = openCmd->getLocalPort(); remotePort = openCmd->getRemotePort(); state->numRequests = openCmd->getNumRequests(); if (rAddr.isUnspecified() || remotePort==0) opp_error("Error processing command OPEN_ACTIVE: remote address and port must be specified"); if (localPort==0) { localPort = sctpMain->getEphemeralPort(); } ev << "OPEN: " << lAddr << ":" << localPort << " --> " << rAddr << ":" << remotePort << "\n"; sctpMain->updateSockPair(this, lAddr, rAddr, localPort, remotePort); state->localRwnd = (long)sctpMain->par("arwnd"); sendInit(); startTimer(T1_InitTimer,state->initRexmitTimeout); break; default: opp_error("Error processing command OPEN_ACTIVE: connection already exists"); } }
void SCTPAssociation::process_CLOSE | ( | SCTPEventCode & | event | ) | [protected] |
Definition at line 249 of file SCTPAssociationEventProc.cc.
Referenced by processAppCommand().
{ sctpEV3 << "SCTPAssociationEventProc:process_CLOSE; assoc=" << assocId << endl; switch(fsm->getState()) { case SCTP_S_ESTABLISHED: sendOnAllPaths(state->getPrimaryPath()); sendShutdown(); break; case SCTP_S_SHUTDOWN_RECEIVED: if (getOutstandingBytes() == 0) { sendShutdownAck(remoteAddr); } break; } }
void SCTPAssociation::process_OPEN_PASSIVE | ( | SCTPEventCode & | event, | |
SCTPCommand * | sctpCommand, | |||
cPacket * | msg | |||
) | [protected] |
Definition at line 77 of file SCTPAssociationEventProc.cc.
Referenced by processAppCommand().
{ IPvXAddress lAddr; int16 localPort; SCTPOpenCommand *openCmd = check_and_cast<SCTPOpenCommand *>(sctpCommand); sctpEV3<<"SCTPAssociationEventProc:process_OPEN_PASSIVE\n"; switch(fsm->getState()) { case SCTP_S_CLOSED: initAssociation(openCmd); state->fork = openCmd->getFork(); localAddressList = openCmd->getLocalAddresses(); sctpEV3<<"process_OPEN_PASSIVE: number of local addresses="<<localAddressList.size()<<"\n"; lAddr = openCmd->getLocalAddresses().front(); localPort = openCmd->getLocalPort(); inboundStreams = openCmd->getInboundStreams(); outboundStreams = openCmd->getOutboundStreams(); state->localRwnd = (long)sctpMain->par("arwnd"); state->numRequests = openCmd->getNumRequests(); state->messagesToPush = openCmd->getMessagesToPush(); if (localPort==0) opp_error("Error processing command OPEN_PASSIVE: local port must be specified"); sctpEV3 << "Assoc "<<assocId<<"::Starting to listen on: " << lAddr << ":" << localPort << "\n"; sctpMain->updateSockPair(this, lAddr, IPvXAddress(), localPort, 0); break; default: opp_error("Error processing command OPEN_PASSIVE: connection already exists"); } }
void SCTPAssociation::process_PRIMARY | ( | SCTPEventCode & | event, | |
SCTPCommand * | sctpCommand | |||
) | [protected] |
Definition at line 229 of file SCTPAssociationEventProc.cc.
Referenced by processAppCommand().
{ SCTPPathInfo *pinfo = check_and_cast<SCTPPathInfo *>(sctpCommand); state->setPrimaryPath(getPath(pinfo->getRemoteAddress())); }
void SCTPAssociation::process_QUEUE_BYTES_LIMIT | ( | const SCTPCommand * | sctpCommand | ) | [protected] |
Definition at line 243 of file SCTPAssociationEventProc.cc.
Referenced by processAppCommand().
{ const SCTPInfo* qinfo = check_and_cast<const SCTPInfo*>(sctpCommand); state->sendQueueLimit = qinfo->getText(); }
void SCTPAssociation::process_QUEUE_MSGS_LIMIT | ( | const SCTPCommand * | sctpCommand | ) | [protected] |
Queue Management
Definition at line 236 of file SCTPAssociationEventProc.cc.
Referenced by processAppCommand().
{ const SCTPInfo* qinfo = check_and_cast<const SCTPInfo*>(sctpCommand); state->queueLimit = qinfo->getText(); sctpEV3<<"state->queueLimit set to "<<state->queueLimit<<"\n"; }
bool SCTPAssociation::process_RCV_Message | ( | SCTPMessage * | sctpseg, | |
const IPvXAddress & | src, | |||
const IPvXAddress & | dest | |||
) | [protected] |
Definition at line 49 of file SCTPAssociationRcvMessage.cc.
Referenced by processSCTPMessage().
{ // ====== Header checks ================================================== sctpEV3 << getFullPath() << " SCTPAssociationRcvMessage:process_RCV_Message" << " localAddr=" << localAddr << " remoteAddr=" << remoteAddr << endl; if ((sctpmsg->hasBitError() || !sctpmsg->getChecksumOk())) { if (((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType() == INIT_ACK) { stopTimer(T1_InitTimer); sctpEV3 << "InitAck with bit-error. Retransmit Init" << endl; retransmitInit(); startTimer(T1_InitTimer,state->initRexmitTimeout); } if (((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType() == COOKIE_ACK) { stopTimer(T1_InitTimer); sctpEV3 << "CookieAck with bit-error. Retransmit CookieEcho" << endl; retransmitCookieEcho(); startTimer(T1_InitTimer,state->initRexmitTimeout); } } SCTPPathVariables* path = getPath(src); const uint16 srcPort = sctpmsg->getDestPort(); const uint16 destPort = sctpmsg->getSrcPort(); const uint32 numberOfChunks = sctpmsg->getChunksArraySize(); sctpEV3 << "numberOfChunks=" <<numberOfChunks << endl; state->sctpmsg = (SCTPMessage*)sctpmsg->dup(); // ====== Handle chunks ================================================== bool trans = true; bool sendAllowed = false; bool dupReceived = false; bool dataChunkReceived = false; bool dataChunkDelivered = false; bool shutdownCalled = false; for (uint32 i = 0; i < numberOfChunks; i++) { const SCTPChunk* header = (const SCTPChunk*)(sctpmsg->removeChunk()); const uint8 type = header->getChunkType(); if ((type != INIT) && (type != ABORT) && (type != ERRORTYPE) && (sctpmsg->getTag() != peerVTag)) { sctpEV3 << " VTag "<< sctpmsg->getTag() << " incorrect. Should be " << peerVTag << " localVTag=" << localVTag << endl; return true; } switch (type) { case INIT: sctpEV3 << "SCTPAssociationRcvMessage: INIT received" << endl; SCTPInitChunk* initChunk; initChunk = check_and_cast<SCTPInitChunk*>(header); if ((initChunk->getNoInStreams() != 0) && (initChunk->getNoOutStreams() != 0) && (initChunk->getInitTag() != 0)) { trans = processInitArrived(initChunk, srcPort, destPort); } i = numberOfChunks-1; delete initChunk; break; case INIT_ACK: sctpEV3 << "SCTPAssociationRcvMessage: INIT_ACK received" << endl; if (fsm->getState() == SCTP_S_COOKIE_WAIT) { SCTPInitAckChunk* initAckChunk; initAckChunk = check_and_cast<SCTPInitAckChunk*>(header); if ((initAckChunk->getNoInStreams() != 0) && (initAckChunk->getNoOutStreams() != 0) && (initAckChunk->getInitTag() != 0)) { trans = processInitAckArrived(initAckChunk); } else if (initAckChunk->getInitTag() == 0) { sendAbort(); sctpMain->removeAssociation(this); } i = numberOfChunks-1; delete initAckChunk; } else { sctpEV3 << "INIT_ACK will be ignored" << endl; } break; case COOKIE_ECHO: sctpEV3 << "SCTPAssociationRcvMessage: COOKIE_ECHO received" << endl; SCTPCookieEchoChunk* cookieEchoChunk; cookieEchoChunk = check_and_cast<SCTPCookieEchoChunk*>(header); trans = processCookieEchoArrived(cookieEchoChunk,src); delete cookieEchoChunk; break; case COOKIE_ACK: sctpEV3 << "SCTPAssociationRcvMessage: COOKIE_ACK received" << endl; if (fsm->getState() == SCTP_S_COOKIE_ECHOED) { SCTPCookieAckChunk* cookieAckChunk; cookieAckChunk = check_and_cast<SCTPCookieAckChunk*>(header); trans = processCookieAckArrived(); delete cookieAckChunk; } break; case DATA: sctpEV3 << "SCTPAssociationRcvMessage: DATA received" << endl; if (fsm->getState() == SCTP_S_COOKIE_ECHOED) { trans = performStateTransition(SCTP_E_RCV_COOKIE_ACK); } if (!(fsm->getState() == SCTP_S_SHUTDOWN_RECEIVED || fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)) { SCTPDataChunk* dataChunk; dataChunk = check_and_cast<SCTPDataChunk*>(header); if ((dataChunk->getByteLength()- 16) > 0) { const SCTPEventCode event = processDataArrived(dataChunk); if (event == SCTP_E_DELIVERED) { dataChunkReceived = true; dataChunkDelivered = true; state->sackAllowed = true; } else if (event==SCTP_E_SEND || event==SCTP_E_IGNORE) { dataChunkReceived = true; state->sackAllowed = true; } else if (event==SCTP_E_DUP_RECEIVED) { dupReceived = true; } } else { sendAbort(); sctpMain->removeAssociation(this); } delete dataChunk; } trans = true; break; case SACK: { sctpEV3 << "SCTPAssociationRcvMessage: SACK received" << endl; const int32 scount = qCounter.roomSumSendStreams; SCTPSackChunk* sackChunk; sackChunk = check_and_cast<SCTPSackChunk*>(header); processSackArrived(sackChunk); trans = true; sendAllowed = true; delete sackChunk; if (getOutstandingBytes()==0 && transmissionQ->getQueueSize()==0 && scount==0) { if (fsm->getState() == SCTP_S_SHUTDOWN_PENDING) { sctpEV3 << "No more packets: send SHUTDOWN" << endl; sendShutdown(); trans = performStateTransition(SCTP_E_NO_MORE_OUTSTANDING); shutdownCalled = true; } else if (fsm->getState() == SCTP_S_SHUTDOWN_RECEIVED) { sctpEV3 << "No more outstanding" << endl; sendShutdownAck(remoteAddr); } } break; } case ABORT: SCTPAbortChunk* abortChunk; abortChunk = check_and_cast<SCTPAbortChunk*>(header); sctpEV3 << "SCTPAssociationRcvMessage: ABORT with T-Bit " << abortChunk->getT_Bit() << " received" << endl; if (sctpmsg->getTag() == localVTag || sctpmsg->getTag() == peerVTag) { sendIndicationToApp(SCTP_I_ABORT); trans = performStateTransition(SCTP_E_ABORT); } delete abortChunk; break; case HEARTBEAT: sctpEV3 << "SCTPAssociationRcvMessage: HEARTBEAT received" << endl; SCTPHeartbeatChunk* heartbeatChunk; heartbeatChunk = check_and_cast<SCTPHeartbeatChunk*>(header); if (!(fsm->getState() == SCTP_S_CLOSED)) { sendHeartbeatAck(heartbeatChunk, dest, src); } trans = true; delete heartbeatChunk; if (path) { path->numberOfHeartbeatsRcvd++; path->pathRcvdHb->record(path->numberOfHeartbeatsRcvd); } break; case HEARTBEAT_ACK: sctpEV3 << "SCTPAssociationRcvMessage: HEARTBEAT_ACK received" << endl; if (fsm->getState() == SCTP_S_COOKIE_ECHOED) { trans = performStateTransition(SCTP_E_RCV_COOKIE_ACK); } SCTPHeartbeatAckChunk* heartbeatAckChunk; heartbeatAckChunk = check_and_cast<SCTPHeartbeatAckChunk*>(header); if (path) { processHeartbeatAckArrived(heartbeatAckChunk, path); } trans = true; delete heartbeatAckChunk; break; case SHUTDOWN: sctpEV3 << "SCTPAssociationRcvMessage: SHUTDOWN received" << endl; SCTPShutdownChunk* shutdownChunk; shutdownChunk = check_and_cast<SCTPShutdownChunk*>(header); if (shutdownChunk->getCumTsnAck()>state->lastTsnAck) { simtime_t rttEstimation = MAXTIME; dequeueAckedChunks(shutdownChunk->getCumTsnAck(), getPath(remoteAddr), rttEstimation); state->lastTsnAck = shutdownChunk->getCumTsnAck(); } trans = performStateTransition(SCTP_E_RCV_SHUTDOWN); sendIndicationToApp(SCTP_I_SHUTDOWN_RECEIVED); trans = true; delete shutdownChunk; break; case SHUTDOWN_ACK: sctpEV3 << "SCTPAssociationRcvMessage: SHUTDOWN_ACK received" << endl; if (fsm->getState()!=SCTP_S_ESTABLISHED) { SCTPShutdownAckChunk* shutdownAckChunk; shutdownAckChunk = check_and_cast<SCTPShutdownAckChunk*>(header); sendShutdownComplete(); stopTimers(); stopTimer(T2_ShutdownTimer); stopTimer(T5_ShutdownGuardTimer); sctpEV3 << "state=" << stateName(fsm->getState()) << endl; if ((fsm->getState() == SCTP_S_SHUTDOWN_SENT) || (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)) { trans = performStateTransition(SCTP_E_RCV_SHUTDOWN_ACK); sendIndicationToApp(SCTP_I_CLOSED); delete state->shutdownChunk; } delete shutdownAckChunk; } break; case SHUTDOWN_COMPLETE: sctpEV3<<"Shutdown Complete arrived" << endl; SCTPShutdownCompleteChunk* shutdownCompleteChunk; shutdownCompleteChunk = check_and_cast<SCTPShutdownCompleteChunk*>(header); trans = performStateTransition(SCTP_E_RCV_SHUTDOWN_COMPLETE); sendIndicationToApp(SCTP_I_PEER_CLOSED); // necessary for NAT-Rendezvous if (trans == true) { stopTimers(); } stopTimer(T2_ShutdownTimer); stopTimer(T5_ShutdownGuardTimer); delete state->shutdownAckChunk; delete shutdownCompleteChunk; break; default: sctpEV3<<"different type" << endl; break; } if (i==numberOfChunks-1 && (dataChunkReceived || dupReceived)) { sendAllowed=true; sctpEV3 << "i=" << i << " sendAllowed=true; scheduleSack" << endl; scheduleSack(); if (fsm->getState() == SCTP_S_SHUTDOWN_SENT && state->ackState>=sackFrequency) { sendSack(); } } // Send any new DATA chunks, SACK chunks, HEARTBEAT chunks etc. sctpEV3 << "SCTPAssociationRcvMessage: send new data? state=" << stateName(fsm->getState()) << " sendAllowed=" << sendAllowed << " shutdownCalled=" << shutdownCalled << endl; if (((fsm->getState() == SCTP_S_ESTABLISHED) || (fsm->getState() == SCTP_S_SHUTDOWN_PENDING) || (fsm->getState() == SCTP_S_SHUTDOWN_RECEIVED)) && (sendAllowed) && (!shutdownCalled)) { sendOnAllPaths(state->getPrimaryPath()); } } // ====== Clean-up ======================================================= disposeOf(state->sctpmsg); return trans; }
void SCTPAssociation::process_RECEIVE_REQUEST | ( | SCTPEventCode & | event, | |
SCTPCommand * | sctpCommand | |||
) | [protected] |
Definition at line 218 of file SCTPAssociationEventProc.cc.
Referenced by processAppCommand().
{ SCTPSendCommand *sendCommand = check_and_cast<SCTPSendCommand *>(sctpCommand); if ((uint32)sendCommand->getSid() > inboundStreams || sendCommand->getSid() < 0) { sctpEV3<<"Application tries to read from invalid stream id....\n"; } state->numMsgsReq[sendCommand->getSid()]+= sendCommand->getNumMsgs(); pushUlp(); }
void SCTPAssociation::process_SEND | ( | SCTPEventCode & | event, | |
SCTPCommand * | sctpCommand, | |||
cPacket * | msg | |||
) | [protected] |
Definition at line 112 of file SCTPAssociationEventProc.cc.
Referenced by processAppCommand().
{ SCTPSendCommand* sendCommand = check_and_cast<SCTPSendCommand*>(sctpCommand); if(fsm->getState() != SCTP_S_ESTABLISHED) { // TD 12.03.2009: since SCTP_S_ESTABLISHED is the only case, the // switch(...)-block has been removed for enhanced readability. sctpEV3 << "process_SEND: state is not SCTP_S_ESTABLISHED -> returning" << endl; return; } sctpEV3 << "process_SEND:" << " assocId=" << assocId << " localAddr=" << localAddr << " remoteAddr=" << remoteAddr << " cmdRemoteAddr="<< sendCommand->getRemoteAddr() << " cmdPrimary=" << (sendCommand->getPrimary() ? "true" : "false") << " appGateIndex=" << appGateIndex << " streamId=" << sendCommand->getSid() << endl; SCTPSimpleMessage* smsg = check_and_cast<SCTPSimpleMessage*>((msg->decapsulate())); SCTP::AssocStatMap::iterator iter = sctpMain->assocStatMap.find(assocId); iter->second.sentBytes += smsg->getBitLength() / 8; // ------ Prepare SCTPDataMsg ----------------------------------------- const uint32 streamId = sendCommand->getSid(); const uint32 sendUnordered = sendCommand->getSendUnordered(); const uint32 ppid = sendCommand->getPpid(); SCTPSendStream* stream = NULL; SCTPSendStreamMap::iterator associter = sendStreams.find(streamId); if (associter != sendStreams.end()) { stream = associter->second; } else { opp_error("stream with id %d not found", streamId); } char name[64]; snprintf(name, sizeof(name), "SDATA-%d-%d", streamId, state->msgNum); smsg->setName(name); SCTPDataMsg* datMsg = new SCTPDataMsg(); datMsg->encapsulate(smsg); datMsg->setSid(streamId); datMsg->setPpid(ppid); datMsg->setEnqueuingTime(simulation.getSimTime()); // ------ Set initial destination address ----------------------------- if (sendCommand->getPrimary()) { if (sendCommand->getRemoteAddr() == IPvXAddress("0.0.0.0")) { datMsg->setInitialDestination(remoteAddr); } else { datMsg->setInitialDestination(sendCommand->getRemoteAddr()); } } else { datMsg->setInitialDestination(state->getPrimaryPathIndex()); } // ------ Optional padding and size calculations ---------------------- datMsg->setBooksize(smsg->getBitLength() / 8 + state->header); qCounter.roomSumSendStreams += ADD_PADDING(smsg->getBitLength() / 8 + SCTP_DATA_CHUNK_LENGTH); qCounter.bookedSumSendStreams += datMsg->getBooksize(); state->sendBuffer += smsg->getByteLength(); datMsg->setMsgNum(++state->msgNum); // ------ Ordered/Unordered modes ------------------------------------- if (sendUnordered == 1) { datMsg->setOrdered(false); stream->getUnorderedStreamQ()->insert(datMsg); } else { datMsg->setOrdered(true); stream->getStreamQ()->insert(datMsg); if ((state->appSendAllowed) && (state->sendQueueLimit > 0) && ((uint64)state->sendBuffer >= state->sendQueueLimit) ) { sendIndicationToApp(SCTP_I_SENDQUEUE_FULL); state->appSendAllowed = false; } sendQueue->record(stream->getStreamQ()->getLength()); } state->queuedMessages++; if ((state->queueLimit > 0) && (state->queuedMessages > state->queueLimit)) { state->queueUpdate = false; } sctpEV3 << "process_SEND:" << " last=" << sendCommand->getLast() <<" queueLimit=" << state->queueLimit << endl; // ------ Call sendCommandInvoked() to send message ------------------- // sendCommandInvoked() itself will call sendOnAllPaths() ... if (sendCommand->getLast() == true) { if (sendCommand->getPrimary()) { sctpAlgorithm->sendCommandInvoked(NULL); } else { sctpAlgorithm->sendCommandInvoked(getPath(datMsg->getInitialDestination())); } } }
void SCTPAssociation::process_STATUS | ( | SCTPEventCode & | event, | |
SCTPCommand * | sctpCommand, | |||
cPacket * | msg | |||
) | [protected] |
Definition at line 276 of file SCTPAssociationEventProc.cc.
{ SCTPStatusInfo *statusInfo = new SCTPStatusInfo(); statusInfo->setState(fsm->getState()); statusInfo->setStateName(stateName(fsm->getState())); statusInfo->setPathId(remoteAddr); statusInfo->setActive(getPath(remoteAddr)->activePath); msg->setControlInfo(statusInfo); sendToApp(msg); }
void SCTPAssociation::process_TIMEOUT_HEARTBEAT | ( | SCTPPathVariables * | path | ) | [protected] |
Definition at line 1464 of file SCTPAssociationRcvMessage.cc.
Referenced by processTimer().
{ bool oldState; /* check if error counters must be increased */ if (path->activePath) { state->errorCount++; path->pathErrorCount++; sctpEV3<<"HB timeout timer expired for path "<<path->remoteAddress<<" --> Increase Error Counters (Assoc: "<<state->errorCount<<", Path: "<<path->pathErrorCount<<")\n"; } /* RTO must be doubled for this path ! */ path->pathRto = (simtime_t)min(2 * path->pathRto.dbl(), sctpMain->par("rtoMax")); path->statisticsPathRTO->record(path->pathRto); /* check if any thresholds are exceeded, and if so, check if ULP must be notified */ if (state->errorCount > (uint32)sctpMain->par("assocMaxRetrans")) { sendIndicationToApp(SCTP_I_CONN_LOST); sendAbort(); sctpMain->removeAssociation(this); return; } else { /* set path state to INACTIVE, if the path error counter is exceeded */ if (path->pathErrorCount > (uint32)sctpMain->par("pathMaxRetrans")) { oldState = path->activePath; path->activePath = false; if (path == state->getPrimaryPath()) { state->setPrimaryPath(getNextPath(path)); } sctpEV3 << "pathErrorCount now "<< path->pathErrorCount << "; PP now " << state->getPrimaryPathIndex() << endl; } /* then: we can check, if all paths are INACTIVE ! */ if (allPathsInactive()) { sctpEV3<<"sctp_do_hb_to_timer() : ALL PATHS INACTIVE --> closing ASSOC\n"; sendIndicationToApp(SCTP_I_CONN_LOST); return; } else if (path->activePath == false && oldState == true) { /* notify the application, in case the PATH STATE has changed from ACTIVE to INACTIVE */ pathStatusIndication(path, false); } } }
void SCTPAssociation::process_TIMEOUT_HEARTBEAT_INTERVAL | ( | SCTPPathVariables * | path, | |
bool | force | |||
) | [protected] |
Definition at line 1444 of file SCTPAssociationRcvMessage.cc.
Referenced by processTimer().
{ sctpEV3<<"HB Interval timer expired -- sending new HB REQ on path "<<path->remoteAddress<<"\n"; /* restart hb_send_timer on this path */ stopTimer(path->HeartbeatIntervalTimer); stopTimer(path->HeartbeatTimer); path->heartbeatIntervalTimeout = (double)sctpMain->par("hbInterval") + path->pathRto; path->heartbeatTimeout = path->pathRto; startTimer(path->HeartbeatIntervalTimer, path->heartbeatIntervalTimeout); if ((simTime() - path->lastAckTime > path->heartbeatIntervalTimeout/2) || path->forceHb) { sendHeartbeat(path); startTimer(path->HeartbeatTimer, path->heartbeatTimeout); path->forceHb = false; } }
void SCTPAssociation::process_TIMEOUT_INIT_REXMIT | ( | SCTPEventCode & | event | ) | [protected] |
Definition at line 1395 of file SCTPAssociationRcvMessage.cc.
Referenced by processTimer().
{ if (++state->initRetransCounter > (int32)sctpMain->par("maxInitRetrans")) { sctpEV3 << "Retransmission count during connection setup exceeds " << (int32)sctpMain->par("maxInitRetrans") << ", giving up\n"; sendIndicationToApp(SCTP_I_CLOSED); sendAbort(); sctpMain->removeAssociation(this); return; } sctpEV3<< "Performing retransmission #" << state->initRetransCounter << "\n"; switch(fsm->getState()) { case SCTP_S_COOKIE_WAIT: retransmitInit(); break; case SCTP_S_COOKIE_ECHOED: retransmitCookieEcho(); break; default: opp_error("Internal error: INIT-REXMIT timer expired while in state %s", stateName(fsm->getState())); } state->initRexmitTimeout *= 2; if (state->initRexmitTimeout > SCTP_TIMEOUT_INIT_REXMIT_MAX) state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT_MAX; startTimer(T1_InitTimer,state->initRexmitTimeout); }
void SCTPAssociation::process_TIMEOUT_PROBING | ( | ) | [protected] |
int32 SCTPAssociation::process_TIMEOUT_RTX | ( | SCTPPathVariables * | path | ) | [protected] |
Definition at line 1588 of file SCTPAssociationRcvMessage.cc.
Referenced by processTimer().
{ sctpEV3 << "Processing retransmission timeout ..." << endl; // ====== Increase the RTO (by doubling it) ============================== path->pathRto = min(2 * path->pathRto.dbl(), sctpMain->par("rtoMax")); path->statisticsPathRTO->record(path->pathRto); sctpEV3 << "Schedule T3 based retransmission for path "<< path->remoteAddress << endl; // ====== Update congestion window ======================================= (this->*ccFunctions.ccUpdateAfterRtxTimeout)(path); // ====== Error Counter Handling ========================================= if (!state->zeroWindowProbing) { state->errorCount++; path->pathErrorCount++; sctpEV3 << "RTX-Timeout: errorCount increased to "<<path->pathErrorCount<<" state->errorCount="<<state->errorCount<<"\n"; } if (state->errorCount >= (uint32)sctpMain->par("assocMaxRetrans")) { /* error counter exceeded terminate the association -- create an SCTPC_EV_CLOSE event and send it to myself */ sctpEV3 << "process_TIMEOUT_RTX : ASSOC ERROR COUNTER EXCEEDED, closing ASSOC" << endl; sendIndicationToApp(SCTP_I_CONN_LOST); sendAbort(); sctpMain->removeAssociation(this); return 0; } else { if (path->pathErrorCount > (uint32)sctpMain->par("pathMaxRetrans")) { bool notifyUlp = false; sctpEV3 << "pathErrorCount exceeded\n"; if (path->activePath) { /* tell the source */ notifyUlp = true; } path->activePath = false; if (path->remoteAddress == state->getPrimaryPathIndex()) { SCTPPathVariables* nextPath = getNextPath(path); if (nextPath != NULL) { state->setPrimaryPath(nextPath); } } sctpEV3 << "process_TIMEOUT_RTX(" << path->remoteAddress << ") : PATH ERROR COUNTER EXCEEDED, path status is INACTIVE" << endl; if (allPathsInactive()) { sctpEV3 << "process_TIMEOUT_RTX: ALL PATHS INACTIVE --> connection LOST!" << endl; sendIndicationToApp(SCTP_I_CONN_LOST); sendAbort(); sctpMain->removeAssociation(this); return 0; } else if (notifyUlp) { // Send notification to the application pathStatusIndication(path, false); } } sctpEV3 << "process_TIMEOUT_RTX(" << path->remoteAddress << ") : PATH ERROR COUNTER now " << path->pathErrorCount << endl; } // ====== Do Retransmission ============================================== // dequeue all chunks not acked so far and put them in the TransmissionQ if (!retransmissionQ->payloadQueue.empty()) { sctpEV3 << "Still " << retransmissionQ->payloadQueue.size() << " chunks in retransmissionQ" << endl; for (SCTPQueue::PayloadQueue::iterator iterator = retransmissionQ->payloadQueue.begin(); iterator != retransmissionQ->payloadQueue.end(); iterator++) { SCTPDataVariables* chunk = iterator->second; assert(chunk != NULL); // ====== Insert chunks into TransmissionQ ============================ // Only insert chunks that were sent to the path that has timed out if ( ((chunkHasBeenAcked(chunk) == false && chunk->countsAsOutstanding) || chunk->hasBeenReneged) && (chunk->getLastDestinationPath() == path) ) { sctpEV3 << simTime() << ": Timer-Based RTX for TSN " << chunk->tsn << " on path " << chunk->getLastDestination() << endl; chunk->getLastDestinationPath()->numberOfTimerBasedRetransmissions++; SCTP::AssocStatMap::iterator iter = sctpMain->assocStatMap.find(assocId); iter->second.numT3Rtx++; moveChunkToOtherPath(chunk, getNextDestination(chunk)); } } } SCTPPathVariables* nextPath = getNextPath(path); sctpEV3 << "TimeoutRTX: sendOnAllPaths()" << endl; sendOnAllPaths(nextPath); return 0; }
void SCTPAssociation::process_TIMEOUT_SHUTDOWN | ( | SCTPEventCode & | event | ) | [protected] |
Definition at line 1418 of file SCTPAssociationRcvMessage.cc.
Referenced by processTimer().
{ if (++state->errorCount > (uint32)sctpMain->par("assocMaxRetrans")) { sendIndicationToApp(SCTP_I_CONN_LOST); sendAbort(); sctpMain->removeAssociation(this); return; } sctpEV3 << "Performing shutdown retransmission. Assoc error count now "<<state->errorCount<<" \n"; if(fsm->getState() == SCTP_S_SHUTDOWN_SENT) { retransmitShutdown(); } else if (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT) retransmitShutdownAck(); state->initRexmitTimeout *= 2; if (state->initRexmitTimeout > SCTP_TIMEOUT_INIT_REXMIT_MAX) state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT_MAX; startTimer(T2_ShutdownTimer,state->initRexmitTimeout); }
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).
Definition at line 495 of file SCTPAssociationBase.cc.
Referenced by SCTP::handleMessage().
{ printConnBrief(); // first do actions SCTPCommand *sctpCommand = (SCTPCommand *)(msg->removeControlInfo()); SCTPEventCode event = preanalyseAppCommandEvent(msg->getKind()); sctpEV3 << "App command: " << eventName(event) << "\n"; switch (event) { case SCTP_E_ASSOCIATE: process_ASSOCIATE(event, sctpCommand, msg); break; case SCTP_E_OPEN_PASSIVE: process_OPEN_PASSIVE(event, sctpCommand, msg); break; case SCTP_E_SEND: process_SEND(event, sctpCommand, msg); break; case SCTP_E_CLOSE: process_CLOSE(event); break; case SCTP_E_ABORT: process_ABORT(event); break; case SCTP_E_RECEIVE: process_RECEIVE_REQUEST(event, sctpCommand); break; case SCTP_E_PRIMARY: process_PRIMARY(event, sctpCommand); break; case SCTP_E_QUEUE_BYTES_LIMIT: process_QUEUE_BYTES_LIMIT(sctpCommand); break; case SCTP_E_QUEUE_MSGS_LIMIT: process_QUEUE_MSGS_LIMIT(sctpCommand); break; case SCTP_E_SHUTDOWN: /*sendShutdown*/ sctpEV3<<"SCTP_E_SHUTDOWN in state "<<stateName(fsm->getState())<<"\n"; if (fsm->getState()==SCTP_S_SHUTDOWN_RECEIVED) { sctpEV3<<"send shutdown ack\n"; sendShutdownAck(remoteAddr); } break; //I.R. case SCTP_E_STOP_SENDING: break; case SCTP_E_SEND_SHUTDOWN_ACK: /*if (fsm->getState()==SCTP_S_SHUTDOWN_RECEIVED && getOutstandingBytes()==0 && qCounter.roomSumSendStreams==0 && transmissionQ->getQueueSize()==0) { sendShutdownAck(state->primaryPathIndex); }*/ break; default: opp_error("wrong event code"); } delete sctpCommand; // then state transitions return performStateTransition(event); }
bool SCTPAssociation::processCookieAckArrived | ( | ) | [protected] |
Definition at line 645 of file SCTPAssociationRcvMessage.cc.
Referenced by process_RCV_Message().
{ bool trans=false; if (fsm->getState() == SCTP_S_COOKIE_ECHOED) { stopTimer(T1_InitTimer); trans=performStateTransition(SCTP_E_RCV_COOKIE_ACK); if (state->cookieChunk->getCookieArraySize()==0) { delete state->cookieChunk->getStateCookie(); } delete state->cookieChunk; return trans; } else sctpEV3<<"State="<<fsm->getState()<<"\n"; return trans; }
bool SCTPAssociation::processCookieEchoArrived | ( | SCTPCookieEchoChunk * | cookieEcho, | |
IPvXAddress | addr | |||
) | [protected] |
Definition at line 554 of file SCTPAssociationRcvMessage.cc.
Referenced by process_RCV_Message().
{ bool trans = false; SCTPCookie* cookie = check_and_cast<SCTPCookie*>(cookieEcho->getStateCookie()); if (cookie->getCreationTime()+(int32)sctpMain->par("validCookieLifetime")<simTime()) { sctpEV3<<"stale Cookie: sendAbort\n"; sendAbort(); delete cookie; return trans; } if (fsm->getState() == SCTP_S_CLOSED) { if (cookie->getLocalTag()!=localVTag || cookie->getPeerTag() != peerVTag) { bool same=true; for (int32 i=0; i<32; i++) { if (cookie->getLocalTieTag(i)!=state->localTieTag[i]) { same = false; break; } if (cookie->getPeerTieTag(i)!=state->peerTieTag[i]) { same = false; break; } } if (!same) { sendAbort(); delete cookie; return trans; } } sctpEV3<<"State is CLOSED, Cookie_Ack has to be sent\n"; trans=performStateTransition(SCTP_E_RCV_VALID_COOKIE_ECHO); if (trans) sendCookieAck(addr);//send to address } else if (fsm->getState() == SCTP_S_ESTABLISHED || fsm->getState() == SCTP_S_COOKIE_WAIT || fsm->getState() == SCTP_S_COOKIE_ECHOED) { sctpEV3<<"State is not CLOSED, but COOKIE_ECHO received. Compare the Tags\n"; // case A: Peer restarted, retrieve information from cookie if (cookie->getLocalTag()!=localVTag && cookie->getPeerTag() != peerVTag ) { bool same=true; for (int32 i=0; i<32; i++) { if (cookie->getLocalTieTag(i)!=state->localTieTag[i]) { same = false; break; } if (cookie->getPeerTieTag(i)!=state->peerTieTag[i]) { same = false; break; } } if (same) { localVTag = cookie->getLocalTag(); peerVTag = cookie->getPeerTag(); sendCookieAck(addr); } } // case B: Setup collision, retrieve information from cookie else if (cookie->getPeerTag()==peerVTag && (cookie->getLocalTag()!=localVTag || cookie->getLocalTag()==0)) { localVTag = cookie->getLocalTag(); peerVTag = cookie->getPeerTag(); performStateTransition(SCTP_E_RCV_VALID_COOKIE_ECHO); sendCookieAck(addr); } else if (cookie->getPeerTag()==peerVTag && cookie->getLocalTag()==localVTag) { sendCookieAck(addr); //send to address src } trans=true; } else { sctpEV3<<"State="<<fsm->getState()<<"\n"; trans = true; } delete cookie; return trans; }
SCTPEventCode SCTPAssociation::processDataArrived | ( | SCTPDataChunk * | dataChunk | ) | [protected] |
Definition at line 1242 of file SCTPAssociationRcvMessage.cc.
Referenced by process_RCV_Message().
{ bool checkCtsnaChange = false; const uint32 tsn = dataChunk->getTsn(); SCTPPathVariables* path = getPath(remoteAddr); state->newChunkReceived = false; state->lastTsnReceived = tsn; state->lastDataSourceAddress = remoteAddr; sctpEV3 << simTime() << " SCTPAssociation::processDataArrived TSN=" << tsn << endl; path->pathRcvdTSN->record(tsn); SCTPSimpleMessage* smsg = check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate()); dataChunk->setBitLength(SCTP_DATA_CHUNK_LENGTH*8); dataChunk->encapsulate(smsg); const uint32 payloadLength = dataChunk->getBitLength()/8-SCTP_DATA_CHUNK_LENGTH; sctpEV3 << "state->bytesRcvd=" << state->bytesRcvd << endl; state->bytesRcvd+=payloadLength; sctpEV3 << "state->bytesRcvd now=" << state->bytesRcvd << endl; SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId); iter->second.rcvdBytes+=dataChunk->getBitLength()/8-SCTP_DATA_CHUNK_LENGTH; if (state->numGaps == 0) { state->highestTsnReceived = state->cTsnAck; } else { state->highestTsnReceived = state->gapStopList[state->numGaps-1]; } if (state->stopReceiving) { return SCTP_E_IGNORE; } if (tsnLe(tsn, state->cTsnAck)) { sctpEV3 << "Duplicate TSN " << tsn << " (smaller than CumAck)" << endl; state->dupList.push_back(tsn); state->dupList.unique(); delete check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate()); return SCTP_E_DUP_RECEIVED; } if ((int32)(state->localRwnd-state->queuedReceivedBytes) <= 0) { if (tsnGt(tsn, state->highestTsnReceived)) { return SCTP_E_IGNORE; } // changed 06.07.05 I.R. else if ((!tsnIsDuplicate(tsn)) && (tsn < state->highestTsnStored)) { if (!makeRoomForTsn(tsn, dataChunk->getBitLength()-SCTP_DATA_CHUNK_LENGTH*8, dataChunk->getUBit())) { delete check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate()); return SCTP_E_IGNORE; } } } if (tsnGt(tsn, state->highestTsnReceived)) { sctpEV3 << "highestTsnReceived=" << state->highestTsnReceived << " tsn=" << tsn << endl; state->highestTsnReceived = state->highestTsnStored = tsn; if (tsn == initPeerTsn) { state->cTsnAck = tsn; } else { sctpEV3 << "Update fragment list" << endl; checkCtsnaChange = updateGapList(tsn); } state->newChunkReceived = true; } else if (tsnIsDuplicate(tsn)) { // TSN value is duplicate within a fragment sctpEV3 << "Duplicate TSN " << tsn << " (copy)" << endl; state->dupList.push_back(tsn); state->dupList.unique(); return SCTP_E_IGNORE; } else { checkCtsnaChange = updateGapList(tsn); } if (state->swsAvoidanceInvoked) { // swsAvoidanceInvoked => schedule a SACK to be sent at once in this case sctpEV3 << "swsAvoidanceInvoked" << endl; state->ackState = sackFrequency; } if (checkCtsnaChange) { advanceCtsna(); } sctpEV3 << "cTsnAck=" << state->cTsnAck << " highestTsnReceived=" << state->highestTsnReceived << endl; SCTPEventCode event = SCTP_E_SEND; if (state->newChunkReceived) { SCTPReceiveStreamMap::iterator iter = receiveStreams.find(dataChunk->getSid()); const int ret = iter->second->enqueueNewDataChunk(makeVarFromMsg(dataChunk)); if (ret > 0) { state->queuedReceivedBytes+=payloadLength; event = SCTP_E_DELIVERED; if (ret < 3) { sendDataArrivedNotification(dataChunk->getSid()); putInDeliveryQ(dataChunk->getSid()); } } state->newChunkReceived = false; } return(event); }
SCTPEventCode SCTPAssociation::processHeartbeatAckArrived | ( | SCTPHeartbeatAckChunk * | heartbeatack, | |
SCTPPathVariables * | path | |||
) | [protected] |
Definition at line 1352 of file SCTPAssociationRcvMessage.cc.
Referenced by process_RCV_Message().
{ path->numberOfHeartbeatAcksRcvd++; path->pathRcvdHbAck->record(path->numberOfHeartbeatAcksRcvd); /* hb-ack goes to pathmanagement, reset error counters, stop timeout timer */ const IPvXAddress addr = hback->getRemoteAddr(); const simtime_t hbTimeField = hback->getTimeField(); stopTimer(path->HeartbeatTimer); /* assume a valid RTT measurement on this path */ simtime_t rttEstimation = simTime() - hbTimeField; pmRttMeasurement(path, rttEstimation); pmClearPathCounter(path); path->confirmed = true; path->lastAckTime = simTime(); if (path->primaryPathCandidate == true) { state->setPrimaryPath(getPath(addr)); path->primaryPathCandidate = false; if (path->pmtu < state->assocPmtu) { state->assocPmtu = path->pmtu; } path->ssthresh = state->peerRwnd; recordCwndUpdate(path); path->heartbeatTimeout = (double)sctpMain->par("hbInterval") + path->pathRto; } if (path->activePath == false) { sctpEV3 << "HB ACK arrived activePath=false. remoteAddress=" <<path->remoteAddress << " initialPP=" << state->initialPrimaryPath << endl; path->activePath = true; if (state->reactivatePrimaryPath && path->remoteAddress == state->initialPrimaryPath) { state->setPrimaryPath(path); } sctpEV3 << "primaryPath now " << state->getPrimaryPathIndex() << endl; } sctpEV3 << "Received HB ACK chunk...resetting error counters on path " << addr <<", rttEstimation=" << rttEstimation << endl; path->pathErrorCount = 0; return SCTP_E_IGNORE; }
bool SCTPAssociation::processInitAckArrived | ( | SCTPInitAckChunk * | initAckChunk | ) | [protected] |
Definition at line 492 of file SCTPAssociationRcvMessage.cc.
Referenced by process_RCV_Message().
{ bool trans = false; if (fsm->getState() == SCTP_S_COOKIE_WAIT) { sctpEV3<<"State is COOKIE_WAIT, Cookie_Echo has to be sent\n"; stopTimer(T1_InitTimer); state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT; trans=performStateTransition(SCTP_E_RCV_INIT_ACK); //delete state->initChunk; will be deleted when state ESTABLISHED is entered if (trans) { state->initialPrimaryPath = remoteAddr; state->setPrimaryPath(getPath(remoteAddr)); initPeerTsn=initAckChunk->getInitTSN(); localVTag= initAckChunk->getInitTag(); state->cTsnAck = initPeerTsn - 1; state->initialPeerRwnd = initAckChunk->getA_rwnd(); state->peerRwnd = state->initialPeerRwnd; remoteAddressList.clear(); numberOfRemoteAddresses =initAckChunk->getAddressesArraySize(); sctpEV3<<"number of remote addresses in initAck="<<numberOfRemoteAddresses<<"\n"; for (uint32 j=0; j<numberOfRemoteAddresses; j++) { if (initAckChunk->getAddresses(j).isIPv6()) continue; for (AddressVector::iterator k=state->localAddresses.begin(); k!=state->localAddresses.end(); ++k) { if (!((*k).isUnspecified())) { sctpEV3<<"addPath "<<initAckChunk->getAddresses(j)<<"\n"; sctpMain->addRemoteAddress(this,(*k), initAckChunk->getAddresses(j)); this->remoteAddressList.push_back(initAckChunk->getAddresses(j)); addPath(initAckChunk->getAddresses(j)); } } } SCTPPathMap::iterator ite=sctpPathMap.find(remoteAddr); if (ite==sctpPathMap.end()) { sctpEV3<<__LINE__<<" get new path for "<<remoteAddr<<"\n"; SCTPPathVariables* path = new SCTPPathVariables(remoteAddr, this); sctpPathMap[remoteAddr] = path; qCounter.roomTransQ[remoteAddr] = 0; qCounter.roomRetransQ[remoteAddr] = 0; qCounter.bookedTransQ[remoteAddr] = 0; } inboundStreams = ((initAckChunk->getNoOutStreams()<inboundStreams)?initAckChunk->getNoOutStreams():inboundStreams); outboundStreams = ((initAckChunk->getNoInStreams()<outboundStreams)?initAckChunk->getNoInStreams():outboundStreams); (this->*ssFunctions.ssInitStreams)(inboundStreams, outboundStreams); sendCookieEcho(initAckChunk); } startTimer(T1_InitTimer, state->initRexmitTimeout); } else sctpEV3<<"State="<<fsm->getState()<<"\n"; printSctpPathMap(); return trans; }
bool SCTPAssociation::processInitArrived | ( | SCTPInitChunk * | initChunk, | |
int32 | sport, | |||
int32 | dport | |||
) | [protected] |
Process incoming SCTP packets. Invoked from process_RCV_Message
Definition at line 323 of file SCTPAssociationRcvMessage.cc.
Referenced by process_RCV_Message().
{ SCTPAssociation* assoc; char timerName[128]; bool trans = false; InterfaceTableAccess interfaceTableAccess; AddressVector adv; sctpEV3<<"processInitArrived\n"; if (fsm->getState() == SCTP_S_CLOSED) { sctpEV3<<"fork="<<state->fork<<" initReceived="<<state->initReceived<<"\n"; if (state->fork && !state->initReceived) { sctpEV3<<"cloneAssociation\n"; assoc = cloneAssociation(); sctpEV3<<"addForkedAssociation\n"; sctpMain->addForkedAssociation(this, assoc, localAddr, remoteAddr, srcPort, destPort); sctpEV3 << "Connection forked: this connection got new assocId=" << assocId << ", " "spinoff keeps LISTENing with assocId=" << assoc->assocId << "\n"; snprintf(timerName, sizeof(timerName), "T2_SHUTDOWN of assoc %d", assocId); T2_ShutdownTimer->setName(timerName); snprintf(timerName, sizeof(timerName), "T5_SHUTDOWN_GUARD of assoc %d", assocId); T5_ShutdownGuardTimer->setName(timerName); snprintf(timerName, sizeof(timerName), "SACK_TIMER of assoc %d", assocId); SackTimer->setName(timerName); snprintf(timerName, sizeof(timerName), "T1_INIT of assoc %d", assocId); T1_InitTimer->setName(timerName); } else { sctpMain->updateSockPair(this, localAddr, remoteAddr, srcPort, destPort); } if (!state->initReceived) { state->initReceived = true; state->initialPrimaryPath = remoteAddr; state->setPrimaryPath(getPath(remoteAddr)); if (initchunk->getAddressesArraySize()==0) { sctpEV3<<__LINE__<<" get new path for "<<remoteAddr<<"\n"; SCTPPathVariables* rPath = new SCTPPathVariables(remoteAddr, this); sctpPathMap[rPath->remoteAddress] = rPath; qCounter.roomTransQ[rPath->remoteAddress] = 0; qCounter.bookedTransQ[rPath->remoteAddress] = 0; qCounter.roomRetransQ[rPath->remoteAddress] = 0; } initPeerTsn=initchunk->getInitTSN(); state->cTsnAck = initPeerTsn - 1; state->initialPeerRwnd = initchunk->getA_rwnd(); state->peerRwnd = state->initialPeerRwnd; localVTag= initchunk->getInitTag(); numberOfRemoteAddresses =initchunk->getAddressesArraySize(); IInterfaceTable *ift = interfaceTableAccess.get(); state->localAddresses.clear(); if (localAddressList.front() == IPvXAddress("0.0.0.0")) { for (int32 i=0; i<ift->getNumInterfaces(); ++i) { if (ift->getInterface(i)->ipv4Data()!=NULL) { adv.push_back(ift->getInterface(i)->ipv4Data()->getIPAddress()); } else if (ift->getInterface(i)->ipv6Data()!=NULL) { adv.push_back(ift->getInterface(i)->ipv6Data()->getAddress(0)); } } } else { adv = localAddressList; } uint32 rlevel = getLevel(remoteAddr); if (rlevel>0) for (AddressVector::iterator i=adv.begin(); i!=adv.end(); ++i) { if (getLevel((*i))>=rlevel) { sctpMain->addLocalAddress(this, (*i)); state->localAddresses.push_back((*i)); } } for (uint32 j=0; j<initchunk->getAddressesArraySize(); j++) { // skip IPv6 because we can't send to them yet if (initchunk->getAddresses(j).isIPv6()) continue; // set path variables for this pathlocalAddresses if (!getPath(initchunk->getAddresses(j))) { SCTPPathVariables* path = new SCTPPathVariables(initchunk->getAddresses(j), this); sctpEV3<<__LINE__<<" get new path for "<<initchunk->getAddresses(j)<<" ptr="<<path<<"\n"; for (AddressVector::iterator k=state->localAddresses.begin(); k!=state->localAddresses.end(); ++k) { sctpMain->addRemoteAddress(this,(*k), initchunk->getAddresses(j)); this->remoteAddressList.push_back(initchunk->getAddresses(j)); } sctpPathMap[path->remoteAddress] = path; qCounter.roomTransQ[path->remoteAddress] = 0; qCounter.bookedTransQ[path->remoteAddress] = 0; qCounter.roomRetransQ[path->remoteAddress] = 0; } } SCTPPathMap::iterator ite=sctpPathMap.find(remoteAddr); if (ite==sctpPathMap.end()) { SCTPPathVariables* path = new SCTPPathVariables(remoteAddr, this); sctpEV3<<__LINE__<<" get new path for "<<remoteAddr<<" ptr="<<path<<"\n"; sctpPathMap[remoteAddr] = path; qCounter.roomTransQ[remoteAddr] = 0; qCounter.bookedTransQ[remoteAddr] = 0; qCounter.roomRetransQ[remoteAddr] = 0; } trans = performStateTransition(SCTP_E_RCV_INIT); if (trans) { sendInitAck(initchunk); } } else if (fsm->getState() == SCTP_S_CLOSED) { trans=performStateTransition(SCTP_E_RCV_INIT); if (trans) { sendInitAck(initchunk); } } else { trans = true; } } else if (fsm->getState() == SCTP_S_COOKIE_WAIT) //INIT-Collision { sctpEV3<<"INIT collision: send Init-Ack\n"; sendInitAck(initchunk); trans=true; } else if (fsm->getState() == SCTP_S_COOKIE_ECHOED || fsm->getState() == SCTP_S_ESTABLISHED) { // check, whether a new address has been added bool addressPresent = false; for (uint32 j=0; j<initchunk->getAddressesArraySize(); j++) { if (initchunk->getAddresses(j).isIPv6()) continue; for (AddressVector::iterator k=remoteAddressList.begin(); k!=remoteAddressList.end(); ++k) { if ((*k)==(initchunk->getAddresses(j))) { addressPresent = true; break; } } if (!addressPresent) { sendAbort(); return true; } } sendInitAck(initchunk); trans=true; } else if (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT) trans = true; printSctpPathMap(); return trans; }
SCTPEventCode SCTPAssociation::processSackArrived | ( | SCTPSackChunk * | sackChunk | ) | [protected] |
Definition at line 709 of file SCTPAssociationRcvMessage.cc.
Referenced by process_RCV_Message().
{ simtime_t rttEstimation = MAXTIME; bool ctsnaAdvanced = false; SCTPPathVariables* path = getPath(remoteAddr); // Path for *this* SACK! const uint64 arwnd = sackChunk->getA_rwnd(); const uint32 tsna = sackChunk->getCumTsnAck(); uint32 highestNewAck = tsna; // Highest newly acked TSN const uint16 numGaps = sackChunk->getNumGaps(); bool getChunkFastFirstTime = true; // ====== Print some information ========================================= sctpEV3 << "##### SACK Processing: TSNa=" << tsna << " #####" << endl; for(SCTPPathMap::iterator piter = sctpPathMap.begin(); piter != sctpPathMap.end(); piter++) { SCTPPathVariables* myPath = piter->second; sctpEV3 << "Path " << myPath->remoteAddress << ":\t" << "outstanding=" << path->outstandingBytes << "\t" << "T3scheduled=" << path->T3_RtxTimer->getArrivalTime() << " " << (path->T3_RtxTimer->isScheduled() ? "[ok]" : "[NOT SCHEDULED]") << "\t" << endl; } // ====== Initialize some variables ====================================== for(SCTPPathMap::iterator piter = sctpPathMap.begin(); piter != sctpPathMap.end(); piter++) { SCTPPathVariables* myPath = piter->second; // T.D. 26.03.09: Remember outstanding bytes before this update // Values are necessary for updating the congestion window! myPath->outstandingBytesBeforeUpdate = myPath->outstandingBytes; // T.D. 14.11.09: Bugfix - copy from myPath, not from path! myPath->requiresRtx = false; myPath->lowestTSNRetransmitted = false; myPath->findLowestTSN = true; myPath->gapAcksInLastSACK = 0; myPath->gapNAcksInLastSACK = 0; myPath->newlyAckedBytes = 0; if (myPath == path) { myPath->lastAckTime = simTime(); } } // ====== Zero Window Probing ============================================ if ( (state->zeroWindowProbing) && (arwnd > 0) ) { state->zeroWindowProbing = false; } // ####################################################################### // #### Processing of CumAck #### // ####################################################################### if (tsnGt(tsna, state->lastTsnAck)) { // Handle new CumAck sctpEV3 << "===== Handling new CumAck for TSN " << tsna << " =====" << endl; // We have got new chunks acked, and our cum ack point is advanced ... // Depending on the parameter osbWithHeader ackedBytes are with or without the header bytes. // T.D. 23.03.09: path->newlyAckedBytes is updated in dequeueAckedChunks()! dequeueAckedChunks(tsna, path, rttEstimation); // chunks with tsn between lastTsnAck and tsna are removed from the transmissionQ and the retransmissionQ; outstandingBytes are decreased state->lastTsnAck = tsna; ctsnaAdvanced = true; } else if (tsnLt(tsna, state->lastTsnAck)) { sctpEV3 << "Stale CumAck (" << tsna << " < " << state->lastTsnAck << ")" << endl; return SCTP_E_IGNORE; } // ====== Handle reneging ================================================ if ((numGaps == 0) && (tsnLt(tsna, state->highestTsnAcked))) { // Reneging, type 0: // In a previous SACK, chunks up to highestTsnAcked have been acked. // This SACK contains a CumAck < highestTsnAcked // => rereg TSNs from CumAck+1 to highestTsnAcked // => new highestTsnAcked = CumAck sctpEV3 << "numGaps=0 && tsna " << tsna << " < highestTsnAcked " << state->highestTsnAcked << endl; uint32 i = state->highestTsnAcked; while (i >= tsna + 1) { SCTPDataVariables* myChunk = retransmissionQ->getChunk(i); if(myChunk) { if(chunkHasBeenAcked(myChunk)) { tsnWasReneged(myChunk, 0); } } i--; } state->highestTsnAcked = tsna; } // ####################################################################### // #### Processing of GapAcks #### // ####################################################################### if ((numGaps > 0) && (!retransmissionQ->payloadQueue.empty()) ) { sctpEV3 << "===== Handling GapAcks after CumTSNAck " << tsna << " =====" << endl; sctpEV3 << "We got " << numGaps << " gap reports" << endl; // We got fragment reports... check for newly acked chunks. const uint32 queuedChunks = retransmissionQ->payloadQueue.size(); sctpEV3 << "Number of chunks in retransmissionQ: " << queuedChunks <<" highestGapStop: " << sackChunk->getGapStop(numGaps-1) <<" highestTsnAcked: " << state->highestTsnAcked << endl; // ====== Handle reneging ============================================= // highest gapStop smaller than highestTsnAcked: there might have been reneging if (tsnLt(sackChunk->getGapStop(numGaps-1), state->highestTsnAcked)) { // Reneging, type 2: // In a previous SACK, chunks up to highestTsnAcked have been acked. // This SACK contains a last gap ack < highestTsnAcked // => rereg TSNs from last gap ack to highestTsnAcked // => new highestTsnAcked = last gap ack uint32 i = state->highestTsnAcked; while (i >= sackChunk->getGapStop(numGaps - 1) + 1) { // ====== Looking up TSN in retransmission queue ================ SCTPDataVariables* myChunk = retransmissionQ->getChunk(i); if(myChunk) { if (chunkHasBeenAcked(myChunk)) { sctpEV3 << "TSN " << i << " was found. It has been un-acked." << endl; tsnWasReneged(myChunk, 2); sctpEV3 << "highestTsnAcked now " << state->highestTsnAcked << endl; } } else { sctpEV3 << "TSN " << i << " not found in retransmissionQ" << endl; } i--; } state->highestTsnAcked = sackChunk->getGapStop(numGaps - 1); } // ====== Looking for changes in the gap reports ====================== sctpEV3 << "Looking for changes in gap reports" << endl; for (int32 key = 0;key < numGaps; key++) { const uint32 lo = sackChunk->getGapStart(key); const uint32 hi = sackChunk->getGapStop(key); // ====== Iterate over TSNs in gap reports ========================= sctpEV3 << "Examine TSNs between " << lo << " and " << hi << endl; for (uint32 pos = lo; pos <= hi; pos++) { SCTPDataVariables* myChunk = retransmissionQ->getChunkFast(pos, getChunkFastFirstTime); if (myChunk) { if(chunkHasBeenAcked(myChunk) == false) { SCTPPathVariables* myChunkLastPath = myChunk->getLastDestinationPath(); assert(myChunkLastPath != NULL); // T.D. 02.02.2010: This chunk has been acked newly. // Let's process this new acknowledgement! handleChunkReportedAsAcked(highestNewAck, rttEstimation, myChunk, path /* i.e. the SACK path for RTT measurement! */); } } } } state->highestTsnAcked = sackChunk->getGapStop(numGaps-1); // ====== Examine chunks between the gap reports ====================== // They might have to be retransmitted or they could have been removed uint32 lo = tsna; for (int32 key = 0; key < numGaps; key++) { const uint32 hi = sackChunk->getGapStart(key); for (uint32 pos = lo+1; pos <= hi - 1; pos++) { SCTPDataVariables* myChunk = retransmissionQ->getChunkFast(pos, getChunkFastFirstTime); if(myChunk) { handleChunkReportedAsMissing(sackChunk, highestNewAck, myChunk, path /* i.e. the SACK path for RTT measurement! */); } else { sctpEV3 << "TSN " << pos << " not found in retransmissionQ" << endl; } } lo = sackChunk->getGapStop(key); } // ====== Validity checks ============================================= } // ====== Update Fast Recovery status, according to SACK ================= updateFastRecoveryStatus(state->lastTsnAck); // ====== Update RTT measurement for newly acked data chunks ============= sctpEV3 << simTime() << ": SACK: rtt=" << rttEstimation << ", path=" << path->remoteAddress << endl; pmRttMeasurement(path, rttEstimation); // ####################################################################### // #### Receiver Window Management #### // ####################################################################### const uint32 osb = getOutstandingBytes(); state->peerRwnd = arwnd - osb; // position of statement changed 20.07.05 I.R. if ((int32)(state->peerRwnd) < 0) { state->peerRwnd = 0; } if (state->peerRwnd > state->initialPeerRwnd) { state->peerRwnd = state->initialPeerRwnd; } if (arwnd == 1 || state->peerRwnd < state->swsLimit || arwnd == 0) { sctpEV3 << "processSackArrived: arwnd=" << arwnd << " state->peerRwnd=" << state->peerRwnd << " set peerWindowFull" << endl; state->peerWindowFull = true; } else { state->peerWindowFull = false; state->zeroWindowProbing = false; } #ifdef PVIATE advancePeerTsn(); #endif // ====== Need for zero-window probing? ================================== if(osb == 0) { if (arwnd == 0) state->zeroWindowProbing = true; } // ####################################################################### // #### Congestion Window Management #### // ####################################################################### sctpEV3 << "Before ccUpdateBytesAcked: "; for(SCTPPathMap::iterator piter = sctpPathMap.begin(); piter != sctpPathMap.end(); piter++) { SCTPPathVariables* myPath = piter->second; const IPvXAddress& myPathId = myPath->remoteAddress; if(myPath->newlyAckedBytes > 0) { // T.D. 07.10.2009: Only call ccUpdateBytesAcked() when there are // acked bytes on this path! const bool advanceWindow = myPath->newCumAck; sctpEV3 << simTime() << ":\tCC " << myPath->newlyAckedBytes << " newly acked on path " << myPathId << ";" << "\t->\tadvanceWindow=" << advanceWindow << endl; (this->*ccFunctions.ccUpdateBytesAcked)(myPath, myPath->newlyAckedBytes, advanceWindow); } } // ====== Update congestion windows on paths (handling decreases) ======== sctpEV3 << "Before ccUpdateAfterSack with tsna=" << tsna << endl; // ccUpdateAfterSack() will iterate over all paths. (this->*ccFunctions.ccUpdateAfterSack)(); // ####################################################################### // #### Path Management #### // ####################################################################### // ====== Need to stop or restart T3 timer? ============================== for(SCTPPathMap::iterator piter = sctpPathMap.begin(); piter != sctpPathMap.end(); piter++) { SCTPPathVariables* myPath = piter->second; const IPvXAddress& myPathId = myPath->remoteAddress; if (myPath->outstandingBytes == 0) { // T.D. 07.01.2010: Only stop T3 timer when there is nothing more to send on this path! if(qCounter.roomTransQ.find(myPath->remoteAddress)->second == 0) { // Stop T3 timer, if there are no more outstanding bytes. stopTimer(myPath->T3_RtxTimer); } } else if (myPath->newCumAck) { stopTimer(myPath->T3_RtxTimer); startTimer(myPath->T3_RtxTimer, myPath->pathRto); } else { /* Also restart T3 timer, when lowest TSN is rtx'ed */ if(myPath->lowestTSNRetransmitted == true) { sctpEV3 << "Lowest TSN retransmitted => restart of T3 timer for path " << myPathId << endl; stopTimer(myPath->T3_RtxTimer); startTimer(myPath->T3_RtxTimer, myPath->pathRto); } } // ====== Clear error counter if TSNs on path have been acked ========= if (myPath->newlyAckedBytes > 0) { pmClearPathCounter(myPath); } } return SCTP_E_IGNORE; }
bool SCTPAssociation::processSCTPMessage | ( | SCTPMessage * | sctpmsg, | |
const IPvXAddress & | srcAddr, | |||
const 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).
Definition at line 458 of file SCTPAssociationBase.cc.
Referenced by SCTP::handleMessage().
{ printConnBrief(); localAddr = msgDestAddr; localPort = sctpmsg->getDestPort(); remoteAddr = msgSrcAddr; remotePort = sctpmsg->getSrcPort(); return process_RCV_Message(sctpmsg, msgSrcAddr, msgDestAddr); }
bool SCTPAssociation::processTimer | ( | cMessage * | msg | ) |
Definition at line 390 of file SCTPAssociationBase.cc.
Referenced by SCTP::handleMessage().
{ SCTPPathVariables* path = NULL; sctpEV3 << msg->getName() << " timer expired at "<<simulation.getSimTime()<<"\n"; SCTPPathInfo* pinfo = check_and_cast<SCTPPathInfo*>(msg->getControlInfo()); IPvXAddress addr = pinfo->getRemoteAddress(); if (addr != IPvXAddress("0.0.0.0")) path = getPath(addr); // first do actions SCTPEventCode event; event = SCTP_E_IGNORE; if (msg==T1_InitTimer) { process_TIMEOUT_INIT_REXMIT(event); } else if (msg==SackTimer) { sctpEV3<<simulation.getSimTime()<<" delayed Sack: cTsnAck="<<state->cTsnAck<<" highestTsnReceived="<<state->highestTsnReceived<<" lastTsnReceived="<<state->lastTsnReceived<<" ackState="<<state->ackState<<" numGaps="<<state->numGaps<<"\n"; sendSack(); } else if (msg==T2_ShutdownTimer) { stopTimer(T2_ShutdownTimer); process_TIMEOUT_SHUTDOWN(event); } else if (msg==T5_ShutdownGuardTimer) { stopTimer(T5_ShutdownGuardTimer); delete state->shutdownChunk; sendIndicationToApp(SCTP_I_CONN_LOST); sendAbort(); sctpMain->removeAssociation(this); } else if (path!=NULL && msg==path->HeartbeatIntervalTimer) { process_TIMEOUT_HEARTBEAT_INTERVAL(path, path->forceHb); } else if (path!=NULL && msg==path->HeartbeatTimer) { process_TIMEOUT_HEARTBEAT(path); } else if (path!=NULL && msg==path->T3_RtxTimer) { process_TIMEOUT_RTX(path); } else if (path!=NULL && msg==path->CwndTimer) { (this->*ccFunctions.ccUpdateAfterCwndTimeout)(path); } else if (strcmp(msg->getName(), "StartTesting")==0) { if (sctpMain->testing == false) { sctpMain->testing = true; sctpEV3<<"set testing to true\n"; } } else { sctpAlgorithm->processTimer(msg, event); } // then state transitions return performStateTransition(event); }
void SCTPAssociation::pushUlp | ( | ) | [protected] |
Definition at line 1051 of file SCTPAssociationUtil.cc.
Referenced by process_RECEIVE_REQUEST().
{ int32 count = 0; for (unsigned int i = 0; i < inboundStreams; i++) { //12.06.08 putInDeliveryQ(i); } if (state->pushMessagesLeft <= 0) { state->pushMessagesLeft = state->messagesToPush; } bool restrict = false; if (state->pushMessagesLeft > 0) { restrict = true; } sctpEV3 << simTime() << " Calling pushUlp(" << state->queuedReceivedBytes << " bytes queued) ..." << endl; uint32 i = state->nextRSid; do { SCTPReceiveStreamMap::iterator iter = receiveStreams.find(i); SCTPReceiveStream* rStream = iter->second; sctpEV3 << "Size of stream " << iter->first << ": " << rStream->getDeliveryQ()->getQueueSize() << endl; while ( (!rStream->getDeliveryQ()->payloadQueue.empty()) && (!restrict || (restrict && state->pushMessagesLeft>0)) ) { SCTPDataVariables* chunk = rStream->getDeliveryQ()->extractMessage(); qCounter.roomSumRcvStreams -= ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH); if (state->pushMessagesLeft >0) state->pushMessagesLeft--; state->queuedReceivedBytes-=chunk->len/8; if (state->swsAvoidanceInvoked) { if ((int32)(state->localRwnd - state->queuedReceivedBytes) >= (int32)(state->swsLimit) && (int32)(state->localRwnd - state->queuedReceivedBytes) <= (int32)(state->swsLimit+state->assocPmtu)) { /* only if the window has opened up more than one MTU we will send a SACK */ state->swsAvoidanceInvoked = false; sctpEV3<<"pushUlp: Window opens up to "<<(int32)state->localRwnd-state->queuedReceivedBytes<<" bytes: sending a SACK. SWS Avoidance INACTIVE\n"; sendSack(); } } else if ((int32)(state->swsLimit) == 0) { sendSack(); } sctpEV3 << "Push TSN " << chunk->tsn << ": sid=" << chunk->sid << " ssn=" << chunk->ssn << endl; cPacket* msg= (cPacket *)chunk->userData; msg->setKind(SCTP_I_DATA); SCTPRcvCommand *cmd = new SCTPRcvCommand("push"); cmd->setAssocId(assocId); cmd->setGate(appGateIndex); cmd->setSid(chunk->sid); cmd->setSsn(chunk->ssn); cmd->setSendUnordered(!chunk->ordered); cmd->setLocalAddr(localAddr); cmd->setRemoteAddr(remoteAddr); cmd->setPpid(chunk->ppid); cmd->setTsn(chunk->tsn); cmd->setCumTsn(state->lastTsnAck); msg->setControlInfo(cmd); state->numMsgsReq[count]--; delete chunk; sendToApp(msg); } i = (i + 1) % inboundStreams; count++; } while (i != state->nextRSid); state->nextRSid = (state->nextRSid + 1) % inboundStreams; if ( (state->queuedReceivedBytes == 0) && (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)) { sctpEV3 << "SCTP_E_CLOSE" << endl; performStateTransition(SCTP_E_CLOSE); } }
void SCTPAssociation::putInDeliveryQ | ( | uint16 | sid | ) | [protected] |
Definition at line 1009 of file SCTPAssociationUtil.cc.
Referenced by processDataArrived(), and pushUlp().
{ SCTPReceiveStreamMap::iterator iter=receiveStreams.find(sid); SCTPReceiveStream* rStream = iter->second; sctpEV3 << "putInDeliveryQ: SSN=" << rStream->getExpectedStreamSeqNum() << " SID=" << sid << " QueueSize="<< rStream->getOrderedQ()->getQueueSize() << endl; while (rStream->getOrderedQ()->getQueueSize()>0) { /* dequeue first from reassembly Q */ SCTPDataVariables* chunk = rStream->getOrderedQ()-> dequeueChunkBySSN(rStream->getExpectedStreamSeqNum()); if (chunk) { sctpEV3 << "putInDeliveryQ::chunk " <<chunk->tsn <<", sid " << chunk->sid <<" and ssn " << chunk->ssn <<" dequeued from ordered queue. queuedReceivedBytes=" << state->queuedReceivedBytes << " will be reduced by " << chunk->len/8 << endl; state->queuedReceivedBytes-=chunk->len/8; qCounter.roomSumRcvStreams -= ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH); if (rStream->getDeliveryQ()->checkAndInsertChunk(chunk->tsn, chunk)) { state->queuedReceivedBytes += chunk->len/8; sctpEV3 << "data put in deliveryQ; queuedBytes now " << state->queuedReceivedBytes << endl; qCounter.roomSumRcvStreams += ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH); int32 seqnum=rStream->getExpectedStreamSeqNum(); rStream->setExpectedStreamSeqNum(++seqnum); if (rStream->getExpectedStreamSeqNum() > 65535) { rStream->setExpectedStreamSeqNum(0); } sendDataArrivedNotification(sid); } } else { break; } } }
void SCTPAssociation::putInTransmissionQ | ( | uint32 | tsn, | |
SCTPDataVariables * | chunk | |||
) | [protected] |
void SCTPAssociation::recordCwndUpdate | ( | SCTPPathVariables * | path | ) | [private] |
Definition at line 30 of file SCTPCCFunctions.cc.
Referenced by cwndUpdateAfterCwndTimeout(), cwndUpdateAfterRtxTimeout(), cwndUpdateAfterSack(), cwndUpdateBytesAcked(), cwndUpdateMaxBurst(), initCCParameters(), processHeartbeatAckArrived(), and removePath().
{ path->statisticsPathSSthresh->record(path->ssthresh); path->statisticsPathCwnd->record(path->cwnd); }
void SCTPAssociation::recordInPathVectors | ( | SCTPMessage * | pMsg, | |
const IPvXAddress & | rDest | |||
) | [protected] |
Definition at line 190 of file SCTPAssociationUtil.cc.
Referenced by sendToIP().
{ uint32 n_chunks = pMsg->getChunksArraySize(); if (n_chunks == 0) return; SCTPPathVariables* p_path = getPath(rDest); for (uint32 i = 0 ; i < n_chunks ; i++) { const SCTPChunk* p_chunk = check_and_cast<const SCTPChunk *>(pMsg->getChunks(i)); if (p_chunk->getChunkType() == DATA) { const SCTPDataChunk* p_data_chunk = check_and_cast<const SCTPDataChunk *>(p_chunk); p_path->pathTSN->record(p_data_chunk->getTsn()); } else if (p_chunk->getChunkType() == HEARTBEAT) { p_path->numberOfHeartbeatsSent++; p_path->pathHb->record(p_path->numberOfHeartbeatsSent); } else if (p_chunk->getChunkType() == HEARTBEAT_ACK) { p_path->numberOfHeartbeatAcksSent++; p_path->pathHbAck->record(p_path->numberOfHeartbeatAcksSent); } } }
void SCTPAssociation::removeFromGapList | ( | const uint32 | removedTsn | ) | [protected] |
Definition at line 1292 of file SCTPAssociationUtil.cc.
Referenced by makeRoomForTsn().
{ int32 gapsize, numgaps; numgaps = state->numGaps; sctpEV3<<"remove TSN "<<removedTsn<<" from GapList. "<<numgaps<<" gaps present, cumTsnAck="<<state->cTsnAck<<"\n"; for (int32 j=0; j<numgaps; j++) sctpEV3<<state->gapStartList[j]<<" - "<<state->gapStopList[j]<<"\n"; for (int32 i=numgaps-1; i>=0; i--) { sctpEV3<<"gapStartList["<<i<<"]="<<state->gapStartList[i]<<", state->gapStopList["<<i<<"]="<<state->gapStopList[i]<<"\n"; if (tsnBetween(state->gapStartList[i], removedTsn, state->gapStopList[i])) { gapsize = (int32)(state->gapStopList[i] - state->gapStartList[i]+1); if (gapsize>1) { if (state->gapStopList[i]==removedTsn) { state->gapStopList[i]--; } else if (state->gapStartList[i]==removedTsn) { state->gapStartList[i]++; } else //gap is split in two { for (int32 j=numgaps-1; j>=i; j--) { state->gapStopList[j+1] = state->gapStopList[j]; state->gapStartList[j+1] = state->gapStartList[j]; } state->gapStopList[i] = removedTsn-1; state->gapStartList[i+1] = removedTsn+1; state->numGaps = min(state->numGaps + 1, MAX_GAP_COUNT); // T.D. 18.12.09: Enforce upper limit! } } else { for (int32 j=i; j<=numgaps-1; j++) { state->gapStopList[j] = state->gapStopList[j+1]; state->gapStartList[j] = state->gapStartList[j+1]; } state->gapStartList[numgaps-1]=0; state->gapStopList[numgaps-1]=0; state->numGaps--; if (state->numGaps == 0) { if (removedTsn == state->lastTsnAck+1) { state->lastTsnAck = removedTsn; } } } } } if (state->numGaps>0) state->highestTsnReceived = state->gapStopList[state->numGaps-1]; else state->highestTsnReceived = state->cTsnAck; }
void SCTPAssociation::removePath | ( | ) |
Definition at line 768 of file SCTPAssociationBase.cc.
Referenced by SCTP::removeAssociation().
{ SCTPPathMap::iterator pathIterator; while((pathIterator = sctpPathMap.begin()) != sctpPathMap.end()) { SCTPPathVariables* path = pathIterator->second; sctpEV3 << getFullPath() << " remove path " << path->remoteAddress << endl; stopTimer(path->HeartbeatTimer); delete path->HeartbeatTimer; stopTimer(path->HeartbeatIntervalTimer); sctpEV3 << "delete timer " << path->HeartbeatIntervalTimer->getName() << endl; delete path->HeartbeatIntervalTimer; stopTimer(path->T3_RtxTimer); delete path->T3_RtxTimer; stopTimer(path->CwndTimer); delete path->CwndTimer; delete path; sctpPathMap.erase(pathIterator); } }
void SCTPAssociation::removePath | ( | const IPvXAddress & | addr | ) |
Definition at line 1170 of file SCTPAssociationUtil.cc.
{ SCTPPathMap::iterator pathIterator = sctpPathMap.find(addr); if (pathIterator != sctpPathMap.end()) { SCTPPathVariables* path = pathIterator->second; path->cwnd = 0; path->ssthresh = 0; recordCwndUpdate(path); stopTimer(path->HeartbeatTimer); delete path->HeartbeatTimer; stopTimer(path->HeartbeatIntervalTimer); delete path->HeartbeatIntervalTimer; stopTimer(path->T3_RtxTimer); delete path->T3_RtxTimer; stopTimer(path->CwndTimer); delete path->CwndTimer; sctpPathMap.erase(pathIterator); delete path; } }
void SCTPAssociation::retransmitCookieEcho | ( | ) | [protected] |
Definition at line 660 of file SCTPAssociationUtil.cc.
Referenced by process_RCV_Message(), and process_TIMEOUT_INIT_REXMIT().
{ SCTPMessage* sctpmsg = new SCTPMessage(); sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); SCTPCookieEchoChunk* cookieEchoChunk=check_and_cast<SCTPCookieEchoChunk*>(state->cookieChunk->dup()); if (cookieEchoChunk->getCookieArraySize()==0) { cookieEchoChunk->setStateCookie(state->cookieChunk->getStateCookie()->dup()); } sctpmsg->addChunk(cookieEchoChunk); sctpEV3<<"retransmitCookieEcho localAddr="<<localAddr<<" remoteAddr"<<remoteAddr<<"\n"; sendToIP(sctpmsg); }
void SCTPAssociation::retransmitInit | ( | ) | [protected] |
Retransmitting chunks
Definition at line 471 of file SCTPAssociationUtil.cc.
Referenced by process_RCV_Message(), and process_TIMEOUT_INIT_REXMIT().
{ SCTPMessage *sctpmsg = new SCTPMessage(); sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); SCTPInitChunk *sctpinit;// = new SCTPInitChunk("INIT"); sctpEV3<<"Retransmit InitChunk="<<&sctpinit<<"\n"; sctpinit=check_and_cast<SCTPInitChunk *>(state->initChunk->dup()); sctpinit->setChunkType(INIT); sctpmsg->addChunk(sctpinit); sendToIP(sctpmsg); }
void SCTPAssociation::retransmitShutdown | ( | ) | [protected] |
Definition at line 824 of file SCTPAssociationUtil.cc.
Referenced by process_TIMEOUT_SHUTDOWN().
{ SCTPMessage *sctpmsg = new SCTPMessage(); sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); SCTPShutdownChunk* shutdownChunk; shutdownChunk=check_and_cast<SCTPShutdownChunk*>(state->shutdownChunk->dup()); sctpmsg->addChunk(shutdownChunk); sctpEV3<<"retransmitShutdown localAddr="<<localAddr<<" remoteAddr"<<remoteAddr<<"\n"; sendToIP(sctpmsg); }
void SCTPAssociation::retransmitShutdownAck | ( | ) | [protected] |
Definition at line 837 of file SCTPAssociationUtil.cc.
Referenced by process_TIMEOUT_SHUTDOWN().
{ SCTPMessage *sctpmsg = new SCTPMessage(); sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); SCTPShutdownAckChunk* shutdownAckChunk; shutdownAckChunk=check_and_cast<SCTPShutdownAckChunk*>(state->shutdownAckChunk->dup()); sctpmsg->addChunk(shutdownAckChunk); sctpEV3<<"retransmitShutdownAck localAddr="<<localAddr<<" remoteAddr"<<remoteAddr<<"\n"; sendToIP(sctpmsg); }
void SCTPAssociation::scheduleSack | ( | ) | [protected] |
Definition at line 851 of file SCTPAssociationUtil.cc.
Referenced by process_RCV_Message().
{ /* increase SACK counter, we received another data PACKET */ if (state->firstChunkReceived) state->ackState++; else { state->ackState = sackFrequency; state->firstChunkReceived = true; } sctpEV3<<"scheduleSack() : ackState is now: "<<state->ackState<<"\n"; if (state->ackState <= sackFrequency - 1) { /* start a SACK timer if none is running, to expire 200 ms (or parameter) from now */ if (!SackTimer->isScheduled()) { startTimer(SackTimer, sackPeriod); } /* else: leave timer running, and do nothing... */ else { /* is this possible at all ? Check this... */ sctpEV3<<"SACK timer running, but scheduleSack() called\n"; } } }
void SCTPAssociation::scheduleTimeout | ( | cMessage * | msg, | |
const simtime_t & | timeout | |||
) | [inline, protected] |
Utility: start a timer
Definition at line 735 of file SCTPAssociation.h.
Referenced by SCTPAssociation(), and startTimer().
{ sctpMain->scheduleAt(simulation.getSimTime() + timeout, msg); }
void SCTPAssociation::sendAbort | ( | ) | [protected] |
Definition at line 780 of file SCTPAssociationUtil.cc.
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().
{ SCTPMessage *msg = new SCTPMessage(); msg->setBitLength(SCTP_COMMON_HEADER*8); sctpEV3<<"SCTPAssociationUtil:sendABORT localPort="<<localPort<<" remotePort="<<remotePort<<"\n"; msg->setSrcPort(localPort); msg->setDestPort(remotePort); SCTPAbortChunk* abortChunk = new SCTPAbortChunk("ABORT"); abortChunk->setChunkType(ABORT); abortChunk->setT_Bit(0); abortChunk->setBitLength(SCTP_ABORT_CHUNK_LENGTH*8); msg->addChunk(abortChunk); sendToIP(msg, remoteAddr); }
void SCTPAssociation::sendCookieAck | ( | const IPvXAddress & | dest | ) | [protected] |
Definition at line 719 of file SCTPAssociationUtil.cc.
Referenced by processCookieEchoArrived().
{ SCTPMessage *sctpcookieack = new SCTPMessage(); sctpcookieack->setBitLength(SCTP_COMMON_HEADER*8); sctpEV3<<"SCTPAssociationUtil:sendCookieACK\n"; sctpcookieack->setSrcPort(localPort); sctpcookieack->setDestPort(remotePort); SCTPCookieAckChunk* cookieAckChunk=new SCTPCookieAckChunk("COOKIE_ACK"); cookieAckChunk->setChunkType(COOKIE_ACK); cookieAckChunk->setBitLength(SCTP_COOKIE_ACK_LENGTH*8); sctpcookieack->addChunk(cookieAckChunk); sendToIP(sctpcookieack, dest); }
void SCTPAssociation::sendCookieEcho | ( | SCTPInitAckChunk * | initackchunk | ) | [protected] |
Definition at line 615 of file SCTPAssociationUtil.cc.
Referenced by processInitAckArrived().
{ SCTPMessage *sctpcookieecho = new SCTPMessage(); sctpcookieecho->setBitLength(SCTP_COMMON_HEADER*8); sctpEV3<<"SCTPAssociationUtil:sendCookieEcho\n"; sctpcookieecho->setSrcPort(localPort); sctpcookieecho->setDestPort(remotePort); SCTPCookieEchoChunk* cookieEchoChunk=new SCTPCookieEchoChunk("COOKIE_ECHO"); cookieEchoChunk->setChunkType(COOKIE_ECHO); int32 len = initAckChunk->getCookieArraySize(); cookieEchoChunk->setCookieArraySize(len); if (len>0) { for (int32 i=0; i<len; i++) cookieEchoChunk->setCookie(i, initAckChunk->getCookie(i)); cookieEchoChunk->setBitLength((SCTP_COOKIE_ACK_LENGTH+len)*8); } else { SCTPCookie* cookie = check_and_cast <SCTPCookie*> (initAckChunk->getStateCookie()); cookieEchoChunk->setStateCookie(cookie); cookieEchoChunk->setBitLength(SCTP_COOKIE_ACK_LENGTH*8 + cookie->getBitLength()); } uint32 unknownLen = initAckChunk->getUnrecognizedParametersArraySize(); if (unknownLen>0) { sctpEV3<<"Found unrecognized Parameters in INIT-ACK chunk with a length of "<<unknownLen<<" bytes.\n"; cookieEchoChunk->setUnrecognizedParametersArraySize(unknownLen); for (uint32 i=0; i<unknownLen; i++) cookieEchoChunk->setUnrecognizedParameters(i,initAckChunk->getUnrecognizedParameters(i)); } else cookieEchoChunk->setUnrecognizedParametersArraySize(0); state->cookieChunk=check_and_cast<SCTPCookieEchoChunk*>(cookieEchoChunk->dup()); if (len==0) { state->cookieChunk->setStateCookie(initAckChunk->getStateCookie()->dup()); } sctpcookieecho->addChunk(cookieEchoChunk); sendToIP(sctpcookieecho); }
void SCTPAssociation::sendDataArrivedNotification | ( | uint16 | sid | ) | [protected] |
Definition at line 992 of file SCTPAssociationUtil.cc.
Referenced by processDataArrived(), and putInDeliveryQ().
{ sctpEV3<<"SendDataArrivedNotification\n"; cPacket* cmsg = new cPacket("DataArrivedNotification"); cmsg->setKind(SCTP_I_DATA_NOTIFICATION); SCTPCommand *cmd = new SCTPCommand("notification"); cmd->setAssocId(assocId); cmd->setSid(sid); cmd->setNumMsgs(1); cmsg->setControlInfo(cmd); sendToApp(cmsg); }
void SCTPAssociation::sendEstabIndicationToApp | ( | ) | [protected] |
Utility: sends SCTP_I_ESTABLISHED indication with SCTPConnectInfo to application
Definition at line 290 of file SCTPAssociationUtil.cc.
Referenced by stateEntered().
{ sctpEV3 << "sendEstabIndicationToApp: localPort=" << localPort << " remotePort=" << remotePort << endl; cPacket* msg = new cPacket(indicationName(SCTP_I_ESTABLISHED)); msg->setKind(SCTP_I_ESTABLISHED); SCTPConnectInfo* establishIndication = new SCTPConnectInfo("CI"); establishIndication->setAssocId(assocId); establishIndication->setLocalAddr(localAddr); establishIndication->setRemoteAddr(remoteAddr); establishIndication->setLocalPort(localPort); establishIndication->setRemotePort(remotePort); establishIndication->setRemoteAddresses(remoteAddressList); establishIndication->setInboundStreams(inboundStreams); establishIndication->setOutboundStreams(outboundStreams); establishIndication->setNumMsgs(state->sendQueueLimit); msg->setControlInfo(establishIndication); sctpMain->send(msg, "to_appl", appGateIndex); }
void SCTPAssociation::sendHeartbeat | ( | const SCTPPathVariables * | path | ) | [protected] |
Definition at line 676 of file SCTPAssociationUtil.cc.
Referenced by pmStartPathManagement(), and process_TIMEOUT_HEARTBEAT_INTERVAL().
{ SCTPMessage* sctpHeartbeatbeat = new SCTPMessage(); sctpHeartbeatbeat->setBitLength(SCTP_COMMON_HEADER*8); sctpHeartbeatbeat->setSrcPort(localPort); sctpHeartbeatbeat->setDestPort(remotePort); SCTPHeartbeatChunk* heartbeatChunk = new SCTPHeartbeatChunk("HEARTBEAT"); heartbeatChunk->setChunkType(HEARTBEAT); heartbeatChunk->setRemoteAddr(path->remoteAddress); heartbeatChunk->setTimeField(simTime()); heartbeatChunk->setBitLength((SCTP_HEARTBEAT_CHUNK_LENGTH+12)*8); sctpHeartbeatbeat->addChunk(heartbeatChunk); sctpEV3 << "sendHeartbeat: sendToIP to " << path->remoteAddress << endl; sendToIP(sctpHeartbeatbeat, path->remoteAddress); }
void SCTPAssociation::sendHeartbeatAck | ( | const SCTPHeartbeatChunk * | heartbeatChunk, | |
const IPvXAddress & | src, | |||
const IPvXAddress & | dest | |||
) | [protected] |
Definition at line 693 of file SCTPAssociationUtil.cc.
Referenced by process_RCV_Message().
{ SCTPMessage* sctpHeartbeatAck = new SCTPMessage(); sctpHeartbeatAck->setBitLength(SCTP_COMMON_HEADER*8); sctpHeartbeatAck->setSrcPort(localPort); sctpHeartbeatAck->setDestPort(remotePort); SCTPHeartbeatAckChunk* heartbeatAckChunk=new SCTPHeartbeatAckChunk("HEARTBEAT_ACK"); heartbeatAckChunk->setChunkType(HEARTBEAT_ACK); heartbeatAckChunk->setRemoteAddr(heartbeatChunk->getRemoteAddr()); heartbeatAckChunk->setTimeField(heartbeatChunk->getTimeField()); const int32 len = heartbeatChunk->getInfoArraySize(); if (len > 0){ heartbeatAckChunk->setInfoArraySize(len); for (int32 i=0; i<len; i++) heartbeatAckChunk->setInfo(i,heartbeatChunk->getInfo(i)); } heartbeatAckChunk->setBitLength(heartbeatChunk->getBitLength()); sctpHeartbeatAck->addChunk(heartbeatAckChunk); sctpEV3 << "sendHeartbeatAck: sendToIP from " << src << " to " << dest << endl; sendToIP(sctpHeartbeatAck, dest); }
void SCTPAssociation::sendIndicationToApp | ( | const int32 | code, | |
const int32 | value = 0 | |||
) | [protected] |
Utility: sends status indication (SCTP_I_xxx) to application
Definition at line 272 of file SCTPAssociationUtil.cc.
Referenced by dequeueAckedChunks(), process_RCV_Message(), process_SEND(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_RTX(), process_TIMEOUT_SHUTDOWN(), processTimer(), sendOnPath(), signalConnectionTimeout(), stateEntered(), and updateCounters().
{ sctpEV3<<"sendIndicationToApp: " << indicationName(code) << endl; cPacket* msg = new cPacket(indicationName(code)); msg->setKind(code); SCTPCommand* indication = new SCTPCommand(indicationName(code)); indication->setAssocId(assocId); indication->setLocalAddr(localAddr); indication->setRemoteAddr(remoteAddr); if (code == SCTP_I_SENDQUEUE_ABATED) { indication->setNumMsgs(value); } msg->setControlInfo(indication); sctpMain->send(msg, "to_appl", appGateIndex); }
void SCTPAssociation::sendInit | ( | ) | [protected] |
Methods for creating and sending chunks
Definition at line 339 of file SCTPAssociationUtil.cc.
Referenced by process_ASSOCIATE().
{ //RoutingTableAccess routingTableAccess; InterfaceTableAccess interfaceTableAccess; AddressVector adv; uint32 length = SCTP_INIT_CHUNK_LENGTH; if (remoteAddr.isUnspecified() || remotePort==0) opp_error("Error processing command ASSOCIATE: foreign socket unspecified"); if (localPort==0) opp_error("Error processing command ASSOCIATE: local port unspecified"); state->setPrimaryPath(getPath(remoteAddr)); // create message consisting of INIT chunk SCTPMessage *sctpmsg = new SCTPMessage(); sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); SCTPInitChunk *initChunk = new SCTPInitChunk("INIT"); initChunk->setChunkType(INIT); initChunk->setInitTag((uint32)(fmod(intrand(INT32_MAX), 1.0+(double)(unsigned)0xffffffffUL)) & 0xffffffffUL); peerVTag = initChunk->getInitTag(); sctpEV3<<"INIT from "<<localAddr<<":InitTag="<<peerVTag<<"\n"; initChunk->setA_rwnd(sctpMain->par("arwnd")); state->localRwnd = (long)sctpMain->par("arwnd"); initChunk->setNoOutStreams(outboundStreams); initChunk->setNoInStreams(inboundStreams); initChunk->setInitTSN(1000); state->nextTSN=initChunk->getInitTSN(); state->lastTSN = initChunk->getInitTSN() + state->numRequests - 1; initTsn=initChunk->getInitTSN(); IInterfaceTable *ift = interfaceTableAccess.get(); sctpEV3<<"add local address\n"; if (localAddressList.front() == IPvXAddress("0.0.0.0")) { for (int32 i=0; i<ift->getNumInterfaces(); ++i) { if (ift->getInterface(i)->ipv4Data()!=NULL) { adv.push_back(ift->getInterface(i)->ipv4Data()->getIPAddress()); } else if (ift->getInterface(i)->ipv6Data()!=NULL) { for (int32 j=0; j<ift->getInterface(i)->ipv6Data()->getNumAddresses(); j++) { sctpEV3<<"add address "<<ift->getInterface(i)->ipv6Data()->getAddress(j)<<"\n"; adv.push_back(ift->getInterface(i)->ipv6Data()->getAddress(j)); } } } } else { adv = localAddressList; sctpEV3<<"gebundene Adresse "<<localAddr<<" wird hinzugefuegt\n"; } uint32 addrNum=0; bool friendly = false; if (remoteAddr.isIPv6()) { for (AddressVector::iterator i=adv.begin(); i!=adv.end(); ++i) { if (!friendly) { initChunk->setAddressesArraySize(addrNum+1); initChunk->setAddresses(addrNum++,(*i)); length+=20; } sctpMain->addLocalAddress(this, (*i)); state->localAddresses.push_back((*i)); if (localAddr.isUnspecified()) localAddr=(*i); } } else { uint32 rlevel = getLevel(remoteAddr); sctpEV3<<"level of remote address="<<rlevel<<"\n"; for (AddressVector::iterator i=adv.begin(); i!=adv.end(); ++i) { sctpEV3<<"level of address "<<(*i)<<" = "<<getLevel((*i))<<"\n"; if (getLevel((*i))>=rlevel) { initChunk->setAddressesArraySize(addrNum+1); initChunk->setAddresses(addrNum++,(*i)); length+=8; sctpMain->addLocalAddress(this, (*i)); state->localAddresses.push_back((*i)); if (localAddr.get4().getInt()==0) localAddr=(*i); } else if (rlevel==4 && getLevel((*i))==3 && friendly) { sctpMain->addLocalAddress(this, (*i)); state->localAddresses.push_back((*i)); if (localAddr.get4().getInt()==0) localAddr=(*i); } } } sctpMain->printInfoConnMap(); initChunk->setBitLength(length*8); sctpmsg->addChunk(initChunk); // set path variables if (remoteAddressList.size()>0) { for (AddressVector::iterator it=remoteAddressList.begin(); it!=remoteAddressList.end(); it++) { sctpEV3<<__LINE__<<" get new path for "<<(*it)<<"\n"; SCTPPathVariables* path = new SCTPPathVariables((*it), this); sctpPathMap[(*it)] = path; qCounter.roomTransQ[(*it)] = 0; qCounter.bookedTransQ[(*it)] = 0; qCounter.roomRetransQ[(*it)] = 0; } } else { sctpEV3<<__LINE__<<" get new path for "<<remoteAddr<<"\n"; SCTPPathVariables* path = new SCTPPathVariables(remoteAddr, this); sctpPathMap[remoteAddr] = path; qCounter.roomTransQ[remoteAddr] = 0; qCounter.bookedTransQ[remoteAddr] = 0; qCounter.roomRetransQ[remoteAddr] = 0; } // send it state->initChunk=check_and_cast<SCTPInitChunk *>(initChunk->dup()); state->initChunk->setName("StateInitChunk"); printSctpPathMap(); sctpEV3<<getFullPath()<<" sendInit: localVTag="<<localVTag<<" peerVTag="<<peerVTag<<"\n"; sendToIP(sctpmsg); sctpMain->assocList.push_back(this); }
void SCTPAssociation::sendInitAck | ( | SCTPInitChunk * | initchunk | ) | [protected] |
Definition at line 487 of file SCTPAssociationUtil.cc.
Referenced by processInitArrived().
{ uint32 length = SCTP_INIT_CHUNK_LENGTH; state->setPrimaryPath(getPath(remoteAddr)); // create segment SCTPMessage *sctpinitack = new SCTPMessage(); sctpinitack->setBitLength(SCTP_COMMON_HEADER*8); sctpinitack->setSrcPort(localPort); sctpinitack->setDestPort(remotePort); sctpEV3<<"sendInitAck at "<<localAddr<<". Provided InitTag="<<initChunk->getInitTag()<<"\n"; SCTPInitAckChunk *initAckChunk = new SCTPInitAckChunk("INIT_ACK"); initAckChunk->setChunkType(INIT_ACK); SCTPCookie *cookie = new SCTPCookie("CookieUtil"); cookie->setCreationTime(simTime()); cookie->setLocalTieTagArraySize(32); cookie->setPeerTieTagArraySize(32); if (fsm->getState()==SCTP_S_CLOSED) { while (peerVTag==0) { peerVTag = (uint32)intrand(INT32_MAX); } initAckChunk->setInitTag(peerVTag); initAckChunk->setInitTSN(2000); state->nextTSN=initAckChunk->getInitTSN(); state->lastTSN = initAckChunk->getInitTSN() + state->numRequests - 1; cookie->setLocalTag(localVTag); cookie->setPeerTag(peerVTag); for (int32 i=0; i<32; i++) { cookie->setLocalTieTag(i,0); cookie->setPeerTieTag(i,0); } sctpinitack->setTag(localVTag); sctpEV3<<"state=closed: localVTag="<<localVTag<<" peerVTag="<<peerVTag<<"\n"; } else if (fsm->getState()==SCTP_S_COOKIE_WAIT || fsm->getState()==SCTP_S_COOKIE_ECHOED) { initAckChunk->setInitTag(peerVTag); sctpEV3<<"different state:set InitTag in InitAck: "<<initAckChunk->getInitTag()<<"\n"; initAckChunk->setInitTSN(state->nextTSN); initPeerTsn=initChunk->getInitTSN(); state->cTsnAck = initPeerTsn - 1; cookie->setLocalTag(initChunk->getInitTag()); cookie->setPeerTag(peerVTag); for (int32 i=0; i<32; i++) { cookie->setPeerTieTag(i,(uint8)(intrand(256))); state->peerTieTag[i] = cookie->getPeerTieTag(i); if (fsm->getState()==SCTP_S_COOKIE_ECHOED) { cookie->setLocalTieTag(i,(uint8)(intrand(256))); state->localTieTag[i] = cookie->getLocalTieTag(i); } else cookie->setLocalTieTag(i,0); } sctpinitack->setTag(initChunk->getInitTag()); sctpEV3<<"VTag in InitAck: "<<sctpinitack->getTag()<<"\n"; } else { sctpEV3<<"other state\n"; uint32 tag=0; while (tag==0) { tag = (uint32)(fmod(intrand(INT32_MAX), 1.0+(double)(unsigned)0xffffffffUL)) & 0xffffffffUL; } initAckChunk->setInitTag(tag); initAckChunk->setInitTSN(state->nextTSN); cookie->setLocalTag(localVTag); cookie->setPeerTag(peerVTag); for (int32 i=0; i<32; i++) { cookie->setPeerTieTag(i,state->peerTieTag[i]); cookie->setLocalTieTag(i,state->localTieTag[i]); } sctpinitack->setTag(initChunk->getInitTag()); } cookie->setBitLength(SCTP_COOKIE_LENGTH*8); initAckChunk->setStateCookie(cookie); initAckChunk->setCookieArraySize(0); initAckChunk->setA_rwnd(sctpMain->par("arwnd")); state->localRwnd = (long)sctpMain->par("arwnd"); initAckChunk->setNoOutStreams((unsigned int)min(outboundStreams,initChunk->getNoInStreams())); initAckChunk->setNoInStreams((unsigned int)min(inboundStreams,initChunk->getNoOutStreams())); initTsn=initAckChunk->getInitTSN(); uint32 addrNum=0; bool friendly = false; if (!friendly) for (AddressVector::iterator k=state->localAddresses.begin(); k!=state->localAddresses.end(); ++k) { initAckChunk->setAddressesArraySize(addrNum+1); initAckChunk->setAddresses(addrNum++,(*k)); length+=8; } uint32 unknownLen = initChunk->getUnrecognizedParametersArraySize(); if (unknownLen>0) { sctpEV3<<"Found unrecognized Parameters in INIT chunk with a length of "<<unknownLen<<" bytes.\n"; initAckChunk->setUnrecognizedParametersArraySize(unknownLen); for (uint32 i=0; i<unknownLen; i++) initAckChunk->setUnrecognizedParameters(i,initChunk->getUnrecognizedParameters(i)); length+=unknownLen; } else initAckChunk->setUnrecognizedParametersArraySize(0); initAckChunk->setBitLength((length+initAckChunk->getCookieArraySize())*8 + cookie->getBitLength()); inboundStreams = ((initChunk->getNoOutStreams()<initAckChunk->getNoInStreams())?initChunk->getNoOutStreams():initAckChunk->getNoInStreams()); outboundStreams = ((initChunk->getNoInStreams()<initAckChunk->getNoOutStreams())?initChunk->getNoInStreams():initAckChunk->getNoOutStreams()); (this->*ssFunctions.ssInitStreams)(inboundStreams, outboundStreams); sctpinitack->addChunk(initAckChunk); if (fsm->getState()==SCTP_S_CLOSED) { sendToIP(sctpinitack, state->initialPrimaryPath); } else { sendToIP(sctpinitack); } sctpMain->assocList.push_back(this); printSctpPathMap(); }
void SCTPAssociation::sendOnAllPaths | ( | SCTPPathVariables * | firstPath | ) |
Definition at line 193 of file SCTPAssociationSendAll.cc.
Referenced by process_ABORT(), process_CLOSE(), process_RCV_Message(), process_TIMEOUT_RTX(), sendShutdownAck(), and stateEntered().
{ // ------ Send on provided path first ... ----------------------------- if(firstPath != NULL) { sendOnPath(firstPath); } // ------ ... then, try sending on all other paths -------------------- for (SCTPPathMap::iterator iterator = sctpPathMap.begin(); iterator != sctpPathMap.end(); ++iterator) { SCTPPathVariables* path = iterator->second; if(path != firstPath) { sendOnPath(path); } } }
void SCTPAssociation::sendOnPath | ( | SCTPPathVariables * | pathId, | |
const bool | firstPass = true | |||
) |
Utility: Send data from sendQueue.
Definition at line 305 of file SCTPAssociationSendAll.cc.
Referenced by SCTPAlg::sendCommandInvoked(), and sendOnAllPaths().
{ // ====== Variables ====================================================== SCTPPathVariables* path = NULL; // Path to send next message to SCTPMessage* sctpMsg = NULL; SCTPSackChunk* sackChunk = NULL; SCTPDataChunk* chunkPtr = NULL; uint16 chunksAdded = 0; uint16 dataChunksAdded = 0; uint32 totalChunksSent = 0; uint32 totalPacketsSent = 0; uint32 packetBytes = 0; uint32 outstandingBytes = 0; uint32 tcount = 0; // Bytes in transmission queue on the selected path uint32 scount = 0; // Bytes in send streams int32 bytesToSend = 0; bool headerCreated = false; bool rtxActive = false; bool sendOneMorePacket = false; bool sendingAllowed = true; bool authAdded = false; bool sackAdded = false; // ====== Obtain path ==================================================== sctpEV3 << endl << "##### sendAll("; if(pathId) { sctpEV3 << pathId->remoteAddress; } sctpEV3 << ") #####" << endl; while(sendingAllowed) { headerCreated = false; if (state->bytesToRetransmit > 0) { // There are bytes in the transmissionQ. They have to be sent first. path = choosePathForRetransmission(); assert(path != NULL); rtxActive = true; } else { if (pathId == NULL) { // No path given => use primary path. path = state->getPrimaryPath(); } else { path = pathId; } } outstandingBytes = path->outstandingBytes; assert((int32)outstandingBytes >= 0); CounterMap::iterator tq = qCounter.roomTransQ.find(path->remoteAddress); tcount = tq->second; scount = qCounter.roomSumSendStreams; // includes header and padding sctpEV3 << "\nsendAll: on " << path->remoteAddress << ":" << " tcount=" << tcount << " scount=" << scount << " nextTSN=" << state->nextTSN << endl; bool sackOnly; bool sackWithData; timeForSack(sackOnly, sackWithData); if (tcount == 0 && scount == 0) { // ====== No DATA chunks to send =================================== sctpEV3 << "No DATA chunk available!" << endl; if (!sackOnly) { // SACK?, no data to send sctpEV3 << "No SACK to send either" << endl; return; } else { bytes.bytesToSend = 0; } } else { bytesAllowedToSend(path, firstPass); } bytesToSend = bytes.bytesToSend; // As there is at least a SACK to be sent, a header can be created if (state->sctpMsg) // ??? Robin: Ist das in Ordnung??? { loadPacket(path, &sctpMsg, &chunksAdded, &dataChunksAdded, &packetBytes, &authAdded); headerCreated = true; } else if (bytesToSend > 0 || bytes.chunk || bytes.packet || sackWithData || sackOnly) { sctpMsg = new SCTPMessage("send"); //printf("%d Name=%s Pointer=%p\n", __LINE__, sctpMsg->getName(), sctpMsg); sctpMsg->setByteLength(SCTP_COMMON_HEADER); packetBytes = 0; headerCreated = true; } if (sackWithData || sackOnly) { // SACK can be sent assert(headerCreated==true); sackChunk = createSack(); chunksAdded++; totalChunksSent++; // ------ Create AUTH chunk, if necessary -------------------------- // ------ Add SACK chunk ------------------------------------------- sctpMsg->addChunk(sackChunk); sackAdded = true; if (sackOnly) // ????? Robin: SACK mit FORWARD_TSN???? { // send the packet and leave //printf("%d Name=%s Pointer=%p, sctpMsg\n", __LINE__, sctpMsg->getName(), sctpMsg); state->ackState = 0; // Stop SACK timer if it is running... stopTimer(SackTimer); sctpAlgorithm->sackSent(); state->sackAllowed = false; sendToIP(sctpMsg, state->lastDataSourceAddress); if ((bytesToSend > 0) || (bytes.chunk) || (bytes.packet)) { sctpMsg = new SCTPMessage("send"); sctpMsg->setByteLength(SCTP_COMMON_HEADER); packetBytes = 0; headerCreated = true; sackAdded = false; } else return; } } // #################################################################### // #### Data Transmission #### // #################################################################### bool packetFull = false; while(!packetFull && headerCreated) { assert(headerCreated == true); sctpEV3 << "bytesToSend=" << bytesToSend << " bytes.chunk=" << bytes.chunk << " bytes.packet=" << bytes.packet << endl; // ====== How many bytes may be transmitted in next packet? ======== int32 allowance = path->pmtu; // Default behaviour: send 1 path MTU if ((bytesToSend > 0) || (bytes.chunk) || (bytes.packet)) { // Allow 1 more MTU } else { // No more sending allowed. allowance = 0; bytesToSend = 0; } if ((allowance > 0) || (bytes.chunk) || (bytes.packet)) { bool firstTime = false; // Is DATA chunk send for the first time? // ====== Retransmission ======================================== // T.D. 05.01.2010: If bytes.packet is true, one packet is allowed // to be retransmitted! SCTPDataVariables* datVar = getOutboundDataChunk(path, path->pmtu - sctpMsg->getByteLength() - 20, (bytes.packet == true) ? path->pmtu : allowance); if (chunksAdded==1 && sackAdded && !sackOnly && datVar==NULL) { sctpMsg->removeChunk(); delete sackChunk; datVar = getOutboundDataChunk(path, path->pmtu - sctpMsg->getByteLength() - 20, (bytes.packet == true) ? path->pmtu : allowance); } if (datVar != NULL) { assert(datVar->getNextDestinationPath() == path); datVar->numberOfRetransmissions++; if (chunkHasBeenAcked(datVar) == false) { sctpEV3 << simTime() << ": Retransmission #" << datVar->numberOfRetransmissions << " of TSN " << datVar->tsn << " on path " << datVar->getNextDestination() << " (last was " << datVar->getLastDestination() << ")" << endl; datVar->countsAsOutstanding = true; datVar->hasBeenReneged = false; increaseOutstandingBytes(datVar, path); // NOTE: path == datVar->getNextDestinationPath() } } // ====== First Transmission ==================================== else if ( ((scount > 0) && (!state->nagleEnabled)) || // Data to send and Nagle off ((uint32)scount >= path->pmtu - 32 - 20) || // Data to fill at least one path MTU ((scount > 0) && (state->nagleEnabled) && (outstandingBytes == 0)) ) { // Data to send, Nagle on and no outstanding bytes if(path == state->getPrimaryPath()) { // ------ Dequeue data message ---------------------------- sctpEV3 << "sendAll: sctpMsg->length=" << sctpMsg->getByteLength() << " length datMsg=" << path->pmtu-sctpMsg->getByteLength() - 20 << endl; SCTPDataMsg* datMsg = dequeueOutboundDataMsg(path->pmtu-sctpMsg->getByteLength() - 20, allowance); if (chunksAdded==1 && sackAdded && !sackOnly && datMsg==NULL) { sctpMsg->removeChunk(); delete sackChunk; datMsg = dequeueOutboundDataMsg(path->pmtu-sctpMsg->getByteLength() - 20, allowance); } // ------ Handle data message ----------------------------- if (datMsg) { firstTime = true; state->queuedMessages--; if ((state->queueLimit > 0) && (state->queuedMessages < state->queueLimit) && (state->queueUpdate == false)) { // Tell upper layer readiness to accept more data sendIndicationToApp(SCTP_I_SEND_MSG); state->queueUpdate = true; } datVar = makeDataVarFromDataMsg(datMsg, path); delete datMsg; sctpEV3 << "sendAll: chunk " << datVar << " dequeued from StreamQ " << datVar->sid << ": tsn=" << datVar->tsn << ", bytes now " << qCounter.roomSumSendStreams << "\n"; } // ------ No data message has been dequeued --------------- else { // ------ Are there any chunks to send? ---------------- if (chunksAdded == 0) { // No -> nothing more to do. if (state->sctpMsg == sctpMsg) { state->sctpMsg = NULL; state->packetBytes = 0; } packetFull = true; // chunksAdded==0, packetFull==true => leave inner while loop } else { // Yes. if (state->nagleEnabled && (outstandingBytes > 0) && nextChunkFitsIntoPacket(path->pmtu-sctpMsg->getByteLength() - 20) && (sctpMsg->getByteLength() < path->pmtu - 32 - 20) && (tcount == 0)) { storePacket(path, sctpMsg, chunksAdded, dataChunksAdded, packetBytes, authAdded); packetBytes = 0; } //chunksAdded = 0; packetFull = true; // chunksAdded==0, packetFull==true => leave inner while loop sctpEV3 << "sendAll: packetFull: msg length = " << sctpMsg->getBitLength() / 8 + 20 << "\n"; } } } } // ------ Handle DATA chunk ------------------------------------- if (datVar != NULL && !packetFull) { // ------ Assign TSN ----------------------------------------- if (firstTime) { assert(datVar->tsn == 0); datVar->tsn = state->nextTSN; sctpEV3 << "sendAll: set TSN=" << datVar->tsn << " sid=" << datVar->sid << ", ssn=" << datVar->ssn << "\n"; state->nextTSN++; } SCTP::AssocStatMap::iterator iterator = sctpMain->assocStatMap.find(assocId); iterator->second.transmittedBytes += datVar->len / 8; datVar->setLastDestination(path); datVar->countsAsOutstanding = true; datVar->hasBeenReneged = false; datVar->sendTime = simTime(); //I.R. to send Fast RTX just once a RTT // ------ First transmission of datVar ----------------------- if (datVar->numberOfTransmissions == 0) { sctpEV3 << "sendAll: " << simTime() << " firstTime, TSN " << datVar->tsn << ": lastDestination set to " << datVar->getLastDestination() << endl; if (!state->firstDataSent) { state->firstDataSent = true; } sctpEV3 << "sendAll: insert in retransmissionQ tsn=" << datVar->tsn << "\n"; if(!retransmissionQ->checkAndInsertChunk(datVar->tsn, datVar)) { opp_error("Cannot add datVar to retransmissionQ!"); // Falls es hier aufschlaegt, muss ueberlegt werden, ob es OK ist, dass datVars nicht eingefuegt werden koennen. } else { sctpEV3 << "sendAll: size of retransmissionQ=" << retransmissionQ->getQueueSize() << "\n"; unackChunk(datVar); increaseOutstandingBytes(datVar, path); } } /* datVar is already in the retransmissionQ */ datVar->numberOfTransmissions++; datVar->gapReports = 0; datVar->hasBeenFastRetransmitted = false; sctpEV3<<"sendAll(): adding new outbound data datVar to packet (tsn="<<datVar->tsn<<")...!!!\n"; chunkPtr = transformDataChunk(datVar); /* update counters */ totalChunksSent++; chunksAdded++; dataChunksAdded++; sctpMsg->addChunk(chunkPtr); if(nextChunkFitsIntoPacket(path->pmtu - sctpMsg->getByteLength() - 20) == false) { // ???? Robin: Ist diese Annahme so richtig? packetFull = true; } state->peerRwnd -= datVar->booksize; if ((bytes.chunk == false) && (bytes.packet == false)) { bytesToSend -= datVar->booksize; } else if (bytes.chunk) { bytes.chunk = false; } else if ((bytes.packet) && (packetFull)) { bytes.packet = false; } if (bytesToSend <= 0) { if ((!packetFull) && (qCounter.roomSumSendStreams > path->pmtu - 32 - 20 || tcount > 0)) { sendOneMorePacket = true; bytes.packet = true; sctpEV3 << "sendAll: one more packet allowed\n"; } else { if (state->nagleEnabled && (outstandingBytes > 0) && nextChunkFitsIntoPacket(path->pmtu-sctpMsg->getByteLength() - 20) && (sctpMsg->getByteLength() < path->pmtu - 32 - 20) && (tcount == 0)) { storePacket(path, sctpMsg, chunksAdded, dataChunksAdded, packetBytes, authAdded); packetBytes = 0; chunksAdded = 0; packetFull = true; // chunksAdded==0, packetFull==true => leave inner while loop } else { packetFull = true; } } bytesToSend = 0; } else if ((qCounter.roomSumSendStreams == 0) && (tq->second==0)) { packetFull = true; sctpEV3 << "sendAll: no data in send and transQ: packet full\n"; } sctpEV3 << "sendAll: bytesToSend after reduction: " << bytesToSend << "\n"; } // ------ There is no DATA chunk, only control chunks possible -- else { // ????? Robin: Kann dieser Fall wirklich eintreten? if (chunksAdded == 0) { // Nothing to do -> return packetFull = true; // chunksAdded==0, packetFull==true => leave inner while loop } else { packetFull = true; sctpEV3 << "sendAll: packetFull: msg length = " << sctpMsg->getBitLength() / 8 + 20 << "\n"; datVar = NULL; } } // ====== Send packet =========================================== if (packetFull) { if(chunksAdded == 0) { // Nothing to send delete sctpMsg; sendingAllowed = false; // sendingAllowed==false => leave outer while loop } else { sctpEV3 << "sendAll: " << simTime() << " packet full:" << " totalLength=" << sctpMsg->getBitLength() / 8 + 20 << ", path=" << path->remoteAddress << " " << dataChunksAdded << " chunks added, outstandingBytes now " << path->outstandingBytes << "\n"; /* new chunks would exceed MTU, so we send old packet and build a new one */ /* this implies that at least one data chunk is send here */ if (dataChunksAdded > 0) { if (!path->T3_RtxTimer->isScheduled()) { // Start retransmission timer, if not scheduled before startTimer(path->T3_RtxTimer, path->pathRto); } else { sctpEV3 << "sendAll: RTX Timer already scheduled -> no need to schedule it\n"; } } if (sendOneMorePacket) { sendOneMorePacket = false; bytesToSend = 0; bytes.packet = false; } sendToIP(sctpMsg, path->remoteAddress); pmDataIsSentOn(path); totalPacketsSent++; // ------ Reset status ------------------------------------ if (state->sctpMsg == sctpMsg) { state->sctpMsg = NULL; path->outstandingBytes += packetBytes; packetBytes = 0; } headerCreated = false; chunksAdded = 0; dataChunksAdded = 0; firstTime = false; sctpEV3 << "sendAll: sending Packet to path " << path->remoteAddress << " scount=" << scount << " tcount=" << tcount << " bytesToSend=" << bytesToSend << endl; } } sctpEV3 << "sendAll: still " << bytesToSend << " bytes to send, headerCreated=" << headerCreated << endl; } // if (bytesToSend > 0 || bytes.chunk || bytes.packet) else { packetFull = true; // Leave inner while loop delete sctpMsg; // T.D. 19.01.2010: Free unsent message } sctpEV3 << "packetFull=" << packetFull << endl; } // while(!packetFull) sctpEV3 << "bytesToSend=" << bytesToSend << " bytes.chunk=" << bytes.chunk << " bytes.packet=" << bytes.packet << endl; if (!(bytesToSend > 0 || bytes.chunk || bytes.packet)) { sendingAllowed = false; } } // while(sendingAllowed) sctpEV3 << "sendAll: nothing more to send... BYE!\n"; }
void SCTPAssociation::sendSack | ( | ) | [protected] |
Definition at line 973 of file SCTPAssociationUtil.cc.
Referenced by process_RCV_Message(), processTimer(), and pushUlp().
{ SCTPSackChunk* sackChunk; sctpEV3 << "Sending SACK" << endl; /* sack timer has expired, reset flag, and send SACK */ stopTimer(SackTimer); state->ackState = 0; sackChunk = createSack(); SCTPMessage* sctpmsg = new SCTPMessage(); sctpmsg->setBitLength(SCTP_COMMON_HEADER*8); sctpmsg->addChunk(sackChunk); // Return the SACK to the address where we last got a data chunk from sendToIP(sctpmsg, state->lastDataSourceAddress); }
void SCTPAssociation::sendShutdown | ( | ) | [protected] |
Definition at line 797 of file SCTPAssociationUtil.cc.
Referenced by process_CLOSE(), process_RCV_Message(), and stateEntered().
{ SCTPMessage *msg = new SCTPMessage(); msg->setBitLength(SCTP_COMMON_HEADER*8); sctpEV3<<"SCTPAssociationUtil:sendShutdown localPort="<<localPort<<" remotePort="<<remotePort<<"\n"; msg->setSrcPort(localPort); msg->setDestPort(remotePort); SCTPShutdownChunk* shutdownChunk = new SCTPShutdownChunk("SHUTDOWN"); shutdownChunk->setChunkType(SHUTDOWN); //shutdownChunk->setCumTsnAck(state->lastTsnAck); shutdownChunk->setCumTsnAck(state->cTsnAck); shutdownChunk->setBitLength(SCTP_SHUTDOWN_CHUNK_LENGTH*8); state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT; state->initRetransCounter = 0; stopTimer(T5_ShutdownGuardTimer); startTimer(T5_ShutdownGuardTimer,SHUTDOWN_GUARD_TIMEOUT); stopTimer(T2_ShutdownTimer); startTimer(T2_ShutdownTimer,state->initRexmitTimeout); state->shutdownChunk=check_and_cast<SCTPShutdownChunk*>(shutdownChunk->dup()); msg->addChunk(shutdownChunk); sendToIP(msg, remoteAddr); performStateTransition(SCTP_E_NO_MORE_OUTSTANDING); }
void SCTPAssociation::sendShutdownAck | ( | const IPvXAddress & | dest | ) | [protected] |
Definition at line 735 of file SCTPAssociationUtil.cc.
Referenced by performStateTransition(), process_CLOSE(), process_RCV_Message(), processAppCommand(), and stateEntered().
{ sendOnAllPaths(getPath(dest)); if (getOutstandingBytes() == 0) { performStateTransition(SCTP_E_NO_MORE_OUTSTANDING); SCTPMessage *sctpshutdownack = new SCTPMessage(); sctpshutdownack->setBitLength(SCTP_COMMON_HEADER*8); sctpEV3 << "SCTPAssociationUtil:sendShutdownACK" << endl; sctpshutdownack->setSrcPort(localPort); sctpshutdownack->setDestPort(remotePort); SCTPShutdownAckChunk* shutdownAckChunk=new SCTPShutdownAckChunk("SHUTDOWN_ACK"); shutdownAckChunk->setChunkType(SHUTDOWN_ACK); shutdownAckChunk->setBitLength(SCTP_COOKIE_ACK_LENGTH*8); sctpshutdownack->addChunk(shutdownAckChunk); state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT; state->initRetransCounter = 0; stopTimer(T2_ShutdownTimer); startTimer(T2_ShutdownTimer,state->initRexmitTimeout); stopTimer(T5_ShutdownGuardTimer); startTimer(T5_ShutdownGuardTimer,SHUTDOWN_GUARD_TIMEOUT); state->shutdownAckChunk=check_and_cast<SCTPShutdownAckChunk*>(shutdownAckChunk->dup()); sendToIP(sctpshutdownack, dest); } }
void SCTPAssociation::sendShutdownComplete | ( | ) | [protected] |
Definition at line 762 of file SCTPAssociationUtil.cc.
Referenced by process_RCV_Message().
{ SCTPMessage *sctpshutdowncomplete = new SCTPMessage(); sctpshutdowncomplete->setBitLength(SCTP_COMMON_HEADER*8); sctpEV3<<"SCTPAssociationUtil:sendShutdownComplete\n"; sctpshutdowncomplete->setSrcPort(localPort); sctpshutdowncomplete->setDestPort(remotePort); SCTPShutdownCompleteChunk* shutdownCompleteChunk=new SCTPShutdownCompleteChunk("SHUTDOWN_COMPLETE"); shutdownCompleteChunk->setChunkType(SHUTDOWN_COMPLETE); shutdownCompleteChunk->setTBit(0); shutdownCompleteChunk->setBitLength(SCTP_SHUTDOWN_ACK_LENGTH*8); sctpshutdowncomplete->addChunk(shutdownCompleteChunk); sendToIP(sctpshutdowncomplete); }
void SCTPAssociation::sendToApp | ( | cPacket * | msg | ) | [protected] |
Utility: sends packet to application
Definition at line 313 of file SCTPAssociationUtil.cc.
Referenced by pathStatusIndication(), process_STATUS(), pushUlp(), and sendDataArrivedNotification().
{ sctpMain->send(msg, "to_appl", appGateIndex); }
void SCTPAssociation::sendToIP | ( | SCTPMessage * | sctpmsg, | |
const IPvXAddress & | dest, | |||
const bool | qs = false | |||
) | [protected] |
Utility: adds control info to message and sends it to IP
Definition at line 214 of file SCTPAssociationUtil.cc.
Referenced by retransmitCookieEcho(), retransmitInit(), retransmitShutdown(), retransmitShutdownAck(), sendAbort(), sendCookieAck(), sendCookieEcho(), sendHeartbeat(), sendHeartbeatAck(), sendInit(), sendInitAck(), sendOnPath(), sendSack(), sendShutdown(), sendShutdownAck(), and sendShutdownComplete().
{ // Final touches on the segment before sending sctpmsg->setSrcPort(localPort); sctpmsg->setDestPort(remotePort); sctpmsg->setChecksumOk(true); const SCTPChunk* chunk = (const SCTPChunk*)(sctpmsg->peekFirstChunk()); if (chunk->getChunkType() == ABORT) { const SCTPAbortChunk* abortChunk = check_and_cast<const SCTPAbortChunk *>(chunk); if (abortChunk->getT_Bit() == 1) { sctpmsg->setTag(peerVTag); } else { sctpmsg->setTag(localVTag); } } else if (sctpmsg->getTag() == 0) { sctpmsg->setTag(localVTag); } if ((bool)sctpMain->par("udpEncapsEnabled")) { sctpmsg->setKind(UDP_C_DATA); UDPControlInfo* controlInfo = new UDPControlInfo(); controlInfo->setSrcPort(9899); controlInfo->setDestAddr(remoteAddr.get4()); controlInfo->setDestPort(9899); sctpmsg->setControlInfo(controlInfo); } else { if (dest.isIPv6()) { IPv6ControlInfo* controlInfo = new IPv6ControlInfo(); controlInfo->setProtocol(IP_PROT_SCTP); controlInfo->setSrcAddr(IPv6Address()); controlInfo->setDestAddr(dest.get6()); sctpmsg->setControlInfo(controlInfo); sctpMain->send(sctpmsg, "to_ipv6"); } else { IPControlInfo* controlInfo = new IPControlInfo(); controlInfo->setProtocol(IP_PROT_SCTP); controlInfo->setSrcAddr(IPAddress("0.0.0.0")); controlInfo->setDestAddr(dest.get4()); sctpmsg->setControlInfo(controlInfo); sctpMain->send(sctpmsg, "to_ip"); } recordInPathVectors(sctpmsg, dest); } sctpEV3 << "Sent to " << dest << endl; }
void SCTPAssociation::sendToIP | ( | SCTPMessage * | sctpmsg, | |
const bool | qs = false | |||
) | [inline, protected] |
Definition at line 726 of file SCTPAssociation.h.
{ sendToIP(sctpmsg, remoteAddr, qs); }
void SCTPAssociation::signalConnectionTimeout | ( | ) | [protected] |
Utility: signal to user that connection timed out
Definition at line 267 of file SCTPAssociationUtil.cc.
static int16 SCTPAssociation::ssnGt | ( | const uint16 | ssn1, | |
const uint16 | ssn2 | |||
) | [inline, static, protected] |
Definition at line 837 of file SCTPAssociation.h.
Referenced by makeRoomForTsn().
{ return ((int16)(ssn1-ssn2)>0); }
void SCTPAssociation::startTimer | ( | cMessage * | timer, | |
const simtime_t & | timeout | |||
) | [protected] |
Definition at line 1534 of file SCTPAssociationRcvMessage.cc.
Referenced by pmDataIsSentOn(), pmStartPathManagement(), process_ASSOCIATE(), process_RCV_Message(), process_TIMEOUT_HEARTBEAT_INTERVAL(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_SHUTDOWN(), processInitAckArrived(), processSackArrived(), scheduleSack(), sendOnPath(), sendShutdown(), sendShutdownAck(), and tsnWasReneged().
{ sctpEV3 << "startTimer " << timer->getName() << " with timeout " << timeout << " to expire at " << simTime() + timeout << endl; scheduleTimeout(timer, timeout); }
void SCTPAssociation::stateEntered | ( | int32 | state | ) | [protected] |
Definition at line 669 of file SCTPAssociationBase.cc.
Referenced by performStateTransition().
{ switch (status) { case SCTP_S_COOKIE_WAIT: break; case SCTP_S_ESTABLISHED: { sctpEV3 << "State ESTABLISHED entered" << endl; stopTimer(T1_InitTimer); if (state->initChunk) { delete state->initChunk; } state->nagleEnabled = (bool)sctpMain->par("nagleEnabled"); state->enableHeartbeats = (bool)sctpMain->par("enableHeartbeats"); state->numGapReports = sctpMain->par("numGapReports"); state->maxBurst = (uint32)sctpMain->par("maxBurst"); state->header = 0; state->swsLimit = (uint32)sctpMain->par("swsLimit"); state->fastRecoverySupported = (bool)sctpMain->par("fastRecoverySupported"); state->reactivatePrimaryPath = (bool)sctpMain->par("reactivatePrimaryPath"); sackPeriod = (double)sctpMain->par("sackPeriod"); sackFrequency = sctpMain->par("sackFrequency"); SCTP::AssocStat stat; stat.assocId = assocId; stat.start = simulation.getSimTime(); stat.stop = 0; stat.rcvdBytes = 0; stat.ackedBytes = 0; stat.sentBytes = 0; stat.transmittedBytes = 0; stat.numFastRtx = 0; stat.numT3Rtx = 0; stat.numDups = 0; stat.numPathFailures = 0; stat.numForwardTsn = 0; stat.lifeTime = 0; stat.throughput = 0; sctpMain->assocStatMap[stat.assocId] = stat; ccModule = sctpMain->par("ccModule"); switch (ccModule) { case RFC4960: { ccFunctions.ccInitParams = &SCTPAssociation::initCCParameters; ccFunctions.ccUpdateAfterSack = &SCTPAssociation::cwndUpdateAfterSack; ccFunctions.ccUpdateAfterCwndTimeout = &SCTPAssociation::cwndUpdateAfterCwndTimeout; ccFunctions.ccUpdateAfterRtxTimeout = &SCTPAssociation::cwndUpdateAfterRtxTimeout; ccFunctions.ccUpdateMaxBurst = &SCTPAssociation::cwndUpdateMaxBurst; ccFunctions.ccUpdateBytesAcked = &SCTPAssociation::cwndUpdateBytesAcked; break; } } pmStartPathManagement(); state->sendQueueLimit = (uint32)sctpMain->par("sendQueueLimit"); sendEstabIndicationToApp(); char str[128]; snprintf(str, sizeof(str), "Cumulated TSN Ack of Association %d", assocId); cumTsnAck = new cOutVector(str); snprintf(str, sizeof(str), "Number of Gap Blocks in Last SACK of Association %d", assocId); numGapBlocks = new cOutVector(str); snprintf(str, sizeof(str), "SendQueue of Association %d", assocId); sendQueue = new cOutVector(str); state->sendQueueLimit = (uint32)sctpMain->par("sendQueueLimit"); SCTP::VTagPair vtagPair; vtagPair.peerVTag = peerVTag; vtagPair.localVTag = localVTag; vtagPair.localPort = localPort; vtagPair.remotePort = remotePort; sctpMain->sctpVTagMap[assocId] = vtagPair; break; } case SCTP_S_CLOSED: { sendIndicationToApp(SCTP_I_CLOSED); break; } case SCTP_S_SHUTDOWN_PENDING: { if (getOutstandingBytes()==0 && transmissionQ->getQueueSize()==0 && qCounter.roomSumSendStreams==0) sendShutdown(); break; } case SCTP_S_SHUTDOWN_RECEIVED: { sctpEV3 << "Entered state SHUTDOWN_RECEIVED, osb=" << getOutstandingBytes() << ", transQ=" << transmissionQ->getQueueSize() << ", scount=" << qCounter.roomSumSendStreams << endl; if (getOutstandingBytes()==0 && transmissionQ->getQueueSize()==0 && qCounter.roomSumSendStreams==0) { sendShutdownAck(remoteAddr); } else { sendOnAllPaths(state->getPrimaryPath()); } break; } } }
const char * SCTPAssociation::stateName | ( | const int32 | state | ) | [static] |
Utility: returns name of SCTP_S_xxx constants
Definition at line 51 of file SCTPAssociationUtil.cc.
Referenced by performStateTransition(), printConnBrief(), process_RCV_Message(), process_STATUS(), process_TIMEOUT_INIT_REXMIT(), and processAppCommand().
{ #define CASE(x) case x: s=#x+7; break const char* s = "unknown"; switch (state) { CASE(SCTP_S_CLOSED); CASE(SCTP_S_COOKIE_WAIT); CASE(SCTP_S_COOKIE_ECHOED); CASE(SCTP_S_ESTABLISHED); CASE(SCTP_S_SHUTDOWN_PENDING); CASE(SCTP_S_SHUTDOWN_SENT); CASE(SCTP_S_SHUTDOWN_RECEIVED); CASE(SCTP_S_SHUTDOWN_ACK_SENT); } return s; #undef CASE }
void SCTPAssociation::stopTimer | ( | cMessage * | timer | ) |
Definition at line 1525 of file SCTPAssociationRcvMessage.cc.
Referenced by moveChunkToOtherPath(), pmDataIsSentOn(), pmStartPathManagement(), process_RCV_Message(), process_TIMEOUT_HEARTBEAT_INTERVAL(), processCookieAckArrived(), processHeartbeatAckArrived(), processInitAckArrived(), processSackArrived(), processTimer(), SCTP::removeAssociation(), removePath(), sendOnPath(), sendSack(), sendShutdown(), sendShutdownAck(), stateEntered(), and stopTimers().
{ ev << "stopTimer " << timer->getName() << endl; if (timer->isScheduled()) { cancelEvent(timer); } }
void SCTPAssociation::stopTimers | ( | ) |
Definition at line 1517 of file SCTPAssociationRcvMessage.cc.
Referenced by process_RCV_Message().
{ for (SCTPPathMap::iterator j = sctpPathMap.begin(); j != sctpPathMap.end(); j++) { stopTimer(j->second->HeartbeatTimer); stopTimer(j->second->HeartbeatIntervalTimer); } }
void SCTPAssociation::storePacket | ( | SCTPPathVariables * | pathVar, | |
SCTPMessage * | sctpMsg, | |||
const uint16 | chunksAdded, | |||
const uint16 | dataChunksAdded, | |||
const uint32 | packetBytes, | |||
const bool | authAdded | |||
) | [private] |
Definition at line 60 of file SCTPAssociationSendAll.cc.
Referenced by sendOnPath().
{ for (uint16 i = 0; i < sctpMsg->getChunksArraySize(); i++) { retransmissionQ->payloadQueue.find(((SCTPDataChunk*)sctpMsg->getChunks(i))->getTsn())->second->countsAsOutstanding = false; } state->sctpMsg = sctpMsg; state->chunksAdded = chunksAdded; state->dataChunksAdded = dataChunksAdded; state->packetBytes = packetBytes; sctpEV3 << "storePacket: path=" << pathVar->remoteAddress << " osb=" << pathVar->outstandingBytes << " -> " << pathVar->outstandingBytes - state->packetBytes << endl; assert(pathVar->outstandingBytes >= state->packetBytes); pathVar->outstandingBytes -= state->packetBytes; qCounter.roomSumSendStreams += state->packetBytes + (dataChunksAdded * SCTP_DATA_CHUNK_LENGTH); qCounter.bookedSumSendStreams += state->packetBytes; }
int32 SCTPAssociation::streamScheduler | ( | bool | peek | ) | [protected] |
Dealing with streams
Definition at line 62 of file SCTPSSFunctions.cc.
{ int32 sid, testsid; sctpEV3<<"Stream Scheduler: RoundRobin\n"; sid = -1; if ((state->ssLastDataChunkSizeSet == false || state->ssNextStream == false) && (sendStreams.find(state->lastStreamScheduled)->second->getUnorderedStreamQ()->length() > 0 || sendStreams.find(state->lastStreamScheduled)->second->getStreamQ()->length() > 0)) { sid = state->lastStreamScheduled; sctpEV3<<"Stream Scheduler: again sid " << sid << ".\n"; state->ssNextStream = true; } else { testsid = state->lastStreamScheduled; do { testsid = (testsid + 1) % outboundStreams; if (sendStreams.find(testsid)->second->getUnorderedStreamQ()->length() > 0 || sendStreams.find(testsid)->second->getStreamQ()->length() > 0) { sid = testsid; sctpEV3<<"Stream Scheduler: chose sid " << sid << ".\n"; if (!peek) state->lastStreamScheduled = sid; } } while (sid == -1 && testsid != (int32) state->lastStreamScheduled); } sctpEV3<<"streamScheduler sid="<<sid<<" lastStream="<<state->lastStreamScheduled<<" outboundStreams="<<outboundStreams<<" next="<<state->ssNextStream<<"\n"; state->ssLastDataChunkSizeSet = false; return sid; }
void SCTPAssociation::timeForSack | ( | bool & | sackOnly, | |
bool & | sackWithData | |||
) | [private] |
Definition at line 174 of file SCTPAssociationSendAll.cc.
Referenced by sendOnPath().
{ sackOnly = sackWithData = false; if (((state->numGaps > 0) || (state->dupList.size() > 0)) && (state->sackAllowed)) { // Schedule sending of SACKs at once, when we have fragments to report state->ackState = sackFrequency; sackOnly = sackWithData = true; // SACK necessary, regardless of data available } if (state->ackState >= sackFrequency) { sackOnly = sackWithData = true; // SACK necessary, regardless of data available } else if (SackTimer->isScheduled()) { sackOnly = false; sackWithData = true; // Only send SACK when data is present. } }
SCTPDataChunk * SCTPAssociation::transformDataChunk | ( | SCTPDataVariables * | chunk | ) | [protected] |
Manipulating chunks
Definition at line 1129 of file SCTPAssociationUtil.cc.
Referenced by sendOnPath().
{ SCTPDataChunk* dataChunk = new SCTPDataChunk("DATA"); SCTPSimpleMessage* msg = check_and_cast<SCTPSimpleMessage*>(chunk->userData->dup()); dataChunk->setChunkType(DATA); dataChunk->setBBit(chunk->bbit); dataChunk->setEBit(chunk->ebit); if (chunk->ordered) { dataChunk->setUBit(0); } else { dataChunk->setUBit(1); } dataChunk->setTsn(chunk->tsn); dataChunk->setSid(chunk->sid); dataChunk->setSsn(chunk->ssn); dataChunk->setPpid(chunk->ppid); dataChunk->setEnqueuingTime(chunk->enqueuingTime); dataChunk->setBitLength(SCTP_DATA_CHUNK_LENGTH*8); msg->setBitLength(chunk->len); dataChunk->encapsulate(msg); return dataChunk; }
static int32 SCTPAssociation::tsnBetween | ( | const uint32 | tsn1, | |
const uint32 | midtsn, | |||
const uint32 | tsn2 | |||
) | [inline, static, protected] |
Definition at line 835 of file SCTPAssociation.h.
Referenced by removeFromGapList(), tsnIsDuplicate(), and updateGapList().
{ return ((tsn2-tsn1)>=(midtsn-tsn1)); }
static int32 SCTPAssociation::tsnGe | ( | const uint32 | tsn1, | |
const uint32 | tsn2 | |||
) | [inline, static, protected] |
Definition at line 833 of file SCTPAssociation.h.
Referenced by createSack(), and dequeueAckedChunks().
{ return ((int32)(tsn1-tsn2)>=0); }
static int32 SCTPAssociation::tsnGt | ( | const uint32 | tsn1, | |
const uint32 | tsn2 | |||
) | [inline, static, protected] |
Definition at line 834 of file SCTPAssociation.h.
Referenced by createSack(), cwndUpdateAfterSack(), processDataArrived(), processSackArrived(), updateFastRecoveryStatus(), and updateGapList().
{ return ((int32)(tsn1-tsn2)>0); }
bool SCTPAssociation::tsnIsDuplicate | ( | const uint32 | tsn | ) | const [protected] |
Methods dealing with the handling of TSNs
Definition at line 1276 of file SCTPAssociationUtil.cc.
Referenced by processDataArrived().
{ for (std::list<uint32>::const_iterator iterator = state->dupList.begin(); iterator != state->dupList.end(); iterator++) { if ((*iterator) == tsn) return true; } for (uint32 i=0; i < state->numGaps; i++) { if (tsnBetween(state->gapStartList[i], tsn, state->gapStopList[i])) { return true; } } return false; }
static int32 SCTPAssociation::tsnLe | ( | const uint32 | tsn1, | |
const uint32 | tsn2 | |||
) | [inline, static, protected] |
Definition at line 832 of file SCTPAssociation.h.
Referenced by processDataArrived().
{ return ((int32)(tsn1-tsn2)<=0); }
static int32 SCTPAssociation::tsnLt | ( | const uint32 | tsn1, | |
const uint32 | tsn2 | |||
) | [inline, static, protected] |
Compare TSNs
Definition at line 831 of file SCTPAssociation.h.
Referenced by processSackArrived().
{ return ((int32)(tsn1-tsn2)<0); }
void SCTPAssociation::tsnWasReneged | ( | SCTPDataVariables * | chunk, | |
const int | type | |||
) | [protected] |
Definition at line 666 of file SCTPAssociationRcvMessage.cc.
Referenced by handleChunkReportedAsMissing(), and processSackArrived().
{ #ifdef PKT if (transmissionQ->getQueueSize() > 0) { for (SCTPQueue::PayloadQueue::iterator tq = transmissionQ->payloadQueue.begin(); tq != transmissionQ->payloadQueue.end(); tq++) { if (tq->second->tsn > chunk->tsn) { if (!transmissionQ->checkAndInsertChunk(chunk->tsn, chunk)) { sctpEV3 << "tsnWasReneged: cannot add message/chunk (TSN=" << chunk->tsn <<") to the transmissionQ" << endl; } else { chunk->enqueuedInTransmissionQ = true; chunk->setNextDestination(chunk->getLastDestinationPath()); CounterMap::iterator q = qCounter.roomTransQ.find(chunk->getNextDestination()); q->second+=ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH); CounterMap::iterator qb=qCounter.bookedTransQ.find(chunk->getNextDestination()); qb->second+=chunk->booksize; return; } } } } #endif sctpEV3 << "TSN " << chunk->tsn << " has been reneged (type " << type << ")" << endl; unackChunk(chunk); if (chunk->countsAsOutstanding) { decreaseOutstandingBytes(chunk); } chunk->hasBeenReneged = true; chunk->gapReports = 1; if (!chunk->getLastDestinationPath()->T3_RtxTimer->isScheduled()) { startTimer(chunk->getLastDestinationPath()->T3_RtxTimer, chunk->getLastDestinationPath()->pathRto); } }
void SCTPAssociation::unackChunk | ( | SCTPDataVariables * | chunk | ) | [inline, private] |
Definition at line 890 of file SCTPAssociation.h.
Referenced by sendOnPath(), and tsnWasReneged().
{ chunk->hasBeenAcked = false; }
int32 SCTPAssociation::updateCounters | ( | SCTPPathVariables * | path | ) | [protected] |
Definition at line 1543 of file SCTPAssociationRcvMessage.cc.
{ bool notifyUlp = false; if (++state->errorCount >= (uint32)sctpMain->par("assocMaxRetrans")) { sctpEV3 << "Retransmission count during connection setup exceeds " << (int32)sctpMain->par("assocMaxRetrans") << ", giving up\n"; sendIndicationToApp(SCTP_I_CLOSED); sendAbort(); sctpMain->removeAssociation(this); return 0; } else if (++path->pathErrorCount >= (uint32)sctpMain->par("pathMaxRetrans")) { if (path->activePath) { /* tell the source */ notifyUlp = true; } path->activePath = false; if (path == state->getPrimaryPath()) { state->setPrimaryPath(getNextPath(path)); } sctpEV3<<"process_TIMEOUT_RESET("<<(path->remoteAddress)<<") : PATH ERROR COUNTER EXCEEDED, path status is INACTIVE\n"; if (allPathsInactive()) { sctpEV3<<"process_TIMEOUT_RESET : ALL PATHS INACTIVE --> closing ASSOC\n"; sendIndicationToApp(SCTP_I_CONN_LOST); sendAbort(); sctpMain->removeAssociation(this); return 0; } else if (notifyUlp) { /* notify the application */ pathStatusIndication(path, false); } sctpEV3<<"process_TIMEOUT_RESET("<<(path->remoteAddress)<<") : PATH ERROR COUNTER now "<<path->pathErrorCount<<"\n"; return 2; } return 1; }
void SCTPAssociation::updateFastRecoveryStatus | ( | const uint32 | lastTsnAck | ) | [protected] |
Definition at line 109 of file SCTPCCFunctions.cc.
Referenced by processSackArrived().
{ for (SCTPPathMap::iterator iter = sctpPathMap.begin(); iter != sctpPathMap.end(); iter++) { SCTPPathVariables* path = iter->second; if (path->fastRecoveryActive) { if ( (tsnGt(lastTsnAck, path->fastRecoveryExitPoint)) || (lastTsnAck == path->fastRecoveryExitPoint) ) { path->fastRecoveryActive = false; path->fastRecoveryExitPoint = 0; sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterSack] Leaving Fast Recovery on path " << path->remoteAddress << ", lastTsnAck=" << lastTsnAck << endl; } } } }
bool SCTPAssociation::updateGapList | ( | const 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
Definition at line 1354 of file SCTPAssociationUtil.cc.
Referenced by processDataArrived().
{ sctpEV3 << "Entering updateGapList (tsn=" << receivedTsn << " cTsnAck=" <<state->cTsnAck << " Number of Gaps=" << state->numGaps << endl; uint32 lo = state->cTsnAck + 1; if ((int32)(state->localRwnd-state->queuedReceivedBytes) <= 0) { sctpEV3 << "Window full" << endl; // Only check if cumTsnAck can be advanced if (receivedTsn == lo) { sctpEV3 << "Window full, but cumTsnAck can be advanced:" << lo << endl; } else return false; } if (tsnGt(receivedTsn, state->highestTsnStored)) { // 17.06.08 state->highestTsnStored = receivedTsn; } for (uint32 i = 0; i<state->numGaps; i++) { if (state->gapStartList[i] > 0) { const uint32 hi = state->gapStartList[i] - 1; if (tsnBetween(lo, receivedTsn, hi)) { const uint32 gapsize = hi - lo + 1; if (gapsize > 1) { if (receivedTsn == hi) { state->gapStartList[i] = receivedTsn; state->newChunkReceived = true; return true; } else if (receivedTsn == lo) { if (receivedTsn == (state->cTsnAck + 1)) { state->cTsnAck++; state->newChunkReceived = true; return true; } /* some gap must increase its upper bound */ state->gapStopList[i-1] = receivedTsn; state->newChunkReceived = true; return true; } else { /* a gap in between */ state->numGaps = min(state->numGaps + 1, MAX_GAP_COUNT); // T.D. 18.12.09: Enforce upper limit! for (uint32 j = state->numGaps - 1; j > i; j--) { // T.D. 18.12.09: Fixed invalid start value. state->gapStartList[j] = state->gapStartList[j-1]; state->gapStopList[j] = state->gapStopList[j-1]; } state->gapStartList[i]=receivedTsn; state->gapStopList[i]=receivedTsn; state->newChunkReceived = true; return true; } } else { /* alright: gapsize is 1: our received tsn may close gap between fragments */ if (lo == state->cTsnAck + 1) { state->cTsnAck = state->gapStopList[i]; if (i == state->numGaps-1) { state->gapStartList[i] = 0; state->gapStopList[i] = 0; } else { for (uint32 j = i; j < state->numGaps - 1; j++) { // T.D. 18.12.09: Fixed invalid end value. state->gapStartList[j] = state->gapStartList[j + 1]; state->gapStopList[j] = state->gapStopList[j + 1]; } } state->numGaps--; state->newChunkReceived = true; return true; } else { state->gapStopList[i-1] = state->gapStopList[i]; if (i == state->numGaps-1) { state->gapStartList[i] = 0; state->gapStopList[i] = 0; } else { for (uint32 j = i; j < state->numGaps - 1; j++) { // T.D. 18.12.09: Fixed invalid end value. state->gapStartList[j] = state->gapStartList[j + 1]; state->gapStopList[j] = state->gapStopList[j + 1]; } } state->numGaps--; state->newChunkReceived = true; return true; } } } else { /* receivedTsn is not in the gap between these fragments... */ lo = state->gapStopList[i] + 1; } } /* end: for */ }/* end: for */ /* (NULL LIST) OR (End of Gap List passed) */ if (receivedTsn == lo) { // just increase ctsna, handle further update of ctsna later if (receivedTsn == state->cTsnAck + 1) { state->cTsnAck = receivedTsn; state->newChunkReceived = true; return true; } /* Update last fragment....increase stop_tsn by one */ state->gapStopList[state->numGaps-1]++; state->newChunkReceived = true; return true; } else { // A new fragment altogether, past the end of the list if(state->numGaps + 1 <= MAX_GAP_COUNT) { // T.D. 18.12.09: Enforce upper limit! state->gapStartList[state->numGaps] = receivedTsn; state->gapStopList[state->numGaps] = receivedTsn; state->numGaps++; state->newChunkReceived = true; } return true; } return false; }
friend class SCTP [friend] |
Definition at line 490 of file SCTPAssociation.h.
friend class SCTPPathVariables [friend] |
Definition at line 491 of file SCTPAssociation.h.
Referenced by addPath(), processInitAckArrived(), processInitArrived(), and sendInit().
cOutVector* SCTPAssociation::advRwnd [protected] |
Definition at line 555 of file SCTPAssociation.h.
Referenced by createSack(), SCTPAssociation(), and ~SCTPAssociation().
Definition at line 523 of file SCTPAssociation.h.
Referenced by SCTP::addForkedAssociation(), cloneAssociation(), printConnBrief(), process_SEND(), pushUlp(), SCTP::removeAssociation(), SCTPAssociation(), sendEstabIndicationToApp(), sendIndicationToApp(), and sendToApp().
int32 SCTPAssociation::assocId |
Definition at line 524 of file SCTPAssociation.h.
Referenced by SCTP::addForkedAssociation(), cloneAssociation(), dequeueAckedChunks(), handleChunkReportedAsMissing(), pathStatusIndication(), printConnBrief(), SCTP::printInfoConnMap(), process_ABORT(), process_CLOSE(), process_OPEN_PASSIVE(), process_SEND(), process_TIMEOUT_RTX(), processDataArrived(), processInitArrived(), pushUlp(), SCTP::removeAssociation(), SCTPAssociation(), SCTPPathVariables::SCTPPathVariables(), sendDataArrivedNotification(), sendEstabIndicationToApp(), sendIndicationToApp(), sendOnPath(), and stateEntered().
BytesToBeSent SCTPAssociation::bytes [protected] |
Definition at line 562 of file SCTPAssociation.h.
Referenced by bytesAllowedToSend(), SCTPAssociation(), and sendOnPath().
CCFunctions SCTPAssociation::ccFunctions [protected] |
Definition at line 552 of file SCTPAssociation.h.
Referenced by process_TIMEOUT_RTX(), processSackArrived(), processTimer(), and stateEntered().
uint16 SCTPAssociation::ccModule [protected] |
Definition at line 553 of file SCTPAssociation.h.
Referenced by stateEntered().
cOutVector* SCTPAssociation::cumTsnAck [protected] |
Definition at line 556 of file SCTPAssociation.h.
Referenced by SCTPAssociation(), stateEntered(), and ~SCTPAssociation().
cFSM* SCTPAssociation::fsm [protected] |
Definition at line 564 of file SCTPAssociation.h.
Referenced by cloneAssociation(), 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(), and ~SCTPAssociation().
uint32 SCTPAssociation::inboundStreams [protected] |
Definition at line 544 of file SCTPAssociation.h.
Referenced by process_OPEN_PASSIVE(), process_RECEIVE_REQUEST(), processInitAckArrived(), pushUlp(), SCTPAssociation(), sendEstabIndicationToApp(), sendInit(), and sendInitAck().
uint32 SCTPAssociation::initPeerTsn [protected] |
Definition at line 549 of file SCTPAssociation.h.
Referenced by processDataArrived(), processInitAckArrived(), processInitArrived(), and sendInitAck().
uint32 SCTPAssociation::initTsn [protected] |
Definition at line 548 of file SCTPAssociation.h.
Referenced by sendInit(), and sendInitAck().
Definition at line 531 of file SCTPAssociation.h.
Definition at line 526 of file SCTPAssociation.h.
Referenced by SCTP::addLocalAddress(), SCTP::addLocalAddressToAllRemoteAddresses(), cloneAssociation(), createSack(), printConnBrief(), process_RCV_Message(), process_SEND(), processInitArrived(), processSCTPMessage(), pushUlp(), retransmitCookieEcho(), retransmitShutdown(), retransmitShutdownAck(), sendEstabIndicationToApp(), sendIndicationToApp(), sendInit(), sendInitAck(), and SCTP::updateSockPair().
AddressVector SCTPAssociation::localAddressList [protected] |
Definition at line 541 of file SCTPAssociation.h.
Referenced by cloneAssociation(), process_ASSOCIATE(), process_OPEN_PASSIVE(), processInitArrived(), and sendInit().
uint16 SCTPAssociation::localPort |
Definition at line 527 of file SCTPAssociation.h.
Referenced by SCTP::addLocalAddress(), SCTP::addLocalAddressToAllRemoteAddresses(), SCTP::addRemoteAddress(), cloneAssociation(), printConnBrief(), process_ASSOCIATE(), process_OPEN_PASSIVE(), processSCTPMessage(), SCTP::removeLocalAddressFromAllRemoteAddresses(), SCTP::removeRemoteAddressFromAllConnections(), SCTPAssociation(), sendAbort(), sendCookieAck(), sendCookieEcho(), sendEstabIndicationToApp(), sendHeartbeat(), sendHeartbeatAck(), sendInit(), sendInitAck(), sendShutdown(), sendShutdownAck(), sendShutdownComplete(), sendToIP(), stateEntered(), and SCTP::updateSockPair().
uint32 SCTPAssociation::localVTag |
Definition at line 529 of file SCTPAssociation.h.
Referenced by process_RCV_Message(), processCookieEchoArrived(), processInitAckArrived(), processInitArrived(), SCTPAssociation(), sendInit(), sendInitAck(), sendToIP(), and stateEntered().
uint32 SCTPAssociation::numberOfRemoteAddresses [protected] |
Definition at line 543 of file SCTPAssociation.h.
Referenced by processInitAckArrived(), processInitArrived(), and SCTPAssociation().
cOutVector* SCTPAssociation::numGapBlocks [protected] |
Definition at line 558 of file SCTPAssociation.h.
Referenced by SCTPAssociation(), stateEntered(), and ~SCTPAssociation().
uint32 SCTPAssociation::outboundStreams [protected] |
Definition at line 545 of file SCTPAssociation.h.
Referenced by initAssociation(), process_OPEN_PASSIVE(), processInitAckArrived(), SCTPAssociation(), sendEstabIndicationToApp(), sendInit(), sendInitAck(), and streamScheduler().
uint32 SCTPAssociation::peerVTag |
Definition at line 530 of file SCTPAssociation.h.
Referenced by process_RCV_Message(), processCookieEchoArrived(), SCTPAssociation(), sendInit(), sendInitAck(), sendToIP(), and stateEntered().
QueueCounter SCTPAssociation::qCounter [protected] |
Definition at line 566 of file SCTPAssociation.h.
Referenced by addPath(), bytesAllowedToSend(), choosePathForRetransmission(), decreaseOutstandingBytes(), dequeueAckedChunks(), dequeueOutboundDataMsg(), getOutboundDataChunk(), handleChunkReportedAsAcked(), handleChunkReportedAsMissing(), increaseOutstandingBytes(), loadPacket(), makeRoomForTsn(), moveChunkToOtherPath(), process_RCV_Message(), process_SEND(), processInitAckArrived(), processInitArrived(), processSackArrived(), pushUlp(), putInDeliveryQ(), SCTPAssociation(), sendInit(), sendOnPath(), stateEntered(), storePacket(), and tsnWasReneged().
SCTPReceiveStreamMap SCTPAssociation::receiveStreams [protected] |
Definition at line 570 of file SCTPAssociation.h.
Referenced by deleteStreams(), initStreams(), makeRoomForTsn(), processDataArrived(), pushUlp(), and putInDeliveryQ().
Definition at line 525 of file SCTPAssociation.h.
Referenced by SCTP::addLocalAddress(), createSack(), performStateTransition(), printConnBrief(), process_CLOSE(), process_RCV_Message(), process_SEND(), process_STATUS(), processAppCommand(), processDataArrived(), processInitAckArrived(), processInitArrived(), processSackArrived(), processSCTPMessage(), pushUlp(), retransmitCookieEcho(), retransmitShutdown(), retransmitShutdownAck(), sendAbort(), sendEstabIndicationToApp(), sendIndicationToApp(), sendInit(), sendInitAck(), sendShutdown(), sendToIP(), stateEntered(), and SCTP::updateSockPair().
AddressVector SCTPAssociation::remoteAddressList [protected] |
Definition at line 542 of file SCTPAssociation.h.
Referenced by process_ASSOCIATE(), processInitAckArrived(), processInitArrived(), sendEstabIndicationToApp(), and sendInit().
uint16 SCTPAssociation::remotePort |
Definition at line 528 of file SCTPAssociation.h.
Referenced by SCTP::addLocalAddress(), SCTP::addLocalAddressToAllRemoteAddresses(), SCTP::addRemoteAddress(), printConnBrief(), process_ASSOCIATE(), processSCTPMessage(), SCTP::removeLocalAddressFromAllRemoteAddresses(), SCTP::removeRemoteAddressFromAllConnections(), SCTPAssociation(), sendAbort(), sendCookieAck(), sendCookieEcho(), sendEstabIndicationToApp(), sendHeartbeat(), sendHeartbeatAck(), sendInit(), sendInitAck(), sendShutdown(), sendShutdownAck(), sendShutdownComplete(), sendToIP(), stateEntered(), and SCTP::updateSockPair().
SCTPQueue* SCTPAssociation::retransmissionQ [protected] |
Definition at line 568 of file SCTPAssociation.h.
Referenced by cloneAssociation(), cwndUpdateAfterSack(), dequeueAckedChunks(), initAssociation(), loadPacket(), peekAbandonedChunk(), process_TIMEOUT_RTX(), processSackArrived(), SCTPAssociation(), sendOnPath(), and storePacket().
uint32 SCTPAssociation::sackFrequency [protected] |
Definition at line 550 of file SCTPAssociation.h.
Referenced by process_RCV_Message(), processDataArrived(), scheduleSack(), stateEntered(), and timeForSack().
double SCTPAssociation::sackPeriod [protected] |
Definition at line 551 of file SCTPAssociation.h.
Referenced by scheduleSack(), SCTPAssociation(), and stateEntered().
cMessage* SCTPAssociation::SackTimer |
Definition at line 537 of file SCTPAssociation.h.
Referenced by processInitArrived(), processTimer(), SCTP::removeAssociation(), scheduleSack(), SCTPAssociation(), sendOnPath(), sendSack(), timeForSack(), and ~SCTPAssociation().
SCTPAlgorithm* SCTPAssociation::sctpAlgorithm [protected] |
Definition at line 571 of file SCTPAssociation.h.
Referenced by cloneAssociation(), initAssociation(), process_SEND(), processTimer(), SCTPAssociation(), sendOnPath(), and ~SCTPAssociation().
SCTP* SCTPAssociation::sctpMain [protected] |
Definition at line 563 of file SCTPAssociation.h.
Referenced by cloneAssociation(), dequeueAckedChunks(), handleChunkReportedAsMissing(), 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(), processTimer(), SCTPAssociation(), sendEstabIndicationToApp(), sendIndicationToApp(), sendInit(), sendInitAck(), sendOnPath(), sendToApp(), sendToIP(), stateEntered(), and updateCounters().
SCTPPathMap SCTPAssociation::sctpPathMap [protected] |
Definition at line 565 of file SCTPAssociation.h.
Referenced by addPath(), allPathsInactive(), choosePathForRetransmission(), cwndUpdateAfterSack(), getNextPath(), getOutstandingBytes(), pmStartPathManagement(), printSctpPathMap(), processInitAckArrived(), processInitArrived(), processSackArrived(), SCTP::removeAssociation(), removePath(), sendInit(), sendOnAllPaths(), stopTimers(), and updateFastRecoveryStatus().
cOutVector* SCTPAssociation::sendQueue [protected] |
Definition at line 557 of file SCTPAssociation.h.
Referenced by dequeueOutboundDataMsg(), process_SEND(), SCTPAssociation(), stateEntered(), and ~SCTPAssociation().
SCTPSendStreamMap SCTPAssociation::sendStreams [protected] |
Definition at line 569 of file SCTPAssociation.h.
Referenced by deleteStreams(), dequeueOutboundDataMsg(), initStreams(), makeDataVarFromDataMsg(), nextChunkFitsIntoPacket(), numUsableStreams(), peekOutboundDataMsg(), process_SEND(), and streamScheduler().
SSFunctions SCTPAssociation::ssFunctions [protected] |
Definition at line 799 of file SCTPAssociation.h.
Referenced by dequeueOutboundDataMsg(), nextChunkFitsIntoPacket(), peekOutboundDataMsg(), processInitAckArrived(), SCTPAssociation(), and sendInitAck().
uint16 SCTPAssociation::ssModule [protected] |
Definition at line 800 of file SCTPAssociation.h.
Referenced by SCTPAssociation().
cMessage* SCTPAssociation::StartTesting |
Definition at line 538 of file SCTPAssociation.h.
Referenced by SCTPAssociation().
SCTPStateVariables* SCTPAssociation::state [protected] |
Definition at line 561 of file SCTPAssociation.h.
Referenced by advanceCtsna(), bytesAllowedToSend(), calculateBytesToSendOnPath(), cloneAssociation(), createSack(), cwndUpdateAfterSack(), cwndUpdateMaxBurst(), decreaseOutstandingBytes(), dequeueAckedChunks(), dequeueOutboundDataMsg(), getNextDestination(), handleChunkReportedAsMissing(), increaseOutstandingBytes(), initAssociation(), initCCParameters(), initStreams(), loadPacket(), makeRoomForTsn(), makeVarFromMsg(), moveChunkToOtherPath(), nextChunkFitsIntoPacket(), performStateTransition(), pmDataIsSentOn(), pmStartPathManagement(), process_ABORT(), process_ASSOCIATE(), process_CLOSE(), process_OPEN_PASSIVE(), process_PRIMARY(), process_QUEUE_BYTES_LIMIT(), process_QUEUE_MSGS_LIMIT(), process_RCV_Message(), process_RECEIVE_REQUEST(), process_SEND(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_RTX(), process_TIMEOUT_SHUTDOWN(), processCookieAckArrived(), processCookieEchoArrived(), processDataArrived(), processHeartbeatAckArrived(), processInitAckArrived(), processInitArrived(), processSackArrived(), processTimer(), pushUlp(), putInDeliveryQ(), removeFromGapList(), retransmitCookieEcho(), retransmitInit(), retransmitShutdown(), retransmitShutdownAck(), scheduleSack(), SCTPAssociation(), sendCookieEcho(), sendEstabIndicationToApp(), sendInit(), sendInitAck(), sendOnPath(), sendSack(), sendShutdown(), sendShutdownAck(), stateEntered(), storePacket(), streamScheduler(), timeForSack(), tsnIsDuplicate(), updateCounters(), updateGapList(), and ~SCTPAssociation().
int32 SCTPAssociation::status [protected] |
Definition at line 547 of file SCTPAssociation.h.
cMessage* SCTPAssociation::T1_InitTimer |
Definition at line 534 of file SCTPAssociation.h.
Referenced by process_ASSOCIATE(), process_RCV_Message(), process_TIMEOUT_INIT_REXMIT(), processCookieAckArrived(), processInitAckArrived(), processInitArrived(), processTimer(), SCTP::removeAssociation(), SCTPAssociation(), stateEntered(), and ~SCTPAssociation().
cMessage* SCTPAssociation::T2_ShutdownTimer |
Definition at line 535 of file SCTPAssociation.h.
Referenced by process_RCV_Message(), process_TIMEOUT_SHUTDOWN(), processInitArrived(), processTimer(), SCTP::removeAssociation(), SCTPAssociation(), sendShutdown(), sendShutdownAck(), and ~SCTPAssociation().
cMessage* SCTPAssociation::T5_ShutdownGuardTimer |
Definition at line 536 of file SCTPAssociation.h.
Referenced by process_RCV_Message(), processInitArrived(), processTimer(), SCTP::removeAssociation(), SCTPAssociation(), sendShutdown(), sendShutdownAck(), and ~SCTPAssociation().
SCTPQueue* SCTPAssociation::transmissionQ [protected] |
Definition at line 567 of file SCTPAssociation.h.
Referenced by cloneAssociation(), dequeueAckedChunks(), getOutboundDataChunk(), handleChunkReportedAsAcked(), handleChunkReportedAsMissing(), initAssociation(), moveChunkToOtherPath(), process_RCV_Message(), SCTPAssociation(), stateEntered(), and tsnWasReneged().