SCTPAssociation Class Reference

#include <SCTPAssociation.h>

List of all members.
int32 getFsmState () const
SCTPStateVariablesgetState ()
SCTPQueuegetTransmissionQueue ()
SCTPQueuegetRetransmissionQueue ()
SCTPAlgorithmgetSctpAlgorithm ()
SCTPgetSctpMain ()
cFSM * getFsm ()
cMessage * getInitTimer ()
cMessage * getShutdownTimer ()
cMessage * getSackTimer ()
uint32 chunkToInt (char *type)
bool processTimer (cMessage *msg)
bool processSCTPMessage (SCTPMessage *sctpmsg, IPvXAddress srcAddr, IPvXAddress destAddr)
bool processAppCommand (cPacket *msg)
void removePath ()
void removePath (IPvXAddress addr)
void removeLastPath (IPvXAddress addr)
void deleteStreams ()
void stopTimer (cMessage *timer)
void stopTimers ()
SCTPPathVariablesgetPath (IPvXAddress pid)
void printSctpPathMap ()
static const char * stateName (int32 state)

Public Member Functions

 SCTPAssociation (SCTP *mod, int32 appGateIndex, int32 assocId)
 ~SCTPAssociation ()
void sendAll (IPvXAddress pathId)

Static Public Member Functions

static const char * indicationName (int32 code)

Public Attributes

int32 appGateIndex
int32 assocId
IPvXAddress remoteAddr
IPvXAddress localAddr
uint16 localPort
uint16 remotePort
bool listen
uint32 localVTag
uint32 peerVTag
cMessage * T1_InitTimer
cMessage * T2_ShutdownTimer
cMessage * T5_ShutdownGuardTimer
cMessage * SackTimer
cMessage * StartTesting

Protected Types

typedef std::map< IPvXAddress,
SCTPPathVariables * > 
SCTPPathMap
typedef std::map< IPvXAddress,
uint32 > 
CounterMap
typedef struct
SCTPAssociation::counter 
QueueCounter
typedef std::map< uint32,
SCTPSendStream * > 
SCTPSendStreamMap
typedef std::map< uint32,
SCTPReceiveStream * > 
SCTPReceiveStreamMap
typedef struct
SCTPAssociation::calcBytesToSend 
BytesToBeSent
typedef struct
SCTPAssociation::congestionControlFunctions 
CCFunctions
typedef struct
SCTPAssociation::streamSchedulingFunctions 
SSFunctions

Protected Member Functions

void startTimer (cMessage *timer, simtime_t timeout)
SCTPAssociationcloneAssociation ()
void initAssociation (SCTPOpenCommand *openCmd)
bool tsnIsDuplicate (uint32 tsn)
bool advanceCtsna ()
bool updateGapList (uint32 tsn)
void removeFromGapList (uint32 removedTsn)
bool makeRoomForTsn (uint32 tsn, uint32 length, bool uBit)
void sendInit ()
void sendInitAck (SCTPInitChunk *initchunk)
void sendCookieEcho (SCTPInitAckChunk *initackchunk)
void sendCookieAck (IPvXAddress dest)
void sendAbort ()
void sendHeartbeat (SCTPPathVariables *path, bool local)
void sendHeartbeatAck (SCTPHeartbeatChunk *heartbeatChunk, IPvXAddress src, IPvXAddress dest)
void sendSack ()
void sendShutdown ()
void sendShutdownAck (IPvXAddress dest)
void sendShutdownComplete ()
SCTPSackChunk * createSack ()
void retransmitInit ()
void retransmitCookieEcho ()
void retransmitShutdown ()
void retransmitShutdownAck ()
void sendToIP (SCTPMessage *sctpmsg)
void sendToIP (SCTPMessage *sctpmsg, IPvXAddress dest)
void sendToIP (SCTPMessage *sctpmsg, IPvXAddress src, IPvXAddress dest)
void scheduleSack ()
void signalConnectionTimeout ()
void scheduleTimeout (cMessage *msg, simtime_t timeout)
cMessage * cancelEvent (cMessage *msg)
void sendToApp (cPacket *msg)
void sendIndicationToApp (int32 code)
void sendEstabIndicationToApp ()
void pushUlp ()
void sendDataArrivedNotification (uint16 sid)
void putInDeliveryQ (uint16 sid)
void printConnBrief ()
void addPath (IPvXAddress addr)
IPvXAddress getNextDestination (SCTPDataVariables *chk)
IPvXAddress getNextAddress (IPvXAddress dpi)
void bytesAllowedToSend (IPvXAddress dpi)
void pathStatusIndication (IPvXAddress pid, bool status)
bool allPathsInactive (void)
uint32 getLevel (IPvXAddress addr)
SCTPDataChunk * transformDataChunk (SCTPDataVariables *datVar)
SCTPDataVariablesmakeVarFromMsg (SCTPDataChunk *datachunk)
int32 streamScheduler (bool peek)
void initStreams (uint32 inStreams, uint32 outStreams)
int32 numUsableStreams (void)
int32 getQueuedBytes (void)
int32 getOutstandingBytes (void)
int32 dequeueAckedChunks (uint32 tsna, IPvXAddress pathId, simtime_t *rttEstimation)
uint32 getOutstandingBytesOnPath (IPvXAddress pathId)
SCTPDataVariablespeekOutboundDataChunk (IPvXAddress pid)
SCTPDataMsg * peekOutboundDataMsg (void)
SCTPDataVariablespeekAbandonedChunk (IPvXAddress pid)
SCTPDataVariablesgetOutboundDataChunk (IPvXAddress pid, int32 bytes)
SCTPDataMsg * dequeueOutboundDataMsg (int32 bytes)
void process_QUEUE (SCTPCommand *sctpCommand)
void pmDataIsSentOn (IPvXAddress pathId)
void pmStartPathManagement (void)
void pmClearPathCounter (IPvXAddress pid)
void pmRttMeasurement (IPvXAddress pathId, simtime_t rttEstimate, int32 acknowledgedBytes)
void fcAdjustCounters (uint32 ackedBytes, uint32 osb, bool ctsnaAdvanced, IPvXAddress pathId, uint32 pathOsb, uint32 newOsb)
int32 tsnLt (uint32 tsn1, uint32 tsn2)
int32 tsnLe (uint32 tsn1, uint32 tsn2)
int32 tsnGe (uint32 tsn1, uint32 tsn2)
int32 tsnGt (uint32 tsn1, uint32 tsn2)
int32 tsnBetween (uint32 tsn1, uint32 midtsn, uint32 tsn2)
int16 ssnGt (uint16 ssn1, uint16 ssn2)
uint32 subBytes (uint32 osb, uint32 bytes)
void disposeOf (SCTPMessage *sctpmsg)
void printOutstandingTsns ()
void initCCParameters (SCTPPathVariables *path)
void cwndUpdateAfterSack (bool rtxNecessary, SCTPPathVariables *path)
void cwndUpdateAfterCwndTimeout (SCTPPathVariables *path)
void cwndUpdateAfterRtxTimeout (SCTPPathVariables *path)
void cwndUpdateMaxBurst (SCTPPathVariables *path)
void cwndUpdateBytesAcked (uint32 ackedBytes, uint32 osb, bool ctsnaAdvanced, IPvXAddress pathId, uint32 pathOsb, uint32 newOsb)
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, IPvXAddress src, 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, uint32 count)
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_CWND (SCTPPathVariables *path)
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 (int32 event)

Protected Attributes

AddressVector localAddressList
AddressVector remoteAddressList
int32 status
uint32 numberOfRemoteAddresses
uint32 initTsn
uint32 initPeerTsn
uint32 inboundStreams
uint32 outboundStreams
uint32 sackFrequency
double sackPeriod
SCTPStateVariablesstate
cOutVector * advRwnd
cOutVector * quBytes
cOutVector * cumTsnAck
cOutVector * sendQueue
SCTPsctpMain
cFSM * fsm
SCTPPathMap sctpPathMap
QueueCounter qCounter
SCTPQueuetransmissionQ
SCTPQueueretransmissionQ
SCTPSendStreamMap sendStreams
SCTPReceiveStreamMap receiveStreams
SCTPAlgorithmsctpAlgorithm
BytesToBeSent bytes
CCFunctions ccFunctions
uint16 ccModule
SSFunctions ssFunctions
uint16 ssModule

Classes

struct  calcBytesToSend
struct  congestionControlFunctions
struct  counter
struct  streamSchedulingFunctions


Member Typedef Documentation

typedef std::map<IPvXAddress, uint32> SCTPAssociation::CounterMap [protected]

typedef std::map<uint32, SCTPSendStream*> SCTPAssociation::SCTPSendStreamMap [protected]

typedef std::map<uint32, SCTPReceiveStream*> SCTPAssociation::SCTPReceiveStreamMap [protected]


Constructor & Destructor Documentation

SCTPAssociation::SCTPAssociation ( SCTP mod,
int32  appGateIndex,
int32  assocId 
)

Constructor.

Referenced by cloneAssociation().

00231 {
00232         sctpMain = _mod;
00233         appGateIndex = _appGateIndex;
00234         assocId = _assocId;
00235 
00236         ev<<"SCTPAssociationBase:SCTPAssociation new assocId="<<assocId<<"\n";
00237 
00238         localPort = remotePort = 0;
00239         localVTag = 0;
00240         peerVTag = 0;
00241         numberOfRemoteAddresses=0;
00242         char fsmname[24];
00243         sprintf(fsmname, "fsm-%d", assocId);
00244         fsm = new cFSM();
00245         fsm->setName(fsmname);
00246         fsm->setState(SCTP_S_CLOSED);
00247         inboundStreams = SCTP_DEFAULT_INBOUND_STREAMS;
00248         outboundStreams = SCTP_DEFAULT_OUTBOUND_STREAMS;
00249         // queues and algorithm will be created on active or passive open
00250         transmissionQ = NULL;
00251         retransmissionQ = NULL;
00252         sctpAlgorithm = NULL;
00253         state = NULL;
00254         SCTPPathInfo* pinfo = new SCTPPathInfo();
00255         pinfo->setRemoteAddress(IPvXAddress("0.0.0.0"));
00256         char timername[70];
00257         sprintf(timername, "T1_INIT of assoc %d", assocId);
00258         T1_InitTimer = new cMessage(timername);
00259         sprintf(timername, "T2_SHUTDOWN of assoc %d", assocId);
00260         T2_ShutdownTimer = new cMessage(timername);
00261         sprintf(timername, "T5_SHUTDOWN_GUARD of assoc %d", assocId);
00262         T5_ShutdownGuardTimer = new cMessage(timername);
00263         sprintf(timername, "SACK_TIMER of assoc %d", assocId);
00264         SackTimer = new cMessage(timername);
00265 
00266         if (sctpMain->testTimeout>0)
00267         {
00268                 StartTesting = new cMessage("StartTesting");
00269                 StartTesting->setContextPointer(this);
00270                 StartTesting->setControlInfo(pinfo->dup());
00271                 scheduleTimeout(StartTesting, sctpMain->testTimeout);
00272         }
00273         sackPeriod = SACK_DELAY;
00274         T1_InitTimer->setContextPointer(this);
00275         T2_ShutdownTimer->setContextPointer(this);
00276         SackTimer->setContextPointer(this);
00277         T5_ShutdownGuardTimer->setContextPointer(this);
00278 
00279         T1_InitTimer->setControlInfo(pinfo);
00280         T2_ShutdownTimer->setControlInfo(pinfo->dup());
00281         SackTimer->setControlInfo(pinfo->dup());
00282         T5_ShutdownGuardTimer->setControlInfo(pinfo->dup());
00283         advRwnd = NULL;
00284         quBytes = NULL;
00285         cumTsnAck = NULL;
00286         sendQueue = NULL;
00287         qCounter.roomSumSendStreams = 0;
00288         qCounter.bookedSumSendStreams = 0;
00289         qCounter.roomSumRcvStreams = 0;
00290         bytes.chunk = false;
00291         bytes.packet = false;
00292         bytes.bytesToSend = 0;
00293         advRwnd = new cOutVector();
00294         sprintf(timername, "Advertised Receiver Window of assoc %d", assocId);
00295         advRwnd->setName(timername);
00296         quBytes = new cOutVector();
00297         sprintf(timername, "Queued Bytes of assoc %d", assocId);
00298         quBytes->setName(timername);
00299         ssModule = sctpMain->par("ssModule");
00300         switch (ssModule)
00301         {
00302                 case ROUND_ROBIN:
00303                 {
00304                         ssFunctions.ssInitStreams = &SCTPAssociation::initStreams;
00305                         ssFunctions.ssGetNextSid = &SCTPAssociation::streamScheduler;
00306                         ssFunctions.ssUsableStreams = &SCTPAssociation::numUsableStreams;
00307                 }
00308         }
00309 }

SCTPAssociation::~SCTPAssociation (  ) 

Destructor.

00312 {
00313         delete T1_InitTimer;
00314         delete T2_ShutdownTimer;
00315         delete T5_ShutdownGuardTimer;
00316         delete SackTimer;
00317         delete fsm;
00318         delete advRwnd;
00319         delete quBytes;
00320         delete cumTsnAck;
00321         delete sendQueue;
00322 }


Member Function Documentation

void SCTPAssociation::sendAll ( IPvXAddress  pathId  ) 

Utility: Send data from sendQueue, at most maxNumBytes (-1 means no limit). If fullSegments is set, don't send segments smaller than MSS (needed for Nagle). Returns true if some data was actually sent.

Referenced by process_ABORT(), process_CLOSE(), process_RCV_Message(), process_TIMEOUT_RTX(), SCTPAlg::sendCommandInvoked(), and sendShutdownAck().

01038 {
01039         SCTPSackChunk* sackChunk=NULL;
01040         uint32 chunksAdded=0,totalChunksSent=0,totalPacketsSent=0;
01041         uint32 nextSsn=0, osb=0;
01042         bool headerCreated=false, forwPresent = false, firstTime=false;
01043         IPvXAddress dpi, newDpi, pd;
01044         int32 dataChunksAdded=0;
01045         SCTPPathVariables* pathVar;
01046         SCTPDataChunk* chunkPtr=NULL;
01047         SCTPMessage* sctpmsg=NULL;
01048         SCTPDataMsg* datMsg;
01049         SCTPDataVariables *chunk=NULL, *datVar=NULL;
01050         bool authAdded = false;
01051         bool sendBeforeRtx = false;
01052         bool rtxActive = false;
01053         bool packetFull = false;
01054         bool probing = false;
01055         bool sendOneMorePacket = false;
01056         int32 tcount = 0, rtcount = 0, scount = 0, bcount = 0, bytesToSend = 0;
01057         sctpEV3<<"sendAll: pathId="<<pathId<<"\n";
01058         printSctpPathMap();
01059         if (pathId == IPvXAddress("0.0.0.0"))
01060                 pd = state->primaryPathIndex;
01061         else
01062                 pd = pathId;
01063         newDpi = pd;
01064         sctpEV3<<"newDpi set to "<<newDpi<<" dpi="<<dpi<<"\n";
01065         CounterMap::iterator tq=qCounter.roomTransQ.find(pd);
01066         if (tq != qCounter.roomTransQ.end())
01067                 tcount = tq->second;
01068         else
01069                 tcount = 0;
01070         CounterMap::iterator rtq=qCounter.roomRetransQ.find(pd);
01071         if (rtq != qCounter.roomRetransQ.end())
01072                 rtcount = rtq->second;
01073         else
01074                 rtcount = 0;
01075         scount = qCounter.roomSumSendStreams;
01076         bcount = qCounter.bookedSumSendStreams;
01077         sctpEV3<<"\nsend all on "<<pd<<": tcount="<<tcount<<"  scount="<<scount<<"  rtcount="<<rtcount<<" nextTsn="<<state->nextTSN<</*" numChunksAllowed="<<state->numChunksAllowed<<*/"\n";
01078         if (!state->stopSending)  //for M3UA
01079         {
01080                 if (tcount>0)
01081                 {
01082                         rtxActive = true;
01083                         dpi = pd;
01084                         sctpEV3<<"dpi=pd="<<dpi<<"\n";
01085                 }
01086 
01087                 if (tcount == 0 && scount == 0)
01088                 {
01089 
01090                         sctpEV3<<"No chunk available!\n";
01091                         bytesToSend = 0;
01092                         bytes.bytesToSend = 0;
01093                         bytes.packet = false;
01094                         bytes.chunk = false;
01095                         dpi = pathId;
01096                         sctpEV3<<"dpi=pathId="<<dpi<<"\n";
01097                 }
01098                 else
01099                 {
01100                                 if (tcount==0)
01101                                 {
01102                                         dpi = state->primaryPathIndex;
01103                                         sctpEV3<<"dpi=primary="<<dpi<<"\n";
01104                                         firstTime=true;
01105                                 }
01106                                 if (!(state->resetPending && firstTime))
01107                                         bytesAllowedToSend(dpi);
01108                         newDpi = dpi;
01109                         sctpEV3<<"newDpi set to "<<newDpi<<" dpi="<<dpi<<"\n";
01110                 }
01111 
01112                 if (newDpi==IPvXAddress("0.0.0.0"))
01113                         opp_error("newDpi unspecified");
01114                 if (bytesToSend < 0)  //24.11.2006
01115                         bytesToSend=0;
01116 
01117                 bytesToSend = bytes.bytesToSend;
01118 
01119                 pathVar=getPath(dpi);
01120 
01121                 sctpEV3<<"after bytesAllowedToSend: bytesToSend="<<bytesToSend<<", packet="<<bytes.packet<<", chunk="<<bytes.chunk<<"\n";
01122                 if (bytes.chunk && (rtcount==0 || tcount>0))
01123                         probing = true;
01124                 /* schedule sending of SACKs at once, when we have fragments to report */
01125                 if ((state->numGaps > 0 || state->dupList.size() > 0) && state->sackAllowed)
01126                 {
01127                         sctpEV3<<"Gaps present ==> ackState = "<<sackFrequency<<"\n";
01128                         state->ackState = sackFrequency;
01129                 }
01130                 if (state->ackState < sackFrequency && bytesToSend == 0 && bytes.chunk==false && bytes.packet==false && forwPresent == false)
01131                 {
01132                         sctpEV3<<"sendAll: nothing to send...chunk pointer is NULL...BYE...\n";
01133                         return;
01134                 }
01135 
01136 
01137                 sctpEV3<<"sendAll::bytesToSend="<<bytesToSend<<" osb="<<pathVar->outstandingBytes<<" cwnd="<<pathVar->cwnd<<" arwnd="<<state->peerRwnd<<"\n";
01138                 osb = pathVar->outstandingBytes;
01139 
01140                 if ((int32)pathVar->outstandingBytes<0)
01141                         opp_error("util %d ,tsna=%d",__LINE__, state->cTsnAck);
01142 
01143         }
01144         else
01145                 dpi = pd;
01146 
01147         sctpEV3<<"ackState="<<state->ackState<<" Sacktimer="<<SackTimer->isScheduled()<<"\n";
01148         if (state->ackState >= sackFrequency || (SackTimer->isScheduled() &&  (state->alwaysBundleSack  == true || pathId == dpi)) )
01149         {
01150                 sctpmsg = new SCTPMessage();
01151                 sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
01152 
01153                 sctpEV3<<"SCTPAssociationUtil:sendAll localPort="<<localPort<<"  remotePort="<<remotePort<<"\n";
01154 
01155                 /*build a SACK chunk....*/
01156                 headerCreated = true;
01157                 sackChunk = createSack();
01158 
01159                 if (dpi!=remoteAddr)
01160                         dpi = remoteAddr;
01161 
01162                 sctpEV3<<"SACK: dpi="<<dpi<<"\n";
01163 
01164                 /* ...and add a SACK to the packet... */
01165 
01166                 chunksAdded++;
01167                 totalChunksSent++;
01168                 sctpmsg->addChunk(sackChunk);
01169 
01170                 if (tcount==0 && bytesToSend>0 && state->nagleEnabled && state->peerRwnd < pathVar->pmtu && pathVar->outstandingBytes > 0)
01171                 {
01172                 // Test whether a full packet can be filled
01173                 sctpEV3<<" peerRwnd="<<state->peerRwnd<<" bytesToSend="<<bytesToSend<<" nextTSN="<<state->nextTSN<<"\n";
01174                         SCTPDataMsg *datMsg = peekOutboundDataMsg();
01175                         uint32 ums = datMsg->getBooksize();
01176                                 uint32 num = (uint32)((pathVar->pmtu-sctpmsg->getByteLength()-20)/(ums+SCTP_DATA_CHUNK_LENGTH));
01177                                 if (num*ums>state->peerRwnd)
01178                                         bytesToSend = 0;
01179                                 else
01180                                         bytesToSend = num * ums;
01181                 }
01182                 sctpEV3<<"sendAll: appended "<<sackChunk->getBitLength()/8<<" bytes SACK chunk, msg length now "<<sctpmsg->getBitLength()/8<<"\n";
01183 
01184                 state->ackState = 0;
01185                         /* stop SACK timer if it is running...                           */
01186                 stopTimer(SackTimer);
01187                 sctpAlgorithm->sackSent();
01188                 state->sackAllowed = false;
01189         }
01190         else
01191 
01192         {
01193                 if (tcount==0 && bytesToSend>0 && state->nagleEnabled && state->peerRwnd < pathVar->pmtu && pathVar->outstandingBytes > 0)
01194                 {
01195                 // Test whether a full packet can be filled
01196                 sctpEV3<<" peerRwnd="<<state->peerRwnd<<" bytesToSend="<<bytesToSend<<" nextTSN="<<state->nextTSN<<"\n";
01197                         SCTPDataMsg *datMsg = peekOutboundDataMsg();
01198                         uint32 ums = datMsg->getBooksize();
01199                                 uint32 num = (uint32)((pathVar->pmtu-32)/(ums+SCTP_DATA_CHUNK_LENGTH));
01200                                 if (num*ums>state->peerRwnd)
01201                                         bytesToSend = 0;
01202                                 else
01203                                         bytesToSend = num * ums;
01204                 }
01205                 if (bytesToSend > 0 || bytes.chunk || bytes.packet || (bytes.chunk && probing))
01206                 {
01207                         if (tcount>0 || scount>0 && (!(state->nagleEnabled && osb>0)||(uint32)scount>=pathVar->pmtu-32 ))
01208                         {
01209                                 sctpmsg = new SCTPMessage();
01210                                 headerCreated=true;
01211                                 sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
01212                         }
01213                 }
01214                 else
01215                 {
01216                         sctpEV3<<"Logic Error in sendAll: no header created....???\n";
01217 
01218                 }
01219         }
01220 
01221         while ((bytesToSend > 0 || bytes.chunk || bytes.packet ) && !(state->resetPending && firstTime) && headerCreated && !state->stopSending)
01222         {
01223                 datVar = NULL;
01224                 datMsg = NULL;
01225                 if (tq->second > 0) //take the chunks out of the transmissionQ first
01226                 {
01227                         sctpEV3<<tq->second<<" bytes are in the transQ\n";
01228                         datVar=getOutboundDataChunk(dpi, pathVar->pmtu-sctpmsg->getBitLength()/8 -20);
01229                         sctpEV3<<"sendAll::sctpmsg->length="<<sctpmsg->getBitLength()/8<<" length datVar="<<pathVar->pmtu-sctpmsg->getBitLength()/8 -20<<"\n";
01230                         if (datVar != NULL)
01231                         {
01232                                 datVar->numberOfRetransmissions++;
01233                                 if (datVar->hasBeenAcked==false)
01234                                 {
01235                                         datVar->countsAsOutstanding = true;
01236                                         datVar->hasBeenRemoved = false;
01237                                         getPath(datVar->nextDestination)->outstandingBytes += (datVar->booksize);
01238                                         sctpEV3<<"osb="<<getPath(datVar->nextDestination)->outstandingBytes<<"\n";
01239                                         CounterMap::iterator i=qCounter.roomRetransQ.find(getPath(datVar->lastDestination)->remoteAddress);
01240                                                 i->second += ADD_PADDING(datVar->booksize+SCTP_DATA_CHUNK_LENGTH);
01241                                 }
01242                         }
01243                         else
01244                         {
01245                                 sctpEV3<<"datVar=NULL -> packetFull\n";
01246                                 packetFull = true;
01247                         }
01248                 }
01249                 else if (scount>0 && dpi==state->primaryPathIndex)
01250                 {
01251                         sctpEV3<<"scount="<<scount<<", nagle="<<state->nagleEnabled<<", osb="<<osb<<", mtu="<<pathVar->pmtu-32<<"\n";
01252                         if (state->nagleEnabled && osb>0 && (uint32)scount<pathVar->pmtu-32)
01253                         {
01254                                 scount = 0;
01255                                 break;
01256                         }
01257                         datMsg=dequeueOutboundDataMsg(pathVar->pmtu-sctpmsg->getBitLength()/8 -20);
01258                         sctpEV3<<"sendAll::sctpmsg->length="<<sctpmsg->getBitLength()/8<<" length datMsg="<<pathVar->pmtu-sctpmsg->getBitLength()/8 -20<<"\n";
01259                         if (datMsg)
01260                         {
01261                                 state->queuedMessages--;
01262                                 if (state->queueLimit>0 && state->queuedMessages < state->queueLimit && state->queueUpdate==false)
01263                                 {
01264                                         sendIndicationToApp(SCTP_I_SEND_MSG);
01265                                         state->queueUpdate = true;
01266                                         sctpEV3 << "\nQueue has to be filled! Queued Messages = "<<state->queuedMessages<<"\n";
01267                                 }
01268                                 datVar=new SCTPDataVariables();
01269                                 datVar->enqueuingTime = datMsg->getEnqueuingTime();
01270                                 datVar->expiryTime = datMsg->getExpiryTime();
01271                                 datVar->ppid = datMsg->getPpid();
01272                                 datMsg->setInitialDestination(state->primaryPathIndex);//I.R.always send on primaryPath
01273                                 datVar->initialDestination = datMsg->getInitialDestination();
01274                                 dpi = datVar->initialDestination;  //I.R. 23.10.07
01275                                 sctpEV3<<"initialDestination="<<datVar->initialDestination<<": data will be sent to "<<dpi<<"\n";
01276                                 // datVar->len just data
01277                                 datVar->len = datMsg->getBitLength();
01278                                 datVar->sid = datMsg->getSid();
01279                                 datVar->allowedNoRetransmissions = datMsg->getRtx();
01280                                 datVar->booksize = datMsg->getBooksize();
01281                                 SCTPSendStreamMap::iterator iter=this->sendStreams.find(datMsg->getSid());
01282                                 SCTPSendStream* stream=iter->second;
01283                                 nextSsn = stream->getNextStreamSeqNum();
01284                                 datVar->userData = datMsg->decapsulate();
01285                                 if (datMsg->getOrdered())
01286                                 {
01287                                         datVar->ssn=nextSsn++;
01288                                         datVar->ordered = true;
01289                                         if (nextSsn > 65535)
01290                                                 stream->setNextStreamSeqNum(0);
01291                                         else
01292                                                 stream->setNextStreamSeqNum(nextSsn);
01293                                 }
01294                                 else
01295                                 {
01296                                         datVar->ssn=0;
01297                                         datVar->ordered = false;
01298                                 }
01299                                 firstTime=true;
01300                                 delete datMsg;
01301 
01302                                 sctpEV3<<"chunk "<<datVar<<" dequeued from StreamQ "<<datVar->sid<<" tsn="<<datVar->tsn<<" bytes now "<<qCounter.roomSumSendStreams<<"\n";
01303                         }
01304                         else
01305                         {
01306                                 if (headerCreated==true)
01307                                 {
01308                                         if (chunksAdded==0)
01309                                         {
01310                                                 delete sctpmsg;
01311                                                 return;
01312                                         }
01313                                         else
01314                                         {
01315                                                 packetFull = true;
01316                                                 sctpEV3<<"packetFull: msg length = "<<sctpmsg->getBitLength()/8+20<<"\n";
01317                                                 datVar=NULL;
01318                                         }
01319                                 }
01320                         }
01321                 }
01322                 chunk=datVar;
01323                 if (chunk!=NULL)
01324                 {
01325                         if (chunk->tsn == 0)
01326                         {
01327                                 chunk->tsn = state->nextTSN;
01328                                 sctpEV3<<"Set TSN="<<chunk->tsn<<" sid="<<chunk->sid<<", ssn="<<chunk->ssn<<"\n";
01329                                 state->nextTSN++;
01330                         }
01331                         pathVar->pathTSN->record(chunk->tsn);
01332                         SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId);
01333                         iter->second.transmittedBytes+=chunk->len/8;
01334                         /* only if it is a first time send event, store the chunk also in the retransmission queue */
01335                         chunk->countsAsOutstanding = true;
01336                         chunk->hasBeenRemoved = false;
01337                         chunk->sendTime = simulation.getSimTime(); //I.R. to send Fast RTX just once a RTT
01338                         if (chunk->numberOfTransmissions == 0)
01339                         {
01340                                 chunk->lastDestination = state->primaryPathIndex;
01341                                 sctpEV3<<simulation.getSimTime()<<" firstTime, TSN "<<chunk->tsn<<": lastDestination set to "<<chunk->lastDestination<<"\n";
01342                                 if (chunk->lastDestination==IPvXAddress("0.0.0.0"))
01343                                         opp_error("primaryPathIndex unspecified");
01344                                 if (!state->firstDataSent)
01345                                         state->firstDataSent=true;
01346                                 sctpEV3<<"insert in retransmissionQ tsn="<<chunk->tsn<<"\n";
01347                                 if(!retransmissionQ->checkAndInsertVar(chunk->tsn, chunk))
01348                                 {
01349                                         sctpEV3<<"Cannot add message/chunk retransmission Q buffer (tsn="<<chunk->tsn<<")...terminating!\n";
01350                                 }
01351                                 else
01352                                 {
01353                                         sctpEV3<<"size of retransmissionQ="<<retransmissionQ->getQueueSize()<<"\n";
01354                                         chunk->hasBeenAcked = false;
01355                                         pathVar->outstandingBytes+=chunk->booksize;
01356                                         sctpEV3<<"osb="<<pathVar->outstandingBytes<<"\n";
01357                                         CounterMap::iterator q=qCounter.roomRetransQ.find(dpi);
01358                                         q->second+= ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH);
01359                                 }
01360                         }
01361                         else
01362                                 sctpEV3<<"numberOfTransmissions="<<chunk->numberOfTransmissions<<"\n";
01363 
01364                                 /* chunk is already in the retransmissionQ */
01365                         chunk->numberOfTransmissions++;
01366 
01367                         chunk->gapReports = 0;
01368                         chunk->hasBeenFastRetransmitted = false;
01369                         sctpEV3<<"sendAll(): adding new outbound data chunk to packet (tsn="<<chunk->tsn<<")...!!!\n";
01370 
01371                         chunkPtr = transformDataChunk(chunk);
01372 
01373                         /* update counters */
01374                         totalChunksSent++;
01375                         chunksAdded++;
01376                         dataChunksAdded++;
01377                         sctpmsg->addChunk(chunkPtr);
01378 
01379                         if (chunk->booksize > state->peerRwnd)
01380                         {
01381                                 state->peerRwnd = 0;
01382                                 bytesToSend = 0;
01383                                 bytes.packet = false;
01384                                 packetFull = true;
01385                         }
01386                         else
01387                         {
01388 
01389                                 state->peerRwnd-=chunk->booksize;
01390                                 if (bytes.chunk==false && bytes.packet==false)
01391                                         bytesToSend -= chunk->booksize;
01392                                 else if (bytes.chunk)
01393                                         bytes.chunk = false;
01394                                 else if (bytes.packet && packetFull)
01395                                         bytes.packet = false;
01396                         }
01397 
01398                         if (bytesToSend <= 0)
01399                         {
01400                                 if (!packetFull && qCounter.roomSumSendStreams>pathVar->pmtu-32)
01401                                 {
01402                                         sendOneMorePacket = true;
01403                                         bytes.packet = true;
01404                                         sctpEV3<<"one more packet allowed\n";
01405                                 }
01406                                 else
01407                                 {
01408                                         bytesToSend = 0;
01409                                         packetFull = true;
01410                                 }
01411                         }
01412                         else if (qCounter.roomSumSendStreams==0 && tq->second==0)
01413                         {
01414                                 packetFull = true;
01415                                 sctpEV3<<"no data in send and transQ: packet full\n";
01416                         }
01417                         sctpEV3<<"bytesToSend after reduction: "<<bytesToSend<<"\n";
01418 
01419                         chunk->lastDestination = newDpi;
01420                         sctpEV3<<simulation.getSimTime()<<" TSN "<<chunk->tsn<<": lastDestination set to "<<chunk->lastDestination<<"\n";
01421                         if (chunk->lastDestination==IPvXAddress("0.0.0.0"))
01422                                         opp_error("newDpi unspecified");
01423                 }
01424                 else if (headerCreated)
01425                 {
01426                         if (chunksAdded==0)
01427                         {
01428                                 delete sctpmsg;
01429                                 return;
01430                         }
01431                         else
01432                         {
01433                                 packetFull = true;
01434                                 sctpEV3<<"packetFull: msg length = "<<sctpmsg->getBitLength()/8+20<<"\n";
01435                                 datVar=NULL;
01436                         }
01437                 }
01438 
01439 
01440                 if (packetFull || (dpi != newDpi) || sendBeforeRtx)
01441                 {
01442 
01443                         sctpEV3<<simulation.getSimTime()<<"  packet full: totalLength="<<sctpmsg->getBitLength()/8 + 20<<", dpi="<<dpi<<", newDpi="<<newDpi<<" "<<dataChunksAdded<<" chunks added, osb now "<<getPath(dpi)->outstandingBytes<<"\n";
01444 
01445                         if (headerCreated == true && chunksAdded > 0)
01446                         {
01447                                 /* new chunks would exceed MTU, so we send old packet and build a new one */
01448                                 /* this implies that at least one data chunk is send here */
01449                                 if (dataChunksAdded > 0)
01450                                 {
01451                                         if (!pathVar->T3_RtxTimer->isScheduled())
01452                                         {
01453                                                 startTimer(pathVar->T3_RtxTimer, pathVar->pathRto);
01454                                         }
01455                                         else
01456                                                 sctpEV3<<"RTX Timer already scheduled\n";
01457                                 }
01458                                 if (sendOneMorePacket)
01459                                 {
01460                                         sendOneMorePacket = false;
01461                                         bytesToSend = 0;
01462                                         bytes.packet = false;
01463                                 }
01464                                 sendToIP(sctpmsg, dpi);
01465                                 pmDataIsSentOn(dpi);
01466                                 totalPacketsSent++;
01467                                 headerCreated = false;
01468                                 authAdded = false;
01469                                 chunksAdded = 0;
01470                                 dataChunksAdded = 0;
01471                                 firstTime = false;
01472                                 sendBeforeRtx = false;
01473                                 packetFull = false;
01474 
01475                                 sctpEV3<<"sendAll: Sending Packet to path "<<dpi<<" scount="<<scount<<"  tcount="<<tcount<<" bytesToSend="<<bytesToSend<<"\n";
01476                                 if (tcount==0 && bytesToSend>0 && state->nagleEnabled && state->peerRwnd < pathVar->pmtu && pathVar->outstandingBytes > 0)
01477                                 {
01478                                 // Test whether a full packet can be filled
01479                                 sctpEV3<<" peerRwnd="<<state->peerRwnd<<" bytesToSend="<<bytesToSend<<" nextTSN="<<state->nextTSN<<"\n";
01480                                         SCTPDataMsg *datMsg = peekOutboundDataMsg();
01481                                         if (datMsg)
01482                                         {
01483                                                 uint32 ums = datMsg->getBooksize();
01484                                                 uint32 num =(uint32)((pathVar->pmtu-32)/(ums+SCTP_DATA_CHUNK_LENGTH));
01485                                                 if (num*ums>state->peerRwnd)
01486                                                         bytesToSend = 0;
01487                                                 else
01488                                                         bytesToSend = num * ums;
01489                                         }
01490                                         else
01491                                                 bytesToSend = 0;
01492                                         sctpEV3<<"bytesToSend set to "<<bytesToSend<<"\n";
01493                                 }
01494                         }
01495                         else
01496                         {
01497 
01498                                 sctpEV3<<"Logic Error: Packet Size + new chunk len exceed path mtu, but chunksAdded==0\n";
01499 
01500                         }
01501 
01502                 }
01503 
01504 
01505                 sctpEV3<<"still "<<bytesToSend<<" bytes to send, headerCreated="<<headerCreated<<"\n";
01506                         /* else { */ /* place left in the MTU, so add chunk to packet...and go on */
01507                 if (!headerCreated && bytesToSend > 0)
01508                 {
01509                         sctpEV3<<"headerCreated="<<headerCreated<<"  bytesToSend="<<bytesToSend<<"  sumSendStreams="<<qCounter.roomSumSendStreams<<"\n";
01510                         if ((state->nagleEnabled==false && (qCounter.roomSumSendStreams>0 || tq->second>0)) || (state->nagleEnabled==true && (qCounter.roomSumSendStreams>= (pathVar->pmtu - 32) || tq->second>0)))
01511                         {
01512                                 sctpmsg = new SCTPMessage();
01513                                 headerCreated=true;
01514                                 sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
01515                                 tcount = tq->second;
01516                                 rtcount = rtq->second;
01517                                 scount = qCounter.roomSumSendStreams;
01518                                 bcount = qCounter.bookedSumSendStreams;
01519                         }
01520                         else
01521                                 bytesToSend=0;
01522                 }
01523 
01524         }
01525 
01526                 //sctpEV3<<"end of while\n";
01527                 /* =============================================================  */
01528 
01529 
01530         if (chunksAdded > 0 && headerCreated == true)
01531         {
01532                 sctpEV3<<"out of while: headerCreated="<<headerCreated<<"  chunksAdded="<<chunksAdded<<" dataChunksAdded="<<dataChunksAdded<<"\n";
01533                 if (state->nagleEnabled==false || osb==0 || firstTime == false || (state->nagleEnabled && qCounter.roomSumSendStreams>= (pathVar->pmtu - 32)) || rtxActive == true)
01534                 {
01535                         /* this destination may have to be changed (e.g. to last fromAddress) */
01536                         if (dpi == IPvXAddress("0.0.0.0"))
01537                                 dpi = state->primaryPathIndex;
01538                         /* start T3 timer, if it is not already running, and turn off probing */
01539 
01540                         if (dataChunksAdded > 0)
01541                         {
01542                                 if (!getPath(dpi)->T3_RtxTimer->isScheduled())
01543                                 {
01544 
01545                                         startTimer(getPath(dpi)->T3_RtxTimer, getPath(dpi)->pathRto);
01546                                 }
01547                         }
01548                 }
01549                 sctpEV3<<"send all queued chunks to "<<dpi<<" and get out. osb now "<<getPath(dpi)->outstandingBytes<<"\n";
01550                 sendToIP(sctpmsg, dpi);
01551                 authAdded = false;
01552                 pmDataIsSentOn(dpi);
01553                 totalPacketsSent++;
01554                 rtxActive=false;
01555                 probing = false;
01556         }
01557         else
01558         {
01559 
01560                 sctpEV3<<"sendAll: nothing more to send...BYE !\n";
01561 
01562         }
01563 
01564 }

const char * SCTPAssociation::indicationName ( int32  code  )  [static]

Utility: returns name of SCTP_I_xxx constants

Referenced by sendEstabIndicationToApp(), and sendIndicationToApp().

00114 {
00115 #define CASE(x) case x: s=#x+7; break
00116         const char *s = "unknown";
00117         switch (code)
00118         {
00119                 CASE(SCTP_I_DATA);
00120                 CASE(SCTP_I_DATA_NOTIFICATION);
00121                 CASE(SCTP_I_ESTABLISHED);
00122                 CASE(SCTP_I_PEER_CLOSED);
00123                 CASE(SCTP_I_CLOSED);
00124                 CASE(SCTP_I_CONNECTION_REFUSED);
00125                 CASE(SCTP_I_CONNECTION_RESET);
00126                 CASE(SCTP_I_TIMED_OUT);
00127                 CASE(SCTP_I_STATUS);
00128                 CASE(SCTP_I_ABORT);
00129                 CASE(SCTP_I_SHUTDOWN_RECEIVED);
00130                 CASE(SCTP_I_SEND_MSG);
00131                 CASE(SCTP_I_SENDQUEUE_FULL);
00132         }
00133         return s;
00134 #undef CASE
00135 }

int32 SCTPAssociation::getFsmState (  )  const [inline]

00491 {return fsm->getState();};

SCTPStateVariables* SCTPAssociation::getState (  )  [inline]

00492 {return state;};

SCTPQueue* SCTPAssociation::getTransmissionQueue (  )  [inline]

Referenced by SCTPAlgorithm::setAssociation().

00493 {return transmissionQ;};

SCTPQueue* SCTPAssociation::getRetransmissionQueue (  )  [inline]

SCTPAlgorithm* SCTPAssociation::getSctpAlgorithm (  )  [inline]

00495 {return sctpAlgorithm;};

SCTP* SCTPAssociation::getSctpMain (  )  [inline]

Referenced by SCTPPathVariables::SCTPPathVariables().

00496 {return sctpMain;};

cFSM* SCTPAssociation::getFsm (  )  [inline]

00497 {return fsm;};

cMessage* SCTPAssociation::getInitTimer (  )  [inline]

00499 {return T1_InitTimer;};

cMessage* SCTPAssociation::getShutdownTimer (  )  [inline]

00500 {return T2_ShutdownTimer;};

cMessage* SCTPAssociation::getSackTimer (  )  [inline]

00501 {return SackTimer;};

const char * SCTPAssociation::stateName ( int32  state  )  [static]

Utility: returns name of SCTP_S_xxx constants

Referenced by performStateTransition(), printConnBrief(), process_STATUS(), and process_TIMEOUT_INIT_REXMIT().

00057 {
00058 #define CASE(x) case x: s=#x+7; break
00059         const char *s = "unknown";
00060         switch (state)
00061         {
00062                 CASE(SCTP_S_CLOSED);
00063                 CASE(SCTP_S_COOKIE_WAIT);
00064                 CASE(SCTP_S_COOKIE_ECHOED);
00065                 CASE(SCTP_S_ESTABLISHED);
00066                 CASE(SCTP_S_SHUTDOWN_PENDING);
00067                 CASE(SCTP_S_SHUTDOWN_SENT);
00068                 CASE(SCTP_S_SHUTDOWN_RECEIVED);
00069                 CASE(SCTP_S_SHUTDOWN_ACK_SENT);
00070         }
00071         return s;
00072 #undef CASE
00073 }

uint32 SCTPAssociation::chunkToInt ( char *  type  ) 

00139 {
00140         if (strcmp(type, "DATA")==0) return 0;
00141         if (strcmp(type,  "INIT")==0) return 1;
00142         if (strcmp(type,  "INIT_ACK")==0) return 2;
00143         if (strcmp(type,  "SACK")==0) return 3;
00144         if (strcmp(type,  "HEARTBEAT")==0) return 4;
00145         if (strcmp(type,  "HEARTBEAT_ACK")==0) return 5;
00146         if (strcmp(type,  "ABORT")==0) return 6;
00147         if (strcmp(type,  "SHUTDOWN")==0) return 7;
00148         if (strcmp(type,  "SHUTDOWN_ACK")==0) return 8;
00149         if (strcmp(type,  "ERRORTYPE")==0) return 9;
00150         if (strcmp(type,  "COOKIE_ECHO")==0) return 10;
00151         if (strcmp(type,  "COOKIE_ACK")==0) return 11;
00152         if (strcmp(type,  "SHUTDOWN_COMPLETE")==0) return 14;
00153         sctpEV3<<"ChunkConversion not successful\n";
00154         return 0;
00155 }

bool SCTPAssociation::processTimer ( cMessage *  msg  ) 

Referenced by SCTP::handleMessage().

00325 {
00326         SCTPPathVariables* path = NULL;
00327 
00328         sctpEV3 << msg->getName() << " timer expired at "<<simulation.getSimTime()<<"\n";
00329 
00330         SCTPPathInfo* pinfo = check_and_cast<SCTPPathInfo*>(msg->getControlInfo());
00331         IPvXAddress addr = pinfo->getRemoteAddress();
00332 
00333         if (addr != IPvXAddress("0.0.0.0"))
00334                 path = getPath(addr);
00335     // first do actions
00336         SCTPEventCode event;
00337         event = SCTP_E_IGNORE;
00338         if (msg==T1_InitTimer)
00339         {
00340                 process_TIMEOUT_INIT_REXMIT(event);
00341         }
00342         else if (msg==SackTimer)
00343         {
00344         sctpEV3<<simulation.getSimTime()<<" delayed Sack: cTsnAck="<<state->cTsnAck<<" highestTsnReceived="<<state->highestTsnReceived<<" lastTsnReceived="<<state->lastTsnReceived<<" ackState="<<state->ackState<<" numGaps="<<state->numGaps<<"\n";
00345                 sendSack();
00346         }
00347         else if (msg==T2_ShutdownTimer)
00348         {
00349                 stopTimer(T2_ShutdownTimer);
00350                 process_TIMEOUT_SHUTDOWN(event);
00351         }
00352         else if (msg==T5_ShutdownGuardTimer)
00353         {
00354                 stopTimer(T5_ShutdownGuardTimer);
00355                 delete state->shutdownChunk;
00356                 sendIndicationToApp(SCTP_I_CONN_LOST);
00357                 sendAbort();
00358                 sctpMain->removeAssociation(this);
00359         }
00360         else if (path!=NULL && msg==path->HeartbeatIntervalTimer)
00361         {
00362                 process_TIMEOUT_HEARTBEAT_INTERVAL(path, path->forceHb);
00363         }
00364         else if (path!=NULL && msg==path->HeartbeatTimer)
00365         {
00366                 process_TIMEOUT_HEARTBEAT(path);
00367         }
00368         else if (path!=NULL && msg==path->T3_RtxTimer)
00369         {
00370                 process_TIMEOUT_RTX(path);
00371         }
00372         else if (path!=NULL && msg==path->CwndTimer)
00373         {
00374                 (this->*ccFunctions.ccUpdateAfterCwndTimeout)(path);
00375         }
00376         else if (msg==StartTesting)
00377         {
00378                 if (sctpMain->testing == false)
00379                 {
00380                         sctpMain->testing = true;
00381                         sctpEV3<<"set testing to true\n";
00382                 }
00383         }
00384         else
00385         {
00386                 sctpAlgorithm->processTimer(msg, event);
00387         }
00388     // then state transitions
00389     return performStateTransition(event);
00390 }

bool SCTPAssociation::processSCTPMessage ( SCTPMessage sctpmsg,
IPvXAddress  srcAddr,
IPvXAddress  destAddr 
)

Process incoming SCTP segment. Normally returns true. A return value of false means that the connection structure must be deleted by the caller (SCTP).

Referenced by SCTP::handleMessage().

00393 {
00394 
00395         printConnBrief();
00396 
00397         localAddr=msgDestAddr;
00398         localPort=sctpmsg->getDestPort();
00399 
00400         remoteAddr=msgSrcAddr;
00401         remotePort=sctpmsg->getSrcPort();
00402 
00403         return process_RCV_Message(sctpmsg, msgSrcAddr, msgDestAddr);
00404 }

bool SCTPAssociation::processAppCommand ( cPacket *  msg  ) 

Process commands from the application. Normally returns true. A return value of false means that the connection structure must be deleted by the caller (SCTP).

Referenced by SCTP::handleMessage().

00429 {
00430         printConnBrief();
00431 
00432         SCTPCommand *sctpCommand = (SCTPCommand *)(msg->removeControlInfo());
00433         SCTPEventCode event = preanalyseAppCommandEvent(msg->getKind());
00434 
00435         sctpEV3 << "App command: " << eventName(event) << "\n";
00436         switch (event)
00437         {
00438                 case SCTP_E_ASSOCIATE: process_ASSOCIATE(event, sctpCommand, msg); break;
00439                 case SCTP_E_OPEN_PASSIVE: process_OPEN_PASSIVE(event, sctpCommand, msg); break;
00440                 case SCTP_E_SEND: process_SEND(event, sctpCommand, msg); break;
00441                 case SCTP_E_CLOSE: process_CLOSE(event); break;
00442                 case SCTP_E_ABORT: process_ABORT(event); break;
00443                 case SCTP_E_RECEIVE: process_RECEIVE_REQUEST(event, sctpCommand); break;
00444                 case SCTP_E_PRIMARY: process_PRIMARY(event, sctpCommand); break;
00445                 case SCTP_E_QUEUE: process_QUEUE(sctpCommand); break;
00446                 case SCTP_E_SHUTDOWN: /*sendShutdown*/ break;  //I.R.
00447                 case SCTP_E_STOP_SENDING: break;
00448                 case SCTP_E_SEND_SHUTDOWN_ACK: if (fsm->getState()==SCTP_S_SHUTDOWN_RECEIVED && getOutstandingBytes()==0) sendShutdownAck(state->primaryPathIndex); break;
00449                 default: opp_error("wrong event code");
00450         }
00451         delete sctpCommand;
00452         // then state transitions
00453         return performStateTransition(event);
00454 }

void SCTPAssociation::removePath (  ) 

Referenced by SCTP::removeAssociation().

00664 {
00665 SCTPPathMap::iterator j;
00666         while((j=sctpPathMap.begin())!=sctpPathMap.end())
00667         {
00668                 stopTimer(j->second->HeartbeatTimer);
00669                 delete j->second->HeartbeatTimer;
00670                 stopTimer(j->second->HeartbeatIntervalTimer);
00671                 delete j->second->HeartbeatIntervalTimer;
00672                 stopTimer(j->second->T3_RtxTimer);
00673                 delete j->second->T3_RtxTimer;
00674                 stopTimer(j->second->CwndTimer);
00675                 delete j->second->CwndTimer;
00676                 delete j->second->pathSsthresh;
00677                 delete j->second->pathCwnd;
00678                 delete j->second->pathTSN;
00679                 delete j->second->pathRcvdTSN;
00680                 delete j->second->pathRTO;
00681                 delete j->second->pathRTT;
00682                 delete j->second;
00683                 sctpPathMap.erase(j);
00684         }
00685 }

void SCTPAssociation::removePath ( IPvXAddress  addr  ) 

01741 {
01742         SCTPPathMap::iterator j = sctpPathMap.find(addr);
01743         if (j!=sctpPathMap.end())
01744         {
01745                 stopTimer(j->second->HeartbeatTimer);
01746                 delete j->second->HeartbeatTimer;
01747                 stopTimer(j->second->HeartbeatIntervalTimer);
01748                 delete j->second->HeartbeatIntervalTimer;
01749                 stopTimer(j->second->T3_RtxTimer);
01750                 delete j->second->T3_RtxTimer;
01751                 stopTimer(j->second->CwndTimer);
01752                 delete j->second->CwndTimer;
01753                 sctpPathMap.erase(j);
01754                 delete j->second;
01755         }
01756 }

void SCTPAssociation::removeLastPath ( IPvXAddress  addr  ) 

01772 {
01773         SCTPPathVariables* path = getPath(addr);
01774         stopTimer(path->HeartbeatTimer);
01775         delete path->HeartbeatTimer;
01776         stopTimer(path->HeartbeatIntervalTimer);
01777         delete path->HeartbeatIntervalTimer;
01778         stopTimer(path->T3_RtxTimer);
01779         delete path->T3_RtxTimer;
01780         stopTimer(path->CwndTimer);
01781         delete path->CwndTimer;
01782 }

void SCTPAssociation::deleteStreams (  ) 

Referenced by SCTP::removeAssociation().

01759 {
01760 
01761         for (SCTPSendStreamMap::iterator it=sendStreams.begin(); it != sendStreams.end(); it++)
01762         {
01763                 it->second->deleteQueue();
01764         }
01765         for (SCTPReceiveStreamMap::iterator it=receiveStreams.begin(); it != receiveStreams.end(); it++)
01766         {
01767                 delete it->second;
01768         }
01769 }

void SCTPAssociation::stopTimer ( cMessage *  timer  ) 

void SCTPAssociation::stopTimers (  ) 

Referenced by process_RCV_Message().

01445 {
01446         for (SCTPPathMap::iterator j = sctpPathMap.begin(); j!=sctpPathMap.end(); j++)
01447         {       
01448                 stopTimer(j->second->HeartbeatTimer);
01449                 stopTimer(j->second->HeartbeatIntervalTimer);
01450         }
01451 }

SCTPPathVariables * SCTPAssociation::getPath ( IPvXAddress  pid  ) 

Referenced by bytesAllowedToSend(), createSack(), cwndUpdateBytesAcked(), dequeueAckedChunks(), fcAdjustCounters(), pmDataIsSentOn(), pmRttMeasurement(), process_STATUS(), process_TIMEOUT_RTX(), processDataArrived(), processSackArrived(), processTimer(), removeLastPath(), and sendAll().

02596 {
02597         SCTPPathMap::iterator i=sctpPathMap.find(pid);
02598         if (i!=sctpPathMap.end())
02599         {
02600                 return i->second;
02601         }
02602         else
02603         {
02604                 return NULL;
02605         }
02606 }

void SCTPAssociation::printSctpPathMap (  ) 

Referenced by processInitAckArrived(), processInitArrived(), sendAll(), sendInit(), and sendInitAck().

00044 {
00045         SCTPPathVariables* path;
00046         sctpEV3<<"\nSCTP PathMap\n";
00047         for (SCTPPathMap::iterator i = sctpPathMap.begin(); i!=sctpPathMap.end(); ++i)
00048         {
00049                 path = i->second;
00050 
00051                         sctpEV3<<"address: "<<path->remoteAddress<<"  osb: "<<path->outstandingBytes<<" cwnd: "<<path->cwnd<<"\n";
00052 
00053         }
00054 }

SCTPEventCode SCTPAssociation::preanalyseAppCommandEvent ( int32  commandCode  )  [protected]

Maps app command codes (msg kind of app command msgs) to SCTP_E_xxx event codes

Referenced by processAppCommand().

00407 {
00408     switch (commandCode)
00409     {
00410         case SCTP_C_ASSOCIATE:  return SCTP_E_ASSOCIATE;
00411         case SCTP_C_OPEN_PASSIVE:       return SCTP_E_OPEN_PASSIVE;
00412         case SCTP_C_SEND:               return SCTP_E_SEND;
00413         case SCTP_C_CLOSE:              return SCTP_E_CLOSE;
00414         case SCTP_C_ABORT:              return SCTP_E_ABORT;
00415         case SCTP_C_RECEIVE:            return SCTP_E_RECEIVE;
00416         case SCTP_C_SEND_UNORDERED:     return SCTP_E_SEND;
00417         case SCTP_C_SEND_ORDERED:       return SCTP_E_SEND;
00418         case SCTP_C_PRIMARY:            return SCTP_E_PRIMARY;
00419         case SCTP_C_QUEUE:              return SCTP_E_QUEUE;
00420         case SCTP_C_SHUTDOWN:           return SCTP_E_SHUTDOWN;
00421         case SCTP_C_NO_OUTSTANDING:     return SCTP_E_SEND_SHUTDOWN_ACK;
00422         default: sctpEV3<<"commandCode="<<commandCode<<"\n";
00423                 opp_error("Unknown message kind in app command");
00424                  return (SCTPEventCode)0; // to satisfy compiler
00425     }
00426 }

bool SCTPAssociation::performStateTransition ( const SCTPEventCode event  )  [protected]

Implemements the pure SCTP state machine

Referenced by process_RCV_Message(), processAppCommand(), processCookieAckArrived(), processCookieEchoArrived(), processInitAckArrived(), processInitArrived(), processTimer(), pushUlp(), and sendShutdownAck().

00458 {
00459         sctpEV3<<"performStateTransition\n";
00460         if (event==SCTP_E_IGNORE)
00461         {
00462                 ev << "Staying in state: " << stateName(fsm->getState()) << " (no FSM event)\n";
00463                 return true;
00464         }
00465 
00466         // state machine
00467         int32 oldState = fsm->getState();
00468         switch (fsm->getState())
00469         {
00470                 case SCTP_S_CLOSED:
00471                         switch (event)
00472                         {
00473                                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00474                                 case SCTP_E_OPEN_PASSIVE: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00475                                 case SCTP_E_ASSOCIATE: FSM_Goto((*fsm), SCTP_S_COOKIE_WAIT); break;
00476                                 case SCTP_E_RCV_INIT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00477                                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00478                                 case SCTP_E_RCV_VALID_COOKIE_ECHO: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break;
00479                                         case SCTP_E_CLOSE: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00480                                 default:;
00481                         }
00482                         break;
00483 
00484                 case SCTP_S_COOKIE_WAIT:
00485                         switch (event)
00486                         {
00487                                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00488                                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00489                                 case SCTP_E_RCV_INIT_ACK: FSM_Goto((*fsm), SCTP_S_COOKIE_ECHOED); break;
00490                                 case SCTP_E_RCV_VALID_COOKIE_ECHO: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break;
00491                                 default:;
00492                         }
00493                         break;
00494 
00495                 case SCTP_S_COOKIE_ECHOED:
00496                         switch (event)
00497                         {
00498                                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00499                                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00500                                 case SCTP_E_RCV_COOKIE_ACK:FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break;
00501                                 default:;
00502                         }
00503                         break;
00504                 case SCTP_S_ESTABLISHED:
00505                         switch (event)
00506                         {
00507                                 case SCTP_E_SEND: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break;
00508                                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00509                                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00510                                 case SCTP_E_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_PENDING);  break;
00511                                 case SCTP_E_STOP_SENDING: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_PENDING); state->stopSending = true; state->lastTSN = state->nextTSN-1; break;  //I.R.
00512                                 case SCTP_E_RCV_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_RECEIVED); break;
00513                                 case SCTP_E_CLOSE: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00514                                 default:;
00515                         }
00516                         break;
00517 
00518                 case SCTP_S_SHUTDOWN_PENDING:
00519                         switch (event)
00520                         {
00521                                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00522                                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00523                                 case SCTP_E_NO_MORE_OUTSTANDING: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_SENT); break;
00524                                 case SCTP_E_RCV_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_RECEIVED); break;
00525                                 case SCTP_E_RCV_SHUTDOWN_ACK: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00526                                 default:;
00527                         }
00528                         break;
00529 
00530                 case SCTP_S_SHUTDOWN_RECEIVED:
00531                         switch (event)
00532                         {
00533                                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00534                                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00535                                 case SCTP_E_NO_MORE_OUTSTANDING: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT); break;
00536                                 default:;
00537                         }
00538                         break;
00539 
00540                 case SCTP_S_SHUTDOWN_SENT:
00541                         switch (event)
00542                         {
00543                                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00544                                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00545                                 case SCTP_E_RCV_SHUTDOWN_ACK: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00546                                 case SCTP_E_RCV_SHUTDOWN: sendShutdownAck(remoteAddr); FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT); break;
00547                                 default:;
00548                         }
00549                         break;
00550 
00551                 case SCTP_S_SHUTDOWN_ACK_SENT:
00552                         switch (event)
00553                         {
00554                                 case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00555                                 case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00556                                 case SCTP_E_RCV_SHUTDOWN_COMPLETE:     FSM_Goto((*fsm), SCTP_S_CLOSED); break;
00557                                 default:;
00558                         }
00559                         break;
00560 
00561         }
00562 
00563         if (oldState!=fsm->getState())
00564         {
00565                 ev << "Transition: " << stateName(oldState) << " --> " << stateName(fsm->getState()) << "  (event was: " << eventName(event) << ")\n";
00566                 sctpEV3 << sctpMain->getName() << ": " << stateName(oldState) << " --> " << stateName(fsm->getState()) << "  (on " << eventName(event) << ")\n";
00567                 stateEntered(fsm->getState());
00568         }
00569         else
00570         {
00571                 ev<< "Staying in state: " << stateName(fsm->getState()) << " (event was: " << eventName(event) << ")\n";
00572         }
00573         if (event==SCTP_E_ABORT && oldState==fsm->getState() && fsm->getState()==SCTP_S_CLOSED)
00574                 return true;
00575 
00576         if (oldState!=fsm->getState() && fsm->getState()==SCTP_S_CLOSED)
00577         {
00578                 return false;
00579         }
00580         else
00581                 return true;
00582 }

void SCTPAssociation::stateEntered ( int32  state  )  [protected]

Referenced by performStateTransition().

00585 {
00586         switch (status)
00587         {
00588                 case SCTP_S_COOKIE_WAIT:
00589 
00590                         break;
00591                 case SCTP_S_ESTABLISHED:
00592                 {
00593                         sctpEV3<<"State ESTABLISHED entered\n";
00594                         char str[70];
00595                         stopTimer(T1_InitTimer);
00596                         if (state->initChunk)
00597                                 delete state->initChunk;
00598                         state->nagleEnabled = (bool)sctpMain->par("nagleEnabled");
00599                                 state->header = 0;
00600                         state->swsLimit = (uint32)sctpMain->par("swsLimit");
00601                         state->reactivatePrimaryPath = (bool)sctpMain->par("reactivatePrimaryPath");
00602                         state->fragment = (bool)sctpMain->par("fragment");
00603                         if (!state->fragment)
00604                                 state->fragment = false;
00605                         sackPeriod = (double)sctpMain->par("sackPeriod");
00606                         sackFrequency = sctpMain->par("sackFrequency");
00607                         SCTP::AssocStat stat;
00608                         stat.assocId = assocId;
00609                         stat.start = simulation.getSimTime();
00610                         stat.stop = 0;
00611                         stat.rcvdBytes=0;
00612                         stat.ackedBytes=0;
00613                         stat.sentBytes=0;
00614                         stat.transmittedBytes=0;
00615                         stat.numFastRtx=0;
00616                         stat.numT3Rtx=0;
00617                         stat.numPathFailures=0;
00618                         stat.numForwardTsn=0;
00619                         stat.lifeTime=0;
00620                         stat.throughput=0;
00621                         sctpMain->assocStatMap[stat.assocId] = stat;
00622                         ccModule = sctpMain->par("ccModule");
00623                         switch (ccModule)
00624                         {
00625                                 case RFC4960:
00626                                 {
00627                                         ccFunctions.ccInitParams = &SCTPAssociation::initCCParameters;
00628                                         ccFunctions.ccUpdateAfterSack = &SCTPAssociation::cwndUpdateAfterSack;
00629                                         ccFunctions.ccUpdateAfterCwndTimeout = &SCTPAssociation::cwndUpdateAfterCwndTimeout;
00630                                         ccFunctions.ccUpdateAfterRtxTimeout = &SCTPAssociation::cwndUpdateAfterRtxTimeout;
00631                                         ccFunctions.ccUpdateMaxBurst = &SCTPAssociation::cwndUpdateMaxBurst;
00632                                         ccFunctions.ccUpdateBytesAcked = &SCTPAssociation::cwndUpdateBytesAcked;
00633                                         break;
00634                                 }
00635                         }
00636                         sendEstabIndicationToApp();
00637                         pmStartPathManagement();
00638                         sprintf(str, "Cumulated TSN Ack of assoc %d", assocId);
00639                         cumTsnAck = new cOutVector(str);
00640                         sprintf(str, "SendQueue of assoc %d", assocId);
00641                         sendQueue = new cOutVector(str);
00642                         state->sendQueueLimit = (uint32)sctpMain->par("sendQueueLimit");
00643                         SCTP::VTagPair vtagPair;
00644                         vtagPair.peerVTag = peerVTag;
00645                         vtagPair.localPort = localPort;
00646                         vtagPair.remotePort = remotePort;
00647                         sctpMain->sctpVTagMap[vtagPair] = this->assocId;
00648                         break;
00649         }
00650                 case SCTP_S_CLOSED:
00651                 {
00652                         sendIndicationToApp(SCTP_I_CLOSED);
00653                         break;
00654                 }
00655                 case SCTP_S_SHUTDOWN_PENDING:
00656                 {
00657                         if (getOutstandingBytes()==0 && transmissionQ->getQueueSize()==0 && qCounter.roomSumSendStreams==0 && fsm->getState() == SCTP_S_SHUTDOWN_PENDING) sendShutdown();
00658                         break;
00659                 }
00660         }
00661 }

void SCTPAssociation::process_ASSOCIATE ( SCTPEventCode event,
SCTPCommand *  sctpCommand,
cPacket *  msg 
) [protected]

Referenced by processAppCommand().

00031 {
00032 IPvXAddress lAddr, rAddr;
00033 
00034         SCTPOpenCommand *openCmd = check_and_cast<SCTPOpenCommand *>(sctpCommand);
00035          
00036         ev<<"SCTPAssociationEventProc:process_ASSOCIATE\n";
00037         
00038         switch(fsm->getState())
00039         {
00040                 case SCTP_S_CLOSED:
00041                 initAssociation(openCmd);
00042                 state->active = true;
00043                 localAddressList = openCmd->getLocalAddresses();
00044                 lAddr = openCmd->getLocalAddresses().front();
00045                 if (!(openCmd->getRemoteAddresses().empty()))
00046                 {
00047                         remoteAddressList = openCmd->getRemoteAddresses();
00048                         rAddr = openCmd->getRemoteAddresses().front();
00049                 }
00050                 else
00051                         rAddr = openCmd->getRemoteAddr();
00052                 localPort = openCmd->getLocalPort();
00053                 remotePort = openCmd->getRemotePort();
00054                 state->numRequests = openCmd->getNumRequests();
00055                 
00056                 if (rAddr.isUnspecified() || remotePort==0)
00057                 opp_error("Error processing command OPEN_ACTIVE: remote address and port must be specified");
00058 
00059                 if (localPort==0)
00060                 {
00061                 localPort = sctpMain->getEphemeralPort();
00062                 }       
00063                 ev << "OPEN: " << lAddr << ":" << localPort << " --> " << rAddr << ":" << remotePort << "\n";
00064 
00065                 sctpMain->updateSockPair(this, lAddr, rAddr, localPort, remotePort);
00066                 state->localRwnd = (long)sctpMain->par("arwnd");
00067                 sendInit();
00068                 startTimer(T1_InitTimer,state->initRexmitTimeout); 
00069                 break;
00070 
00071         default:
00072                 opp_error("Error processing command OPEN_ACTIVE: connection already exists");
00073 }
00074 
00075 }

void SCTPAssociation::process_OPEN_PASSIVE ( SCTPEventCode event,
SCTPCommand *  sctpCommand,
cPacket *  msg 
) [protected]

Referenced by processAppCommand().

00078 {
00079         IPvXAddress lAddr;
00080         int16 localPort;
00081     
00082         SCTPOpenCommand *openCmd = check_and_cast<SCTPOpenCommand *>(sctpCommand);
00083 
00084         sctpEV3<<"SCTPAssociationEventProc:process_OPEN_PASSIVE\n";
00085         
00086         switch(fsm->getState())
00087         {
00088                 case SCTP_S_CLOSED:
00089                         initAssociation(openCmd);
00090                         state->fork = openCmd->getFork();
00091                         localAddressList = openCmd->getLocalAddresses();
00092                         sctpEV3<<"process_OPEN_PASSIVE: number of local addresses="<<localAddressList.size()<<"\n";
00093                         lAddr = openCmd->getLocalAddresses().front();
00094                         localPort = openCmd->getLocalPort();
00095                         state->localRwnd = (long)sctpMain->par("arwnd");
00096                         state->numRequests = openCmd->getNumRequests();
00097                         state->messagesToPush = openCmd->getMessagesToPush();
00098                         
00099                         if (localPort==0)
00100                                 opp_error("Error processing command OPEN_PASSIVE: local port must be specified");
00101                         sctpEV3 << "Assoc "<<assocId<<"::Starting to listen on: " << lAddr << ":" << localPort << "\n"; 
00102                 
00103                         sctpMain->updateSockPair(this, lAddr, IPvXAddress(), localPort, 0);
00104                         break;
00105                 default:
00106                 opp_error("Error processing command OPEN_PASSIVE: connection already exists");
00107         }
00108 }

void SCTPAssociation::process_SEND ( SCTPEventCode event,
SCTPCommand *  sctpCommand,
cPacket *  msg 
) [protected]

Referenced by processAppCommand().

00111 {
00112 uint32 pkSize=0, streamId, sendUnordered, ppid=0;
00113 SCTPSendStream* stream;
00114 
00115         SCTPSendCommand *sendCommand = check_and_cast<SCTPSendCommand *>(sctpCommand);
00116         switch(fsm->getState())
00117         {
00118                 case SCTP_S_ESTABLISHED:  
00119                          
00120                         sctpEV3<<"SCTPAssociationEventProc: process_SEND  localAddr="<<localAddr<<"  remoteAddr="<<remoteAddr<<"  appGateIndex="<<appGateIndex<<"  assocId="<<assocId<<"\n";    
00121                         
00122                         SCTPSimpleMessage* smsg = check_and_cast<SCTPSimpleMessage*>((msg->decapsulate()));
00123                         SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId);
00124                         iter->second.sentBytes+=smsg->getBitLength()/8; 
00125                         pkSize = smsg->getBitLength()+SCTP_DATA_CHUNK_LENGTH*8;
00126                         
00127                                 /* check that message is shorter than the MSS, else use segmentation */
00128                         if (pkSize <= SCTP_MAX_PAYLOAD * 8) 
00129                         {
00130                                 streamId = sendCommand->getSid();
00131                                 sendUnordered = sendCommand->getSendUnordered();
00132                                 ppid = sendCommand->getPpid();
00133                                 SCTPDataMsg* datMsg = new SCTPDataMsg();
00134                                 SCTPSendStreamMap::iterator iter=sendStreams.find(streamId);
00135                                 if (iter!=sendStreams.end())
00136                                         stream=iter->second;
00137                                 else
00138                                         opp_error("stream with id %d not found",streamId);
00139                                 char stri[20];
00140                                 sprintf(stri, "SDATA-%d-%d",streamId,state->msgNum);
00141                                 smsg->setName(stri);
00142                                 datMsg->encapsulate(smsg);
00143                                 datMsg->setSid(streamId);
00144                                 datMsg->setPpid(ppid);
00145                                 if (sendCommand->getPrimary())
00146                                 {
00147                                         if (sendCommand->getRemoteAddr()==IPvXAddress("0.0.0.0"))
00148                                                 datMsg->setInitialDestination(remoteAddr);
00149                                         else
00150                                                 datMsg->setInitialDestination(sendCommand->getRemoteAddr());
00151                                 }
00152                                 else
00153                                         datMsg->setInitialDestination(state->primaryPathIndex);
00154                                 datMsg->setEnqueuingTime(simulation.getSimTime());
00155                                         datMsg->setBooksize(smsg->getBitLength()/8 + state->header);
00156                                 qCounter.roomSumSendStreams += ADD_PADDING(smsg->getBitLength()/8 + SCTP_DATA_CHUNK_LENGTH);
00157 
00158                                 qCounter.bookedSumSendStreams += datMsg->getBooksize();
00159                                 datMsg->setMsgNum(++state->msgNum);
00160 
00161                                 if (sendUnordered==1)
00162                                 {
00163                                         datMsg->setOrdered(false);
00164                                         stream->getUnorderedStreamQ()->insert(datMsg);
00165                                 }
00166                                 else
00167                                 { 
00168                                         datMsg->setOrdered(true);
00169                                         stream->getStreamQ()->insert(datMsg);
00170 
00171                                         if (stream->getStreamQ()->getLength()==state->sendQueueLimit)
00172                                         {
00173                                                 sendIndicationToApp(SCTP_I_SENDQUEUE_FULL);
00174                                                 state->appSendAllowed = false;
00175                                         }
00176                                         sendQueue->record(stream->getStreamQ()->getLength());
00177                                 }
00178                                 state->queuedMessages++;        
00179                                 if (state->queueLimit>0 && state->queuedMessages>state->queueLimit)
00180                                 {
00181                                         state->queueUpdate = false;
00182                                 }
00183                                 sctpEV3<<"\nlast="<<sendCommand->getLast()<<", queueLimit="<<state->queueLimit<<"\n";
00184                                 if (sendCommand->getLast()==true)
00185                                 {
00186                                         if (sendCommand->getPrimary())
00187                                                 sctpAlgorithm->sendCommandInvoked(IPvXAddress("0.0.0.0"));
00188                                         else
00189                                                 sctpAlgorithm->sendCommandInvoked(datMsg->getInitialDestination());
00190                                 }
00191                         }
00192                 break;
00193         }
00194 }

void SCTPAssociation::process_CLOSE ( SCTPEventCode event  )  [protected]

Referenced by processAppCommand().

00224 {
00225          
00226         sctpEV3<<"SCTPAssociationEventProc:process_CLOSE; assoc="<<assocId<<"\n";
00227         
00228         switch(fsm->getState())
00229         {
00230                 case SCTP_S_ESTABLISHED: 
00231                         sendAll(state->primaryPathIndex);
00232                                 
00233                         if (remoteAddr!=state->primaryPathIndex)
00234                                 sendAll(remoteAddr);
00235                                         
00236                         sendShutdown();
00237                         break;
00238                 case SCTP_S_SHUTDOWN_RECEIVED:
00239                         if (getOutstandingBytes()==0)
00240                                 sendShutdownAck(remoteAddr);
00241                         break;         
00242     }
00243 }

void SCTPAssociation::process_ABORT ( SCTPEventCode event  )  [protected]

Referenced by processAppCommand().

00246 {
00247         sctpEV3<<"SCTPAssociationEventProc:process_ABORT\n";
00248         switch(fsm->getState())
00249         {
00250                 case SCTP_S_ESTABLISHED: 
00251                         if (state->ackState < sackFrequency)
00252                         {
00253                                 state->ackState = sackFrequency;        
00254                                 sendAll(state->primaryPathIndex);
00255                                 if (remoteAddr!=state->primaryPathIndex)
00256                                         sendAll(remoteAddr);    
00257                         }
00258                         sendAbort();
00259                         break;         
00260         }
00261 
00262 }

void SCTPAssociation::process_STATUS ( SCTPEventCode event,
SCTPCommand *  sctpCommand,
cPacket *  msg 
) [protected]

00265 {
00266         SCTPStatusInfo *statusInfo = new SCTPStatusInfo();
00267         statusInfo->setState(fsm->getState());
00268         statusInfo->setStateName(stateName(fsm->getState()));
00269         
00270         statusInfo->setPathId(remoteAddr);
00271         statusInfo->setActive(getPath(remoteAddr)->activePath);
00272         
00273         msg->setControlInfo(statusInfo);
00274         sendToApp(msg);
00275 }

void SCTPAssociation::process_RECEIVE_REQUEST ( SCTPEventCode event,
SCTPCommand *  sctpCommand 
) [protected]

Referenced by processAppCommand().

00197 {
00198         SCTPSendCommand *sendCommand = check_and_cast<SCTPSendCommand *>(sctpCommand);
00199         if ((uint32)sendCommand->getSid() > inboundStreams || sendCommand->getSid() < 0) 
00200         {
00201                  
00202                 sctpEV3<<"Application tries to read from invalid stream id....\n";      
00203                 
00204         }
00205          
00206         state->numMsgsReq[sendCommand->getSid()]+= sendCommand->getNumMsgs();
00207         pushUlp();
00208 }

void SCTPAssociation::process_PRIMARY ( SCTPEventCode event,
SCTPCommand *  sctpCommand 
) [protected]

Referenced by processAppCommand().

00211 {
00212         SCTPPathInfo *pinfo = check_and_cast<SCTPPathInfo *>(sctpCommand);
00213         state->primaryPathIndex = pinfo->getRemoteAddress();
00214 }

bool SCTPAssociation::process_RCV_Message ( SCTPMessage sctpseg,
IPvXAddress  src,
IPvXAddress  dest 
) [protected]

Referenced by processSCTPMessage().

00030 {
00031         uint8 type;
00032         bool trans=true, sendAllowed=false, dupReceived=false, dataChunkReceived=false, dataChunkDelivered = false;
00033         bool shutdownCalled=false;
00034         SCTPPathVariables* path;
00035         SCTPChunk* header;
00036         SCTPEventCode event;
00037         int32 srcPort, destPort;
00038         uint32 dataChunkCount = 0;
00039         
00040          
00041         sctpEV3<<getFullPath()<<" SCTPAssociationRcvMessage:process_RCV_Message\n";
00042         sctpEV3<<"localAddr="<<localAddr<<"  remoteAddr="<<remoteAddr<<"\n";
00043         uint32 numberOfChunks = sctpmsg->getChunksArraySize();
00044         sctpEV3<<"numberOfChunks="<<numberOfChunks<<"\n";
00045 
00046 
00047         if ((sctpmsg->hasBitError() || !sctpmsg->getChecksumOk()))
00048         {
00049                 if (((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType()==INIT_ACK)
00050                 {
00051                         stopTimer(T1_InitTimer);
00052                         sctpEV3<<"InitAck with bit-error. Retransmit Init\n";
00053                         retransmitInit();
00054                         startTimer(T1_InitTimer,state->initRexmitTimeout);
00055                 }
00056                 if (((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType()==COOKIE_ACK)
00057                 {
00058                         stopTimer(T1_InitTimer);
00059                         sctpEV3<<"CookieAck with bit-error. Retransmit CookieEcho\n";
00060                         retransmitCookieEcho();
00061                         startTimer(T1_InitTimer,state->initRexmitTimeout);
00062                 }
00063         }
00064 
00065         srcPort = sctpmsg->getDestPort();
00066         destPort = sctpmsg->getSrcPort();
00067         
00068         SCTPPathMap::iterator it=sctpPathMap.find(src);
00069         if (it!=sctpPathMap.end())
00070                 path=it->second;
00071         else
00072                 path=NULL;
00073         state->sctpmsg = (SCTPMessage*)sctpmsg->dup();
00074         for (uint32 i=0; i<numberOfChunks; i++)
00075         {
00076                 header=(SCTPChunk*)(sctpmsg->removeChunk());
00077                 type = header->getChunkType();
00078 
00079                 if (type!=INIT && type!=ABORT && sctpmsg->getTag()!= peerVTag)
00080                 {
00081                         
00082                         ev<<" VTag "<<sctpmsg->getTag()<<" incorrect. Should be "<<peerVTag<<" localVTag="<<localVTag<<"\n";
00083                         
00084                         return true;
00085                 }
00086 
00087                 switch (type)
00088                 {
00089                 case INIT: 
00090                         
00091                         sctpEV3<<"SCTPAssociationRcvMessage: INIT received\n";
00092                         
00093                         SCTPInitChunk* initChunk;
00094                         initChunk = check_and_cast<SCTPInitChunk *>(header);
00095                         if (initChunk->getNoInStreams()!=0 && initChunk->getNoOutStreams()!=0 && initChunk->getInitTag()!=0)
00096                                 trans = processInitArrived(initChunk, srcPort, destPort);
00097                         i = numberOfChunks-1;
00098                         delete initChunk;
00099                         break;
00100                 case INIT_ACK:
00101                         sctpEV3<<"SCTPAssociationRcvMessage: INIT_ACK received\n"; 
00102                         if (fsm->getState()==SCTP_S_COOKIE_WAIT)
00103                         {
00104                                 SCTPInitAckChunk* initAckChunk;
00105                                 initAckChunk = check_and_cast<SCTPInitAckChunk *>(header);
00106                                 if (initAckChunk->getNoInStreams()!=0 && initAckChunk->getNoOutStreams()!=0 && initAckChunk->getInitTag()!=0)
00107                                         trans = processInitAckArrived(initAckChunk);
00108                                 else if (initAckChunk->getInitTag()==0)
00109                                 {
00110                                         sendAbort();
00111                                         sctpMain->removeAssociation(this);      
00112                                 }
00113                                 i = numberOfChunks-1;
00114                                 delete initAckChunk;
00115                         }
00116                         else
00117                                 sctpEV3<<"INIT_ACK will be ignored\n";
00118                         break;
00119                 case COOKIE_ECHO:
00120                         sctpEV3<<"SCTPAssociationRcvMessage: COOKIE_ECHO received\n";
00121                         SCTPCookieEchoChunk* cookieEchoChunk;
00122                         cookieEchoChunk = check_and_cast<SCTPCookieEchoChunk *>(header);
00123                         trans = processCookieEchoArrived(cookieEchoChunk,src);
00124                         delete cookieEchoChunk;
00125                         break;
00126                 case COOKIE_ACK: 
00127                         
00128                         sctpEV3<<"SCTPAssociationRcvMessage: COOKIE_ACK received\n";
00129                         if (fsm->getState()==SCTP_S_COOKIE_ECHOED)
00130                         {
00131                                 SCTPCookieAckChunk* cookieAckChunk;
00132                                 cookieAckChunk = check_and_cast<SCTPCookieAckChunk *>(header);
00133                                 trans = processCookieAckArrived();
00134                                 delete cookieAckChunk;
00135                         }
00136                         break;
00137                 case DATA: 
00138                         
00139                         sctpEV3<<"\nSCTPAssociationRcvMessage: DATA received\n";
00140                         if (fsm->getState()==SCTP_S_COOKIE_ECHOED)
00141                                 trans=performStateTransition(SCTP_E_RCV_COOKIE_ACK);
00142                         
00143                         if (!(fsm->getState()==SCTP_S_SHUTDOWN_RECEIVED || fsm->getState()==SCTP_S_SHUTDOWN_ACK_SENT))
00144                         {
00145                                 SCTPDataChunk* dataChunk;
00146                                 dataChunk = check_and_cast<SCTPDataChunk *>(header);
00147                                 if (dataChunk->getByteLength()-16>0)
00148                                 {
00149                                         dataChunkCount++;
00150                                         event=processDataArrived(dataChunk, dataChunkCount);
00151                                         if (event == SCTP_E_DELIVERED)
00152                                         {
00153                                                 dataChunkReceived=true;
00154                                                 dataChunkDelivered = true;
00155                                                 state->sackAllowed = true;                              
00156                                         }
00157                                         else if (event==SCTP_E_SEND || event==SCTP_E_IGNORE)
00158                                         {
00159                                                 dataChunkReceived=true;
00160                                                 state->sackAllowed = true;
00161                                         }
00162                                         else if (event==SCTP_E_DUP_RECEIVED)
00163                                         {
00164                                                 dupReceived=true;
00165                                         }
00166                                 }
00167                                 else
00168                                 {
00169                                         sendAbort();
00170                                         sctpMain->removeAssociation(this);
00171                                 }
00172                                 
00173                                 delete dataChunk;
00174                         }
00175                         trans = true;
00176                         break;  
00177                 case SACK: 
00178                 {
00179                         CounterMap::iterator rtq=qCounter.roomRetransQ.find(remoteAddr);
00180                         int32 scount;
00181                         scount = qCounter.roomSumSendStreams;
00182                         sctpEV3<<"SCTPAssociationRcvMessage: SACK received\n";
00183                         
00184                         SCTPSackChunk* sackChunk;
00185                         sackChunk = check_and_cast<SCTPSackChunk *>(header);
00186                         processSackArrived(sackChunk);
00187                         trans=true;
00188                         sendAllowed=true;
00189                         delete sackChunk;
00190                         sctpEV3<<"state->lastTsnAck="<<state->lastTsnAck<<" state->lastTSN="<<state->lastTSN<<" getOutstandingBytes()="<<getOutstandingBytes()<<" transmissionQ->getQueueSize()="<<transmissionQ->getQueueSize()<<" scount="<<scount<<" fsm->getState()="<<fsm->getState()<<"\n";
00191                         if ((state->lastTsnAck == state->lastTSN || (getOutstandingBytes()==0 && transmissionQ->getQueueSize()==0 && scount==0)) && fsm->getState() == SCTP_S_SHUTDOWN_PENDING)
00192                         {
00193                                 sctpEV3<<"no more packets: send Shutdown\n";
00194                                 sendShutdown();
00195                                 trans=performStateTransition(SCTP_E_NO_MORE_OUTSTANDING);
00196                                 shutdownCalled=true;    
00197                         }
00198                         else if (fsm->getState()==SCTP_S_SHUTDOWN_RECEIVED && getOutstandingBytes()==0)
00199                         {
00200                                 sctpEV3<<"no more outstanding\n";
00201                                 sendShutdownAck(remoteAddr);
00202                                 trans=performStateTransition(SCTP_E_NO_MORE_OUTSTANDING);
00203                         }
00204                         break;
00205                 }
00206                 case ABORT:
00207                         SCTPAbortChunk* abortChunk;
00208                         abortChunk = check_and_cast<SCTPAbortChunk *>(header);
00209                         sctpEV3<<"SCTPAssociationRcvMessage: ABORT with T-Bit "<<abortChunk->getT_Bit() << " received\n";
00210                         if (sctpmsg->getTag() == localVTag || sctpmsg->getTag() == peerVTag)
00211                         {
00212                                 sendIndicationToApp(SCTP_I_ABORT);
00213                                 trans=performStateTransition(SCTP_E_ABORT);
00214                         }
00215                         delete abortChunk;
00216                         break;  
00217                 case HEARTBEAT: 
00218                         
00219                         sctpEV3<<"SCTPAssociationRcvMessage: HEARTBEAT received\n";     
00220                         
00221                         SCTPHeartbeatChunk* heartbeatChunk;
00222                         heartbeatChunk = check_and_cast<SCTPHeartbeatChunk *>(header);  
00223                         if (!(fsm->getState()==SCTP_S_CLOSED ))
00224                         {
00225                                 sendHeartbeatAck(heartbeatChunk, dest,src);     
00226                         }
00227                         trans=true;
00228                         delete heartbeatChunk;
00229                         break;
00230                 case HEARTBEAT_ACK:
00231                         
00232                         sctpEV3<<"SCTPAssociationRcvMessage: HEARTBEAT_ACK received\n";
00233                         if (fsm->getState()==SCTP_S_COOKIE_ECHOED)
00234                                 trans=performStateTransition(SCTP_E_RCV_COOKIE_ACK);
00235                         
00236                         SCTPHeartbeatAckChunk* heartbeatAckChunk;
00237                         heartbeatAckChunk = check_and_cast<SCTPHeartbeatAckChunk *>(header);    
00238                         if (path)
00239                                 processHeartbeatAckArrived(heartbeatAckChunk, path);    
00240                         trans=true;
00241                         delete heartbeatAckChunk;
00242                         break;
00243                 case SHUTDOWN:
00244                         sctpEV3<<"Shutdown received\n";
00245                         SCTPShutdownChunk* shutdownChunk;
00246                         shutdownChunk = check_and_cast<SCTPShutdownChunk *>(header);
00247                         if (shutdownChunk->getCumTsnAck()>state->lastTsnAck)
00248                         {
00249                                 simtime_t rttEst=-1.0;
00250                                 dequeueAckedChunks(shutdownChunk->getCumTsnAck(), remoteAddr, &rttEst); 
00251                                 state->lastTsnAck = shutdownChunk->getCumTsnAck();
00252                         }
00253                         trans=performStateTransition(SCTP_E_RCV_SHUTDOWN);
00254                         sendIndicationToApp(SCTP_I_SHUTDOWN_RECEIVED);  
00255                         trans=true;
00256                         delete shutdownChunk;
00257                         break;
00258                 case SHUTDOWN_ACK:
00259                         sctpEV3<<"ShutdownAck received\n";
00260                         if (fsm->getState()!=SCTP_S_ESTABLISHED)
00261                         {
00262                                 SCTPShutdownAckChunk* shutdownAckChunk;
00263                                 shutdownAckChunk = check_and_cast<SCTPShutdownAckChunk *>(header);
00264                                 sendShutdownComplete();
00265                                 stopTimers();
00266                                 stopTimer(T2_ShutdownTimer);
00267                                 stopTimer(T5_ShutdownGuardTimer);
00268                                 
00269                                 if (fsm->getState()==SCTP_S_SHUTDOWN_SENT || fsm->getState()==SCTP_S_SHUTDOWN_ACK_SENT)
00270                                 {
00271                                         trans=performStateTransition(SCTP_E_RCV_SHUTDOWN_ACK);  
00272                                         sendIndicationToApp(SCTP_I_CLOSED);
00273                                         delete state->shutdownChunk;
00274                                 }
00275                                 
00276                                 delete shutdownAckChunk;
00277                         }
00278                         break;  
00279                 case SHUTDOWN_COMPLETE:
00280                         sctpEV3<<"Shutdown Complete arrived\n";
00281                         SCTPShutdownCompleteChunk* shutdownCompleteChunk;
00282                         shutdownCompleteChunk = check_and_cast<SCTPShutdownCompleteChunk *>(header);
00283                         trans=performStateTransition(SCTP_E_RCV_SHUTDOWN_COMPLETE);
00284                         sendIndicationToApp(SCTP_I_PEER_CLOSED);        // necessary for NAT-Rendezvous
00285                         if (trans==true)
00286                                 stopTimers();
00287                         stopTimer(T2_ShutdownTimer);
00288                         stopTimer(T5_ShutdownGuardTimer);       
00289                         delete state->shutdownAckChunk;
00290                         delete shutdownCompleteChunk;
00291                         break;  
00292                 default: sctpEV3<<"different type\n"; break;
00293                 }
00294                 
00295                 if (i==numberOfChunks-1 && (dataChunkReceived || dupReceived))
00296                 {
00297                         sendAllowed=true;
00298                         sctpEV3<<"i="<<i<<" sendAllowed=true; scheduleSack\n";
00299                         scheduleSack(); 
00300                         if (fsm->getState()==SCTP_S_SHUTDOWN_SENT && state->ackState>=sackFrequency)
00301                                 sendSack();
00302                 }
00303 
00304                                                 
00305                 /* send any new DATA chunks, SACK chunks, HB chunks etc. */
00306                 if ((fsm->getState()==SCTP_S_ESTABLISHED || fsm->getState()==SCTP_S_SHUTDOWN_PENDING) && sendAllowed && !shutdownCalled)
00307                 {
00308                         sctpEV3<<"SCTPRcvMessage 449:sendAll to primaryPath:"<<state->primaryPathIndex<<"\n";
00309                         sendAll(state->primaryPathIndex);       
00310                         if (remoteAddr!=state->primaryPathIndex)
00311                         {
00312                                 sctpEV3<<"SCTPRcvMessage 453:sendAll to remoteAddr: "<<remoteAddr<<"\n";
00313                                 sendAll(remoteAddr);
00314                         }
00315                                 
00316                 }
00317         }
00318         disposeOf(state->sctpmsg);
00319         sctpEV3<<"trans="<<trans<<"\n";
00320         return trans;
00321 }

bool SCTPAssociation::processInitArrived ( SCTPInitChunk *  initChunk,
int32  sport,
int32  dport 
) [protected]

Process incoming SCTP packets. Invoked from process_RCV_Message

Referenced by process_RCV_Message().

00324 {
00325         SCTPAssociation* assoc;
00326         char timername[70];
00327         bool trans = false;
00328         InterfaceTableAccess interfaceTableAccess;
00329         AddressVector adv;
00330         sctpEV3<<"processInitArrived\n";
00331         if (fsm->getState()==SCTP_S_CLOSED)
00332         {
00333                 sctpEV3<<"fork="<<state->fork<<" initReceived="<<state->initReceived<<"\n";
00334                 if (state->fork && !state->initReceived)
00335                 {
00336                         sctpEV3<<"cloneAssociation\n";
00337                         assoc = cloneAssociation(); 
00338                         sctpEV3<<"addForkedAssociation\n";
00339                         sctpMain->addForkedAssociation(this, assoc, localAddr, remoteAddr, srcPort, destPort);
00340 
00341                         sctpEV3 << "Connection forked: this connection got new assocId=" << assocId << ", "
00342                                 "spinoff keeps LISTENing with assocId=" << assoc->assocId << "\n";
00343                         sprintf(timername, "T2_SHUTDOWN of assoc %d", assocId);
00344                         T2_ShutdownTimer->setName(timername);
00345                         sprintf(timername, "SACK_TIMER of assoc %d", assocId);
00346                         SackTimer->setName(timername);
00347                         sprintf(timername, "T1_INIT of assoc %d", assocId);
00348                         T1_InitTimer->setName(timername);
00349                 }
00350                 else
00351                 {
00352                         sctpMain->updateSockPair(this, localAddr, remoteAddr, srcPort, destPort);
00353 
00354                 } 
00355                 if (!state->initReceived)
00356                 {
00357                         state->initReceived = true;
00358                         state->initialPrimaryPath = remoteAddr;
00359                         state->primaryPathIndex = remoteAddr;
00360                         if (initchunk->getAddressesArraySize()==0)
00361                         {
00362                                 SCTPPathVariables* rPath = new SCTPPathVariables(remoteAddr, this);
00363                                 sctpPathMap[rPath->remoteAddress] = rPath;
00364                                 qCounter.roomTransQ[rPath->remoteAddress] = 0;
00365                                 qCounter.roomRetransQ[rPath->remoteAddress] = 0;
00366                                 qCounter.bookedTransQ[rPath->remoteAddress] = 0;
00367                         }
00368                         initPeerTsn=initchunk->getInitTSN();
00369                         state->cTsnAck = initPeerTsn - 1;
00370                         state->initialPeerRwnd = initchunk->getA_rwnd();
00371                         state->peerRwnd = state->initialPeerRwnd;
00372                         localVTag= initchunk->getInitTag();
00373                         numberOfRemoteAddresses =initchunk->getAddressesArraySize(); 
00374                         IInterfaceTable *ift = interfaceTableAccess.get();
00375                         state->localAddresses.clear();
00376                         if (localAddressList.front() == IPvXAddress("0.0.0.0"))
00377                         {
00378                                 for (int32 i=0; i<ift->getNumInterfaces(); ++i)
00379                                 {
00380                                         //if (ift->getInterface(i)->ipv4()!=NULL)
00381                                         if (ift->getInterface(i)->ipv4Data()!=NULL)
00382                                         { 
00383                                                 //adv.push_back(ift->getInterface(i)->ipv4()->getIPAddress());
00384                                                 adv.push_back(ift->getInterface(i)->ipv4Data()->getIPAddress());
00385                                         }
00386                                         else if (ift->getInterface(i)->ipv6Data()!=NULL)
00387                                         { 
00388                                                 adv.push_back(ift->getInterface(i)->ipv6Data()->getAddress(0));
00389                                         }
00390                                 }
00391                         }
00392                         else
00393                         {       
00394                                 adv = localAddressList;
00395                         }
00396                         uint32 rlevel = getLevel(remoteAddr);
00397                         if (rlevel>0)
00398                                 for (AddressVector::iterator i=adv.begin(); i!=adv.end(); ++i)
00399                                 {
00400                                         if (getLevel((*i))>=rlevel)
00401                                         {
00402                                                 sctpMain->addLocalAddress(this, (*i));
00403                                                 state->localAddresses.push_back((*i));
00404                                         }
00405                                 }
00406                         for (uint32 j=0; j<initchunk->getAddressesArraySize(); j++)
00407                         {
00408                                 // skip IPv6 because we can't send to them yet
00409                                 if (initchunk->getAddresses(j).isIPv6())
00410                                         continue;
00411                                 // set path variables for this pathlocalAddresses
00412                                 SCTPPathVariables* path = new SCTPPathVariables(initchunk->getAddresses(j), this);
00413                                 for (AddressVector::iterator k=state->localAddresses.begin(); k!=state->localAddresses.end(); ++k)
00414                                 {
00415                                         sctpMain->addRemoteAddress(this,(*k), initchunk->getAddresses(j));
00416                                         this->remoteAddressList.push_back(initchunk->getAddresses(j));
00417                                 }                       
00418                                 sctpPathMap[path->remoteAddress] = path;
00419                                 qCounter.roomTransQ[path->remoteAddress] = 0;
00420                                 qCounter.roomRetransQ[path->remoteAddress] = 0;
00421                                 qCounter.bookedTransQ[path->remoteAddress] = 0;
00422                         }
00423                         SCTPPathMap::iterator ite=sctpPathMap.find(remoteAddr);
00424                         if (ite==sctpPathMap.end())
00425                         {
00426                                 SCTPPathVariables* path = new SCTPPathVariables(remoteAddr, this);
00427                                 sctpPathMap[remoteAddr] = path;
00428                                 qCounter.roomTransQ[remoteAddr] = 0;
00429                                 qCounter.roomRetransQ[remoteAddr] = 0;
00430                                 qCounter.bookedTransQ[remoteAddr] = 0;
00431                         }
00432                         trans=performStateTransition(SCTP_E_RCV_INIT);
00433                         if (trans)
00434                         {
00435                                 sendInitAck(initchunk);
00436                         }
00437                 }
00438                 else if (fsm->getState()==SCTP_S_CLOSED)
00439                 {
00440                         trans=performStateTransition(SCTP_E_RCV_INIT);
00441                         if (trans)
00442                                 sendInitAck(initchunk);
00443                 }
00444                 else 
00445                         trans = true;
00446         }
00447         else if (fsm->getState()==SCTP_S_COOKIE_WAIT) //INIT-Collision
00448         {
00449                 sctpEV3<<"INIT collision: send Init-Ack\n";     
00450                 sendInitAck(initchunk);  
00451                 trans=true;
00452         }
00453         else if (fsm->getState()==SCTP_S_COOKIE_ECHOED || fsm->getState()==SCTP_S_ESTABLISHED)
00454         {
00455                 // check, whether a new address has been added
00456                 bool addressPresent = false;
00457                 for (uint32 j=0; j<initchunk->getAddressesArraySize(); j++)
00458                 {
00459                         if (initchunk->getAddresses(j).isIPv6())
00460                                 continue;
00461                         for (AddressVector::iterator k=remoteAddressList.begin(); k!=remoteAddressList.end(); ++k)
00462                         {
00463                                 if ((*k)==(initchunk->getAddresses(j)))
00464                                 {
00465                                         addressPresent = true;
00466                                         break;
00467                                 }
00468                         }
00469                         if (!addressPresent)
00470                         {
00471                                 sendAbort();
00472                                 return true;
00473                         }
00474                 }
00475                 sendInitAck(initchunk);
00476                 trans=true;
00477         }
00478         else if (fsm->getState()==SCTP_S_SHUTDOWN_ACK_SENT)
00479                 trans = true;
00480         printSctpPathMap();
00481         return trans;
00482 }

bool SCTPAssociation::processInitAckArrived ( SCTPInitAckChunk *  initAckChunk  )  [protected]

Referenced by process_RCV_Message().

00486 {
00487         bool trans = false;
00488         if (fsm->getState()==SCTP_S_COOKIE_WAIT)
00489         {
00490                 sctpEV3<<"State is COOKIE_WAIT, Cookie_Echo has to be sent\n";
00491                 stopTimer(T1_InitTimer);
00492                 state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT;
00493                 trans=performStateTransition(SCTP_E_RCV_INIT_ACK);
00494                 //delete state->initChunk; will be deleted when state ESTABLISHED is entered
00495                 if (trans)
00496                 {
00497                         state->initialPrimaryPath = remoteAddr;
00498                         state->primaryPathIndex = remoteAddr;
00499                         initPeerTsn=initAckChunk->getInitTSN();
00500                         localVTag= initAckChunk->getInitTag();
00501                         state->cTsnAck = initPeerTsn - 1;
00502                         state->initialPeerRwnd = initAckChunk->getA_rwnd();
00503                         state->peerRwnd = state->initialPeerRwnd;
00504                         remoteAddressList.clear();
00505                         numberOfRemoteAddresses =initAckChunk->getAddressesArraySize(); 
00506                         sctpEV3<<"number of remote addresses in initAck="<<numberOfRemoteAddresses<<"\n";
00507                         for (uint32 j=0; j<numberOfRemoteAddresses; j++)
00508                         {
00509                                 if (initAckChunk->getAddresses(j).isIPv6())
00510                                         continue;
00511                                 for (AddressVector::iterator k=state->localAddresses.begin(); k!=state->localAddresses.end(); ++k)
00512                                 {
00513                                         if (!((*k).isUnspecified()))
00514                                         {
00515                                                 sctpEV3<<"addPath "<<initAckChunk->getAddresses(j)<<"\n";
00516                                                 sctpMain->addRemoteAddress(this,(*k), initAckChunk->getAddresses(j));
00517                                                 this->remoteAddressList.push_back(initAckChunk->getAddresses(j));
00518                                                 addPath(initAckChunk->getAddresses(j));
00519                                         }
00520                                 }
00521                         }
00522                         SCTPPathMap::iterator ite=sctpPathMap.find(remoteAddr);
00523                         if (ite==sctpPathMap.end())
00524                         {
00525                                 SCTPPathVariables* path = new SCTPPathVariables(remoteAddr, this);
00526                                 sctpPathMap[remoteAddr] = path;
00527                                 qCounter.roomTransQ[remoteAddr] = 0;
00528                                 qCounter.roomRetransQ[remoteAddr] = 0;
00529                                 qCounter.bookedTransQ[remoteAddr] = 0;
00530                         }
00531                 
00532                         inboundStreams = ((initAckChunk->getNoOutStreams()<inboundStreams)?initAckChunk->getNoOutStreams():inboundStreams);
00533                         outboundStreams = ((initAckChunk->getNoInStreams()<outboundStreams)?initAckChunk->getNoInStreams():outboundStreams);
00534                         (this->*ssFunctions.ssInitStreams)(inboundStreams, outboundStreams);
00535                         sendCookieEcho(initAckChunk);
00536                 }
00537                 startTimer(T1_InitTimer, state->initRexmitTimeout);
00538                 
00539         }
00540         else
00541                 sctpEV3<<"State="<<fsm->getState()<<"\n";
00542         printSctpPathMap();
00543         return trans;
00544 }

bool SCTPAssociation::processCookieEchoArrived ( SCTPCookieEchoChunk *  cookieEcho,
IPvXAddress  addr 
) [protected]

Referenced by process_RCV_Message().

00549 {
00550         bool trans = false;
00551         SCTPCookie* cookie = check_and_cast<SCTPCookie*>(cookieEcho->getStateCookie());
00552         if (cookie->getCreationTime()+(int32)sctpMain->par("validCookieLifetime")<simulation.getSimTime())
00553         {
00554                 sctpEV3<<"stale Cookie: sendAbort\n";
00555                 sendAbort();
00556                 delete cookie;
00557                 return trans;
00558         }
00559         if (fsm->getState()==SCTP_S_CLOSED)
00560         {
00561                 if (cookie->getLocalTag()!=localVTag || cookie->getPeerTag() != peerVTag) 
00562                 {
00563                         bool same=true;
00564                         for (int32 i=0; i<32; i++)
00565                         {
00566                                 if (cookie->getLocalTieTag(i)!=state->localTieTag[i])
00567                                 {
00568                                         same = false;
00569                                         break;
00570                                 }
00571                                 if (cookie->getPeerTieTag(i)!=state->peerTieTag[i])
00572                                 {
00573                                         same = false;
00574                                         break;
00575                                 }
00576                         }
00577                         if (!same)
00578                         {
00579                                 sendAbort();
00580                                 delete cookie;
00581                                 return trans;
00582                         }
00583                 }
00584                 
00585                 sctpEV3<<"State is CLOSED, Cookie_Ack has to be sent\n";
00586                 trans=performStateTransition(SCTP_E_RCV_VALID_COOKIE_ECHO);
00587                 if (trans)
00588                         sendCookieAck(addr);//send to address
00589         }
00590         else if (fsm->getState()==SCTP_S_ESTABLISHED || fsm->getState()==SCTP_S_COOKIE_WAIT || fsm->getState()==SCTP_S_COOKIE_ECHOED)
00591         {
00592                 sctpEV3<<"State is not CLOSED, but COOKIE_ECHO received. Compare the Tags\n";
00593                 // case A: Peer restarted, retrieve information from cookie
00594                 if (cookie->getLocalTag()!=localVTag && cookie->getPeerTag() != peerVTag )
00595                 {
00596                         bool same=true;
00597                         for (int32 i=0; i<32; i++)
00598                         {
00599                                 if (cookie->getLocalTieTag(i)!=state->localTieTag[i])
00600                                 {
00601                                         same = false;
00602                                         break;
00603                                 }
00604                                 if (cookie->getPeerTieTag(i)!=state->peerTieTag[i])
00605                                 {
00606                                         same = false;
00607                                         break;
00608                                 }
00609                         }
00610                         if (same)
00611                         {
00612                                 localVTag = cookie->getLocalTag();
00613                                 peerVTag = cookie->getPeerTag();
00614                                 sendCookieAck(addr);
00615                         }
00616                 }
00617                 // case B: Setup collision, retrieve information from cookie
00618                 else if (cookie->getPeerTag()==peerVTag && (cookie->getLocalTag()!=localVTag || cookie->getLocalTag()==0))
00619                 {
00620                         localVTag = cookie->getLocalTag();
00621                         peerVTag = cookie->getPeerTag();
00622                         performStateTransition(SCTP_E_RCV_VALID_COOKIE_ECHO);
00623                         sendCookieAck(addr);
00624                 }
00625                 else if (cookie->getPeerTag()==peerVTag && cookie->getLocalTag()==localVTag)
00626                 {
00627                         sendCookieAck(addr); //send to address src
00628                 }
00629                 trans=true;
00630         }
00631         else 
00632         {
00633                 sctpEV3<<"State="<<fsm->getState()<<"\n";
00634                 trans = true;
00635         }
00636         delete cookie;
00637         return trans;
00638 }

bool SCTPAssociation::processCookieAckArrived (  )  [protected]

Referenced by process_RCV_Message().

00641 {
00642 bool trans=false;
00643 
00644         if (fsm->getState()==SCTP_S_COOKIE_ECHOED)
00645         {
00646                 stopTimer(T1_InitTimer);
00647                 trans=performStateTransition(SCTP_E_RCV_COOKIE_ACK);
00648                 if (state->cookieChunk->getCookieArraySize()==0)
00649                 {
00650                                 delete state->cookieChunk->getStateCookie();
00651                 }
00652                 delete state->cookieChunk;
00653                 return trans;                   
00654         }
00655         else
00656                 sctpEV3<<"State="<<fsm->getState()<<"\n";
00657 
00658         return trans;
00659 }

SCTPEventCode SCTPAssociation::processDataArrived ( SCTPDataChunk *  dataChunk,
uint32  count 
) [protected]

Referenced by process_RCV_Message().

01103 {
01104         SCTPEventCode event;
01105         uint32 tsn;
01106         bool checkCtsnaChange=false;
01107         
01108         //recordScalar("delay", simulation.getSimTime()-dataChunk->getEnqueuingTime());
01109         state->newChunkReceived = false;
01110         state->lastDataSourceAddress = remoteAddr;
01111         SCTPPathVariables* path=getPath(remoteAddr);
01112         tsn=dataChunk->getTsn();
01113 
01114         sctpEV3<<simulation.getSimTime()<<"  SCTPAssociation::processDataArrived TSN="<<tsn<<", SID="<<dataChunk->getSid()<<", SSN="<<dataChunk->getSsn()<<"\n";
01115         sctpEV3<<"localRwnd="<<state->localRwnd<<", queuedRcvBytes="<<state->queuedRcvBytes<<"\n";
01116         sctpEV3<<"Laenge="<<dataChunk->getBitLength()<<"\n";
01117         sctpEV3<<simulation.getSimTime()<<"  SCTPAssociation::processDataArrived TSN="<<tsn<<"\n";
01118         path->pathRcvdTSN->record(tsn);
01119         state->lastTsnReceived=tsn;
01120         SCTPSimpleMessage* smsg = check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate());
01121         dataChunk->setBitLength(SCTP_DATA_CHUNK_LENGTH*8);
01122         dataChunk->encapsulate(smsg);
01123         uint32 payloadLength = dataChunk->getBitLength()/8-SCTP_DATA_CHUNK_LENGTH;
01124         sctpEV3<<"state->bytesRcvd="<<state->bytesRcvd<<"\n";
01125         state->bytesRcvd+=payloadLength;
01126         sctpEV3<<"state->bytesRcvd now="<<state->bytesRcvd<<"\n";
01127         SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId);
01128         iter->second.rcvdBytes+=dataChunk->getBitLength()/8-SCTP_DATA_CHUNK_LENGTH;
01129         
01130         if (state->numGaps == 0)
01131                 state->highestTsnReceived = state->cTsnAck;
01132         else
01133                 state->highestTsnReceived = state->gapStopList[state->numGaps-1];
01134         
01135         if (state->stopReceiving)
01136         {
01137                 return SCTP_E_IGNORE;
01138         }
01139         
01140         if (tsnLe(tsn, state->cTsnAck))
01141         {
01142 
01143                         sctpEV3<<"sctp_handle_incoming_data_chunk: old TSN value...inserted to duplist - returning\n tsn="<<tsn<<"  lastAcked="<<state->cTsnAck<<"\n";
01144                         
01145                         state->dupList.push_back(tsn);
01146                         state->dupList.unique();
01147                         delete check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate());
01148                         return SCTP_E_DUP_RECEIVED;
01149         }
01150 
01151 
01152         if ((int32)(state->localRwnd-state->queuedRcvBytes)<=0)
01153         {
01154                 if (tsnGt(tsn, state->highestTsnReceived))
01155                 {
01156                         sctpEV3<<"sctp_handle_incoming_data_chunk: dropping new chunk due to full receive buffer -- wait for rwnd to open up\n";
01157                         
01158                         return SCTP_E_IGNORE;
01159                 }
01160                 // changed 06.07.05 I.R.
01161                 else if (!tsnIsDuplicate(tsn) && tsn<state->highestTsnStored)
01162                 { 
01163                         if (!makeRoomForTsn(tsn, dataChunk->getBitLength()-SCTP_DATA_CHUNK_LENGTH*8, dataChunk->getUBit()))
01164                         {
01165                                 delete check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate());
01166                                 return SCTP_E_IGNORE;
01167                         }
01168                         quBytes->record(state->queuedRcvBytes);
01169                 }
01170         }
01171         if (tsnGt(tsn, state->highestTsnReceived)) 
01172         {
01173                 sctpEV3<<"highestTsnReceived="<<state->highestTsnReceived<<"; tsn="<<tsn<<"\n";
01174                 state->highestTsnReceived = state->highestTsnStored = tsn;
01175                 if (tsn==initPeerTsn)
01176                 {
01177                         state->cTsnAck = tsn;
01178                 }
01179                 else
01180                 {
01181                 /* UPDATE fragment list   */
01182                         sctpEV3<<"update fragment list\n";
01183                         checkCtsnaChange = updateGapList(tsn);
01184                 }
01185                 state->newChunkReceived = true;         
01186         } 
01187         else if (tsnIsDuplicate(tsn)) 
01188         {       
01189                 state->dupList.push_back(tsn);
01190                 state->dupList.unique();
01191                  
01192                 sctpEV3<<"sctp_handle_incoming_data_chunk: TSN value is duplicate within a fragment -- returning";
01193                 
01194                 return SCTP_E_IGNORE;           
01195         } 
01196         else 
01197         {
01198                 sctpEV3<<"else: updateGapList\n";
01199                 checkCtsnaChange = updateGapList(tsn);
01200         }
01201         
01202         if (state->swsAvoidanceInvoked) 
01203         {
01204                 /* schedule a SACK to be sent at once in this case */
01205                 sctpEV3<<"swsAvoidanceInvoked\n";
01206                 state->ackState = sackFrequency;
01207         }               
01208                 
01209         if (checkCtsnaChange) 
01210         {
01211                 advanceCtsna();
01212         }
01213         event=SCTP_E_SEND; 
01214         
01215         sctpEV3<<"\ncTsnAck="<<state->cTsnAck<<" highestTsnReceived="<<state->highestTsnReceived<<"\n";
01216         
01217         if (state->newChunkReceived)
01218         {
01219                 SCTPReceiveStreamMap::iterator iter=receiveStreams.find(dataChunk->getSid());
01220 
01221                 if ((iter->second->enqueueNewDataChunk(makeVarFromMsg(dataChunk)))>0)
01222                 {
01223 
01224         state->queuedRcvBytes+=payloadLength;
01225 
01226                         event = SCTP_E_DELIVERED;
01227                         sendDataArrivedNotification(dataChunk->getSid());
01228                         putInDeliveryQ(dataChunk->getSid());
01229                 }
01230                 state->newChunkReceived=false;
01231         }
01232         
01233 
01234         return event;
01235 }

SCTPEventCode SCTPAssociation::processSackArrived ( SCTPSackChunk *  sackChunk  )  [protected]

Referenced by process_RCV_Message().

00664 {
00665         uint32 tsna, ackedBytes=0, osb=0, bufferPosition, osbPathBefore, osbBefore, lo, hi, hiAcked;
00666         uint64 arwnd;
00667         uint16 numGaps, numDups;
00668         bool ctsnaAdvanced = false, rtxNecessary=false, lowestTsnRetransmitted = false;
00669         SCTPDataVariables *datVar;
00670         simtime_t  timeDiff, rttEst = -1.0;
00671         SCTPPathVariables* path;
00672         IPvXAddress pathId, pid;
00673 
00674         tsna=sackChunk->getCumTsnAck();
00675         arwnd = sackChunk->getA_rwnd();
00676         numGaps=sackChunk->getNumGaps();
00677         numDups=sackChunk->getNumDupTsns();     
00678         hiAcked = tsna;
00679         pathId = remoteAddr;    
00680         path=getPath(pathId);
00681 
00682         path->pathRcvdTSN->record(tsna);
00683         sctpEV3<<simulation.getSimTime()<<" processSackArrived at "<<localAddr<<": tsna="<<tsna<<" arwnd="<<arwnd<<"  numGaps="<<numGaps<<"  numDups="<<numDups<<" osb on path "<<pathId<<"="<<path->outstandingBytes<<" highestTsnReceived="<<state->highestTsnReceived<<" highestTsnAcked="<<state->highestTsnAcked<<" lastTsnAcked="<<state->lastTsnAck<<"\n";
00684         if ((int32)path->outstandingBytes<0)
00685                 opp_error("rcv %d ,tsna=%d",__LINE__, tsna);
00686         for (int32 j=0; j<numGaps; j++)
00687         {
00688                 sctpEV3<<sackChunk->getGapStart(j)<<" - "<<sackChunk->getGapStop(j)<<"\n";
00689         }
00690         for(SCTPPathMap::iterator it=sctpPathMap.begin(); it!=sctpPathMap.end(); it++) 
00691         {
00692                 it->second->requiresRtx = false;
00693                 if (it->second->remoteAddress == pathId)
00694                         it->second->lastAckTime = simulation.getSimTime();
00695         }
00696 
00697         if (state->zeroWindowProbing && arwnd>0)
00698                 state->zeroWindowProbing = false;
00699 
00700         osbPathBefore = path->outstandingBytes;
00701         osbBefore = getOutstandingBytes();
00702         sctpEV3<<"osb="<<osbPathBefore<<", osbPathBefore="<<osbPathBefore<<"\n";        
00703 
00704         if (tsnGt(tsna, state->lastTsnAck)) 
00705         {
00706                 /* we have got new chunks acked, and our cum ack point is advanced... */
00707                 /* depending on the parameter osbWithHeader ackedBytes are with or without the header bytes*/
00708                 ackedBytes = dequeueAckedChunks(tsna, pathId, &rttEst); // chunks with tsn between lastTsnAck and tsna are removed from the transmissionQ and the retransmissionQ; outstandingBytes are decreased
00709 
00710                 state->lastTsnAck = tsna;
00711                 ctsnaAdvanced = true;
00712         } 
00713         else if (tsnLt(tsna, state->lastTsnAck)) 
00714         {
00715                  
00716                 sctpEV3<<"processSackArrived : stale CTSNA....returning";
00717                 
00718                 return SCTP_E_IGNORE;
00719         }
00720         
00721         if (state->fastRecoveryActive) 
00722         {
00723                 if (tsnGt(state->lastTsnAck, state->fastRecoveryExitPoint) || (state->lastTsnAck == state->fastRecoveryExitPoint)) 
00724                 {
00725                          
00726                         sctpEV3<<"===> Leaving FAST RECOVERY !!! CTSNA == "<<state->lastTsnAck<<" <==\n";
00727                         
00728                         state->fastRecoveryActive = false;
00729                         state->fastRecoveryExitPoint = 0;
00730                 }
00731         }
00732         
00733         if (numGaps == 0 && tsnLt(tsna, state->highestTsnAcked)) 
00734         {
00735                 sctpEV3<<"numGaps=0 && tsna "<<tsna<<" < highestTsnAcked "<<state->highestTsnAcked<<"\n";
00736                 SCTPQueue::PayloadQueue::iterator pq;
00737                 uint32 i=state->highestTsnAcked;
00738                 pq=retransmissionQ->payloadQueue.find(i); 
00739                 while (i>=tsna+1)
00740                 {
00741                         if (pq!=retransmissionQ->payloadQueue.end())
00742                         {
00743                                 if (pq->second->hasBeenAcked)
00744                                 {
00745                                         pq->second->hasBeenAcked=false;
00746                                         if (!pq->second->countsAsOutstanding)   //12.06.08
00747                                         {
00748                                                 if (i>tsna+1 && retransmissionQ->payloadQueue.find(i-1)->second->hasBeenAcked)
00749                                                         state->highestTsnAcked = i-1;  //I.R.
00750                                                 else
00751                                                         state->highestTsnAcked = tsna;
00752                                                 #ifdef PKT
00753                                                 tsnWasReneged(pq->second);
00754                                                 #else
00755                                                 sctpEV3<<"tsn "<<pq->second->tsn<<" has been removed\n";
00756                                                 pq->second->hasBeenRemoved = true;
00757                                                 pq->second->gapReports = 1;
00758                                                 if (!getPath(pq->second->lastDestination)->T3_RtxTimer->isScheduled())
00759                                                         startTimer(getPath(pq->second->lastDestination)->T3_RtxTimer, getPath(pq->second->lastDestination)->pathRto);
00760                                                 sctpEV3<<"highestTsnAcked now "<<state->highestTsnAcked<<"\n";
00761                                                 #endif
00762                                         }
00763                                 }       
00764                         }
00765                         i--;
00766                         pq=retransmissionQ->payloadQueue.find(i);
00767                 }
00768         }
00769 
00770                 
00771         if (numGaps > 0 && !retransmissionQ->payloadQueue.empty())
00772         {
00773                  
00774                 sctpEV3<<"We got "<<numGaps<<" GAP reports\n";
00775                 sctpEV3<<"tsna="<<tsna<<"  nextTSN="<<state->nextTSN<<"\n";
00776                 
00777                 /* we got fragment reports...check for newly acked chunks */
00778                 uint32 queuedChunks=retransmissionQ->payloadQueue.size();
00779                 sctpEV3<<"number of chunks in retransmissionQ: "<<queuedChunks<<" highestGapStop: "<<sackChunk->getGapStop(numGaps-1)<<" highestTsnAcked: "<<state->highestTsnAcked<<"\n";
00780 
00781                 SCTPQueue::PayloadQueue::iterator pq;
00782                         
00783                 //highest gapStop smaller than highestTsnAcked: there might have been reneging
00784                 if (tsnLt(sackChunk->getGapStop(numGaps-1), state->highestTsnAcked))
00785                 {
00786                         uint32 i=state->highestTsnAcked;
00787                         pq=retransmissionQ->payloadQueue.find(i); 
00788                         while (i>=sackChunk->getGapStop(numGaps-1)+1)
00789                         {
00790                                 sctpEV3<<"looking for TSN "<<i<<" in retransmissionQ\n";
00791                                 if (pq != retransmissionQ->payloadQueue.end())
00792                                 {
00793                                         if (pq->second->hasBeenAcked)
00794                                         {
00795                                                 pq->second->hasBeenAcked=false;
00796                                                 sctpEV3<<i<<" was found. It has been set to hasBeenAcked=false.\n";
00797                                                 if (pq->second->countsAsOutstanding)
00798                                                 {
00799                                                         pq->second->countsAsOutstanding = false; //I.R. FIXME:
00800                                                         getPath(pq->second->lastDestination)->outstandingBytes -= (pq->second->booksize);
00801                                                         sctpEV3<<"osb="<<getPath(pq->second->lastDestination)->outstandingBytes<<"\n";
00802                                                         CounterMap::iterator i=qCounter.roomRetransQ.find(getPath(pq->second->lastDestination)->remoteAddress);
00803                                                                 i->second -= ADD_PADDING(pq->second->booksize+SCTP_DATA_CHUNK_LENGTH);
00804                                                 }
00805 
00806                                                 if (retransmissionQ->payloadQueue.find(i-1)!=retransmissionQ->payloadQueue.end() &&  retransmissionQ->payloadQueue.find(i-1)->second->hasBeenAcked)
00807                                                         state->highestTsnAcked = i-1;  //I.R. 12.06.08
00808                                                 #ifdef PKT
00809                                                 tsnWasReneged(pq->second);
00810                                                 #else
00811                                                 sctpEV3<<"tsn "<<pq->second->tsn<<" was removed\n";
00812                                                 pq->second->hasBeenRemoved = true;
00813                                                 pq->second->hasBeenAcked = false;  //12.06.08
00814                                                 if (!getPath(pq->second->lastDestination)->T3_RtxTimer->isScheduled())
00815                                                         startTimer(getPath(pq->second->lastDestination)->T3_RtxTimer, getPath(pq->second->lastDestination)->pathRto);
00816                                                 pq->second->gapReports = 1;
00817                                                 sctpEV3<<"highestTsnAcked now "<<state->highestTsnAcked<<"\n";
00818                                                 #endif
00819                                         }
00820                                 }
00821                                 else
00822                                         sctpEV3<<"TSN "<<i<<" not found in retransmissionQ\n";
00823                                 i--;
00824                                 pq=retransmissionQ->payloadQueue.find(i); 
00825                         }
00826                 }
00827                 
00828                 //looking for changes in the gap reports
00829                 for (int32 key=0; key<numGaps; key++)
00830                 {
00831                         lo = sackChunk->getGapStart(key);
00832                         hi = sackChunk->getGapStop(key);
00833                         sctpEV3<<"examine TSNs between "<<lo<<" and "<<hi<<"\n";
00834                         for (uint32 pos=lo; pos<=hi; pos++)
00835                         {
00836                                 datVar = retransmissionQ->getVar(pos);
00837                                 if (datVar)
00838                                 {               
00839                                         /*sctpEV3<<"TSN "<<datVar->tsn<<" found in retransmissionQ\n";
00840                                         sctpEV3<<"acked="<<datVar->hasBeenAcked<<", abandoned="<<datVar->hasBeenAbandoned<<", removed="<<datVar->hasBeenRemoved<<"\n";*/
00841                                         pmClearPathCounter(datVar->lastDestination);
00842                                         if (datVar->numberOfTransmissions == 1 && datVar->lastDestination == pathId && datVar->hasBeenAcked == false && datVar->hasBeenRemoved == false) 
00843                                         {
00844                                                 timeDiff = simulation.getSimTime() - datVar->sendTime;
00845                                                 if (timeDiff < rttEst || rttEst == -1.0) 
00846                                                 {
00847                                                         rttEst = timeDiff;
00848                                                 } 
00849                                                         
00850                                                 sctpEV3<<simulation.getSimTime()<<" processSackArrived: computed rtt time diff == "<<timeDiff<<" for TSN "<<datVar->tsn<<"\n";
00851                                                 
00852                                         }
00853                                         if (datVar->hasBeenAcked == false && datVar->hasBeenAbandoned == false && datVar->hasBeenRemoved == false) 
00854                                         {
00855                                                 ackedBytes += (datVar->booksize);
00856                                                 sctpEV3<<simulation.getSimTime()<<": "<<datVar->tsn<<" added to newly acked bytes:  "<<ackedBytes<<"\n";
00857                                                 if (datVar->tsn > hiAcked)
00858                                                         hiAcked = datVar->tsn;
00859                                                 datVar->hasBeenAcked = true;
00860                                                 if (datVar->countsAsOutstanding)
00861                                                 {
00862                                                         
00863                                                         sctpEV3<<"outstanding\n";
00864                                                         sctpEV3<<"lastDestination="<<datVar->lastDestination<<"\n";
00865                                                         sctpEV3<<"booksize="<<datVar->booksize<<"\n";
00866                                                         sctpEV3<<"outstanding bytes on path="<<getPath(datVar->lastDestination)->outstandingBytes<<"\n";
00867 
00868                                                         getPath(datVar->lastDestination)->outstandingBytes -= datVar->booksize;
00869                                                         datVar->countsAsOutstanding = false;
00870                                                         sctpEV3<<"osb="<<getPath(datVar->lastDestination)->outstandingBytes<<"\n";
00871                                                         CounterMap::iterator i=qCounter.roomRetransQ.find(getPath(datVar->lastDestination)->remoteAddress);
00872                                                                 i->second -= ADD_PADDING(datVar->booksize+SCTP_DATA_CHUNK_LENGTH);
00873                                                 }
00874                                                 if (transmissionQ->getVar(datVar->tsn))  //2.1.07
00875                                                 {
00876                                                         sctpEV3<<"found tsn "<<datVar->tsn<<" in transmissionQ. Remove Message.\n";
00877                                                         transmissionQ->removeMsg(datVar->tsn);
00878                                                         CounterMap::iterator q = qCounter.roomTransQ.find(datVar->nextDestination);
00879                                                         q->second-=ADD_PADDING(datVar->len/8+SCTP_DATA_CHUNK_LENGTH);
00880                                                         CounterMap::iterator qb=qCounter.bookedTransQ.find(datVar->nextDestination);
00881                                                         qb->second-=datVar->booksize;
00882                                                         
00883                                                         
00884                                                 }
00885                                                 sctpEV3<<"not outstanding\n";
00886                                                 
00887                                                 
00888                                                 datVar->gapReports = 0;         
00889                                         } 
00890                                 }
00891                                 
00892                         }                        
00893                 }
00894                 lo = tsna;
00895                 //examine chunks between the gap reports; they might have to be retransmitted or they could have been removed
00896                 for (int32 key=0; key<numGaps; key++)
00897                 {
00898                         hi = sackChunk->getGapStart(key);
00899 
00900                         for (uint32 i = lo+1; i<=hi-1; i++)
00901                         {
00902                                 pq=retransmissionQ->payloadQueue.find(i); 
00903                                 if (pq != retransmissionQ->payloadQueue.end())
00904                                 {
00905                                         sctpEV3<<"TSN "<<pq->second->tsn<<"\t";
00906                                         if (pq->second->hasBeenAcked)
00907                                         {
00908                                                 sctpEV3<<" has been acked\n";
00909                                                 pq->second->hasBeenAcked=false;
00910                                                 if (pq->second->countsAsOutstanding)
00911                                                 {
00912                                                         sctpEV3<<"counts as outstanding\n";
00913                                                         pq->second->countsAsOutstanding = false;
00914                                                         getPath(pq->second->lastDestination)->outstandingBytes -= (pq->second->booksize);
00915                                                         sctpEV3<<"osb="<<getPath(pq->second->lastDestination)->outstandingBytes<<"\n";
00916                                                         CounterMap::iterator i=qCounter.roomRetransQ.find(getPath(pq->second->lastDestination)->remoteAddress);
00917                                                                 i->second -= ADD_PADDING(pq->second->booksize+SCTP_DATA_CHUNK_LENGTH);
00918                                                 }
00919                                                 #ifdef PKT
00920                                                 tsnWasReneged(pq->second);
00921                                                 #else
00922                                                 sctpEV3<<"not PKT: TSN "<<pq->second->tsn<<"hasBeenRemoved\n"; 
00923                                                 pq->second->hasBeenRemoved = true;
00924                                                 pq->second->gapReports = 1;
00925                                                 if (!getPath(pq->second->lastDestination)->T3_RtxTimer->isScheduled())
00926                                                         startTimer(getPath(pq->second->lastDestination)->T3_RtxTimer, getPath(pq->second->lastDestination)->pathRto);
00927                                                 #endif
00928                                         }
00929                                         else
00930                                         {
00931                                                 sctpEV3<<" has not been acked, hiAcked="<<hiAcked<<" countsAsOutstanding="<<pq->second->countsAsOutstanding<<"\n";
00932                                                 if (hiAcked > pq->second->tsn)
00933                                                 {
00934                                                         pq->second->gapReports++;
00935                                                         sctpEV3<<"increase gap reports of TSN "<<pq->second->tsn<<" to "<<pq->second->gapReports<<"\n";
00936                                                         if (pq->second->gapReports >= (uint32) sctpMain->par("numGapReports")) 
00937                                                         {
00938                                                                 /* chunks are only fast retransmitted once */
00939 bool fastRtx = false;
00940         fastRtx = ((pq->second->hasBeenFastRetransmitted == false) && (pq->second->numberOfRetransmissions==0));
00941                                                                 if (fastRtx)
00942                                                                 {
00943                                                                         sctpEV3<<simulation.getSimTime()<<" Got "<<pq->second->gapReports<<" gap_reports, scheduling "<<pq->second->tsn<<" for RTX\n";
00944                                                                         sctpEV3<<"last sendTime for TSN "<<pq->second->tsn<<" was "<<pq->second->sendTime<<". RTT for path "<<pq->second->lastDestination<<" is "<<getPath(pq->second->lastDestination)->srtt<<"\n";
00945                                                                         
00946 
00947                                                                         SCTPQueue::PayloadQueue::iterator it=transmissionQ->payloadQueue.find(pq->second->tsn);
00948                                                                         if (it==transmissionQ->payloadQueue.end()) 
00949                                                                         {
00950                                                                                 
00951                                                                                 SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId);
00952                                                                                 iter->second.numFastRtx++;      
00953                                                                                 sctpEV3<<"insert in transmissionQ tsn="<<pq->second->tsn<<"\n";
00954                                                                                 pq->second->hasBeenFastRetransmitted = true;
00955                                                                                 IPvXAddress oldPid=pq->second->lastDestination;
00956                                                                                 pid = getNextDestination(pq->second);
00957                                                                                 pq->second->nextDestination = pid;
00958                                                                                 if (pq->second->countsAsOutstanding) 
00959                                                                                 {
00960                                                                                 getPath(pq->second->lastDestination)->outstandingBytes -= pq->second->booksize;
00961                                                                                 pq->second->countsAsOutstanding = false;
00962                                                                                 CounterMap::iterator i=qCounter.roomRetransQ.find(getPath(pq->second->lastDestination)->remoteAddress);
00963                                                                                         i->second -= ADD_PADDING(pq->second->booksize+SCTP_DATA_CHUNK_LENGTH);
00964                                                                                 }
00965                                                                                 if (!transmissionQ->checkAndInsertVar(pq->second->tsn, pq->second))  
00966                                                                                 {
00967                                                                                         
00968                                                                                         ev<<"Fast RTX: cannot add message/chunk (TSN="<<pq->second->tsn<<") to the transmission Q\n";
00969                                                                                         
00970                                                                                 }
00971                                                                                 else
00972                                                                                 {
00973                                                                                         CounterMap::iterator q = qCounter.roomTransQ.find(pq->second->nextDestination);
00974                                                                                         q->second+=ADD_PADDING(pq->second->len/8+SCTP_DATA_CHUNK_LENGTH);
00975                                                                                         CounterMap::iterator qb=qCounter.bookedTransQ.find(pq->second->nextDestination);
00976                                                                                         qb->second+=pq->second->booksize;
00977                                                                                         sctpEV3<<"Fast RTX: "<<transmissionQ->getQueueSize()<<" chunks = "<<q->second<<"bytes. OldPid="<<oldPid<<", newPid="<<pid<<"\n";
00978                                                                                 }
00979                                                                                 path->requiresRtx = true;
00980                                                                                 rtxNecessary = true;
00981                                                                                 if(bufferPosition == 0)
00982                                                                                         lowestTsnRetransmitted = true;
00983                                                                         }
00984                                                                 }
00985                                                         }
00986                                                 }
00987                                                 else 
00988                                                 {
00989                                                         pq->second->hasBeenFastRetransmitted = false;
00990                                                         sctpEV3<<"TSN "<<pq->second->tsn<<" countsAsOutstanding="<<pq->second->countsAsOutstanding<<"\n";
00991                                                         if (hiAcked > pq->second->tsn)
00992                                                                 pq->second->gapReports++;
00993                                                 }
00994                                         }
00995                                 }
00996                                 else
00997                                         sctpEV3<<"TSN "<<i<<" not found in retransmissionQ\n";
00998                         }
00999                         lo = sackChunk->getGapStop(key);
01000                 }
01001 
01002                 state->highestTsnAcked = sackChunk->getGapStop(numGaps-1);
01003                 if (state->highestTsnAcked < state->nextTSN-1)
01004                 {
01005                         SCTPQueue::PayloadQueue::iterator iter;
01006 
01007                         for (uint32 i=state->highestTsnAcked+1; i< state->nextTSN; i++)
01008                         {
01009                                 iter=retransmissionQ->payloadQueue.find(i); 
01010                                 if (iter!=retransmissionQ->payloadQueue.end())
01011                                 {
01012                                         iter->second->hasBeenAcked=false;
01013                                 }
01014                         }
01015                 }
01016         }
01017                 /* update RTT measurement for newly acked data chunks */
01018         sctpEV3<<simulation.getSimTime()<<": SACK: rtt="<<rttEst<<", ackedBytes="<<ackedBytes<<", pathId="<<pathId<<"\n";
01019         pmRttMeasurement(pathId, rttEst, ackedBytes);
01020         
01021         osb = getOutstandingBytes();
01022         
01023         /* compute current receiver window */
01024         state->peerRwnd = arwnd - osb;
01025 
01026         // position of statement changed 20.07.05 I.R.
01027         if ((int32)(state->peerRwnd)< 0) state->peerRwnd= 0;
01028 
01029         if (state->peerRwnd > state->initialPeerRwnd)
01030                 state->peerRwnd = state->initialPeerRwnd;
01031 
01032         sctpEV3<<"rwnd set to "<<state->peerRwnd<<" ("<<arwnd<<"-"<<osb<<")\n";
01033         sctpEV3<<"pathFlow="<<state->peerRwnd/rttEst<<"="<<state->peerRwnd<<"/"<<rttEst<<"\n";   
01034         sctpEV3<<"state->peerRwnd now "<<state->peerRwnd<<"\n";
01035         if (arwnd == 1 || state->peerRwnd < state->swsLimit || arwnd == 0)
01036         {
01037                 sctpEV3<<"processSackArrived: arwnd="<<arwnd<<" state->peerRwnd="<<state->peerRwnd<<" set peerWindowFull\n";
01038                 state->peerWindowFull = true;
01039         }
01040         else
01041         {
01042                 state->peerWindowFull = false;
01043                 state->zeroWindowProbing = false;
01044         }
01045 
01046         
01047         if (ackedBytes > 0) 
01048         {               
01049                 /* adjust congestion control variables for the corresponding path */
01050                  
01051                 sctpEV3<<"processSackArrived: "<<ackedBytes<<" bytes were acked\n";
01052                 (this->*ccFunctions.ccUpdateBytesAcked)(ackedBytes, osbBefore,  ctsnaAdvanced, pathId, osbPathBefore, osb);
01053         }       
01054 
01055         if (osb == 0) 
01056         {       
01057                 for (SCTPPathMap::iterator iter=sctpPathMap.begin(); iter!=sctpPathMap.end(); iter++)
01058                 {
01059                         stopTimer(iter->second->T3_RtxTimer);
01060                 }
01061                 if (arwnd == 0)
01062                         state->zeroWindowProbing = true;
01063 
01064         } 
01065         else 
01066         {
01067                 sctpEV3<<"outstandingBytes on path "<<pathId<<" = "<<getPath(pathId)->outstandingBytes<<"\n";
01068                 /* there is still something outstanding */
01069                 if (getPath(pathId)->outstandingBytes == 0)
01070                 {
01071                         /* if all data is acked on **this path** stop T3 timer */
01072                         stopTimer(getPath(pathId)->T3_RtxTimer);
01073                 } 
01074                 else if (ctsnaAdvanced) 
01075                 {
01076                         /* if new data is ACKED, restart T3 timer */
01077                          
01078                         sctpEV3<<"CTSNA was advanced to "<<state->lastTsnAck<<" by incoming SACK chunk, now restart T3 timer for path id "<<(pathId)<<"\n";
01079                         stopTimer(getPath(pathId)->T3_RtxTimer);
01080                         startTimer(getPath(pathId)->T3_RtxTimer,getPath(pathId)->pathRto);
01081                 } 
01082                 else
01083                 /* AJ - added next clause - 07.04.2004 - also restart T3 timer, when lowest TSN is rtx'ed */
01084                         if (lowestTsnRetransmitted == true) 
01085                         {
01086                                  
01087                                 sctpEV3<<"Lowest tsn "<<state->lastTsnAck<<" was retransmitted, now restart T3 timer for path id "<<(pathId)<<"\n";
01088                                 stopTimer(getPath(pathId)->T3_RtxTimer);
01089                                 startTimer(getPath(pathId)->T3_RtxTimer,getPath(pathId)->pathRto);                      
01090                         }
01091         }
01092 
01093         
01094         (this->*ccFunctions.ccUpdateAfterSack)(rtxNecessary, path);
01095 
01096 
01097         return SCTP_E_IGNORE;
01098 }

SCTPEventCode SCTPAssociation::processHeartbeatAckArrived ( SCTPHeartbeatAckChunk *  heartbeatack,
SCTPPathVariables path 
) [protected]

Referenced by process_RCV_Message().

01239 {
01240         simtime_t rttEstimate = 0.0;
01241         IPvXAddress addr;
01242         simtime_t hbTimeField = 0.0;
01243 
01244         /* hb-ack goes to pathmanagement, reset error counters, stop timeout timer */
01245         addr = hback->getRemoteAddr(); 
01246         hbTimeField = hback->getTimeField();
01247         stopTimer(path->HeartbeatTimer);
01248         /* assume a valid RTT measurement on this path */
01249         rttEstimate = simulation.getSimTime() - hbTimeField;
01250         pmRttMeasurement(addr, rttEstimate, 1);
01251         path->hbWasAcked = true;
01252         path->confirmed = true;
01253         path->lastAckTime = simulation.getSimTime();
01254         if (path->primaryPathCandidate == true)
01255         {
01256                 state->primaryPathIndex = addr;
01257                 path->primaryPathCandidate = false;
01258                 if (path->pmtu < state->assocPmtu) 
01259                         state->assocPmtu = path->pmtu;
01260                 path->cwndAdjustmentTime = simulation.getSimTime();
01261                 path->ssthresh = state->peerRwnd;
01262                 path->pathSsthresh->record(path->ssthresh);
01263                 path->heartbeatTimeout= (double)sctpMain->par("hbInterval")+path->pathRto;
01264         }
01265                 
01266         if (path->activePath == false)
01267         {
01268                 sctpEV3<<"HB-Ack arrived activePath=false. remoteAddress="<<path->remoteAddress<<" initialPP="<<state->initialPrimaryPath<<"\n";
01269                 path->activePath = true;
01270                 if (state->reactivatePrimaryPath && path->remoteAddress == state->initialPrimaryPath)
01271                         state->primaryPathIndex = path->remoteAddress;
01272                 sctpEV3<<"primaryPath now "<<state->primaryPathIndex<<"\n";
01273         }
01274         path->pathErrorCount = 0;
01275         return SCTP_E_IGNORE;
01276 }

int32 SCTPAssociation::process_TIMEOUT_RTX ( SCTPPathVariables path  )  [protected]

Referenced by processTimer().

01525 {
01526         SCTPDataVariables* chunk = NULL;
01527         bool notifyUlp = false;
01528 
01529         /* increase the RTO (by doubling it) */
01530         path->pathRto = min(2*path->pathRto.dbl(),sctpMain->par("rtoMax"));
01531         path->pathRTO->record(path->pathRto);
01532          
01533         sctpEV3<<"Schedule T3 based retransmission for path "<<(path->remoteAddress)<<"\n";
01534         
01535 
01536         (this->*ccFunctions.ccUpdateAfterRtxTimeout)(path);
01537         
01538         if (!state->zeroWindowProbing)
01539         {
01540                 state->errorCount++;
01541                 path->pathErrorCount++;
01542                 sctpEV3<<"RTX-Timeout: errorCount increased to "<<path->pathErrorCount<<"  state->errorCount="<<state->errorCount<<"\n";
01543         }
01544         if (state->errorCount >=  (uint32)sctpMain->par("assocMaxRetrans"))
01545         {
01546                 /* error counter exceeded terminate the association -- create an SCTPC_EV_CLOSE event and send it to myself */ 
01547                  
01548                 sctpEV3<<"process_TIMEOUT_RTX : ASSOC ERROR COUNTER EXCEEDED, closing ASSOC\n";
01549                 
01550                 sendIndicationToApp(SCTP_I_CONN_LOST);
01551                 sendAbort();
01552                 sctpMain->removeAssociation(this);
01553                 return 0;
01554 
01555         } 
01556         else 
01557         {
01558                 if (path->pathErrorCount >=  (uint32)sctpMain->par("pathMaxRetrans")) 
01559                 {
01560                         sctpEV3<<"pathErrorCount exceeded\n";
01561                         if (path->activePath)
01562                         {
01563                                 /* tell the source */
01564                                 notifyUlp = true;
01565                         }
01566                         path->activePath = false;
01567                         if (path->remoteAddress == state->primaryPathIndex)
01568                         {
01569                                 IPvXAddress adr = getNextAddress(path->remoteAddress); 
01570                                 if (adr!=IPvXAddress("0.0.0.0"))
01571                                         state->primaryPathIndex = adr; 
01572                         }
01573                         sctpEV3<<"process_TIMEOUT_RTX("<<(path->remoteAddress)<<") : PATH ERROR COUNTER EXCEEDED, path status is INACTIVE\n";
01574                         
01575                         if (allPathsInactive())
01576                         {
01577                                  
01578                                 sctpEV3<<"process_TIMEOUT_RTX : ALL PATHS INACTIVE --> closing ASSOC\n";
01579                                 
01580                                 sendIndicationToApp(SCTP_I_CONN_LOST);
01581                                 sendAbort();
01582                                 sctpMain->removeAssociation(this);
01583                                 return 0;
01584                                 
01585                         } 
01586                         else if (notifyUlp)
01587                         {
01588                                 /* notify the application */
01589                                 pathStatusIndication(path->remoteAddress, false);                               
01590                         }
01591                 }
01592                  
01593                 sctpEV3<<"process_TIMEOUT_RTX("<<(path->remoteAddress)<<") : PATH ERROR COUNTER now "<<path->pathErrorCount<<"\n";
01594                 
01595         }
01596 
01597         /*======================================================================*/
01598         /*                                              do retransmission                                                               */
01599         /*======================================================================*/
01600         
01601         /* dequeue all chunks not acked so far and put them in the TransmissionQ */
01602         
01603         if (retransmissionQ->payloadQueue.empty()) return 1;            
01604         sctpEV3<<"Still "<<retransmissionQ->payloadQueue.size()<<" chunks in retransmissionQ\n";
01605         for (SCTPQueue::PayloadQueue::iterator iter=retransmissionQ->payloadQueue.begin(); iter!=retransmissionQ->payloadQueue.end(); iter++)
01606         {
01607                 chunk = iter->second;
01608                 if (chunk == NULL) 
01609                 { 
01610                         sctpEV3<<"sctp assoc: chunk pointer is NULL in sctp_handle_t3_timeout()\n";
01611                 }
01612 
01613                 /*========================================================================*/
01614                 /* only insert chunks that were sent to the path that has timed out       */
01615                 /*========================================================================*/
01616                 
01617                 if ((chunk->hasBeenAcked == false && chunk->countsAsOutstanding || chunk->hasBeenRemoved )&& chunk->lastDestination == path->remoteAddress ) 
01618                 {
01619                         iter->second->hasBeenFastRetransmitted = false;
01620                         iter->second->gapReports = 0;
01621                         IPvXAddress oldpid = chunk->lastDestination;
01622                         iter->second->nextDestination = getNextDestination(chunk);
01623                         sctpEV3<<simulation.getSimTime()<<" RTX for TSN "<<iter->second->tsn<<": lastDestination="<<iter->second->lastDestination<<" nextDestination="<<iter->second->nextDestination<<"\n";
01624                         /* check, if chunk_ptr->tsn is already in transmission queue */
01625                         /* this can happen in case multiple timeouts occur in succession    */
01626                         if (!transmissionQ->checkAndInsertVar(chunk->tsn, chunk))
01627                         {
01628                                 sctpEV3<<"TSN "<<chunk->tsn<<" already in transmissionQ\n";
01629                                 continue;
01630                         }
01631                         else
01632                         {
01633                                 sctpEV3<<"insert "<<chunk->tsn<<" in transmissionQ. hasBeenAcked="<<iter->second->hasBeenAcked<<" countsAsOutstanding="<<iter->second->countsAsOutstanding<<"\n";
01634                                 CounterMap::iterator q = qCounter.roomTransQ.find(iter->second->nextDestination);
01635                                 q->second += ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH);
01636                                 CounterMap::iterator qb = qCounter.bookedTransQ.find(iter->second->nextDestination);
01637                                 qb->second += chunk->booksize;
01638                                 sctpEV3<<"RTX-Timeout: "<<transmissionQ->getQueueSize()<<" chunks = "<<q->second<<" bytes. Osb="<<getPath(iter->second->lastDestination)->outstandingBytes<<"\n";
01639 
01640                                 if (iter->second->countsAsOutstanding)
01641                                 {
01642                                         getPath(iter->second->lastDestination)->outstandingBytes -= iter->second->booksize;
01643                                         sctpEV3<<"osb after substraction="<<getPath(iter->second->lastDestination)->outstandingBytes<<"\n";
01644                                         iter->second->countsAsOutstanding = false; 
01645                                 }
01646                                 CounterMap::iterator i=qCounter.roomRetransQ.find(getPath(iter->second->lastDestination)->remoteAddress);
01647                                 qb->second += chunk->booksize;
01648                                 sctpEV3<<"RTX-Timeout: "<<transmissionQ->getQueueSize()<<" chunks = "<<q->second<<" bytes. Osb="<<getPath(iter->second->lastDestination)->outstandingBytes<<"\n";
01649 
01650                                 if (iter->second->countsAsOutstanding)
01651                                 {
01652                                         getPath(iter->second->lastDestination)->outstandingBytes -= iter->second->booksize;
01653                                         sctpEV3<<"osb after substraction="<<getPath(iter->second->lastDestination)->outstandingBytes<<"\n";
01654                                         iter->second->countsAsOutstanding = false; 
01655                                 }
01656                                 i->second -= ADD_PADDING(iter->second->booksize+SCTP_DATA_CHUNK_LENGTH);
01657                                 
01658                                 state->peerRwnd += (chunk->booksize); 
01659                                 SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId);
01660                                 iter->second.numT3Rtx++;
01661                         }
01662                         if (state->peerRwnd > state->initialPeerRwnd)
01663                                 state->peerRwnd = state->initialPeerRwnd;
01664                         sctpEV3<<"T3 Timeout: Chunk (TSN="<<chunk->tsn<<") has been requeued in transmission Q, rwnd was set to "<<state->peerRwnd<<"\n";
01665                         
01666                 }
01667         }
01668 
01669         IPvXAddress addr=getNextAddress(path->remoteAddress);
01670         sctpEV3<<"TimeoutRTX sendAll to addr: "<<addr<<"\n";
01671         sendAll(addr);
01672         if (addr != state->primaryPathIndex)
01673         {
01674                 sctpEV3<<"TimeoutRTX sendAll to pp: "<<state->primaryPathIndex<<"\n";
01675                 sendAll(state->primaryPathIndex);
01676         }
01677         else
01678         if (addr != path->remoteAddress)
01679         {
01680                 sctpEV3<<"TimeoutRTX sendAll to remoteAddr: "<<remoteAddr<<"\n";
01681                 sendAll(path->remoteAddress);
01682         }
01683         
01684         
01685          
01686         sctpEV3<<"process_TIMEOUT_RTX sendAll returned\n";
01687         
01688         return 0;
01689 }

void SCTPAssociation::process_TIMEOUT_HEARTBEAT ( SCTPPathVariables path  )  [protected]

Referenced by processTimer().

01383 {
01384         bool oldState;
01385 
01386         /* check if error counters must be increased */
01387         if (path->hbWasAcked)
01388         {
01389                 sctpEV3<<"ERROR : HB Timeout timer expired for a path --> The Timer should already have been stopped !!!\n";
01390 
01391         } 
01392         else 
01393         {
01394                 if (path->activePath)
01395                 {
01396                         state->errorCount++;
01397                         path->pathErrorCount++;
01398                         
01399                         sctpEV3<<"HB timeout timer expired for path "<<path->remoteAddress<<" --> Increase Error Counters (Assoc: "<<state->errorCount<<", Path: "<<path->pathErrorCount<<")\n";
01400                 }
01401         }
01402         
01403         /* RTO must be doubled for this path ! */
01404         path->pathRto = (simtime_t)min(2 * path->pathRto.dbl(), sctpMain->par("rtoMax"));
01405         path->pathRTO->record(path->pathRto);
01406         /* check if any thresholds are exceeded, and if so, check if ULP must be notified */
01407         if (state->errorCount > (uint32)sctpMain->par("assocMaxRetrans"))
01408         {
01409                 sendIndicationToApp(SCTP_I_CONN_LOST);
01410                 sendAbort();
01411                 sctpMain->removeAssociation(this);
01412                 return;
01413                 
01414         } 
01415         else 
01416         {
01417                 /* set path state to INACTIVE, if the path error counter is exceeded */
01418                 if (path->pathErrorCount >  (uint32)sctpMain->par("pathMaxRetrans"))
01419                 {               
01420                         oldState = path->activePath;            
01421                         path->activePath = false;
01422                         if (path->remoteAddress == state->primaryPathIndex)
01423                                 state->primaryPathIndex = getNextAddress(path->remoteAddress);
01424                         sctpEV3<<"pathErrorCount now "<<path->pathErrorCount<<"  PP now "<<state->primaryPathIndex<<"\n";
01425                 }
01426                 /* then: we can check, if all paths are INACTIVE ! */   
01427                 if (allPathsInactive())
01428                 {
01429                          
01430                         sctpEV3<<"sctp_do_hb_to_timer() : ALL PATHS INACTIVE --> closing ASSOC\n";
01431                         
01432                         sendIndicationToApp(SCTP_I_CONN_LOST);
01433                         return;
01434 
01435                 } else if (path->activePath == false && oldState == true) 
01436                 {
01437                         /* notify the application, in case the PATH STATE has changed from ACTIVE to INACTIVE */
01438                         pathStatusIndication(path->remoteAddress, false);
01439                 }
01440 
01441         }               
01442 }

void SCTPAssociation::process_TIMEOUT_HEARTBEAT_INTERVAL ( SCTPPathVariables path,
bool  force 
) [protected]

Referenced by processTimer().

01356 {
01357 
01358          
01359         sctpEV3<<"HB Interval timer expired -- sending new HB REQ on path "<<path->remoteAddress<<"\n";
01360         
01361         /* restart hb_send_timer on this path */
01362         
01363         stopTimer(path->HeartbeatIntervalTimer);
01364         stopTimer(path->HeartbeatTimer);
01365         
01366         path->heartbeatIntervalTimeout = (double)sctpMain->par("hbInterval") +  path->pathRto;  
01367         path->heartbeatTimeout = path->pathRto;
01368         
01369         startTimer(path->HeartbeatIntervalTimer, path->heartbeatIntervalTimeout);
01370         
01371         if (simulation.getSimTime() - path->lastAckTime > path->heartbeatIntervalTimeout/2 || path->forceHb)
01372         {
01373                 sendHeartbeat(path, false);
01374                 startTimer(path->HeartbeatTimer, path->heartbeatTimeout);
01375 
01376                 path->forceHb = false;
01377         }
01378         
01379 }

void SCTPAssociation::process_TIMEOUT_INIT_REXMIT ( SCTPEventCode event  )  [protected]

Referenced by processTimer().

01281 {
01282 
01283         if (++state->initRetransCounter > (int32)sctpMain->par("maxInitRetrans"))
01284         {
01285                 sctpEV3 << "Retransmission count during connection setup exceeds " << (int32)sctpMain->par("maxInitRetrans") << ", giving up\n";
01286                 sendIndicationToApp(SCTP_I_CLOSED);
01287                 sendAbort();
01288                 sctpMain->removeAssociation(this);      
01289                 return;
01290         }
01291         
01292         sctpEV3<< "Performing retransmission #" << state->initRetransCounter << "\n";
01293         
01294         switch(fsm->getState())
01295         {
01296                 case SCTP_S_COOKIE_WAIT: retransmitInit(); break;
01297                 case SCTP_S_COOKIE_ECHOED: retransmitCookieEcho(); break;
01298                 default:  opp_error("Internal error: INIT-REXMIT timer expired while in state %s", stateName(fsm->getState()));
01299         }
01300         
01301         state->initRexmitTimeout *= 2;
01302         
01303         if (state->initRexmitTimeout > SCTP_TIMEOUT_INIT_REXMIT_MAX)
01304                 state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT_MAX;
01305                 
01306         startTimer(T1_InitTimer,state->initRexmitTimeout);
01307 }

void SCTPAssociation::process_TIMEOUT_CWND ( SCTPPathVariables path  )  [protected]

01341 {
01342         /* 
01343          *  When the association does not transmit data on a given transport address
01344          *  within an RTO, the cwnd of the transport address SHOULD be adjusted to 2*MTU.
01345          */
01346 
01347         path->cwnd = (int32)min(4 * path->pmtu, max(2 * path->pmtu, 4380));
01348         path->pathCwnd->record(path->cwnd);
01349          
01350         sctpEV3<<"CWND timer run off: readjusting CWND(path=="<<path->remoteAddress<<") = "<<path->cwnd<<"\n";
01351         
01352         path->cwndAdjustmentTime = simulation.getSimTime();
01353 }

void SCTPAssociation::process_TIMEOUT_PROBING (  )  [protected]

void SCTPAssociation::process_TIMEOUT_SHUTDOWN ( SCTPEventCode event  )  [protected]

Referenced by processTimer().

01310 {
01311 
01312         if (++state->errorCount > (uint32)sctpMain->par("assocMaxRetrans"))
01313         {
01314                 sendIndicationToApp(SCTP_I_CONN_LOST);
01315                 sendAbort();
01316                 sctpMain->removeAssociation(this);
01317                 return;
01318                 
01319         } 
01320         
01321         sctpEV3 << "Performing shutdown retransmission. Assoc error count now "<<state->errorCount<<" \n";
01322         
01323         if(fsm->getState()==SCTP_S_SHUTDOWN_SENT)
01324         {
01325                 retransmitShutdown(); 
01326         }
01327         else if (fsm->getState()==SCTP_S_SHUTDOWN_ACK_SENT)
01328                 retransmitShutdownAck(); 
01329         
01330         state->initRexmitTimeout *= 2;
01331         
01332         if (state->initRexmitTimeout > SCTP_TIMEOUT_INIT_REXMIT_MAX)
01333                 state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT_MAX;
01334                 
01335         startTimer(T2_ShutdownTimer,state->initRexmitTimeout);
01336 }

int32 SCTPAssociation::updateCounters ( SCTPPathVariables path  )  [protected]

01475 {
01476         bool notifyUlp = false;
01477         
01478         if (++state->errorCount >=  (uint32)sctpMain->par("assocMaxRetrans"))
01479         {
01480                 sctpEV3 << "Retransmission count during connection setup exceeds " << (int32)sctpMain->par("assocMaxRetrans") << ", giving up\n";
01481                 sendIndicationToApp(SCTP_I_CLOSED);
01482                 sendAbort();
01483                 sctpMain->removeAssociation(this);      
01484                 return 0;
01485         }
01486         else if (++path->pathErrorCount >=  (uint32)sctpMain->par("pathMaxRetrans")) 
01487         {
01488                 if (path->activePath)
01489                 {
01490                         /* tell the source */
01491                         notifyUlp = true;
01492                 }
01493 
01494                 path->activePath = false;
01495                 if (path->remoteAddress == state->primaryPathIndex)
01496                         state->primaryPathIndex = getNextAddress(path->remoteAddress); 
01497                 sctpEV3<<"process_TIMEOUT_RESET("<<(path->remoteAddress)<<") : PATH ERROR COUNTER EXCEEDED, path status is INACTIVE\n";
01498                 
01499                 if (allPathsInactive())
01500                 {
01501                                 
01502                         sctpEV3<<"process_TIMEOUT_RESET : ALL PATHS INACTIVE --> closing ASSOC\n";
01503                         
01504                         sendIndicationToApp(SCTP_I_CONN_LOST);
01505                         sendAbort();
01506                         sctpMain->removeAssociation(this);
01507                         return 0;
01508                         
01509                 } 
01510                 else if (notifyUlp)
01511                 {
01512                         /* notify the application */
01513                         pathStatusIndication(path->remoteAddress, false);       
01514                 } 
01515                 sctpEV3<<"process_TIMEOUT_RESET("<<(path->remoteAddress)<<") : PATH ERROR COUNTER now "<<path->pathErrorCount<<"\n";
01516                 return 2;
01517         }
01518         return 1;
01519 }

void SCTPAssociation::startTimer ( cMessage *  timer,
simtime_t  timeout 
) [protected]

Referenced by pmDataIsSentOn(), pmStartPathManagement(), process_ASSOCIATE(), process_RCV_Message(), process_TIMEOUT_HEARTBEAT_INTERVAL(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_SHUTDOWN(), processInitAckArrived(), processSackArrived(), scheduleSack(), sendAll(), sendShutdown(), and sendShutdownAck().

01465 {
01466          
01467         sctpEV3<<"startTimer "<<timer->getName()<<" with timeout "<<timeout<<" to expire at "<<simulation.getSimTime()+timeout<<"\n";
01468         
01469         scheduleTimeout(timer, timeout);
01470 }

SCTPAssociation * SCTPAssociation::cloneAssociation (  )  [protected]

Utility: clone a listening association. Used for forking.

Referenced by processInitArrived().

00180 {
00181         SCTPAssociation *assoc = new SCTPAssociation(sctpMain,appGateIndex,assocId);
00182         const char *queueClass = transmissionQ->getClassName();
00183         assoc->transmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass));
00184         assoc->retransmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass));
00185 
00186         const char *sctpAlgorithmClass = sctpAlgorithm->getClassName();
00187         assoc->sctpAlgorithm = check_and_cast<SCTPAlgorithm *>(createOne(sctpAlgorithmClass));
00188         assoc->sctpAlgorithm->setAssociation(assoc);
00189         assoc->sctpAlgorithm->initialize();
00190         assoc->state = assoc->sctpAlgorithm->createStateVariables();
00191 
00192         assoc->state->active = false;
00193         assoc->state->fork = true;
00194         assoc->localAddr = localAddr;
00195         assoc->localPort = localPort;
00196         assoc->localAddressList = localAddressList;
00197 
00198         FSM_Goto((*assoc->fsm), SCTP_S_CLOSED);
00199         sctpMain->printInfoConnMap();
00200         return assoc;
00201 }

void SCTPAssociation::initAssociation ( SCTPOpenCommand *  openCmd  )  [protected]

Utility: creates send/receive queues and sctpAlgorithm

Referenced by process_ASSOCIATE(), and process_OPEN_PASSIVE().

00357 {
00358         sctpEV3<<"SCTPAssociationUtil:initAssociation\n";
00359         // create send/receive queues
00360         const char *queueClass = openCmd->getQueueClass();
00361         transmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass));
00362 
00363         retransmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass));
00364         outboundStreams = openCmd->getOutboundStreams();
00365         // create algorithm
00366         const char *sctpAlgorithmClass = openCmd->getSctpAlgorithmClass();
00367         if (!sctpAlgorithmClass || !sctpAlgorithmClass[0])
00368                 sctpAlgorithmClass = sctpMain->par("sctpAlgorithmClass");
00369         sctpAlgorithm = check_and_cast<SCTPAlgorithm *>(createOne(sctpAlgorithmClass));
00370         sctpAlgorithm->setAssociation(this);
00371         sctpAlgorithm->initialize();
00372         // create state block
00373         state = sctpAlgorithm->createStateVariables();
00374 }

bool SCTPAssociation::tsnIsDuplicate ( uint32  tsn  )  [protected]

Methods dealing with the handling of TSNs

Referenced by processDataArrived().

01856 {
01857         for (std::list<uint32>::iterator it=state->dupList.begin(); it!=state->dupList.end(); it++)
01858         {
01859                 if ((*it)==tsn)
01860                         return true;
01861         }
01862         for (uint32 i=0; i<state->numGaps; i++)
01863                 if (tsnBetween(state->gapStartList[i], tsn, state->gapStopList[i]))
01864                         return true;
01865         return false;
01866 }

bool SCTPAssociation::advanceCtsna ( void   )  [protected]

Referenced by processDataArrived().

02111 {
02112 int32 listLength, counter;
02113 
02114         ev<<"Entering advanceCtsna(ctsna now =="<< state->cTsnAck<<"\n";;
02115 
02116         listLength = state->numGaps;
02117 
02118         /* if there are no fragments, we cannot advance the ctsna */
02119         if (listLength == 0) return false;
02120         counter = 0;
02121 
02122         while(counter < listLength)
02123         {
02124                 /* if we take out a fragment here, we need to modify either counter or list_length */
02125 
02126                 if (state->cTsnAck + 1 == state->gapStartList[0])
02127                 {
02128                         /* BINGO ! */
02129                         state->cTsnAck = state->gapStopList[0];
02130                         /* we can take out a maximum of list_length fragments */
02131                         counter++;
02132                         for (uint32 i=1; i<state->numGaps; i++)
02133                         {
02134                                 state->gapStartList[i-1] = state->gapStartList[i];
02135                                 state->gapStopList[i-1] = state->gapStopList[i];
02136                         }
02137 
02138                 }
02139                 else
02140                 {
02141                         ev<<"Entering advanceCtsna(when leaving: ctsna=="<<state->cTsnAck<<"\n";
02142                         return false;
02143                 }
02144 
02145         }       /* end while */
02146 
02147         ev<<"Entering advanceCtsna(when leaving: ctsna=="<< state->cTsnAck<<"\n";
02148         return true;
02149 }

bool SCTPAssociation::updateGapList ( uint32  tsn  )  [protected]

TSN either sits at the end of one gap, and thus changes gap boundaries, or it is in between two gaps, and becomes a new gap

Referenced by processDataArrived().

01932 {
01933         uint32 lo, hi, gapsize;
01934 
01935 
01936         sctpEV3<<"Entering updateGapList(tsn=="<< receivedTsn<<" cTsnAck="<<state->cTsnAck<<" Number of Gaps="<<state->numGaps<<"\n";
01937 
01938         lo = state->cTsnAck + 1;
01939         if ((int32)(state->localRwnd-state->queuedRcvBytes)<=0)
01940         {
01941                 sctpEV3<<"window full\n";
01942                 //only check if cumTsnAck can be advanced
01943                 if (receivedTsn == lo)
01944                 {
01945                         sctpEV3<<"Window full, but cumTsnAck can be advanced:"<<lo<<"\n";
01946 
01947                 }
01948                 else
01949                         return false;
01950         }
01951 
01952         if (tsnGt(receivedTsn, state->highestTsnStored))        //17.06.08
01953                 state->highestTsnStored = receivedTsn;
01954 
01955         for (uint32 i=0; i<state->numGaps; i++)
01956         {
01957                 if (state->gapStartList[i]>0)
01958                 {
01959                         hi = state->gapStartList[i] - 1;
01960                         if (tsnBetween(lo, receivedTsn, hi))
01961                         {
01962                                 gapsize = hi - lo + 1;
01963                                 if (gapsize > 1)
01964                                 {
01969                                         if (receivedTsn == hi)
01970                                         {
01971 
01972                                                 sctpEV3<<"receivedTsn==hi....";
01973 
01974                                                 state->gapStartList[i] = receivedTsn;
01975                                                 state->newChunkReceived = true;
01976                                                 return true;
01977                                         }
01978                                         else if (receivedTsn == lo)
01979                                         {
01980 
01981                                                 sctpEV3<<"receivedTsn==lo=="<<lo<<"....."<< lo<<"\n";
01982 
01983                                                 if (receivedTsn == (state->cTsnAck + 1))
01984                                                 {
01985                                                         state->cTsnAck++;
01986                                                         state->newChunkReceived = true;
01987                                                         return true;
01988                                                 }
01989                                                 /* some gap must increase its upper bound */
01990                                                 state->gapStopList[i-1] = receivedTsn;
01991                                                 state->newChunkReceived = true;
01992                                                 return true;
01993                                         }
01994                                         else
01995                                         {    /* a gap in between */
01996                                                 state->numGaps++;
01997 
01998                                                 sctpEV3<<"Inserting new gap (start==stop=="<<receivedTsn<<"\n";
01999 
02000                                                 for (uint32 j=state->numGaps; j>i; j--)
02001                                                 {
02002                                                         state->gapStartList[j] = state->gapStartList[j-1];
02003                                                         state->gapStopList[j] = state->gapStopList[j-1];
02004                                                 }
02005                                                 state->gapStartList[i]=receivedTsn;
02006                                                 state->gapStopList[i]=receivedTsn;
02007                                                 state->newChunkReceived = true;
02008                                                 for (uint32 k=0; k<state->numGaps; k++)
02009 
02010                                                         sctpEV3<<"Gap "<<k<<": "<<state->gapStartList[k]<<" - "<<state->gapStopList[k]<<"\n";
02011 
02012                                                 return true;
02013                                         }
02014                                 }
02015                                 else
02016                                 { /* alright: gapsize is 1: our received tsn may close gap between fragments */
02017 
02018                                         sctpEV3<<"gapsize="<<gapsize<<"\n";
02019 
02020                                         if (lo == state->cTsnAck + 1)
02021                                         {
02022                                                 state->cTsnAck = state->gapStopList[i];
02023                                                 if (i==state->numGaps-1)
02024                                                 {
02025                                                         state->gapStartList[i] = 0;
02026                                                         state->gapStopList[i] = 0;
02027                                                 }
02028                                                 else
02029                                                         for (uint32 j=i; j<state->numGaps; j++)
02030                                                         {
02031                                                                 state->gapStartList[j] = state->gapStartList[j+1];
02032                                                                 state->gapStopList[j] = state->gapStopList[j+1];
02033                                                         }
02034                                                 state->numGaps--;
02035 
02036                                                 sctpEV3<<"state->numGaps="<<state->numGaps<<"\n";
02037 
02038                                                 state->newChunkReceived = true;
02039                                                 return true;
02040                                         }
02041                                         else
02042                                         {
02043                                                 state->gapStopList[i-1] = state->gapStopList[i];
02044                                                 if (i==state->numGaps-1)
02045                                                 {
02046                                                         state->gapStartList[i] = 0;
02047                                                         state->gapStopList[i] = 0;
02048                                                 }
02049                                                 else
02050                                                         for (uint32 j=i; j<=state->numGaps; j++)
02051                                                         {
02052                                                                 state->gapStartList[j] = state->gapStartList[j+1];
02053                                                                 state->gapStopList[j] = state->gapStopList[j+1];
02054                                                         }
02055                                                 state->numGaps--;
02056                                                 state->newChunkReceived = true;
02057                                                 return true;
02058                                         }
02059 
02060                                 }
02061 
02062                         }
02063                         else
02064                         {  /* receivedTsn is not in the gap between these fragments... */
02065                                 lo = state->gapStopList[i] + 1;
02066                         }
02067                 } /* end: for */
02068         }/* end: for */
02069 
02070         /* (NULL LIST)  OR  (End of Gap List passed) */
02071         if (receivedTsn == lo)
02072         {
02073                 /* just increase ctsna, handle further update of ctsna later */
02074                 if (receivedTsn == state->cTsnAck + 1)
02075                 {
02076 
02077                         sctpEV3<<"Updating cTsnAck....now cTsnAck=="<<receivedTsn<<"\n";
02078 
02079                         state->cTsnAck = receivedTsn;
02080                         state->newChunkReceived = true;
02081                         return true;
02082                 }
02083                 /* Update last fragment....increase stop_tsn by one */
02084                 state->gapStopList[state->numGaps-1]++;
02085 
02086                 state->newChunkReceived = true;
02087                 return true;
02088 
02089         }
02090         else
02091         {                    /* a new fragment altogether, past the end of the list */
02092 
02093                 sctpEV3<<"Inserting new fragment after the end of the list (start==stop=="<<receivedTsn<<"\n";
02094 
02095                 state->gapStartList[state->numGaps] = receivedTsn;
02096                 state->gapStopList[state->numGaps] = receivedTsn;
02097                 state->numGaps++;
02098                 state->newChunkReceived = true;
02099                 for (uint32 k=0; k<state->numGaps; k++)
02100 
02101                         sctpEV3<<"Gap "<<k<<": "<<state->gapStartList[k]<<" - "<<state->gapStopList[k]<<"\n";
02102 
02103                 return true;
02104         }
02105 
02106         return false;
02107 
02108 }

void SCTPAssociation::removeFromGapList ( uint32  removedTsn  )  [protected]

Referenced by makeRoomForTsn().

01869 {
01870 int32 gapsize, numgaps;
01871 
01872         numgaps = state->numGaps;
01873         sctpEV3<<"remove TSN "<<removedTsn<<" from GapList. "<<numgaps<<" gaps present, cumTsnAck="<<state->cTsnAck<<"\n";
01874         for (int32 j=0; j<numgaps; j++)
01875                 sctpEV3<<state->gapStartList[j]<<" - "<<state->gapStopList[j]<<"\n";
01876         for (int32 i=numgaps-1; i>=0; i--)
01877         {
01878                 sctpEV3<<"gapStartList["<<i<<"]="<<state->gapStartList[i]<<", state->gapStopList["<<i<<"]="<<state->gapStopList[i]<<"\n";
01879                 if (tsnBetween(state->gapStartList[i], removedTsn, state->gapStopList[i]))
01880                 {
01881                         gapsize = (int32)(state->gapStopList[i] - state->gapStartList[i]+1);
01882                         if (gapsize>1)
01883                         {
01884                                 if (state->gapStopList[i]==removedTsn)
01885                                 {
01886                                         state->gapStopList[i]--;
01887                                 }
01888                                 else if (state->gapStartList[i]==removedTsn)
01889                                 {
01890                                         state->gapStartList[i]++;
01891                                 }
01892                                 else //gap is split in two
01893                                 {
01894                                         for (int32 j=numgaps-1; j>=i; j--)
01895                                         {
01896                                                 state->gapStopList[j+1] = state->gapStopList[j];
01897                                                 state->gapStartList[j+1] = state->gapStartList[j];
01898                                         }
01899                                         state->gapStopList[i] = removedTsn-1;
01900                                         state->gapStartList[i+1] = removedTsn+1;
01901                                         state->numGaps++;
01902                                 }
01903                         }
01904                         else
01905                         {
01906 
01907                                 for (int32 j=i; j<=numgaps-1; j++)
01908                                 {
01909                                         state->gapStopList[j] = state->gapStopList[j+1];
01910                                         state->gapStartList[j] = state->gapStartList[j+1];
01911                                 }
01912                                 state->gapStartList[numgaps-1]=0;
01913                                 state->gapStopList[numgaps-1]=0;
01914                                 state->numGaps--;
01915                                 if (state->numGaps == 0)
01916                                 {
01917                                         if (removedTsn == state->lastTsnAck+1)
01918                                         {
01919                                                 state->lastTsnAck = removedTsn;
01920                                         }
01921                                 }
01922                         }
01923                 }
01924         }
01925         if (state->numGaps>0)
01926                 state->highestTsnReceived = state->gapStopList[state->numGaps-1];
01927         else
01928                 state->highestTsnReceived = state->cTsnAck;
01929 }

bool SCTPAssociation::makeRoomForTsn ( uint32  tsn,
uint32  length,
bool  uBit 
) [protected]

Referenced by processDataArrived().

01785 {
01786 SCTPDataVariables* datVar=NULL;
01787 SCTPQueue* stream, dStream;
01788 uint32 sum=0, comp=0;
01789 bool delQ = false;
01790 uint32 high = state->highestTsnStored;
01791 sctpEV3<<simulation.getSimTime()<<": makeRoomForTsn: tsn="<<tsn<<", length="<<length<<" high="<<high<<"\n";
01792         while (sum<length && state->highestTsnReceived>state->lastTsnAck)
01793         {
01794                 comp = sum;
01795                 for (SCTPReceiveStreamMap::iterator iter=receiveStreams.begin();iter!=receiveStreams.end(); iter++)
01796                 {
01797                         if (tsn > high)
01798                                 return false;
01799                         if (uBit)
01800                                 stream = iter->second->getUnorderedQ();
01801                         else
01802                                 stream = iter->second->getOrderedQ();
01803                         datVar = stream->getVar(high);
01804                         if (datVar==NULL)       //12.06.08
01805                         {
01806                                 sctpEV3<<high<<" not found in orderedQ. Try deliveryQ\n";
01807                                 stream = iter->second->getDeliveryQ();
01808                                 datVar = stream->getVar(high);
01809                                 delQ = true;
01810                         }
01811                         if (datVar!=NULL)
01812                         {
01813 
01814                                 sum+=datVar->len;
01815                                 if (stream->deleteMsg(high))
01816                                 {
01817                                 sctpEV3<<high<<" found and deleted\n";
01818 
01819                                 state->queuedRcvBytes-=datVar->len/8; //12.06.08
01820                                 if (ssnGt(iter->second->getExpectedStreamSeqNum(),datVar->ssn))
01821                                         iter->second->setExpectedStreamSeqNum(datVar->ssn);
01822                                 }
01823                                 qCounter.roomSumRcvStreams -= ADD_PADDING(datVar->len/8 + SCTP_DATA_CHUNK_LENGTH);
01824                                 if (high == state->highestTsnReceived)
01825                                         state->highestTsnReceived--;
01826                                 removeFromGapList(high);
01827 
01828                                 if (tsn > state->highestTsnReceived)
01829                                         state->highestTsnReceived=tsn;
01830                                 high--;
01831                                 break;
01832                         }
01833                         else
01834                         {
01835 
01836                                 sctpEV3<<"TSN "<<high<<" not found in stream "<<iter->second->getStreamId()<<"\n";
01837 
01838                         }
01839                 }
01840 
01841                 if (comp == sum)
01842                 {
01843                         //removeFromGapList(high);
01844                         sctpEV3<<high<<" not found in any stream\n";
01845                         high--;
01846                 }
01847                 state->highestTsnStored = high;
01848 
01849                 if (tsn > state->highestTsnReceived)
01850                         return false;
01851         }
01852         return true;
01853 }

void SCTPAssociation::sendInit (  )  [protected]

Methods for creating and sending chunks

Referenced by process_ASSOCIATE().

00378 {
00379         //RoutingTableAccess routingTableAccess;
00380         InterfaceTableAccess interfaceTableAccess;
00381         AddressVector adv;
00382         uint32 length = SCTP_INIT_CHUNK_LENGTH;
00383 
00384         if (remoteAddr.isUnspecified() || remotePort==0)
00385                 opp_error("Error processing command ASSOCIATE: foreign socket unspecified");
00386         if (localPort==0)
00387                 opp_error("Error processing command ASSOCIATE: local port unspecified");
00388         state->primaryPathIndex = remoteAddr;
00389         // create message consisting of INIT chunk
00390         SCTPMessage *sctpmsg = new SCTPMessage();
00391         sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
00392         SCTPInitChunk *initChunk = new SCTPInitChunk("INIT");
00393         initChunk->setChunkType(INIT);
00394 
00395         initChunk->setInitTag(uint32rand());
00396 
00397         peerVTag = initChunk->getInitTag();
00398         sctpEV3<<"INIT from "<<localAddr<<":InitTag="<<peerVTag<<"\n";
00399         initChunk->setA_rwnd(sctpMain->par("arwnd"));
00400         initChunk->setNoOutStreams(outboundStreams);
00401         initChunk->setNoInStreams(SCTP_DEFAULT_INBOUND_STREAMS);
00402         initChunk->setInitTSN(1000);
00403         state->nextTSN=initChunk->getInitTSN();
00404         state->lastTSN = initChunk->getInitTSN() + state->numRequests - 1;
00405         initTsn=initChunk->getInitTSN();
00406         IInterfaceTable *ift = interfaceTableAccess.get();
00407         sctpEV3<<"add local address\n";
00408         if (localAddressList.front() == IPvXAddress("0.0.0.0"))
00409         {
00410                 for (int32 i=0; i<ift->getNumInterfaces(); ++i)
00411                 {
00412                         if (ift->getInterface(i)->ipv4Data()!=NULL)
00413                         {
00414                                 sctpEV3<<"save address "<<ift->getInterfaceById(i)->ipv4Data()->getIPAddress()<<"\n";
00415                                 adv.push_back(ift->getInterface(i)->ipv4Data()->getIPAddress());
00416                         }
00417                         else if (ift->getInterface(i)->ipv6Data()!=NULL)
00418                         {
00419                                 for (int32 j=0; j<ift->getInterface(i)->ipv6Data()->getNumAddresses(); j++)
00420                                 {
00421                                         sctpEV3<<"add address "<<ift->getInterface(i)->ipv6Data()->getAddress(j)<<"\n";
00422                                         adv.push_back(ift->getInterface(i)->ipv6Data()->getAddress(j));
00423                                 }
00424                         }
00425                 }
00426         }
00427         else
00428         {
00429                 adv = localAddressList;
00430                 sctpEV3<<"gebundene Adresse "<<localAddr<<" wird hinzugefuegt\n";
00431         }
00432         uint32 addrNum=0;
00433         bool friendly = false;
00434         if (remoteAddr.isIPv6())
00435         {
00436                 for (AddressVector::iterator i=adv.begin(); i!=adv.end(); ++i)
00437                 {
00438                         if (!friendly)
00439                         {
00440                                 initChunk->setAddressesArraySize(addrNum+1);
00441                                 initChunk->setAddresses(addrNum++,(*i));
00442                                 length+=20;
00443                         }
00444                         sctpMain->addLocalAddress(this, (*i));
00445                         state->localAddresses.push_back((*i));
00446                         if (localAddr.isUnspecified())
00447                                 localAddr=(*i);
00448                 }
00449         }
00450         else
00451         {
00452                 uint32 rlevel = getLevel(remoteAddr);
00453                 sctpEV3<<"level of remote address="<<rlevel<<"\n";
00454                 for (AddressVector::iterator i=adv.begin(); i!=adv.end(); ++i)
00455                 {
00456                         sctpEV3<<"level of address "<<(*i)<<" = "<<getLevel((*i))<<"\n";
00457                         if (getLevel((*i))>=rlevel)
00458                         {
00459                                 initChunk->setAddressesArraySize(addrNum+1);
00460                                 initChunk->setAddresses(addrNum++,(*i));
00461                                 length+=8;
00462                                 sctpMain->addLocalAddress(this, (*i));
00463                                 state->localAddresses.push_back((*i));
00464                                 if (localAddr.get4().getInt()==0)
00465                                         localAddr=(*i);
00466                         }
00467                         else if (rlevel==4 && getLevel((*i))==3 && friendly)
00468                         {
00469                                 sctpMain->addLocalAddress(this, (*i));
00470                                 state->localAddresses.push_back((*i));
00471                                 if (localAddr.get4().getInt()==0)
00472                                         localAddr=(*i);
00473                         }
00474                 }
00475         }
00476         sctpMain->printInfoConnMap();
00477         initChunk->setBitLength(length*8);
00478         sctpmsg->addChunk(initChunk);
00479         // set path variables
00480         if (remoteAddressList.size()>0)
00481         {
00482                 for (AddressVector::iterator it=remoteAddressList.begin(); it!=remoteAddressList.end(); it++)
00483                 {
00484                         SCTPPathVariables* path = new SCTPPathVariables((*it), this);
00485                         sctpPathMap[(*it)] = path;
00486                         qCounter.roomTransQ[(*it)] = 0;
00487                         qCounter.roomRetransQ[(*it)] = 0;
00488                         qCounter.bookedTransQ[(*it)] = 0;
00489                 }
00490         }
00491         else
00492         {
00493                 SCTPPathVariables* path = new SCTPPathVariables(remoteAddr, this);
00494                 sctpPathMap[remoteAddr] = path;
00495                 qCounter.roomTransQ[remoteAddr] = 0;
00496                 qCounter.roomRetransQ[remoteAddr] = 0;
00497                 qCounter.bookedTransQ[remoteAddr] = 0;
00498         }
00499         // send it
00500         state->initChunk=check_and_cast<SCTPInitChunk *>(initChunk->dup());
00501         state->initChunk->setName("StateInitChunk");
00502         printSctpPathMap();
00503         sctpEV3<<getFullPath()<<" sendInit: localVTag="<<localVTag<<" peerVTag="<<peerVTag<<"\n";
00504         sendToIP(sctpmsg);
00505 }

void SCTPAssociation::sendInitAck ( SCTPInitChunk *  initchunk  )  [protected]

Referenced by processInitArrived().

00526 {
00527         uint32 length = SCTP_INIT_CHUNK_LENGTH;
00528 
00529         state->primaryPathIndex = remoteAddr;
00530         // create segment
00531         SCTPMessage *sctpinitack = new SCTPMessage();
00532         sctpinitack->setBitLength(SCTP_COMMON_HEADER*8);
00533 
00534         sctpinitack->setSrcPort(localPort);
00535         sctpinitack->setDestPort(remotePort);
00536         SCTPInitAckChunk *initAckChunk = new SCTPInitAckChunk("INIT_ACK");
00537         initAckChunk->setChunkType(INIT_ACK);
00538         SCTPCookie *cookie = new SCTPCookie("CookieUtil");
00539         cookie->setCreationTime(simulation.getSimTime());
00540         cookie->setLocalTieTagArraySize(32);
00541         cookie->setPeerTieTagArraySize(32);
00542         if (fsm->getState()==SCTP_S_CLOSED)
00543         {
00544                 do
00545                 {
00546                         peerVTag = uint32rand();
00547                 } while (peerVTag==0);
00548                 initAckChunk->setInitTag(peerVTag);
00549                 initAckChunk->setInitTSN(2000);
00550                 state->nextTSN=initAckChunk->getInitTSN();
00551                 state->lastTSN = initAckChunk->getInitTSN() + state->numRequests - 1;
00552                 cookie->setLocalTag(localVTag);
00553                 cookie->setPeerTag(peerVTag);
00554                 for (int32 i=0; i<32; i++)
00555                 {
00556                         cookie->setLocalTieTag(i,0);
00557                         cookie->setPeerTieTag(i,0);
00558                 }
00559                 sctpinitack->setTag(localVTag);
00560                 sctpEV3<<"state=closed: localVTag="<<localVTag<<" peerVTag="<<peerVTag<<"\n";
00561         }
00562         else if (fsm->getState()==SCTP_S_COOKIE_WAIT || fsm->getState()==SCTP_S_COOKIE_ECHOED)
00563         {
00564                 initAckChunk->setInitTag(peerVTag);
00565                 sctpEV3<<"different state:set InitTag in InitAck: "<<initAckChunk->getInitTag()<<"\n";
00566                 initAckChunk->setInitTSN(state->nextTSN);
00567                 initPeerTsn=initChunk->getInitTSN();
00568                 state->cTsnAck = initPeerTsn - 1;
00569                 cookie->setLocalTag(initChunk->getInitTag());
00570                 cookie->setPeerTag(peerVTag);
00571                 for (int32 i=0; i<32; i++)
00572                 {
00573                         cookie->setPeerTieTag(i,(uint8)intrand(256));
00574                         state->peerTieTag[i] = cookie->getPeerTieTag(i);
00575                         if (fsm->getState()==SCTP_S_COOKIE_ECHOED)
00576                         {
00577                                 cookie->setLocalTieTag(i,(uint8)intrand(256));
00578                                 state->localTieTag[i] = cookie->getLocalTieTag(i);
00579                         }
00580                         else
00581                                 cookie->setLocalTieTag(i,0);
00582                 }
00583                 sctpinitack->setTag(initChunk->getInitTag());
00584                 sctpEV3<<"VTag in InitAck: "<<sctpinitack->getTag()<<"\n";
00585         }
00586         else
00587         {
00588                 sctpEV3<<"other state\n";
00589                 uint32 tag;
00590                 do
00591                 {
00592                                 tag = uint32rand();
00593                 } while (tag==0);
00594                                 initAckChunk->setInitTag(tag);
00595                 initAckChunk->setInitTSN(state->nextTSN);
00596                 cookie->setLocalTag(localVTag);
00597                 cookie->setPeerTag(peerVTag);
00598                 for (int32 i=0; i<32; i++)
00599                 {
00600                         cookie->setPeerTieTag(i,state->peerTieTag[i]);
00601                         cookie->setLocalTieTag(i,state->localTieTag[i]);
00602                 }
00603                 sctpinitack->setTag(initChunk->getInitTag());
00604         }
00605         cookie->setBitLength(SCTP_COOKIE_LENGTH*8);
00606         initAckChunk->setStateCookie(cookie);
00607         initAckChunk->setCookieArraySize(0);
00608         initAckChunk->setA_rwnd(sctpMain->par("arwnd"));
00609         initAckChunk->setNoOutStreams((unsigned int)min(outboundStreams,initChunk->getNoInStreams()));
00610         initAckChunk->setNoInStreams(SCTP_DEFAULT_INBOUND_STREAMS);
00611 
00612         initTsn=initAckChunk->getInitTSN();
00613         uint32 addrNum=0;
00614         bool friendly = false;
00615         if (!friendly)
00616         for (AddressVector::iterator k=state->localAddresses.begin(); k!=state->localAddresses.end(); ++k)
00617         {
00618                 initAckChunk->setAddressesArraySize(addrNum+1);
00619                 initAckChunk->setAddresses(addrNum++,(*k));
00620                 length+=8;
00621         }
00622         uint32 unknownLen = initChunk->getUnrecognizedParametersArraySize();
00623         if (unknownLen>0)
00624         {
00625                 sctpEV3<<"Found unrecognized Parameters in INIT chunk with a length of "<<unknownLen<<" bytes.\n";
00626                 initAckChunk->setUnrecognizedParametersArraySize(unknownLen);
00627                 for (uint32 i=0; i<unknownLen; i++)
00628                         initAckChunk->setUnrecognizedParameters(i,initChunk->getUnrecognizedParameters(i));
00629                 length+=unknownLen;
00630         }
00631         else
00632                 initAckChunk->setUnrecognizedParametersArraySize(0);
00633 
00634         initAckChunk->setBitLength((length+initAckChunk->getCookieArraySize())*8 + cookie->getBitLength());
00635         inboundStreams = ((initChunk->getNoOutStreams()<initAckChunk->getNoInStreams())?initChunk->getNoOutStreams():initAckChunk->getNoInStreams());
00636         outboundStreams = ((initChunk->getNoInStreams()<initAckChunk->getNoOutStreams())?initChunk->getNoInStreams():initAckChunk->getNoOutStreams());
00637         (this->*ssFunctions.ssInitStreams)(inboundStreams, outboundStreams);
00638         sctpinitack->addChunk(initAckChunk);
00639         if (fsm->getState()==SCTP_S_CLOSED)
00640         {
00641                 sendToIP(sctpinitack, state->initialPrimaryPath);
00642         }
00643         else
00644         {
00645                 sendToIP(sctpinitack);
00646 
00647         }
00648         printSctpPathMap();
00649 }

void SCTPAssociation::sendCookieEcho ( SCTPInitAckChunk *  initackchunk  )  [protected]

Referenced by processInitAckArrived().

00652 {
00653         SCTPMessage *sctpcookieecho = new SCTPMessage();
00654         sctpcookieecho->setBitLength(SCTP_COMMON_HEADER*8);
00655 
00656         sctpEV3<<"SCTPAssociationUtil:sendCookieEcho\n";
00657 
00658         sctpcookieecho->setSrcPort(localPort);
00659         sctpcookieecho->setDestPort(remotePort);
00660         SCTPCookieEchoChunk* cookieEchoChunk=new SCTPCookieEchoChunk("COOKIE_ECHO");
00661         cookieEchoChunk->setChunkType(COOKIE_ECHO);
00662         int32 len = initAckChunk->getCookieArraySize();
00663         cookieEchoChunk->setCookieArraySize(len);
00664         if (len>0)
00665         {
00666                 for (int32 i=0; i<len; i++)
00667                         cookieEchoChunk->setCookie(i, initAckChunk->getCookie(i));
00668                 cookieEchoChunk->setBitLength((SCTP_COOKIE_ACK_LENGTH+len)*8);
00669         }
00670         else
00671         {
00672                 SCTPCookie* cookie = check_and_cast <SCTPCookie*> (initAckChunk->getStateCookie());
00673                 cookieEchoChunk->setStateCookie(cookie);
00674                 cookieEchoChunk->setBitLength(SCTP_COOKIE_ACK_LENGTH*8 + cookie->getBitLength());
00675         }
00676         uint32 unknownLen = initAckChunk->getUnrecognizedParametersArraySize();
00677         if (unknownLen>0)
00678         {
00679                 sctpEV3<<"Found unrecognized Parameters in INIT-ACK chunk with a length of "<<unknownLen<<" bytes.\n";
00680                 cookieEchoChunk->setUnrecognizedParametersArraySize(unknownLen);
00681                 for (uint32 i=0; i<unknownLen; i++)
00682                         cookieEchoChunk->setUnrecognizedParameters(i,initAckChunk->getUnrecognizedParameters(i));
00683         }
00684         else
00685                 cookieEchoChunk->setUnrecognizedParametersArraySize(0);
00686         state->cookieChunk=check_and_cast<SCTPCookieEchoChunk*>(cookieEchoChunk->dup());
00687         if (len==0)
00688         {
00689                 state->cookieChunk->setStateCookie(initAckChunk->getStateCookie()->dup());
00690                         }
00691         sctpcookieecho->addChunk(cookieEchoChunk);
00692                 sendToIP(sctpcookieecho);
00693 }

void SCTPAssociation::sendCookieAck ( IPvXAddress  dest  )  [protected]

Referenced by processCookieEchoArrived().

00767 {
00768         SCTPMessage *sctpcookieack = new SCTPMessage();
00769         sctpcookieack->setBitLength(SCTP_COMMON_HEADER*8);
00770 
00771         sctpEV3<<"SCTPAssociationUtil:sendCookieACK\n";
00772 
00773         sctpcookieack->setSrcPort(localPort);
00774         sctpcookieack->setDestPort(remotePort);
00775         SCTPCookieAckChunk* cookieAckChunk=new SCTPCookieAckChunk("COOKIE_ACK");
00776         cookieAckChunk->setChunkType(COOKIE_ACK);
00777         cookieAckChunk->setBitLength(SCTP_COOKIE_ACK_LENGTH*8);
00778         sctpcookieack->addChunk(cookieAckChunk);
00779         sendToIP(sctpcookieack, dest);
00780 }

void SCTPAssociation::sendAbort (  )  [protected]

Referenced by process_ABORT(), process_RCV_Message(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_RTX(), process_TIMEOUT_SHUTDOWN(), processCookieEchoArrived(), processInitArrived(), processTimer(), and updateCounters().

00831 {
00832         SCTPMessage *msg = new SCTPMessage();
00833         msg->setBitLength(SCTP_COMMON_HEADER*8);
00834 
00835         sctpEV3<<"SCTPAssociationUtil:sendABORT localPort="<<localPort<<"  remotePort="<<remotePort<<"\n";
00836 
00837         msg->setSrcPort(localPort);
00838         msg->setDestPort(remotePort);
00839         SCTPAbortChunk* abortChunk = new SCTPAbortChunk("ABORT");
00840         abortChunk->setChunkType(ABORT);
00841         abortChunk->setT_Bit(0);
00842         abortChunk->setBitLength(SCTP_ABORT_CHUNK_LENGTH*8);
00843         msg->addChunk(abortChunk);
00844         sendToIP(msg, remoteAddr);
00845 }

void SCTPAssociation::sendHeartbeat ( SCTPPathVariables path,
bool  local 
) [protected]

Referenced by pmStartPathManagement(), and process_TIMEOUT_HEARTBEAT_INTERVAL().

00714 {
00715         SCTPMessage *sctpheartbeat = new SCTPMessage();
00716         sctpheartbeat->setBitLength(SCTP_COMMON_HEADER*8);
00717 
00718         sctpheartbeat->setSrcPort(localPort);
00719         sctpheartbeat->setDestPort(remotePort);
00720         SCTPHeartbeatChunk* heartbeatChunk=new SCTPHeartbeatChunk("HEARTBEAT");
00721         heartbeatChunk->setChunkType(HEARTBEAT);
00722         heartbeatChunk->setRemoteAddr(path->remoteAddress);
00723         heartbeatChunk->setTimeField(simulation.getSimTime());
00724         heartbeatChunk->setBitLength((SCTP_HEARTBEAT_CHUNK_LENGTH+12)*8);
00725         //heartbeatChunk->setBitLength((SCTP_HEARTBEAT_CHUNK_LENGTH+12+1000)*8);
00726         sctpheartbeat->addChunk(heartbeatChunk);
00727         if (local)
00728         {
00729                 sctpEV3<<"sendHeartbeat: sendToIP from "<<localAddr<<" to "<<path->remoteAddress<<"\n";
00730                 sendToIP(sctpheartbeat, localAddr, path->remoteAddress);
00731         }
00732         else
00733         {
00734                 sctpEV3<<"sendHeartbeat: sendToIP  to "<<path->remoteAddress<<"\n";
00735                 sendToIP(sctpheartbeat, path->remoteAddress);
00736         }
00737         path->hbWasAcked=false;
00738 }

void SCTPAssociation::sendHeartbeatAck ( SCTPHeartbeatChunk *  heartbeatChunk,
IPvXAddress  src,
IPvXAddress  dest 
) [protected]

Referenced by process_RCV_Message().

00741 {
00742         SCTPMessage *sctpheartbeatack = new SCTPMessage();
00743         sctpheartbeatack->setBitLength(SCTP_COMMON_HEADER*8);
00744 
00745         sctpheartbeatack->setSrcPort(localPort);
00746         sctpheartbeatack->setDestPort(remotePort);
00747         SCTPHeartbeatAckChunk* heartbeatAckChunk=new SCTPHeartbeatAckChunk("HEARTBEAT_ACK");
00748         heartbeatAckChunk->setChunkType(HEARTBEAT_ACK);
00749         heartbeatAckChunk->setRemoteAddr(heartbeatChunk->getRemoteAddr());
00750         heartbeatAckChunk->setTimeField(heartbeatChunk->getTimeField());
00751         int32 len=heartbeatChunk->getInfoArraySize();
00752         if (len>0)
00753         {
00754                 heartbeatAckChunk->setInfoArraySize(len);
00755                 for (int32 i=0; i<len; i++)
00756                         heartbeatAckChunk->setInfo(i,heartbeatChunk->getInfo(i));
00757         }
00758 
00759         heartbeatAckChunk->setBitLength(heartbeatChunk->getBitLength());
00760         sctpheartbeatack->addChunk(heartbeatAckChunk);
00761         sctpEV3<<"try to get path for "<<dest<<"\n";
00762         sctpEV3<<"send heartBeatAck from "<<src<<" to "<<dest<<"\n";
00763         sendToIP(sctpheartbeatack, src, dest);
00764 }

void SCTPAssociation::sendSack ( void   )  [protected]

Referenced by process_RCV_Message(), processTimer(), and pushUlp().

01018 {
01019         sctpEV3<<"sendSack\n";
01020         SCTPSackChunk* sackChunk;
01021         IPvXAddress dpi;                /* destination path index that will actually be used/was used on last send */
01022         /* sack timer has expired, reset flag, and send SACK */
01023         stopTimer(SackTimer);
01024         state->ackState = 0;
01025         sackChunk = createSack();
01026 
01027         /* return the SACK to the address where we last got a data chunk from */
01028         dpi = state->lastDataSourceAddress;
01029         SCTPMessage* sctpmsg = new SCTPMessage();
01030         sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
01031         sctpmsg->addChunk(sackChunk);
01032         sendToIP(sctpmsg, dpi);
01033 }

void SCTPAssociation::sendShutdown (  )  [protected]

Referenced by process_CLOSE(), process_RCV_Message(), and stateEntered().

00848 {
00849         SCTPMessage *msg = new SCTPMessage();
00850         msg->setBitLength(SCTP_COMMON_HEADER*8);
00851 
00852         sctpEV3<<"SCTPAssociationUtil:sendShutdown localPort="<<localPort<<"  remotePort="<<remotePort<<"\n";
00853 
00854         msg->setSrcPort(localPort);
00855         msg->setDestPort(remotePort);
00856         SCTPShutdownChunk* shutdownChunk = new SCTPShutdownChunk("Shutdown");
00857         shutdownChunk->setChunkType(SHUTDOWN);
00858         //shutdownChunk->setCumTsnAck(state->lastTsnAck);
00859         shutdownChunk->setCumTsnAck(state->cTsnAck);
00860         shutdownChunk->setBitLength(SCTP_SHUTDOWN_CHUNK_LENGTH*8);
00861         state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT;
00862         state->initRetransCounter = 0;
00863         stopTimer(T5_ShutdownGuardTimer);
00864         startTimer(T5_ShutdownGuardTimer,SHUTDOWN_GUARD_TIMEOUT);
00865         stopTimer(T2_ShutdownTimer);
00866         startTimer(T2_ShutdownTimer,state->initRexmitTimeout);
00867         state->shutdownChunk=check_and_cast<SCTPShutdownChunk*>(shutdownChunk->dup());
00868         msg->addChunk(shutdownChunk);
00869         sendToIP(msg, remoteAddr);
00870 }

void SCTPAssociation::sendShutdownAck ( IPvXAddress  dest  )  [protected]

Referenced by performStateTransition(), process_CLOSE(), process_RCV_Message(), and processAppCommand().

00783 {
00784         sendAll(dest);
00785         if (dest!=state->primaryPathIndex)
00786                 sendAll(state->primaryPathIndex);
00787         if (getOutstandingBytes()==0)
00788         {
00789                 performStateTransition(SCTP_E_NO_MORE_OUTSTANDING);
00790                 SCTPMessage *sctpshutdownack = new SCTPMessage();
00791                 sctpshutdownack->setBitLength(SCTP_COMMON_HEADER*8);
00792 
00793                 sctpEV3<<"SCTPAssociationUtil:sendShutdownACK\n";
00794 
00795                 sctpshutdownack->setSrcPort(localPort);
00796                 sctpshutdownack->setDestPort(remotePort);
00797                 SCTPShutdownAckChunk* shutdownAckChunk=new SCTPShutdownAckChunk("SHUTDOWN_ACK");
00798                 shutdownAckChunk->setChunkType(SHUTDOWN_ACK);
00799                 shutdownAckChunk->setBitLength(SCTP_COOKIE_ACK_LENGTH*8);
00800                 sctpshutdownack->addChunk(shutdownAckChunk);
00801                 state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT;
00802                 state->initRetransCounter = 0;
00803                 stopTimer(T2_ShutdownTimer);
00804                 startTimer(T2_ShutdownTimer,state->initRexmitTimeout);
00805                 stopTimer(T5_ShutdownGuardTimer);
00806                 startTimer(T5_ShutdownGuardTimer,SHUTDOWN_GUARD_TIMEOUT);
00807                 state->shutdownAckChunk=check_and_cast<SCTPShutdownAckChunk*>(shutdownAckChunk->dup());
00808                 sendToIP(sctpshutdownack, dest);
00809         }
00810 }

void SCTPAssociation::sendShutdownComplete (  )  [protected]

Referenced by process_RCV_Message().

00813 {
00814         SCTPMessage *sctpshutdowncomplete = new SCTPMessage();
00815         sctpshutdowncomplete->setBitLength(SCTP_COMMON_HEADER*8);
00816 
00817         sctpEV3<<"SCTPAssociationUtil:sendShutdownComplete\n";
00818 
00819         sctpshutdowncomplete->setSrcPort(localPort);
00820         sctpshutdowncomplete->setDestPort(remotePort);
00821         SCTPShutdownCompleteChunk* shutdownCompleteChunk=new SCTPShutdownCompleteChunk("SHUTDOWN_COMPLETE");
00822         shutdownCompleteChunk->setChunkType(SHUTDOWN_COMPLETE);
00823         shutdownCompleteChunk->setTBit(0);
00824         shutdownCompleteChunk->setBitLength(SCTP_SHUTDOWN_ACK_LENGTH*8);
00825         sctpshutdowncomplete->addChunk(shutdownCompleteChunk);
00826         sendToIP(sctpshutdowncomplete);
00827 }

SCTPSackChunk * SCTPAssociation::createSack (  )  [protected]

Referenced by sendAll(), and sendSack().

00932 {
00933 uint32 key=0, arwnd=0;
00934 
00935         sctpEV3<<"SCTPAssociationUtil:createSACK localPort="<<localPort<<"  remotePort="<<remotePort<<"\n";
00936 
00937         sctpEV3<<" localRwnd="<<state->localRwnd<<"  queuedBytes="<<state->queuedRcvBytes<<"\n";
00938         if ((int32)(state->localRwnd - state->queuedRcvBytes) <= 0)
00939         {
00940                 arwnd = 0;
00941                 if (state->swsLimit > 0)
00942                         state->swsAvoidanceInvoked = true;
00943         }
00944         else if (state->localRwnd - state->queuedRcvBytes < state->swsLimit || state->swsAvoidanceInvoked == true)
00945         {
00946                 arwnd = 1;
00947                 if (state->swsLimit > 0)
00948                         state->swsAvoidanceInvoked = true;
00949                 // SWS Avoidance ACTIVE !!!
00950         }
00951         else
00952         {
00953                 arwnd = state->localRwnd - state->queuedRcvBytes;
00954                 sctpEV3<<simulation.getSimTime()<<" arwnd = "<<state->localRwnd<<" - "<<state->queuedRcvBytes<<" = "<<arwnd<<"\n";
00955         }
00956         advRwnd->record(arwnd);
00957         quBytes->record(state->queuedRcvBytes);
00958         SCTPSackChunk* sackChunk=new SCTPSackChunk("SACK");
00959         sackChunk->setChunkType(SACK);
00960         sackChunk->setCumTsnAck(state->cTsnAck);
00961         sackChunk->setA_rwnd(arwnd);
00962         uint32 numGaps=state->numGaps;
00963         uint32 numDups=state->dupList.size();
00964         uint16 sackLength=SCTP_SACK_CHUNK_LENGTH + numGaps*4 + numDups*4;
00965         uint32 mtu = getPath(remoteAddr)->pmtu;
00966 
00967         if (sackLength > mtu-32) // FIXME
00968         {
00969                 if (SCTP_SACK_CHUNK_LENGTH + numGaps*4 > mtu-32)
00970                 {
00971                         numDups = 0;
00972                         numGaps = (uint32)((mtu-32-SCTP_SACK_CHUNK_LENGTH)/4);
00973                 }
00974                 else
00975                 {
00976                         numDups = (uint32)((mtu-32-SCTP_SACK_CHUNK_LENGTH - numGaps*4)/4);
00977                 }
00978                 sackLength=SCTP_SACK_CHUNK_LENGTH + numGaps*4 + numDups*4;
00979         }
00980         sackChunk->setNumGaps(numGaps);
00981         sackChunk->setNumDupTsns(numDups);
00982         sackChunk->setBitLength(sackLength*8);
00983 
00984         sctpEV3<<"Sack arwnd="<<sackChunk->getA_rwnd()<<" ctsnAck="<<state->cTsnAck<<" numGaps="<<numGaps<<" numDups="<<numDups<<"\n";
00985 
00986         if (numGaps > 0)
00987         {
00988                 sackChunk->setGapStartArraySize(numGaps);
00989                 sackChunk->setGapStopArraySize(numGaps);
00990                 for (key=0; key<numGaps; key++)
00991                 {
00992                         sackChunk->setGapStart(key, state->gapStartList[key]);
00993                         sackChunk->setGapStop(key, state->gapStopList[key]);
00994                 }
00995         }
00996         if (numDups > 0)
00997         {
00998                 sackChunk->setDupTsnsArraySize(numDups);
00999                 key=0;
01000                 for(std::list<uint32>::iterator iter=state->dupList.begin(); iter!=state->dupList.end(); iter++)
01001                 {
01002                         sackChunk->setDupTsns(key, (*iter));
01003                         key++;
01004                         if (key == numDups)
01005                                 break;
01006                 }
01007                 state->dupList.clear();
01008         }
01009         sctpEV3<<endl;
01010         for (uint32 i=0; i<numGaps; i++)
01011                 sctpEV3<<sackChunk->getGapStart(i)<<" - "<<sackChunk->getGapStop(i)<<"\n";
01012 
01013         sctpEV3<<"send "<<sackChunk->getName()<<" from "<<localAddr<<" to "<<state->lastDataSourceAddress<<"\n";
01014         return sackChunk;
01015 }

void SCTPAssociation::retransmitInit (  )  [protected]

Retransmitting chunks

Referenced by process_RCV_Message(), and process_TIMEOUT_INIT_REXMIT().

00508 {
00509         SCTPMessage *sctpmsg = new SCTPMessage();
00510         sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
00511         SCTPInitChunk *sctpinit;// = new SCTPInitChunk("INIT");
00512 
00513         sctpEV3<<"Retransmit InitChunk="<<&sctpinit<<"\n";
00514 
00515         sctpinit=check_and_cast<SCTPInitChunk *>(state->initChunk->dup());
00516         sctpinit->setChunkType(INIT);
00517         sctpmsg->addChunk(sctpinit);
00518 
00519         sendToIP(sctpmsg);
00520 
00521 }

void SCTPAssociation::retransmitCookieEcho (  )  [protected]

Referenced by process_RCV_Message(), and process_TIMEOUT_INIT_REXMIT().

00698 {
00699         SCTPMessage *sctpmsg = new SCTPMessage();
00700         sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
00701         SCTPCookieEchoChunk* cookieEchoChunk=check_and_cast<SCTPCookieEchoChunk*>(state->cookieChunk->dup());
00702         if (cookieEchoChunk->getCookieArraySize()==0)
00703         {
00704                 cookieEchoChunk->setStateCookie(state->cookieChunk->getStateCookie()->dup());
00705         }
00706         sctpmsg->addChunk(cookieEchoChunk);
00707 
00708         sctpEV3<<"retransmitCookieEcho localAddr="<<localAddr<<"  remoteAddr"<<remoteAddr<<"\n";
00709 
00710         sendToIP(sctpmsg);
00711 }

void SCTPAssociation::retransmitShutdown (  )  [protected]

Referenced by process_TIMEOUT_SHUTDOWN().

00874 {
00875         SCTPMessage *sctpmsg = new SCTPMessage();
00876         sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
00877         SCTPShutdownChunk* shutdownChunk;
00878         shutdownChunk=check_and_cast<SCTPShutdownChunk*>(state->shutdownChunk->dup());
00879 
00880         sctpmsg->addChunk(shutdownChunk);
00881 
00882         sctpEV3<<"retransmitShutdown localAddr="<<localAddr<<"  remoteAddr"<<remoteAddr<<"\n";
00883 
00884         sendToIP(sctpmsg);
00885 }

void SCTPAssociation::retransmitShutdownAck (  )  [protected]

Referenced by process_TIMEOUT_SHUTDOWN().

00888 {
00889         SCTPMessage *sctpmsg = new SCTPMessage();
00890         sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
00891         SCTPShutdownAckChunk* shutdownAckChunk;
00892         shutdownAckChunk=check_and_cast<SCTPShutdownAckChunk*>(state->shutdownAckChunk->dup());
00893         sctpmsg->addChunk(shutdownAckChunk);
00894 
00895         sctpEV3<<"retransmitShutdownAck localAddr="<<localAddr<<"  remoteAddr"<<remoteAddr<<"\n";
00896 
00897         sendToIP(sctpmsg);
00898 }

void SCTPAssociation::sendToIP ( SCTPMessage sctpmsg  )  [protected]

Utility: adds control info to message and sends it to IP

Referenced by retransmitCookieEcho(), retransmitInit(), retransmitShutdown(), retransmitShutdownAck(), sendAbort(), sendAll(), sendCookieAck(), sendCookieEcho(), sendHeartbeat(), sendHeartbeatAck(), sendInit(), sendInitAck(), sendSack(), sendShutdown(), sendShutdownAck(), and sendShutdownComplete().

00204 {
00205         // final touches on the segment before sending
00206         sctpmsg->setSrcPort(localPort);
00207         sctpmsg->setDestPort(remotePort);
00208         if (sctpmsg->getTag()==0)
00209                 sctpmsg->setTag(localVTag);
00210         sctpmsg->setChecksumOk(true);
00211         if (remoteAddr.isIPv6())
00212         {
00213                 IPv6ControlInfo *controlInfo = new IPv6ControlInfo();
00214                 controlInfo->setProtocol(IP_PROT_SCTP);
00215                 controlInfo->setSrcAddr(IPv6Address());
00216                 controlInfo->setDestAddr(remoteAddr.get6());
00217                 sctpmsg->setControlInfo(controlInfo);
00218                 sctpMain->send(sctpmsg,"to_ipv6");
00219         }
00220         else
00221         {
00222                 IPControlInfo *controlInfo = new IPControlInfo();
00223                 controlInfo->setProtocol(IP_PROT_SCTP);
00224                 controlInfo->setSrcAddr(IPAddress("0.0.0.0"));
00225                 controlInfo->setDestAddr(remoteAddr.get4());
00226                 sctpmsg->setControlInfo(controlInfo);
00227                 sctpMain->send(sctpmsg,"to_ip");
00228         }
00229 }

void SCTPAssociation::sendToIP ( SCTPMessage sctpmsg,
IPvXAddress  dest 
) [protected]

00232 {
00233 
00234         sctpmsg->setSrcPort(localPort);
00235         sctpmsg->setDestPort(remotePort);
00236         sctpmsg->setChecksumOk(true);
00237         SCTPChunk* chunk = (SCTPChunk*)(sctpmsg->peekFirstChunk());
00238         if (chunk->getChunkType() == ABORT)
00239         {
00240                 SCTPAbortChunk* abortChunk;
00241                 abortChunk = check_and_cast<SCTPAbortChunk *>(chunk);
00242                 if (abortChunk->getT_Bit()==1)
00243                         sctpmsg->setTag(peerVTag);
00244                 else
00245                         sctpmsg->setTag(localVTag);
00246         }
00247         else if (sctpmsg->getTag()==0)
00248                 sctpmsg->setTag(localVTag);
00249 
00250         if (dest.isIPv6())
00251         {
00252                 IPv6ControlInfo *controlInfo = new IPv6ControlInfo();
00253                 controlInfo->setProtocol(IP_PROT_SCTP);
00254                 controlInfo->setSrcAddr(IPv6Address());
00255                 controlInfo->setDestAddr(dest.get6());
00256                 sctpmsg->setControlInfo(controlInfo);
00257                 sctpMain->send(sctpmsg,"to_ipv6");
00258         }
00259         else
00260         {
00261                 IPControlInfo *controlInfo = new IPControlInfo();
00262                 controlInfo->setProtocol(IP_PROT_SCTP);
00263                 controlInfo->setSrcAddr(IPAddress("0.0.0.0"));
00264                 controlInfo->setDestAddr(dest.get4());
00265                 sctpmsg->setControlInfo(controlInfo);
00266                 sctpMain->send(sctpmsg,"to_ip");
00267         }
00268 
00269         sctpEV3 << "Sent to "<<dest<<"\n ";
00270 
00271 }

void SCTPAssociation::sendToIP ( SCTPMessage sctpmsg,
IPvXAddress  src,
IPvXAddress  dest 
) [protected]

00274 {
00275 
00276         sctpmsg->setSrcPort(localPort);
00277         sctpmsg->setDestPort(remotePort);
00278         sctpmsg->setChecksumOk(true);
00279         SCTPChunk* chunk = (SCTPChunk*)(sctpmsg->peekFirstChunk());
00280         if (chunk->getChunkType() == ABORT)
00281         {
00282                 SCTPAbortChunk* abortChunk;
00283                 abortChunk = check_and_cast<SCTPAbortChunk *>(chunk);
00284                 if (abortChunk->getT_Bit()==1)
00285                         sctpmsg->setTag(peerVTag);
00286                 else
00287                         sctpmsg->setTag(localVTag);
00288         }
00289         else if (sctpmsg->getTag()==0)
00290                 sctpmsg->setTag(localVTag);
00291 
00292         if (dest.isIPv6())
00293         {
00294                 IPv6ControlInfo *controlInfo = new IPv6ControlInfo();
00295                 controlInfo->setProtocol(IP_PROT_SCTP);
00296                 controlInfo->setSrcAddr(src.get6());
00297                 controlInfo->setDestAddr(dest.get6());
00298                 sctpmsg->setControlInfo(controlInfo);
00299                 sctpMain->send(sctpmsg,"to_ipv6");
00300         }
00301         else
00302         {
00303                 IPControlInfo *controlInfo = new IPControlInfo();
00304                 controlInfo->setProtocol(IP_PROT_SCTP);
00305                 controlInfo->setSrcAddr(src.get4());
00306                 controlInfo->setDestAddr(dest.get4());
00307                 sctpmsg->setControlInfo(controlInfo);
00308                 sctpMain->send(sctpmsg,"to_ip");
00309         }
00310 
00311         sctpEV3 << "Sent to "<<dest<<"\n ";
00312 
00313 }

void SCTPAssociation::scheduleSack ( void   )  [protected]

Referenced by process_RCV_Message().

00902 {
00903         /* increase SACK counter, we received another data PACKET */
00904         if (state->firstChunkReceived)
00905                 state->ackState++;
00906         else
00907         {
00908                 state->ackState = sackFrequency;
00909                 state->firstChunkReceived = true;
00910         }
00911 
00912         sctpEV3<<"scheduleSack() : ackState is now: "<<state->ackState<<"\n";
00913 
00914         if (state->ackState <= sackFrequency - 1)
00915         {
00916                 /* start a SACK timer if none is running, to expire 200 ms (or parameter) from now */
00917                 if (!SackTimer->isScheduled())
00918                 {
00919                         startTimer(SackTimer, sackPeriod);
00920                 }
00921                 /* else: leave timer running, and do nothing... */ else {
00922                         /* is this possible at all ? Check this... */
00923 
00924                         sctpEV3<<"SACK timer running, but scheduleSack() called\n";
00925 
00926                 }
00927         }
00928 }

void SCTPAssociation::signalConnectionTimeout (  )  [protected]

Utility: signal to user that connection timed out

00316 {
00317         sendIndicationToApp(SCTP_I_TIMED_OUT);
00318 }

void SCTPAssociation::scheduleTimeout ( cMessage *  msg,
simtime_t  timeout 
) [inline, protected]

Utility: start a timer

Referenced by SCTPAssociation(), and startTimer().

00641                         {sctpMain->scheduleAt(simulation.getSimTime()+timeout, msg);}

cMessage* SCTPAssociation::cancelEvent ( cMessage *  msg  )  [inline, protected]

Utility: cancel a timer

Referenced by stopTimer().

00644 {return sctpMain->cancelEvent(msg);}

void SCTPAssociation::sendToApp ( cPacket *  msg  )  [protected]

Utility: sends packet to application

Referenced by pathStatusIndication(), process_STATUS(), pushUlp(), and sendDataArrivedNotification().

00351 {
00352 
00353         sctpMain->send(msg, "to_appl", appGateIndex);
00354 }

void SCTPAssociation::sendIndicationToApp ( int32  code  )  [protected]

Utility: sends status indication (SCTP_I_xxx) to application

Referenced by dequeueOutboundDataMsg(), process_RCV_Message(), process_SEND(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_RTX(), process_TIMEOUT_SHUTDOWN(), processTimer(), sendAll(), signalConnectionTimeout(), stateEntered(), and updateCounters().

00321 {
00322         cPacket *msg = new cPacket(indicationName(code));
00323         msg->setKind(code);
00324         SCTPCommand *ind = new SCTPCommand(indicationName(code));
00325         ind->setAssocId(assocId);
00326         ind->setLocalAddr(localAddr);
00327         ind->setRemoteAddr(remoteAddr);
00328         msg->setControlInfo(ind);
00329         sctpMain->send(msg, "to_appl", appGateIndex);
00330 }

void SCTPAssociation::sendEstabIndicationToApp (  )  [protected]

Utility: sends SCTP_I_ESTABLISHED indication with SCTPConnectInfo to application

Referenced by stateEntered().

00333 {
00334         cPacket *msg = new cPacket(indicationName(SCTP_I_ESTABLISHED));
00335         msg->setKind(SCTP_I_ESTABLISHED);
00336 
00337         SCTPConnectInfo *ind = new SCTPConnectInfo("CI");
00338         ind->setAssocId(assocId);
00339         ind->setLocalAddr(localAddr);
00340         ind->setRemoteAddr(remoteAddr);
00341         ind->setLocalPort(localPort);
00342         ind->setRemotePort(remotePort);
00343         ind->setRemoteAddresses(remoteAddressList);
00344         ind->setInboundStreams(inboundStreams);
00345         ind->setOutboundStreams(outboundStreams);
00346         msg->setControlInfo(ind);
00347         sctpMain->send(msg, "to_appl", appGateIndex);
00348 }

void SCTPAssociation::pushUlp (  )  [protected]

Referenced by process_RECEIVE_REQUEST().

01624 {
01625         int32 count=0;
01626         SCTPReceiveStream* rStream;
01627         SCTPDataVariables* chunk;
01628         for (unsigned i=0; i<inboundStreams; i++)       //12.06.08
01629                 putInDeliveryQ(i);
01630         if (state->pushMessagesLeft <=0)
01631                 state->pushMessagesLeft = state->messagesToPush;
01632         bool restrict = false;
01633 
01634         if (state->pushMessagesLeft > 0)
01635                 restrict = true;
01636 
01637         quBytes->record(state->queuedRcvBytes);
01638 
01639         sctpEV3<<simulation.getSimTime()<<" Calling PUSH_ULP ("<<state->queuedRcvBytes<<" bytes queued)...\n";
01640         uint32 i=state->nextRSid;
01641         do
01642         {
01643                 SCTPReceiveStreamMap::iterator iter=receiveStreams.find(i);
01644                 rStream=iter->second;
01645                 sctpEV3<<"Size of stream "<<iter->first<<": "<<rStream->getDeliveryQ()->getQueueSize()<<"\n";
01646 
01647                 while (!rStream->getDeliveryQ()->payloadQueue.empty() && (!restrict || (restrict && state->pushMessagesLeft>0)))
01648                 {
01649                         chunk = rStream->getDeliveryQ()->extractMessage();
01650                         qCounter.roomSumRcvStreams -= ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH);
01651 
01652                         if (state->pushMessagesLeft >0)
01653                                 state->pushMessagesLeft--;
01654 
01655                         state->queuedRcvBytes-=chunk->len/8;
01656 
01657                         if (state->swsAvoidanceInvoked)
01658                         {
01659                                 quBytes->record(state->queuedRcvBytes);
01660                                 if ((int32)(state->localRwnd - state->queuedRcvBytes) >= (int32)(state->swsLimit) && (int32)(state->localRwnd - state->queuedRcvBytes) <= (int32)(state->swsLimit+state->assocPmtu))
01661 
01662                                 {
01663                                         /* only if the window has opened up more than one MTU we will send a SACK */
01664                                         state->swsAvoidanceInvoked = false;
01665                                         sctpEV3<<"pushUlp: Window opens up to "<<(int32)state->localRwnd-state->queuedRcvBytes<<" bytes: sending a SACK. SWS Avoidance INACTIVE\n";
01666 
01667                                         sendSack();
01668                                 }
01669                         }
01670                         sctpEV3<<"Push TSN "<<chunk->tsn<<": sid="<<chunk->sid<<" ssn="<<chunk->ssn<<"\n";
01671                         cPacket* msg= (cPacket *)chunk->userData;
01672                         msg->setKind(SCTP_I_DATA);
01673                         SCTPCommand *cmd = new SCTPCommand("push");
01674                         cmd->setAssocId(assocId);
01675                         cmd->setGate(appGateIndex);
01676                         cmd->setSid(chunk->sid);
01677                         cmd->setLocalAddr(localAddr);
01678                         cmd->setRemoteAddr(remoteAddr);
01679                         msg->setControlInfo(cmd);
01680                         state->numMsgsReq[count]--;
01681                         delete chunk;
01682                         sendToApp(msg);
01683                 }
01684 
01685                 i = (i+1)%inboundStreams;
01686 
01687                 count++;
01688         } while (i!=state->nextRSid);
01689 
01690         state->nextRSid = (state->nextRSid+1)%inboundStreams;
01691 
01692         if (state->queuedRcvBytes==0 && fsm->getState()==SCTP_S_SHUTDOWN_ACK_SENT)
01693 {
01694                 sctpEV3<<"SCTP_E_CLOSE\n";
01695                 performStateTransition(SCTP_E_CLOSE);
01696 }
01697 }

void SCTPAssociation::sendDataArrivedNotification ( uint16  sid  )  [protected]

Referenced by processDataArrived(), and putInDeliveryQ().

01568 {
01569 
01570         sctpEV3<<"SendDataArrivedNotification\n";
01571 
01572         cPacket* cmsg = new cPacket("DataArrivedNotification");
01573         cmsg->setKind(SCTP_I_DATA_NOTIFICATION);
01574         SCTPCommand *cmd = new SCTPCommand("notification");
01575         cmd->setAssocId(assocId);
01576         cmd->setSid(sid);
01577         cmd->setNumMsgs(1);
01578         cmsg->setControlInfo(cmd);
01579 
01580         sendToApp(cmsg);
01581 }

void SCTPAssociation::putInDeliveryQ ( uint16  sid  )  [protected]

Referenced by processDataArrived(), and pushUlp().

01585 {
01586         SCTPReceiveStream* rStream;
01587         SCTPDataVariables* chunk;
01588         SCTPReceiveStreamMap::iterator iter=receiveStreams.find(sid);
01589         rStream = iter->second;
01590         sctpEV3<<"putInDeliveryQ: first look for SSN "<<rStream->getExpectedStreamSeqNum()<<" of SID "<<sid<<" in orderedQ of size "<<rStream->getOrderedQ()->getQueueSize()<<"\n";
01591         while (rStream->getOrderedQ()->getQueueSize()>0)
01592         {
01593                 /* dequeue first from reassembly Q */
01594                 chunk = rStream->getOrderedQ()-> dequeueVarBySsn(rStream->getExpectedStreamSeqNum());
01595                 if (chunk)
01596                 {
01597                         sctpEV3<<"putInDeliveryQ::chunk "<<chunk->tsn<<" , sid "<<chunk->sid<<" and ssn "<<chunk->ssn<<" dequeued from ordered queue. queuedRcvBytes="<<state->queuedRcvBytes<<" will be reduced by "<<chunk->len/8<<"\n";
01598                         state->queuedRcvBytes-=chunk->len/8;
01599 
01600 
01601                         qCounter.roomSumRcvStreams -= ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH);
01602                         if (rStream->getDeliveryQ()->checkAndInsertVar(chunk->tsn, chunk))
01603                         {
01604 
01605                                 state->queuedRcvBytes+=chunk->len/8;
01606 
01607                                 sctpEV3<<"data put in deliveryQ; queuedBytes now "<<state->queuedRcvBytes<<"\n";
01608                                 qCounter.roomSumRcvStreams += ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH);
01609                                 int32 seqnum=rStream->getExpectedStreamSeqNum();
01610                                 rStream->setExpectedStreamSeqNum(++seqnum);
01611                                 if (rStream->getExpectedStreamSeqNum() > 65535)
01612                                         rStream->setExpectedStreamSeqNum(0);
01613                                 sendDataArrivedNotification(sid);
01614                         }
01615                 }
01616                 else
01617                 {
01618                         break;
01619                 }
01620         }
01621 }

void SCTPAssociation::printConnBrief (  )  [protected]

Utility: prints local/remote addr/port and app gate index/assocId

Referenced by processAppCommand(), and processSCTPMessage().

00161 {
00162         sctpEV3 << "Connection " << this << " ";
00163         sctpEV3 << localAddr << ":" << localPort << " to " << remoteAddr << ":" << remotePort;
00164         sctpEV3 << "  on app[" << appGateIndex << "],assocId=" << assocId;
00165         sctpEV3 << "  in " << stateName(fsm->getState()) << "\n";
00166 
00167 }

void SCTPAssociation::printSegmentBrief ( SCTPMessage sctpmsg  )  [static, protected]

Utility: prints important header fields

00170 {
00171 
00172         sctpEV3 << "." << sctpmsg->getSrcPort() << " > ";
00173         sctpEV3 << "." << sctpmsg->getDestPort() << ": ";
00174 
00175         sctpEV3 << "initTag "<< sctpmsg->getTag() << "\n";
00176 
00177 }

const char * SCTPAssociation::eventName ( int32  event  )  [static, protected]

Utility: returns name of SCTP_E_xxx constants

Referenced by performStateTransition(), and processAppCommand().

00076 {
00077 #define CASE(x) case x: s=#x+7; break
00078         const char *s = "unknown";
00079         switch (event)
00080         {
00081                 CASE(SCTP_E_OPEN_PASSIVE);
00082                 CASE(SCTP_E_ASSOCIATE);
00083                 CASE(SCTP_E_SHUTDOWN);
00084                 CASE(SCTP_E_CLOSE);
00085                 CASE(SCTP_E_ABORT);
00086                 CASE(SCTP_E_SEND);
00087                 CASE(SCTP_E_RCV_INIT);
00088                 CASE(SCTP_E_RCV_ABORT);
00089                 CASE(SCTP_E_RCV_VALID_COOKIE_ECHO);
00090                 CASE(SCTP_E_RCV_INIT_ACK);
00091                 CASE(SCTP_E_RCV_COOKIE_ACK);
00092                 CASE(SCTP_E_RCV_SHUTDOWN);
00093                 CASE(SCTP_E_RCV_SHUTDOWN_ACK);
00094                 CASE(SCTP_E_RCV_SHUTDOWN_COMPLETE);
00095                 CASE(SCTP_E_TIMEOUT_INIT_TIMER);
00096                 CASE(SCTP_E_TIMEOUT_SHUTDOWN_TIMER);
00097                 CASE(SCTP_E_TIMEOUT_RTX_TIMER);
00098                 CASE(SCTP_E_TIMEOUT_HEARTBEAT_TIMER);
00099                 CASE(SCTP_E_RECEIVE);
00100                 CASE(SCTP_E_DUP_RECEIVED);
00101                 CASE(SCTP_E_PRIMARY);
00102                 CASE(SCTP_E_QUEUE);
00103                 CASE(SCTP_E_NO_MORE_OUTSTANDING);
00104                 CASE(SCTP_E_IGNORE);
00105                 CASE(SCTP_E_DELIVERED);
00106                 CASE(SCTP_E_SEND_SHUTDOWN_ACK);
00107                 CASE(SCTP_E_STOP_SENDING);
00108         }
00109         return s;
00110 #undef CASE
00111 }

void SCTPAssociation::addPath ( IPvXAddress  addr  )  [protected]

Referenced by processInitAckArrived().

01725 {
01726 
01727         sctpEV3<<"Add Path remote address: "<<addr<<"\n";
01728 
01729         SCTPPathMap::iterator i = sctpPathMap.find(addr);
01730         if (i==sctpPathMap.end())
01731         {
01732                 SCTPPathVariables* path = new SCTPPathVariables(addr, this);
01733                 sctpPathMap[addr] = path;
01734                 qCounter.roomTransQ[addr] = 0;
01735                 qCounter.roomRetransQ[addr] = 0;
01736                 qCounter.bookedTransQ[addr] = 0;
01737         }
01738 }

IPvXAddress SCTPAssociation::getNextDestination ( SCTPDataVariables chk  )  [protected]

Referenced by process_TIMEOUT_RTX(), and processSackArrived().

02380 {
02381         IPvXAddress dpi, last;
02382 
02383 
02384         sctpEV3<<"getNextDestination\n";
02385 
02386         if (chk->numberOfTransmissions == 0)
02387         {
02388                 if (chk->initialDestination == IPvXAddress("0.0.0.0"))
02389                 {
02390                         dpi = state->primaryPathIndex;
02391                 }
02392                 else
02393                 {
02394                         dpi = chk->initialDestination;
02395                 }
02396         }
02397         else
02398         {
02399                 if (chk->hasBeenFastRetransmitted)
02400                 {
02401 
02402                         sctpEV3<<"Chunk is scheduled for FastRetransmission. Next destination = "<<chk->lastDestination<<"\n";
02403 
02404                         //chk->hasBeenFastRetransmitted=false;
02405                         return chk->lastDestination;
02406                 }
02407                 dpi = last = chk->lastDestination;
02408                 /* if this is a retransmission, we should choose another, active path */
02409                 SCTPPathMap::iterator iter=sctpPathMap.find(dpi);
02410                 do
02411                 {
02412 
02413                         sctpEV3<<"old dpi="<<iter->first<<"\n";
02414 
02415                         iter++;
02416                         if (iter==sctpPathMap.end())
02417                                 iter=sctpPathMap.begin();
02418                         dpi=iter->first;
02419 
02420                 } while (iter->first != last && iter->second->activePath == false || iter->second->confirmed==false);
02421         }
02422 
02423 
02424         sctpEV3<<"sctp_get_next_destination: chunk was last sent to "<<last<<", will next be sent to path "<<dpi<<"\n";
02425 
02426         sctpEV3<<"new dpi="<<dpi<<"\n";
02427         return (dpi);
02428 }

IPvXAddress SCTPAssociation::getNextAddress ( IPvXAddress  dpi  )  [protected]

Referenced by process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_RTX(), and updateCounters().

02357 {
02358 
02359         int32 hit=0;
02360 
02361         if (sctpPathMap.size()>1)
02362         {
02363                 for (SCTPPathMap::iterator iter=sctpPathMap.begin(); iter!=sctpPathMap.end(); iter++)
02364                 {
02365                         if (iter->first==pid)
02366                         {
02367                                 if (++hit==1)
02368                                         continue;
02369                                 else
02370                                         break;
02371                         }
02372                         if (iter->second->activePath)
02373                                 return iter->first;
02374                 }
02375         }
02376         return IPvXAddress("0.0.0.0");
02377 }

void SCTPAssociation::bytesAllowedToSend ( IPvXAddress  dpi  )  [protected]

Referenced by sendAll().

02431 {
02432         uint32 osb = 0;
02433         int32 diff = 0;
02434         SCTPPathMap::iterator iter;
02435         bytes.chunk = false;
02436         bytes.packet = false;
02437         bytes.bytesToSend = 0;
02438 
02439         iter=sctpPathMap.find(dpi);
02440         osb = getPath(dpi)->outstandingBytes;
02441         sctpEV3<<"bytesAllowedToSend: osb="<<osb<<"  cwnd="<<iter->second->cwnd<<"\n";
02442         if (!state->firstDataSent)
02443         {
02444                 bytes.chunk = true;
02445                 return;
02446         }
02447         if (state->peerWindowFull)
02448         {
02449                 if (osb==0)
02450                 {
02451                         sctpEV3<<"probingIsAllowed\n";
02452                         state->zeroWindowProbing=true;
02453                         bytes.chunk = true;
02454                 }
02455                 return;
02456         }
02457         else
02458         {
02459 
02460 
02461                 sctpEV3<<"bytesAllowedToSend: osb="<<osb<<"  cwnd="<<iter->second->cwnd<<"\n";
02462                 CounterMap::iterator it = qCounter.roomTransQ.find(dpi);
02463                 sctpEV3<<"bytes in transQ="<<it->second<<"\n";
02464                 if (it->second>0)
02465                 {
02466                         diff = iter->second->cwnd - osb;
02467                         sctpEV3<<"cwnd-osb="<<diff<<"\n";
02468                         if (state->peerRwnd<iter->second->pmtu)
02469                         {
02470                                 bytes.bytesToSend = state->peerRwnd;
02471                                 return;
02472                         }
02473                         if (diff > 0)
02474                         {
02475                                 CounterMap::iterator bit = qCounter.bookedTransQ.find(dpi);
02476                                 if (bit->second > (uint32)diff)
02477                                 {
02478                                         bytes.bytesToSend = diff;
02479                                         sctpEV3<<"cwnd does not allow all RTX\n";
02480                                         return;
02481                                 }
02482                                 else
02483                                 {
02484                                         bytes.bytesToSend = bit->second;
02485                                         sctpEV3<<"cwnd allows more than those "<<bytes.bytesToSend<<" bytes for retransmission\n";
02486                                 }
02487                         }
02488                         else // You may transmit one packet
02489                         {
02490                                 bytes.packet = true;
02491                                 sctpEV3<<"diff<=0: retransmit one packet\n";
02492                                 return;
02493                         }
02494                 }
02495 
02496                 if (!bytes.chunk && !bytes.packet)
02497                 {
02498                         if (osb < iter->second->cwnd && !state->peerWindowFull )
02499                         {
02500                                 sctpEV3<<"bookedSumSendStreams="<<qCounter.bookedSumSendStreams<<" bytes.bytesToSend="<<bytes.bytesToSend<<"\n";
02501                                 diff = iter->second->cwnd - osb - bytes.bytesToSend;
02502                                 if (diff>0)
02503                                 if (qCounter.bookedSumSendStreams > (uint32)diff)
02504                                 {
02505                                         bytes.bytesToSend =  iter->second->cwnd - osb ;
02506                                         sctpEV3<<"bytesToSend are limited by cwnd: "<<bytes.bytesToSend<<"\n";
02507                                 }
02508                                 else
02509                                 {
02510                                         bytes.bytesToSend += qCounter.bookedSumSendStreams;
02511                                         sctpEV3<<"send all stored bytes: "<<bytes.bytesToSend<<"\n";
02512                                 }
02513                         }
02514                 }
02515         }
02516 
02517 }

void SCTPAssociation::pathStatusIndication ( IPvXAddress  pid,
bool  status 
) [protected]

Referenced by pmClearPathCounter(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_RTX(), and updateCounters().

02817 {
02818         cPacket* msg=new cPacket("StatusInfo");
02819         msg->setKind(SCTP_I_STATUS);
02820         SCTPStatusInfo *cmd = new SCTPStatusInfo();
02821         cmd->setPathId(pid);
02822         cmd->setAssocId(assocId);
02823         cmd->setActive(status);
02824         msg->setControlInfo(cmd);
02825         if (!status)
02826         {
02827                 SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId);
02828                 iter->second.numPathFailures++;
02829         }
02830         sendToApp(msg);
02831 }

bool SCTPAssociation::allPathsInactive ( void   )  [protected]

Referenced by process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_RTX(), and updateCounters().

02947 {
02948         for(SCTPPathMap::iterator i=sctpPathMap.begin(); i!=sctpPathMap.end(); i++)
02949         {
02950                 if (i->second->activePath)
02951                         return false;
02952         }
02953 
02954         return true;
02955 }

uint32 SCTPAssociation::getLevel ( IPvXAddress  addr  )  [protected]

Referenced by processInitArrived(), and sendInit().

02958 {
02959         if (addr.isIPv6())
02960         {
02961                 if (addr.get6().getScope()==IPv6Address::UNSPECIFIED || addr.get6().getScope()==IPv6Address::MULTICAST)
02962                         return 0;
02963                 if (addr.get6().getScope()==IPv6Address::LOOPBACK)
02964                         return 1;
02965                 if (addr.get6().getScope()==IPv6Address::LINK)
02966                         return 2;
02967                 if (addr.get6().getScope()==IPv6Address::SITE)
02968                         return 3;
02969         }
02970         else
02971         {
02972                 //Addresses usable with SCTP, but not as destination or source address
02973                 if (addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("0.0.0.0"), IPAddress("255.0.0.0")) ||
02974                         addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("224.0.0.0"), IPAddress("240.0.0.0")) ||
02975                         addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("198.18.0.0"), IPAddress("255.255.255.0")) ||
02976                         addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("192.88.99.0"), IPAddress("255.255.255.0")))
02977                         return 0;
02978 
02979                 //Loopback
02980                 if (addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("127.0.0.0"), IPAddress("255.0.0.0")))
02981                 return 1;
02982 
02983                 //Link-local
02984                 if (addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("169.254.0.0"), IPAddress("255.255.0.0")))
02985                         return 2;
02986 
02987                 //Private
02988                 if (addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("10.0.0.0"), IPAddress("255.0.0.0")) ||
02989                         addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("172.16.0.0"), IPAddress("255.240.0.0")) ||
02990                         addr.get4().maskedAddrAreEqual(addr.get4(), IPAddress("192.168.0.0"), IPAddress("255.255.0.0")))
02991                         return 3;
02992          }
02993         //Global
02994         return 4;
02995 }

SCTPDataChunk * SCTPAssociation::transformDataChunk ( SCTPDataVariables datVar  )  [protected]

Manipulating chunks

Referenced by sendAll().

01700 {
01701 
01702         SCTPDataChunk* dataChunk=new SCTPDataChunk("DATA");
01703         SCTPSimpleMessage* msg=check_and_cast<SCTPSimpleMessage*>(datVar->userData->dup());
01704         dataChunk->setChunkType(DATA);
01705         // no fragmentation implemented yet
01706         dataChunk->setBBit(1);
01707         dataChunk->setEBit(1);
01708         if (datVar->ordered)
01709                 dataChunk->setUBit(0);
01710         else
01711                 dataChunk->setUBit(1);
01712         dataChunk->setTsn(datVar->tsn);
01713         dataChunk->setSid(datVar->sid);
01714         dataChunk->setSsn(datVar->ssn);
01715         dataChunk->setPpid(datVar->ppid);
01716         dataChunk->setEnqueuingTime(datVar->enqueuingTime);
01717         dataChunk->setBitLength(SCTP_DATA_CHUNK_LENGTH*8);
01718         msg->setBitLength(datVar->len);
01719         dataChunk->encapsulate(msg);
01720         return dataChunk;
01721 }

SCTPDataVariables * SCTPAssociation::makeVarFromMsg ( SCTPDataChunk *  datachunk  )  [protected]

Referenced by processDataArrived().

02152 {
02153 SCTPDataVariables* datVar=new SCTPDataVariables();
02154 
02155         datVar->sid = dataChunk->getSid();
02156         datVar->ssn = dataChunk->getSsn();
02157         datVar->ppid = dataChunk->getPpid();
02158         datVar->tsn = dataChunk->getTsn();
02159         if (!dataChunk->getUBit())
02160                 datVar->ordered = true;
02161         else
02162                 datVar->ordered = false;
02163         SCTPSimpleMessage* smsg=check_and_cast<SCTPSimpleMessage*>(dataChunk->decapsulate());
02164 
02165         datVar->userData = smsg;
02166                 datVar->len = smsg->getDataLen()*8;
02167         sctpEV3<<"Datenlaenge="<<datVar->len/8<<"\n";
02168 
02169 
02170         sctpEV3<<"makeVarFromMsg::queuedBytes have been increased to "<<state->queuedRcvBytes<<"\n";
02171         return datVar;
02172 }

int32 SCTPAssociation::streamScheduler ( bool  peek  )  [protected]

Dealing with streams

Referenced by SCTPAssociation().

00063 {
00064         
00065         uint32 sid = 0;
00066         int32 num = 0;
00067         
00068         //num = numUsableStreams();
00069         num = (this->*ssFunctions.ssUsableStreams)();
00070 
00071         if (num > 1)
00072         {
00073                 sid = (state->lastStreamScheduled + 1) % outboundStreams;
00074                  
00075                 sctpEV3<<"streamScheduler sid="<<sid<<" lastStream="<<state->lastStreamScheduled<<" outboundStreams="<<outboundStreams<<"\n";
00076                 
00077                 num = (this->*ssFunctions.ssUsableStreams)();
00078                 while (sid!=state->lastStreamScheduled)
00079                 {
00080                         SCTPSendStreamMap::iterator iter=sendStreams.find(sid);
00081                         SCTPSendStream* stream=iter->second;
00082                         cQueue* strQ=stream->getUnorderedStreamQ();
00083                          
00084                         sctpEV3<<"Laenge unordered StreamQueue Nr "<<sid<<" = "<<strQ->length()<<"\n";
00085                         
00086                         if (strQ && strQ->length()>0) 
00087                         {
00088                                 sid =(iter->first);
00089 
00090                                 if (!peek)
00091                                         state->lastStreamScheduled = sid;
00092                                 return sid;
00093                         }
00094                         strQ=stream->getStreamQ();
00095                          
00096                         sctpEV3<<"Laenge StreamQueue Nr "<<sid<<" = "<<strQ->length()<<"\n";
00097                         
00098                         if (strQ && strQ->length()>0) 
00099                         {
00100                                 sid =(iter->first);
00101 
00102                                 if (!peek)
00103                                         state->lastStreamScheduled = sid;
00104                                 return sid;
00105                         }
00106                         else
00107                         {
00108                                 sid = (sid+1)%outboundStreams;
00109                                  
00110                                 sctpEV3<<"new sid="<<sid<<"\n";
00111                                 
00112                         }
00113                 }
00114         }
00115         else if (num == 1)
00116         {
00117                 for (SCTPSendStreamMap::iterator iter=sendStreams.begin(); iter!=sendStreams.end(); ++iter)
00118                 {
00119                         if (iter->second->getUnorderedStreamQ()->length()>0)
00120                         {
00121                                 sid = iter->first;
00122                                 if (!peek)
00123                                         state->lastStreamScheduled = sid;
00124                                 return sid;
00125                         }
00126                         if (iter->second->getStreamQ()->length()>0)
00127                         {
00128                                 sid = iter->first;
00129                                 if (!peek)
00130                                         state->lastStreamScheduled = sid;
00131                                 return sid;
00132                         }
00133                 }
00134         }
00135                 
00136 
00137          
00138         sctpEV3<<"Stream Scheduler: found no stream with data queued !\n";
00139         
00140         return (-1);
00141 }

void SCTPAssociation::initStreams ( uint32  inStreams,
uint32  outStreams 
) [protected]

Referenced by SCTPAssociation().

00037 {
00038 uint32 i;
00039          
00040         sctpEV3<<"initStreams instreams="<<inStreams<<"  outstream="<<outStreams<<"\n";
00041         if (receiveStreams.size()==0 && sendStreams.size()==0)
00042         {
00043                 for (i=0; i<inStreams; i++)
00044                 {
00045                         SCTPReceiveStream* rcvStream = new SCTPReceiveStream(); 
00046                                 
00047                         this->receiveStreams[i]=rcvStream;
00048                         rcvStream->setStreamId(i);
00049                         
00050                         this->state->numMsgsReq[i]=0;
00051                 }
00052                 for (i=0; i<outStreams; i++)
00053                 {
00054                         SCTPSendStream* sendStream = new SCTPSendStream(i);             
00055                         this->sendStreams[i]=sendStream;
00056                         sendStream->setStreamId(i);
00057                 }
00058         }
00059 }

int32 SCTPAssociation::numUsableStreams ( void   )  [protected]

Referenced by SCTPAssociation().

00145 {
00146         int32 count=0;
00147         
00148 
00149         for (SCTPSendStreamMap::iterator iter=sendStreams.begin(); iter!=sendStreams.end(); iter++)
00150                 if (iter->second->getStreamQ()->length()>0 || iter->second->getUnorderedStreamQ()->length()>0)
00151                 {
00152                         count++;
00153                 }
00154         return count;
00155 }

int32 SCTPAssociation::getQueuedBytes ( void   )  [protected]

Queue Management

02684 {
02685         int32 qb = 0;
02686         SCTPReceiveStream* rStream;
02687         SCTPQueue* sq;
02688 
02689     for (SCTPReceiveStreamMap::iterator iter=receiveStreams.begin(); iter!=receiveStreams.end(); iter++)
02690         {
02691                 rStream = iter->second;
02692                 sq = rStream->getOrderedQ();
02693                 if (sq)
02694                 {
02695                         qb+=sq->getNumBytes();
02696                 }
02697                 sq = rStream->getUnorderedQ();
02698                 if (sq)
02699                 {
02700                         qb+=sq->getNumBytes();
02701                 }
02702                 sq = rStream->getDeliveryQ();
02703                 if (sq)
02704                 {
02705                         qb+=sq->getNumBytes();
02706                 }
02707         }
02708 
02709 
02710         sctpEV3<<"getQueuedBytes : currently "<<qb<<"  bytes  buffered\n";
02711 
02712         return (qb);
02713 }

int32 SCTPAssociation::getOutstandingBytes ( void   )  [protected]

Referenced by process_CLOSE(), process_RCV_Message(), processAppCommand(), processSackArrived(), sendShutdownAck(), and stateEntered().

02716 {
02717         int32 osb = 0;
02718         for (SCTPPathMap::iterator pm=sctpPathMap.begin(); pm != sctpPathMap.end(); pm++)
02719                 osb += pm->second->outstandingBytes;
02720         return osb;
02721 }

int32 SCTPAssociation::dequeueAckedChunks ( uint32  tsna,
IPvXAddress  pathId,
simtime_t *  rttEstimation 
) [protected]

Referenced by process_RCV_Message(), and processSackArrived().

02724 {
02725         int32 newlyAckedBytes = 0;
02726         SCTPDataVariables* chunk = NULL;
02727         simtime_t timeDiff = 0.0;
02728 
02729         /* set it ridiculously high */
02730         *rttEstimation = -1.0;
02731 
02732         /* are there chunks in the retransmission queue ? If Yes -> check for dequeue */
02733         while (!retransmissionQ->payloadQueue.empty())
02734         {
02735 
02736                 SCTPQueue::PayloadQueue::iterator iter=retransmissionQ->payloadQueue.begin();
02737                 chunk = iter->second;
02738 
02739                 sctpEV3<<"dequeueAckedChunks() found chunk tsn "<<chunk->tsn<<" in the retransmissionQ\n";
02740 
02741 
02742                 if (tsnGe(tsna,chunk->tsn))
02743                 {
02744                         /* dequeue chunk, cause it has been acked */
02745                         if (transmissionQ->getVar(chunk->tsn))
02746                         {
02747                                 sctpEV3<<"Chunk was found in transmissionQ. Remove it\n";
02748                                 transmissionQ->removeMsg(chunk->tsn);
02749                                 CounterMap::iterator q = qCounter.roomTransQ.find(chunk->nextDestination);
02750                                 q->second -= ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH);
02751                                 CounterMap::iterator qb = qCounter.bookedTransQ.find(chunk->nextDestination);
02752                                 qb->second -= chunk->booksize;
02753                         }
02754                         chunk = retransmissionQ->getAndExtractMessage(chunk->tsn);
02755                         sctpEV3<<"dequeueAckedChunks(): dequeue chunk tsn="<<chunk->tsn<<", tsna="<<tsna<<", "<<retransmissionQ->getQueueSize()<<" chunks still in queue \n";
02756 
02757                         if (!chunk->hasBeenAcked)
02758                                 newlyAckedBytes += (chunk->booksize);
02759                         SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId);
02760                         iter->second.ackedBytes+=chunk->len/8;
02761 
02762                         if (chunk->hasBeenAcked == false && chunk->countsAsOutstanding)
02763                         {
02764                                 chunk->hasBeenAcked = true;
02765                                 chunk->countsAsOutstanding = false;
02766                                 if (chunk->numberOfTransmissions == 1 && chunk->lastDestination == pathId)
02767                                 {
02768                                         timeDiff = simulation.getSimTime() - chunk->sendTime;
02769 
02770                                         if (timeDiff < *rttEstimation || *rttEstimation == -1.0)
02771                                                 *rttEstimation = timeDiff;
02772 
02773                                         sctpEV3<<"dequeueAckedChunks(): computed rtt time diff == "<<timeDiff<<" for TSN"<<chunk->tsn<<"\n";
02774                                 }
02775                                 getPath(chunk->lastDestination)->outstandingBytes -= chunk->booksize;
02776                                 sctpEV3<<"osb="<<getPath(chunk->lastDestination)->outstandingBytes<<"\n";
02777                                 CounterMap::iterator i=qCounter.roomRetransQ.find(getPath(chunk->lastDestination)->remoteAddress);
02778                                                 i->second -= ADD_PADDING(chunk->booksize+SCTP_DATA_CHUNK_LENGTH);
02779                         }
02780                         pmClearPathCounter(chunk->lastDestination);
02781                         if (chunk->userData != NULL)
02782                         {
02783                                 delete chunk->userData;
02784                         }
02785                         delete chunk;
02786                 }
02787                 else
02788                         break;
02789         }
02790 
02791 
02792         sctpEV3<<"dequeueAckedChunks(): newly_acked_bytes== "<<newlyAckedBytes<<", rtt estimation == "<<*rttEstimation<<"\n";
02793 
02794 
02795         return (newlyAckedBytes);
02796 }

uint32 SCTPAssociation::getOutstandingBytesOnPath ( IPvXAddress  pathId  )  [protected]

02552 {
02553         uint32 osb = 0, queueLength = 0, first=0, second = 0;
02554 
02555 
02556         if (retransmissionQ->payloadQueue.empty()) return 0;
02557 
02558         queueLength = retransmissionQ->getQueueSize();
02559         sctpEV3<<"queueLength of retransmissionQ="<<queueLength<<"\n";
02560         sctpEV3<<"outstanding TSNs\n";
02561         for(SCTPQueue::PayloadQueue::iterator pl=retransmissionQ->payloadQueue.begin();pl!=retransmissionQ->payloadQueue.end();pl++)
02562         {
02563                 if (pl->second->lastDestination == pathId)
02564                 {
02565                         if (pl->second->hasBeenAcked == false && pl->second->countsAsOutstanding == true)
02566                         {
02567                                 //osb += pl->second->len/8;
02568                                 if (pl->second->tsn > second+1)
02569                                 {
02570                                         if (second != 0)
02571                                         {
02572                                                 sctpEV3<<" - "<<second<<"\t";;
02573 
02574                                         }
02575                                         first = second = pl->second->tsn;
02576                                         sctpEV3<<pl->second->tsn;
02577                                 }
02578                                 else if (pl->second->tsn == second+1)
02579                                 {
02580                                         second = pl->second->tsn;
02581                                 }
02582                                 first = pl->second->tsn;
02583                                 osb += pl->second->booksize;
02584                         }
02585                 }
02586         }
02587         sctpEV3<<" - "<<second<<"\n";
02588 
02589         sctpEV3<<"getOutstandingBytesOnPath("<<(pathId)<<") : currently "<<osb<<" bytes outstanding\n";
02590 
02591 
02592         return (osb);
02593 }

SCTPDataVariables * SCTPAssociation::peekOutboundDataChunk ( IPvXAddress  pid  )  [protected]

02213 {
02214         SCTPDataVariables* chunk = NULL;
02215 
02216         /* are there chunks in the transmission queue ? If Yes -> dequeue and return it */
02217         if (!transmissionQ->payloadQueue.empty())
02218         {
02219                 for(SCTPQueue::PayloadQueue::iterator it=transmissionQ->payloadQueue.begin(); it!=transmissionQ->payloadQueue.end(); it++)
02220                 {
02221                         chunk = it->second;
02222                         if (chunk->nextDestination == pid)
02223                         {
02224                                 sctpEV3<<"peekOutboundDataChunk() found chunk "<<chunk->tsn<<" in the transmission queue\n";
02225                                 if (chunk->hasBeenAcked)
02226                                 {
02227                                         transmissionQ->payloadQueue.erase(it);
02228                                         CounterMap::iterator i=qCounter.roomTransQ.find(pid);
02229                                         i->second-= ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH);
02230                                         CounterMap::iterator ib=qCounter.bookedTransQ.find(pid);
02231                                         ib->second-= chunk->booksize;
02232                                 }
02233                                 else
02234                                 {
02235                                                 return chunk;
02236                                 }
02237                         }
02238                 }
02239         }
02240 
02241         return NULL;
02242 }

SCTPDataMsg * SCTPAssociation::peekOutboundDataMsg ( void   )  [protected]

Referenced by sendAll().

02268 {
02269         SCTPDataMsg* datMsg=NULL;
02270         int32 nextStream = -1;
02271         nextStream = (this->*ssFunctions.ssGetNextSid)(true);
02272 
02273         if (nextStream == -1)
02274         {
02275 
02276                 sctpEV3<<"peekOutboundDataMsg(): no valid stream found -> returning NULL !\n";
02277 
02278                 return NULL;
02279         }
02280 
02281 
02282         for (SCTPSendStreamMap::iterator iter=sendStreams.begin(); iter!=sendStreams.end(); ++iter)
02283         {
02284                 if ((int32)iter->first==nextStream)
02285                 {
02286                         SCTPSendStream* stream=iter->second;
02287                         if (!stream->getUnorderedStreamQ()->empty())
02288                         {
02289                                         return (datMsg);
02290 
02291                         }
02292                         if (!stream->getStreamQ()->empty())
02293                         {
02294                                         return (datMsg);
02295 
02296                         }
02297                 }
02298         }
02299         return NULL;
02300 
02301 }

SCTPDataVariables * SCTPAssociation::peekAbandonedChunk ( IPvXAddress  pid  )  [protected]

02245 {
02246         SCTPDataVariables* chunk = NULL;
02247 
02248         /* are there chunks in the retransmission queue ? If Yes -> dequeue and return it */
02249         if (!retransmissionQ->payloadQueue.empty())
02250         {
02251                 for(SCTPQueue::PayloadQueue::iterator it=retransmissionQ->payloadQueue.begin(); it!=retransmissionQ->payloadQueue.end(); it++)
02252                 {
02253                         chunk=it->second;
02254                         sctpEV3<<"peek Chunk "<<chunk->tsn<<"\n";
02255                         if (chunk->lastDestination == pid && chunk->hasBeenAbandoned)
02256                         {
02257                                 sctpEV3<<"peekAbandonedChunk() found chunk in the retransmission queue\n";
02258                                 return chunk;
02259                         }
02260                 }
02261         }
02262 
02263         return NULL;
02264 }

SCTPDataVariables * SCTPAssociation::getOutboundDataChunk ( IPvXAddress  pid,
int32  bytes 
) [protected]

Referenced by sendAll().

02178 {
02179 int32 len;
02180         /* are there chunks in the transmission queue ? If Yes -> dequeue and return it */
02181         sctpEV3<<"getOutboundDataChunk: pid="<<pid<<" bytes="<<bytes<<"\n";
02182         sctpEV3<<"chunks in transmissionQ="<<transmissionQ->getQueueSize()<<"\n";
02183         if (!transmissionQ->payloadQueue.empty())
02184         {
02185                 sctpEV3<<"transmissionQ not empty\n";
02186                 for(SCTPQueue::PayloadQueue::iterator it=transmissionQ->payloadQueue.begin(); it!=transmissionQ->payloadQueue.end(); it++)
02187                 {
02188                         SCTPDataVariables* chunk=it->second;
02189                         sctpEV3<<"chunk->nextDestination="<<chunk->nextDestination<<"\n";
02190                         if (chunk->nextDestination == pid)
02191                         {
02192                                 len = ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH);
02193                                 sctpEV3<<"getOutboundDataChunk() found chunk "<<chunk->tsn<<" in the transmission queue, length="<<len<<"\n";
02194                                 if (len<=bytes)
02195                                 {
02196                                         transmissionQ->payloadQueue.erase(it);
02197                                         CounterMap::iterator i=qCounter.roomTransQ.find(pid);
02198                                         i->second-= ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH);
02199                                         CounterMap::iterator ib=qCounter.bookedTransQ.find(pid);
02200                                         ib->second-= chunk->booksize;
02201                                         if (chunk->hasBeenAcked==false)
02202                                                 return chunk;
02203                                 }
02204                         }
02205                 }
02206         }
02207         else
02208                 sctpEV3<<"transmissionQ empty!\n";
02209         return NULL;
02210 }

SCTPDataMsg * SCTPAssociation::dequeueOutboundDataMsg ( int32  bytes  )  [protected]

Referenced by sendAll().

02304 {
02305         SCTPDataMsg* datMsg=NULL;
02306         int32 nextStream = -1;
02307 
02308         sctpEV3<<"dequeueOutboundDataMsg: "<<bytes<<" bytes left to be sent\n";
02309         nextStream = (this->*ssFunctions.ssGetNextSid)(false);
02310 
02311         if (nextStream == -1)
02312                 return NULL;
02313 
02314         for (SCTPSendStreamMap::iterator iter=sendStreams.begin(); iter!=sendStreams.end(); ++iter)
02315         {
02316                 if ((int32)iter->first==nextStream)
02317                 {
02318                         SCTPSendStream* stream=iter->second;
02319                         if (!stream->getUnorderedStreamQ()->empty())
02320                         {
02321                                 datMsg = (SCTPDataMsg*)stream->getUnorderedStreamQ()->pop();
02322 
02323                                 sctpEV3<<"DequeueOutboundDataMsg() found chunk ("<<&datMsg<<")  in the unordered stream queue "<<&iter->first<<"("<<stream->getUnorderedStreamQ()<<") queue size="<<stream->getUnorderedStreamQ()->getLength()<<"\n";
02324                         }
02325                         else if (!stream->getStreamQ()->empty())
02326                         {
02327 
02328                                 int32 b=ADD_PADDING( (check_and_cast<SCTPSimpleMessage*>(((SCTPDataMsg*)stream->getStreamQ()->back())->getEncapsulatedMsg())->getBitLength()/8+SCTP_DATA_CHUNK_LENGTH));
02329                                  if (b<=bytes)
02330                                  {
02331                                         datMsg = (SCTPDataMsg*)stream->getStreamQ()->pop();
02332                                         if (!state->appSendAllowed && stream->getStreamQ()->getLength()<=state->sendQueueLimit)
02333                                         {
02334                                                 state->appSendAllowed = true;
02335                                                 sendIndicationToApp(SCTP_I_SENDQUEUE_ABATED);
02336                                         }
02337                                         sendQueue->record(stream->getStreamQ()->getLength());
02338                                 sctpEV3<<"DequeueOutboundDataMsg() found chunk ("<<&datMsg<<")  in the stream queue "<<&iter->first<<"("<<stream->getStreamQ()<<") queue size="<<stream->getStreamQ()->getLength()<<"\n";
02339                                 }
02340                                 else
02341                                         sctpEV3<<"chunk too long\n";
02342                         }
02343                         break;
02344                 }
02345         }
02346         if (datMsg != NULL)
02347         {
02348                 qCounter.roomSumSendStreams -= ADD_PADDING( (check_and_cast<SCTPSimpleMessage*>(datMsg->getEncapsulatedMsg())->getBitLength()/8+SCTP_DATA_CHUNK_LENGTH));
02349                 qCounter.bookedSumSendStreams -= datMsg->getBooksize();
02350         }
02351         return (datMsg);
02352 }

void SCTPAssociation::process_QUEUE ( SCTPCommand *  sctpCommand  )  [protected]

Referenced by processAppCommand().

00218 {
00219         SCTPInfo* qinfo = check_and_cast<SCTPInfo*>(sctpCommand);
00220         state->queueLimit = qinfo->getText();
00221 }

void SCTPAssociation::pmDataIsSentOn ( IPvXAddress  pathId  )  [protected]

Flow control

Referenced by sendAll().

02609 {
02610         SCTPPathVariables* path;
02611 
02612         /* restart hb_timer on this path */
02613         path=getPath(pathId);
02614         path->heartbeatTimeout = path->pathRto+ (double)sctpMain->par("hbInterval");
02615         stopTimer(path->HeartbeatTimer);
02616         startTimer(path->HeartbeatTimer, path->heartbeatTimeout);
02617         path->cwndTimeout = path->pathRto;
02618         stopTimer(path->CwndTimer);
02619         startTimer(path->CwndTimer, path->cwndTimeout);
02620 
02621 
02622         sctpEV3<<"Restarting HB timer on path "<<(pathId)<<" to expire at time "<<path->heartbeatTimeout<<"\n";
02623         sctpEV3<<"Restarting CWND timer on path "<<(pathId)<<" to expire at time "<<path->cwndTimeout<<"\n";
02624 
02625 
02626         /* AJ - 02-04-2004 - added for fullfilling section 8.2 */
02627         state->lastUsedDataPath = pathId;
02628 }

void SCTPAssociation::pmStartPathManagement ( void   )  [protected]

Referenced by stateEntered().

02631 {
02632         RoutingTableAccess routingTableAccess;
02633         SCTPPathVariables* path;
02634         int32 i=0;
02635         /* populate path structures !!! */
02636         /* set a high start value...this is appropriately decreased later (below) */
02637         state->assocPmtu = state->localRwnd;
02638         for(SCTPPathMap::iterator piter=sctpPathMap.begin(); piter!=sctpPathMap.end(); piter++)
02639         {
02640                 path=piter->second;
02641                 path->pathErrorCount = 0;
02642                 InterfaceEntry *rtie = routingTableAccess.get()->getInterfaceForDestAddr(path->remoteAddress.get4());
02643                 path->pmtu = rtie->getMTU();
02644                 if (path->pmtu < state->assocPmtu)
02645                 {
02646                         state->assocPmtu = path->pmtu;
02647                 }
02648                 initCCParameters(path);
02649                 path->pathRto = (double)sctpMain->par("rtoInitial");
02650                 path->srtt = path->pathRto;
02651                 path->rttvar = 0.0;
02652                 /* from now on we may have one update per RTO/SRTT */
02653                 path->updateTime = 0.0;
02654 
02655 
02656                 path->partialBytesAcked = 0;
02657                 path->outstandingBytes = 0;
02658                 path->activePath = true;
02659                 path->hbWasAcked = true;
02660                 // Timer probably not running, but stop it anyway I.R.
02661                 stopTimer(path->T3_RtxTimer);
02662 
02663                 path->heartbeatTimeout= (double)sctpMain->par("hbInterval")+i*path->pathRto;
02664                 stopTimer(path->HeartbeatTimer);
02665                 if (path->remoteAddress == state->initialPrimaryPath && !path->confirmed)
02666                 {
02667                         path->confirmed = true;
02668 
02669                 }
02670                 sctpEV3<<getFullPath()<<" numberOfLocalAddresses="<<state->localAddresses.size()<<"\n";
02671                 if (state->localAddresses.size()>1)
02672                         sendHeartbeat(path, false);
02673                 else
02674                         sendHeartbeat(path, true);
02675                 startTimer(path->HeartbeatTimer, path->heartbeatTimeout);
02676                 startTimer(path->HeartbeatIntervalTimer, path->heartbeatIntervalTimeout);
02677                 path->pathRTO->record(path->pathRto);
02678                 i++;
02679         }
02680 }

void SCTPAssociation::pmClearPathCounter ( IPvXAddress  pid  )  [protected]

Referenced by dequeueAckedChunks(), pmRttMeasurement(), and processSackArrived().

02799 {
02800         SCTPPathMap::iterator pm=sctpPathMap.find(pathId);
02801         if (pm!=sctpPathMap.end())
02802         {
02803                 pm->second->pathErrorCount = 0;
02804 
02805                 if (pm->second->activePath==false)
02806                 {
02807                         /* notify the application */
02808                         pathStatusIndication(pathId, true);
02809 
02810                         sctpEV3<<"Path "<<pathId<<" state changes from INACTIVE to ACTIVE !!!!\n";
02811 
02812                 }
02813         }
02814 }

void SCTPAssociation::pmRttMeasurement ( IPvXAddress  pathId,
simtime_t  rttEstimate,
int32  acknowledgedBytes 
) [protected]

Referenced by processHeartbeatAckArrived(), and processSackArrived().

02834 {
02835 
02836         if (rttEstimate != -1.0)
02837         {
02838                 /* we have a valid estimation */
02839                 SCTPPathVariables* path=getPath(pathId);
02840 
02841                 if (simulation.getSimTime() > path->updateTime)
02842                 {
02843 
02844                         if (path->updateTime == 0.0)
02845                         {
02846                                 path->rttvar = rttEstimate / 2;
02847                                 path->srtt = rttEstimate;
02848                                 path->pathRto = 3 * rttEstimate;
02849                                 path->pathRto = max(min(path->pathRto.dbl(), sctpMain->par("rtoMax")), (double)sctpMain->par("rtoMin"));
02850 
02851                         }
02852                         else
02853                         {
02854 
02855                                 path->rttvar = (1.0 - (double)sctpMain->par("rtoBeta")) * path->rttvar +        (double)sctpMain->par("rtoBeta") * fabs(path->srtt - rttEstimate);
02856 
02857                                 path->srtt = (1.0 - (double)sctpMain->par("rtoAlpha")) * path->srtt + (double)sctpMain->par("rtoAlpha") * rttEstimate;
02858 
02859                                 path->pathRto = path->srtt + 4 * path->rttvar;
02860 
02861                                 path->pathRto = max(min(path->pathRto.dbl(), sctpMain->par("rtoMax")), (double)sctpMain->par("rtoMin"));
02862                         }
02863 
02864                         sctpEV3<<simulation.getSimTime()<<": Updating timer values for path "<<pathId<<"...RTO == "<<path->pathRto<<"\n";
02865                         sctpEV3<<" rttEstimat="<<rttEstimate<<"  SRTT == "<<path->srtt<<" ------>  RTTVAR == "<<path->rttvar<<"\n";
02866 
02867                         /* RFC2960, sect.6.3.1: new RTT measurements SHOULD be made no more than once per round-trip */
02868                         path->updateTime = simulation.getSimTime() + path->srtt;
02869                 }
02870                 path->pathRTO->record(path->pathRto);
02871                 path->pathRTT->record(rttEstimate);
02872     }
02873 
02874         if (acknowledgedBytes > 0)
02875         {
02876                 /* we received a (new) SACK/HB ACK from our peer -- reset the error counters for this path */
02877                 state->errorCount = 0;
02878                 pmClearPathCounter(pathId);
02879         }
02880 
02881 }

void SCTPAssociation::fcAdjustCounters ( uint32  ackedBytes,
uint32  osb,
bool  ctsnaAdvanced,
IPvXAddress  pathId,
uint32  pathOsb,
uint32  newOsb 
) [protected]

From the implementers guide: increase cwnd only if

  • the current congestion window is being fully utilized,
  • an incoming SACK advances the Cumulative TSN Ack Point,
  • and the data sender (sack receiver) is not in Fast Recovery.
02884 {
02885         SCTPPathVariables* path=getPath(pathId);
02886 
02887 
02888         sctpEV3<<"fcAdjustCounters: cwnd="<<path->cwnd<<" ssthresh="<<path->ssthresh<<" pathOsbBefore="<<pathOsb<<" osbBefore="<<osb<<" ackedBytes="<<ackedBytes<<"\n";
02889 
02890 
02891         if (path->cwnd <=path->ssthresh)
02892         {
02893                 for (SCTPPathMap::iterator iter=sctpPathMap.begin(); iter!=sctpPathMap.end(); iter++)
02894                 {
02895                         iter->second->partialBytesAcked = 0;
02896                 }
02897 
02905                 sctpEV3<<"ctsnaAdvanced="<<ctsnaAdvanced<<"  fastRecoveryActive="<<state->fastRecoveryActive<<"\n";
02906 
02907                 if (ctsnaAdvanced == true && pathOsb >= path->cwnd )
02908                 {
02909                         path->cwndAdjustmentTime = simulation.getSimTime();
02910 
02911                         path->cwnd += (int32)min(path->pmtu, ackedBytes);
02912                         path->pathCwnd->record(path->cwnd);
02913 
02914                         sctpEV3<<"SLOW START: Setting CWND of path "<<pathId<<" to "<<path->cwnd<<" bytes\n";
02915 
02916                 }
02917 
02918         }
02919         else
02920         {
02921                 path->partialBytesAcked += ackedBytes;
02922         sctpEV3<<"partialBytesAcked="<<path->partialBytesAcked<<"  cwnd="<<path->cwnd<<"  osb="<<osb<<" advanced="<<ctsnaAdvanced<<"\n";
02923                 if ((path->partialBytesAcked  >= path->cwnd) &&
02924                         (osb >= path->cwnd) && (ctsnaAdvanced == true))
02925                 {
02926                         path->cwnd += path->pmtu;
02927                         path->pathCwnd->record(path->cwnd);
02928                         // I.R. make the term easier
02929                         path->partialBytesAcked =
02930                                 ((path->cwnd < path->partialBytesAcked) ?
02931                                         (path->partialBytesAcked - path->cwnd) : 0);
02932 
02933                         /* get and store the time when CWND was adjusted here */
02934                         path->cwndAdjustmentTime = simulation.getSimTime();
02935 
02936 
02937                         sctpEV3<<"CONG.AVOID.: Setting CWND of path "<<pathId<<" to "<<path->cwnd<<" bytes\n";
02938 
02939                 }
02940         }
02941 
02942 
02943         if (newOsb == 0) path->partialBytesAcked = 0;
02944 }

int32 SCTPAssociation::tsnLt ( uint32  tsn1,
uint32  tsn2 
) [inline, protected]

Compare TSNs

Referenced by processSackArrived().

00725 { return ((int32)(tsn1-tsn2)<0); }

int32 SCTPAssociation::tsnLe ( uint32  tsn1,
uint32  tsn2 
) [inline, protected]

Referenced by processDataArrived().

00726 { return ((int32)(tsn1-tsn2)<=0); }

int32 SCTPAssociation::tsnGe ( uint32  tsn1,
uint32  tsn2 
) [inline, protected]

Referenced by dequeueAckedChunks().

00727 { return ((int32)(tsn1-tsn2)>=0); }

int32 SCTPAssociation::tsnGt ( uint32  tsn1,
uint32  tsn2 
) [inline, protected]

Referenced by cwndUpdateAfterSack(), processDataArrived(), processSackArrived(), and updateGapList().

00728 { return ((int32)(tsn1-tsn2)>0); }

int32 SCTPAssociation::tsnBetween ( uint32  tsn1,
uint32  midtsn,
uint32  tsn2 
) [inline, protected]

Referenced by removeFromGapList(), tsnIsDuplicate(), and updateGapList().

00729 { return ((tsn2-tsn1)>=(midtsn-tsn1)); }

int16 SCTPAssociation::ssnGt ( uint16  ssn1,
uint16  ssn2 
) [inline, protected]

Referenced by makeRoomForTsn().

00731 { return ((int16)(ssn1-ssn2)>0); }

uint32 SCTPAssociation::subBytes ( uint32  osb,
uint32  bytes 
) [inline, protected]

00733 {return (((int32)(osb-bytes)>0)?osb-bytes:0);}

void SCTPAssociation::disposeOf ( SCTPMessage sctpmsg  )  [protected]

Referenced by process_RCV_Message().

02998 {
02999 SCTPChunk* chunk;
03000         uint32 numberOfChunks = sctpmsg->getChunksArraySize();
03001         if (numberOfChunks>0)
03002         for (uint32 i=0; i<numberOfChunks; i++)
03003         {
03004                 chunk = (SCTPChunk*)(sctpmsg->removeChunk());
03005                 if (chunk->getChunkType()==DATA)
03006                         delete (SCTPSimpleMessage*)chunk->decapsulate();
03007                 delete chunk;
03008         }
03009         delete sctpmsg;
03010 }

void SCTPAssociation::printOutstandingTsns (  )  [protected]

02520 {
02521         uint32 first=0, second = 0;
02522 
02523         if (retransmissionQ->payloadQueue.empty())
02524         {
02525                 return;
02526         }
02527         for(SCTPQueue::PayloadQueue::iterator pl=retransmissionQ->payloadQueue.begin();pl!=retransmissionQ->payloadQueue.end();pl++)
02528         {
02529                 if (pl->second->hasBeenAcked == false && pl->second->countsAsOutstanding == true)
02530                 {
02531                         if (pl->second->tsn > second+1)
02532                         {
02533                                 if (second != 0)
02534                                 {
02535                                         sctpEV3<<" - "<<second<<"\t";;
02536 
02537                                 }
02538                                 first = second = pl->second->tsn;
02539                                 sctpEV3<<pl->second->tsn;
02540                         }
02541                         else if (pl->second->tsn == second+1)
02542                         {
02543                                 second = pl->second->tsn;
02544                         }
02545                         first = pl->second->tsn;
02546                 }
02547         }
02548         sctpEV3<<" - "<<second<<"\n";
02549 }

void SCTPAssociation::initCCParameters ( SCTPPathVariables path  )  [protected]

SCTPCCFunctions

Referenced by pmStartPathManagement(), and stateEntered().

00022 {
00023         path->cwnd = (int32)min(4 * path->pmtu, max(2 * path->pmtu, 4380));
00024         path->pathCwnd->record(path->cwnd);
00025         path->cwndAdjustmentTime = simulation.getSimTime();
00026         path->ssthresh = state->peerRwnd;
00027         path->pathSsthresh->record(path->ssthresh);
00028 }

void SCTPAssociation::cwndUpdateAfterSack ( bool  rtxNecessary,
SCTPPathVariables path 
) [protected]

Referenced by stateEntered().

00033 {
00034         if (rtxNecessary == true && state->fastRecoveryActive == false) 
00035         {
00036                 for (SCTPPathMap::iterator iter=sctpPathMap.begin(); iter!=sctpPathMap.end(); iter++)
00037                 {       
00038                         path=iter->second;
00039                         if (path->requiresRtx) 
00040                         {
00041                                 path->ssthresh = (int32)max(path->cwnd / 2,  4 * path->pmtu);
00042                                 path->pathSsthresh->record(path->ssthresh);;
00043                                 path->cwnd = path->ssthresh;
00044                                 path->pathCwnd->record(path->cwnd);
00045                                 path->partialBytesAcked = 0;
00046                                 /* get and store the time when CWND was adjusted here */
00047                                 path->cwndAdjustmentTime = simulation.getSimTime();
00048                                 
00049                                 if (state->fastRecoverySupported) 
00050                                 {
00051                                         state->highestTsnAcked = state->lastTsnAck;
00052                                         for (SCTPQueue::PayloadQueue::iterator pq=retransmissionQ->payloadQueue.begin(); pq!=retransmissionQ->payloadQueue.end(); pq++)
00053                                         {
00054                                                 if (pq->second->hasBeenAcked == true && tsnGt(pq->second->tsn, state->highestTsnAcked)) 
00055                                                 {
00056                                                         state->highestTsnAcked = pq->second->tsn;
00057                                                 }
00058                                         }
00059                                         /* this can ONLY become TRUE, when Fast Recovery IS supported */
00060                                         state->fastRecoveryActive = true;
00061                                         state->fastRecoveryExitPoint = state->highestTsnAcked;
00062                                          
00063                                         sctpEV3<<"===> ENTERING FAST RECOVERY.....Exit Point == "<< state->fastRecoveryExitPoint<<"\n";
00064                                         
00065                                         
00066                                 } /* end: if (fast_recovery_supported */
00067                         }         /* end: if (path_requires_rtx...      */
00068                 }                 /* end: for (counter...                       */
00069         }                         /* end: if (rtx_necessary                     */    
00070         
00071 }

void SCTPAssociation::cwndUpdateAfterCwndTimeout ( SCTPPathVariables path  )  [protected]

Referenced by stateEntered().

00074 {
00075         /* 
00076          *  When the association does not transmit data on a given transport address
00077          *  within an RTO, the cwnd of the transport address SHOULD be adjusted to 2*MTU.
00078          */
00079 
00080         path->cwnd = (int32)min(4 * path->pmtu, max(2 * path->pmtu, 4380));
00081         path->pathCwnd->record(path->cwnd);
00082          
00083         sctpEV3<<"CWND timer run off: readjusting CWND(path=="<<path->remoteAddress<<") = "<<path->cwnd<<"\n";
00084         
00085         path->cwndAdjustmentTime = simulation.getSimTime();
00086 }

void SCTPAssociation::cwndUpdateAfterRtxTimeout ( SCTPPathVariables path  )  [protected]

Referenced by stateEntered().

00089 {
00090         /* implement optional FAST RECOVERY */
00091         if (state->fastRecoveryActive == false) 
00092         {
00093                 path->ssthresh = (int32)max(path->cwnd / 2, 4 * path->pmtu);
00094 
00095                 path->pathSsthresh->record(path->ssthresh);
00096                 path->cwnd = path->pmtu;
00097                 path->pathCwnd->record(path->cwnd);
00098                 path->partialBytesAcked = 0;
00099 
00100                 path->cwndAdjustmentTime = simulation.getSimTime();
00101 
00102         }
00103 }

void SCTPAssociation::cwndUpdateMaxBurst ( SCTPPathVariables path  )  [protected]

Referenced by stateEntered().

00107 {
00108         if(path->cwnd > ((path->outstandingBytes + (uint32)sctpMain->par("maxBurst") * path->pmtu))) 
00109         {
00110                 path->cwnd = path->outstandingBytes + ((uint32)sctpMain->par("maxBurst") * path->pmtu);
00111                 path->pathCwnd->record(path->cwnd); 
00112                 path->cwndAdjustmentTime = simulation.getSimTime();
00113         }
00114 }

void SCTPAssociation::cwndUpdateBytesAcked ( uint32  ackedBytes,
uint32  osb,
bool  ctsnaAdvanced,
IPvXAddress  pathId,
uint32  pathOsb,
uint32  newOsb 
) [protected]

Referenced by stateEntered().

00118 {
00119         SCTPPathVariables* path=getPath(pathId);        
00120         
00121          
00122         sctpEV3<<simulation.getSimTime()<<" fcAdjustCounters: path="<<pathId<<" cwnd="<<path->cwnd<<" ssthresh="<<path->ssthresh<<" pathOsbBefore="<<pathOsb<<" osbBefore="<<osb<<" ackedBytes="<<ackedBytes<<"\n";
00123         
00124         
00125         if (path->cwnd <=path->ssthresh) 
00126         {       
00127                 // SLOW START 
00128                 for (SCTPPathMap::iterator iter=sctpPathMap.begin(); iter!=sctpPathMap.end(); iter++)
00129                 {
00130                         iter->second->partialBytesAcked = 0;
00131                 }
00132 
00133                  
00134                 sctpEV3<<"ctsnaAdvanced="<<ctsnaAdvanced<<"  fastRecoveryActive="<<state->fastRecoveryActive<<"\n";
00135                 sctpEV3<<simulation.getSimTime()<<" primaryPath="<<state->primaryPathIndex<<", pathOsb="<<pathOsb<<", cwnd="<<path->cwnd<<"\n";
00136                 if ((ctsnaAdvanced == true && pathOsb >= path->cwnd))
00137                 {
00138                         path->cwndAdjustmentTime = simulation.getSimTime();
00139                         
00140                         path->cwnd += (int32)min(path->pmtu, ackedBytes);
00141                         path->pathCwnd->record(path->cwnd);
00142                          
00143                         sctpEV3<<simulation.getSimTime()<<" SLOW START: Setting CWND of path "<<pathId<<" to "<<path->cwnd<<" bytes. Osb = "<<pathOsb<<"\n";
00144                         
00145                 }
00146                 
00147         } 
00148         else 
00149         {
00150                 // CONGESTION AVOIDANCE 
00151                 path->partialBytesAcked += ackedBytes;
00152         sctpEV3<<"partialBytesAcked="<<path->partialBytesAcked<<"  cwnd="<<path->cwnd<<"  osb="<<osb<<" advanced="<<ctsnaAdvanced<<"  fastRecoveryActive="<<state->fastRecoveryActive<<"\n";
00153                 if ((path->partialBytesAcked  >= path->cwnd) &&
00154                         (osb >= path->cwnd) && (ctsnaAdvanced == true)) 
00155                 {               
00156                         path->cwnd += path->pmtu;
00157                         path->pathCwnd->record(path->cwnd);
00158                         path->partialBytesAcked = 
00159                                 ((path->cwnd < path->partialBytesAcked) ?
00160                                         (path->partialBytesAcked - path->cwnd) : 0);
00161 
00162                         /* get and store the time when CWND was adjusted here */
00163                         path->cwndAdjustmentTime = simulation.getSimTime();
00164                         
00165                          
00166                         sctpEV3<<"CONG.AVOID.: Setting CWND of path "<<pathId<<" to "<<path->cwnd<<" bytes\n";
00167                         
00168                 }
00169         }
00170                         
00171 
00172         if (newOsb == 0) path->partialBytesAcked = 0;
00173 }


Member Data Documentation

Referenced by processTimer(), and SCTPAssociation().

int32 SCTPAssociation::status [protected]

uint32 SCTPAssociation::initTsn [protected]

Referenced by sendInit(), and sendInitAck().

uint32 SCTPAssociation::initPeerTsn [protected]

uint32 SCTPAssociation::inboundStreams [protected]

uint32 SCTPAssociation::sackFrequency [protected]

double SCTPAssociation::sackPeriod [protected]

cOutVector* SCTPAssociation::advRwnd [protected]

cOutVector* SCTPAssociation::quBytes [protected]

cOutVector* SCTPAssociation::cumTsnAck [protected]

cOutVector* SCTPAssociation::sendQueue [protected]

cFSM* SCTPAssociation::fsm [protected]

uint16 SCTPAssociation::ccModule [protected]

Referenced by stateEntered().

uint16 SCTPAssociation::ssModule [protected]

Referenced by SCTPAssociation().


The documentation for this class was generated from the following files:

Generated on Fri Mar 20 18:51:21 2009 for INET Framework for OMNeT++/OMNEST by  doxygen 1.5.5