Classes | Public Member Functions | Static Public Member Functions | Public Attributes | Protected Types | Protected Member Functions | Static Protected Member Functions | Protected Attributes | Private Types | Private Member Functions | Friends

SCTPAssociation Class Reference

#include <SCTPAssociation.h>

List of all members.

Classes

struct  calcBytesToSend
struct  congestionControlFunctions
struct  counter
struct  streamSchedulingFunctions

Public Member Functions

 SCTPAssociation (SCTP *mod, int32 appGateIndex, int32 assocId)
 ~SCTPAssociation ()
void sendOnPath (SCTPPathVariables *pathId, const bool firstPass=true)
void sendOnAllPaths (SCTPPathVariables *firstPath)

Static Public Member Functions

static const char * indicationName (const int32 code)

Public Attributes

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

Protected Types

typedef struct
SCTPAssociation::streamSchedulingFunctions 
SSFunctions

Protected Member Functions

void startTimer (cMessage *timer, const simtime_t &timeout)
SCTPAssociationcloneAssociation ()
void initAssociation (SCTPOpenCommand *openCmd)
bool tsnIsDuplicate (const uint32 tsn) const
bool advanceCtsna ()
bool updateGapList (const uint32 tsn)
void removeFromGapList (const uint32 removedTsn)
bool makeRoomForTsn (const uint32 tsn, const uint32 length, const bool uBit)
void sendInit ()
void sendInitAck (SCTPInitChunk *initchunk)
void sendCookieEcho (SCTPInitAckChunk *initackchunk)
void sendCookieAck (const IPvXAddress &dest)
void sendAbort ()
void sendHeartbeat (const SCTPPathVariables *path)
void sendHeartbeatAck (const SCTPHeartbeatChunk *heartbeatChunk, const IPvXAddress &src, const IPvXAddress &dest)
void sendSack ()
void sendShutdown ()
void sendShutdownAck (const IPvXAddress &dest)
void sendShutdownComplete ()
SCTPSackChunk * createSack ()
void retransmitInit ()
void retransmitCookieEcho ()
void retransmitShutdown ()
void retransmitShutdownAck ()
void sendToIP (SCTPMessage *sctpmsg, const IPvXAddress &dest, const bool qs=false)
void sendToIP (SCTPMessage *sctpmsg, const bool qs=false)
void recordInPathVectors (SCTPMessage *pMsg, const IPvXAddress &rDest)
void scheduleSack ()
void signalConnectionTimeout ()
void scheduleTimeout (cMessage *msg, const simtime_t &timeout)
cMessage * cancelEvent (cMessage *msg)
void sendToApp (cPacket *msg)
void sendIndicationToApp (const int32 code, const int32 value=0)
void sendEstabIndicationToApp ()
void pushUlp ()
void sendDataArrivedNotification (uint16 sid)
void putInDeliveryQ (uint16 sid)
void printConnBrief ()
void addPath (const IPvXAddress &addr)
SCTPPathVariablesgetNextPath (const SCTPPathVariables *oldPath) const
const IPvXAddressgetNextAddress (const SCTPPathVariables *oldPath) const
SCTPPathVariablesgetNextDestination (SCTPDataVariables *chunk) const
void bytesAllowedToSend (SCTPPathVariables *path, const bool firstPass)
void pathStatusIndication (const SCTPPathVariables *path, const bool status)
bool allPathsInactive () const
SCTPDataChunk * transformDataChunk (SCTPDataVariables *chunk)
SCTPDataVariablesmakeVarFromMsg (SCTPDataChunk *datachunk)
int32 streamScheduler (bool peek)
void initStreams (uint32 inStreams, uint32 outStreams)
int32 numUsableStreams ()
void process_QUEUE_MSGS_LIMIT (const SCTPCommand *sctpCommand)
void process_QUEUE_BYTES_LIMIT (const SCTPCommand *sctpCommand)
int32 getOutstandingBytes () const
uint32 dequeueAckedChunks (const uint32 tsna, SCTPPathVariables *path, simtime_t &rttEstimation)
SCTPDataMsg * peekOutboundDataMsg ()
SCTPDataVariablespeekAbandonedChunk (const SCTPPathVariables *path)
SCTPDataVariablesgetOutboundDataChunk (const SCTPPathVariables *path, const int32 availableSpace, const int32 availableCwnd)
SCTPDataMsg * dequeueOutboundDataMsg (const int32 availableSpace, const int32 availableCwnd)
bool nextChunkFitsIntoPacket (int32 bytes)
void putInTransmissionQ (uint32 tsn, SCTPDataVariables *chunk)
void pmStartPathManagement ()
void pmDataIsSentOn (SCTPPathVariables *path)
void pmClearPathCounter (SCTPPathVariables *path)
void pmRttMeasurement (SCTPPathVariables *path, const simtime_t &rttEstimation)
void disposeOf (SCTPMessage *sctpmsg)
void tsnWasReneged (SCTPDataVariables *chunk, const int type)
void printOutstandingTsns ()
void initCCParameters (SCTPPathVariables *path)
void updateFastRecoveryStatus (const uint32 lastTsnAck)
void cwndUpdateAfterSack ()
void cwndUpdateAfterCwndTimeout (SCTPPathVariables *path)
void cwndUpdateAfterRtxTimeout (SCTPPathVariables *path)
void cwndUpdateMaxBurst (SCTPPathVariables *path)
void cwndUpdateBytesAcked (SCTPPathVariables *path, const uint32 ackedBytes, const bool ctsnaAdvanced)
FSM transitions: analysing events and executing state transitions

SCTPEventCode preanalyseAppCommandEvent (int32 commandCode)
bool performStateTransition (const SCTPEventCode &event)
void stateEntered (int32 state)
Processing app commands. Invoked from processAppCommand().

void process_ASSOCIATE (SCTPEventCode &event, SCTPCommand *sctpCommand, cPacket *msg)
void process_OPEN_PASSIVE (SCTPEventCode &event, SCTPCommand *sctpCommand, cPacket *msg)
void process_SEND (SCTPEventCode &event, SCTPCommand *sctpCommand, cPacket *msg)
void process_CLOSE (SCTPEventCode &event)
void process_ABORT (SCTPEventCode &event)
void process_STATUS (SCTPEventCode &event, SCTPCommand *sctpCommand, cPacket *msg)
void process_RECEIVE_REQUEST (SCTPEventCode &event, SCTPCommand *sctpCommand)
void process_PRIMARY (SCTPEventCode &event, SCTPCommand *sctpCommand)
Processing SCTP message arrivals. Invoked from processSCTPMessage().

bool process_RCV_Message (SCTPMessage *sctpseg, const IPvXAddress &src, const IPvXAddress &dest)
bool processInitArrived (SCTPInitChunk *initChunk, int32 sport, int32 dport)
bool processInitAckArrived (SCTPInitAckChunk *initAckChunk)
bool processCookieEchoArrived (SCTPCookieEchoChunk *cookieEcho, IPvXAddress addr)
bool processCookieAckArrived ()
SCTPEventCode processDataArrived (SCTPDataChunk *dataChunk)
SCTPEventCode processSackArrived (SCTPSackChunk *sackChunk)
SCTPEventCode processHeartbeatAckArrived (SCTPHeartbeatAckChunk *heartbeatack, SCTPPathVariables *path)
Processing timeouts. Invoked from processTimer().

int32 process_TIMEOUT_RTX (SCTPPathVariables *path)
void process_TIMEOUT_HEARTBEAT (SCTPPathVariables *path)
void process_TIMEOUT_HEARTBEAT_INTERVAL (SCTPPathVariables *path, bool force)
void process_TIMEOUT_INIT_REXMIT (SCTPEventCode &event)
void process_TIMEOUT_PROBING ()
void process_TIMEOUT_SHUTDOWN (SCTPEventCode &event)
int32 updateCounters (SCTPPathVariables *path)

Static Protected Member Functions

static void printSegmentBrief (SCTPMessage *sctpmsg)
static const char * eventName (const int32 event)
static int32 tsnLt (const uint32 tsn1, const uint32 tsn2)
static int32 tsnLe (const uint32 tsn1, const uint32 tsn2)
static int32 tsnGe (const uint32 tsn1, const uint32 tsn2)
static int32 tsnGt (const uint32 tsn1, const uint32 tsn2)
static int32 tsnBetween (const uint32 tsn1, const uint32 midtsn, const uint32 tsn2)
static int16 ssnGt (const uint16 ssn1, const uint16 ssn2)

Protected Attributes

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

Private Types

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

Private Member Functions

SCTPDataVariablesmakeDataVarFromDataMsg (SCTPDataMsg *datMsg, SCTPPathVariables *path)
SCTPPathVariableschoosePathForRetransmission ()
void timeForSack (bool &sackOnly, bool &sackWithData)
void recordCwndUpdate (SCTPPathVariables *path)
void handleChunkReportedAsAcked (uint32 &highestNewAck, simtime_t &rttEstimation, SCTPDataVariables *myChunk, SCTPPathVariables *sackPath)
void handleChunkReportedAsMissing (const SCTPSackChunk *sackChunk, const uint32 highestNewAck, SCTPDataVariables *myChunk, const SCTPPathVariables *sackPath)
void moveChunkToOtherPath (SCTPDataVariables *chunk, SCTPPathVariables *newPath)
void decreaseOutstandingBytes (SCTPDataVariables *chunk)
void increaseOutstandingBytes (SCTPDataVariables *chunk, SCTPPathVariables *path)
int32 calculateBytesToSendOnPath (const SCTPPathVariables *pathVar)
void storePacket (SCTPPathVariables *pathVar, SCTPMessage *sctpMsg, const uint16 chunksAdded, const uint16 dataChunksAdded, const uint32 packetBytes, const bool authAdded)
void loadPacket (SCTPPathVariables *pathVar, SCTPMessage **sctpMsg, uint16 *chunksAdded, uint16 *dataChunksAdded, uint32 *packetBytes, bool *authAdded)
void ackChunk (SCTPDataVariables *chunk)
void unackChunk (SCTPDataVariables *chunk)
bool chunkHasBeenAcked (const SCTPDataVariables *chunk) const
bool chunkHasBeenAcked (const uint32 tsn) const

Friends

class SCTP
class SCTPPathVariables



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

Detailed Description

Definition at line 488 of file SCTPAssociation.h.


Member Typedef Documentation

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

Definition at line 496 of file SCTPAssociation.h.

Definition at line 494 of file SCTPAssociation.h.

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

Definition at line 519 of file SCTPAssociation.h.

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

Definition at line 518 of file SCTPAssociation.h.


Constructor & Destructor Documentation

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

Constructor.

Definition at line 276 of file SCTPAssociationBase.cc.

Referenced by cloneAssociation().

{
    // ====== Initialize variables ===========================================
    sctpMain                            = _module;
    appGateIndex                        = _appGateIndex;
    assocId                             = _assocId;
    localPort                           = 0;
    remotePort                          = 0;
    localVTag                           = 0;
    peerVTag                            = 0;
    numberOfRemoteAddresses             = 0;
    inboundStreams                      = SCTP_DEFAULT_INBOUND_STREAMS;
    outboundStreams                     = SCTP_DEFAULT_OUTBOUND_STREAMS;
    // queues and algorithm will be created on active or passive open
    transmissionQ                       = NULL;
    retransmissionQ                     = NULL;
    sctpAlgorithm                       = NULL;
    state                               = NULL;
    sackPeriod                          = SACK_DELAY;
/*
    totalCwndAdjustmentTime         = simTime();
    lastTotalSSthresh                   = ~0;
    lastTotalCwnd                       = ~0;*/

    cumTsnAck                           = NULL;
    sendQueue                           = NULL;
    numGapBlocks                        = NULL;

    qCounter.roomSumSendStreams = 0;
    qCounter.bookedSumSendStreams = 0;
    qCounter.roomSumRcvStreams      = 0;
    bytes.chunk                         = false;
    bytes.packet                        = false;
    bytes.bytesToSend                   = 0;

    sctpEV3 << "SCTPAssociationBase::SCTPAssociation(): new assocId="
              << assocId << endl;

    // ====== FSM ============================================================
    char fsmName[64];
    snprintf(fsmName, sizeof(fsmName), "fsm-%d", assocId);
    fsm = new cFSM();
    fsm->setName(fsmName);
    fsm->setState(SCTP_S_CLOSED);


    // ====== Path Info ======================================================
    SCTPPathInfo* pinfo = new SCTPPathInfo("pathInfo");
    pinfo->setRemoteAddress(IPvXAddress("0.0.0.0"));

    // ====== Timers =========================================================
    char timerName[128];
    snprintf(timerName, sizeof(timerName), "T1_INIT of Association %d", assocId);
    T1_InitTimer = new cMessage(timerName);
    snprintf(timerName, sizeof(timerName), "T2_SHUTDOWN of Association %d", assocId);
    T2_ShutdownTimer = new cMessage(timerName);
    snprintf(timerName, sizeof(timerName), "T5_SHUTDOWN_GUARD of Association %d", assocId);
    T5_ShutdownGuardTimer = new cMessage(timerName);
    snprintf(timerName, sizeof(timerName), "SACK_TIMER of Association %d", assocId);
    SackTimer = new cMessage(timerName);

    if (sctpMain->testTimeout > 0){
        StartTesting = new cMessage("StartTesting");
        StartTesting->setContextPointer(this);
        StartTesting->setControlInfo(pinfo->dup());
        scheduleTimeout(StartTesting, sctpMain->testTimeout);
    }
    T1_InitTimer->setContextPointer(this);
    T2_ShutdownTimer->setContextPointer(this);
    SackTimer->setContextPointer(this);
    T5_ShutdownGuardTimer->setContextPointer(this);

    T1_InitTimer->setControlInfo(pinfo);
    T2_ShutdownTimer->setControlInfo(pinfo->dup());
    SackTimer->setControlInfo(pinfo->dup());
    T5_ShutdownGuardTimer->setControlInfo(pinfo->dup());

    // ====== Output vectors =================================================
    char vectorName[128];
    snprintf(vectorName, sizeof(vectorName), "Advertised Receiver Window %d", assocId);
    advRwnd = new cOutVector(vectorName);

    // ====== Stream scheduling ==============================================
    ssModule = sctpMain->par("ssModule");
    switch (ssModule)
    {
        case ROUND_ROBIN:
            ssFunctions.ssInitStreams    = &SCTPAssociation::initStreams;
            ssFunctions.ssGetNextSid     = &SCTPAssociation::streamScheduler;
            ssFunctions.ssUsableStreams  = &SCTPAssociation::numUsableStreams;
            break;
    }
}

SCTPAssociation::~SCTPAssociation (  ) 

Destructor.

Definition at line 370 of file SCTPAssociationBase.cc.

{
    sctpEV3 << "Destructor SCTPAssociation" << endl;

    delete T1_InitTimer;
    delete T2_ShutdownTimer;
    delete T5_ShutdownGuardTimer;
    delete SackTimer;

    delete advRwnd;
    delete cumTsnAck;
    delete numGapBlocks;
    delete sendQueue;


    delete fsm;
    delete state;
    delete sctpAlgorithm;
}


Member Function Documentation

void SCTPAssociation::ackChunk ( SCTPDataVariables chunk  )  [inline, private]

Definition at line 887 of file SCTPAssociation.h.

Referenced by dequeueAckedChunks(), and handleChunkReportedAsAcked().

                                                       {
            chunk->hasBeenAcked = true;
        }

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

Definition at line 1153 of file SCTPAssociationUtil.cc.

Referenced by processInitAckArrived().

{
    sctpEV3<<"Add Path remote address: "<<addr<<"\n";

    SCTPPathMap::iterator i = sctpPathMap.find(addr);
    if (i==sctpPathMap.end())
    {
        sctpEV3<<__LINE__<<" get new path for "<<addr<<"\n";
        SCTPPathVariables* path = new SCTPPathVariables(addr, this);
        sctpPathMap[addr] = path;
        qCounter.roomTransQ[addr]    = 0;
        qCounter.bookedTransQ[addr] = 0;
        qCounter.roomRetransQ[addr] = 0;
    }
    sctpEV3<<"path added\n";
}

bool SCTPAssociation::advanceCtsna (  )  [protected]

Definition at line 1483 of file SCTPAssociationUtil.cc.

Referenced by processDataArrived().

{
    int32 listLength, counter;

    ev<<"Entering advanceCtsna(ctsna now =="<< state->cTsnAck<<"\n";;

    listLength = state->numGaps;

    /* if there are no fragments, we cannot advance the ctsna */
    if (listLength == 0) return false;
    counter = 0;

    while(counter < listLength)
    {
        /* if we take out a fragment here, we need to modify either counter or list_length */

        if (state->cTsnAck + 1 == state->gapStartList[0])
        {
            /* BINGO ! */
            state->cTsnAck = state->gapStopList[0];
            /* we can take out a maximum of list_length fragments */
            counter++;
            for (uint32 i=1; i<state->numGaps; i++)
            {
                state->gapStartList[i-1] = state->gapStartList[i];
                state->gapStopList[i-1] = state->gapStopList[i];
            }

        }
        else
        {
            ev<<"Entering advanceCtsna(when leaving: ctsna=="<<state->cTsnAck<<"\n";
            return false;
        }

    }    /* end while */

    ev<<"Entering advanceCtsna(when leaving: ctsna=="<< state->cTsnAck<<"\n";
    return true;
}

bool SCTPAssociation::allPathsInactive (  )  const [protected]

Definition at line 2074 of file SCTPAssociationUtil.cc.

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

{
    for(SCTPPathMap::const_iterator it = sctpPathMap.begin(); it != sctpPathMap.end(); it++) {
        if (it->second->activePath) {
            return false;
        }
    }
    return true;
}

void SCTPAssociation::bytesAllowedToSend ( SCTPPathVariables path,
const bool  firstPass 
) [protected]

Definition at line 213 of file SCTPAssociationSendAll.cc.

Referenced by sendOnPath().

{
    assert(path != NULL);

    bytes.chunk         = false;
    bytes.packet        = false;
    bytes.bytesToSend = 0;

    sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "):"
              << " osb=" << path->outstandingBytes << " cwnd=" << path->cwnd << endl;

    // ====== First transmission =============================================
    if (!state->firstDataSent) {
        bytes.chunk = true;
    }

    // ====== Transmission allowed by peer's receiver window? ================
    else if (state->peerWindowFull)
    {
        if (path->outstandingBytes == 0) {
            // Zero Window Probing
            sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): zeroWindowProbing" << endl;
            state->zeroWindowProbing = true;
            bytes.chunk = true;
        }
    }

    // ====== Retransmissions ================================================
    else {
        CounterMap::const_iterator it = qCounter.roomTransQ.find(path->remoteAddress);
        sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): bytes in transQ=" << it->second << endl;
        if (it->second > 0) {
            const int32 allowance = path->cwnd - path->outstandingBytes;
            sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): cwnd-osb=" << allowance << endl;
            if (state->peerRwnd < path->pmtu) {
                bytes.bytesToSend = state->peerRwnd;
                sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): rwnd<pmtu" << endl;
                return;
            }
            else if (allowance > 0) {
                CounterMap::const_iterator bit = qCounter.bookedTransQ.find(path->remoteAddress);
                if (bit->second > (uint32)allowance) {
                    bytes.bytesToSend = allowance;
                    sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): cwnd does not allow all RTX" << endl;
                    return;  // More bytes available than allowed -> just return what is allowed.
                }
                else {
                    bytes.bytesToSend = bit->second;
                    sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): cwnd allows more than those "
                                 << bytes.bytesToSend << " bytes for retransmission" << endl;
                }
            }
            else {  // You may retransmit one packet
                bytes.packet = true;
                sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): allowance<=0: retransmit one packet" << endl;
            }
        }

        // ====== New transmissions ===========================================
        if (!bytes.chunk && !bytes.packet) {
            if ((path->outstandingBytes < path->cwnd) &&
                 (!state->peerWindowFull)) {
                sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "):"
                          << " bookedSumSendStreams=" << qCounter.bookedSumSendStreams
                          << " bytes.bytesToSend="      << bytes.bytesToSend << endl;
                const int32 allowance = path->cwnd - path->outstandingBytes - bytes.bytesToSend;
                if (allowance > 0) {
                    if (qCounter.bookedSumSendStreams > (uint32)allowance) {
                        bytes.bytesToSend = path->cwnd - path->outstandingBytes;
                        sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): bytesToSend are limited by cwnd: "
                                  << bytes.bytesToSend << endl;
                    }
                    else {
                        bytes.bytesToSend += qCounter.bookedSumSendStreams;
                        sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "): send all stored bytes: "
                                  << bytes.bytesToSend << endl;
                    }
                }
            }
        }
    }

    sctpEV3 << "bytesAllowedToSend(" << path->remoteAddress << "):"
              << " osb="  << path->outstandingBytes
              << " cwnd=" << path->cwnd
              << " bytes.packet=" << (bytes.packet ? "YES!" : "no")
              << " bytes.chunk="     << (bytes.chunk    ? "YES!" : "no")
              << " bytes.bytesToSend=" << bytes.bytesToSend << endl;
}

int32 SCTPAssociation::calculateBytesToSendOnPath ( const SCTPPathVariables pathVar  )  [private]

Definition at line 38 of file SCTPAssociationSendAll.cc.

{
    int32                    bytesToSend;
    const SCTPDataMsg* datMsg = peekOutboundDataMsg();
    if(datMsg != NULL) {
        const uint32 ums = datMsg->getBooksize();        // Get user message size
            const uint32 num = (uint32)floor((double)(pathVar->pmtu - 32) / (ums + SCTP_DATA_CHUNK_LENGTH));
            if (num * ums > state->peerRwnd) {
                // Receiver cannot handle data yet
                bytesToSend = 0;
            }
            else {
                // Receiver will accept data
                bytesToSend = num * ums;
            }
    }
    else {
        bytesToSend = 0;
    }
    return(bytesToSend);
}

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

Utility: cancel a timer

Definition at line 740 of file SCTPAssociation.h.

Referenced by stopTimer().

                                                    {
            return sctpMain->cancelEvent(msg);
        }

SCTPPathVariables * SCTPAssociation::choosePathForRetransmission (  )  [private]

Definition at line 158 of file SCTPAssociationSendAll.cc.

Referenced by sendOnPath().

{
    uint32               max    = 0;
    SCTPPathVariables* temp = NULL;

    for (SCTPPathMap::iterator iterator = sctpPathMap.begin(); iterator != sctpPathMap.end(); ++iterator) {
        SCTPPathVariables*          path = iterator->second;
        CounterMap::const_iterator tq     = qCounter.roomTransQ.find(path->remoteAddress);
        if ((tq != qCounter.roomTransQ.end()) && (tq->second > max)) {
            max = tq->second;
            temp = path;
        }
    }
    return temp;
}

bool SCTPAssociation::chunkHasBeenAcked ( const SCTPDataVariables chunk  )  const [inline, private]
bool SCTPAssociation::chunkHasBeenAcked ( const uint32  tsn  )  const [inline, private]

Definition at line 896 of file SCTPAssociation.h.

                                                              {
            const SCTPDataVariables* chunk = retransmissionQ->getChunk(tsn);
            if(chunk) {
                return(chunkHasBeenAcked(chunk));
            }
            return(false);
        }

uint32 SCTPAssociation::chunkToInt ( const char *  type  )  [static]

Definition at line 132 of file SCTPAssociationUtil.cc.

{
    if (strcmp(type, "DATA")==0) return 0;
    if (strcmp(type, "INIT")==0) return 1;
    if (strcmp(type, "INIT_ACK")==0) return 2;
    if (strcmp(type, "SACK")==0) return 3;
    if (strcmp(type, "HEARTBEAT")==0) return 4;
    if (strcmp(type, "HEARTBEAT_ACK")==0) return 5;
    if (strcmp(type, "ABORT")==0) return 6;
    if (strcmp(type, "SHUTDOWN")==0) return 7;
    if (strcmp(type, "SHUTDOWN_ACK")==0) return 8;
    if (strcmp(type, "ERRORTYPE")==0) return 9;
    if (strcmp(type, "COOKIE_ECHO")==0) return 10;
    if (strcmp(type, "COOKIE_ACK")==0) return 11;
    if (strcmp(type, "SHUTDOWN_COMPLETE")==0) return 14;
    sctpEV3<<"ChunkConversion not successful\n";
    return 0;
}

SCTPAssociation * SCTPAssociation::cloneAssociation (  )  [protected]

Utility: clone a listening association. Used for forking.

Definition at line 166 of file SCTPAssociationUtil.cc.

Referenced by processInitArrived().

{
    SCTPAssociation* assoc = new SCTPAssociation(sctpMain,appGateIndex,assocId);
    const char* queueClass = transmissionQ->getClassName();
    assoc->transmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass));
    assoc->retransmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass));

    const char* sctpAlgorithmClass = sctpAlgorithm->getClassName();
    assoc->sctpAlgorithm = check_and_cast<SCTPAlgorithm *>(createOne(sctpAlgorithmClass));
    assoc->sctpAlgorithm->setAssociation(assoc);
    assoc->sctpAlgorithm->initialize();
    assoc->state = assoc->sctpAlgorithm->createStateVariables();

    assoc->state->active = false;
    assoc->state->fork = true;
    assoc->localAddr = localAddr;
    assoc->localPort = localPort;
    assoc->localAddressList = localAddressList;

    FSM_Goto((*assoc->fsm), SCTP_S_CLOSED);
    sctpMain->printInfoConnMap();
    return assoc;
}

SCTPSackChunk * SCTPAssociation::createSack (  )  [protected]

Definition at line 881 of file SCTPAssociationUtil.cc.

Referenced by sendOnPath(), and sendSack().

{
    uint32 key=0, arwnd=0;

    sctpEV3<<"SCTPAssociationUtil:createSACK localAddress="<<localAddr<<"  remoteAddress="<<remoteAddr<<"\n";

    sctpEV3<<" localRwnd="<<state->localRwnd<<" queuedBytes="<<state->queuedReceivedBytes<<"\n";
    if ((int32)(state->localRwnd - state->queuedReceivedBytes) <= 0)
    {
        arwnd = 0;
        if (state->swsLimit > 0)
            state->swsAvoidanceInvoked = true;
    }
    else if (state->localRwnd - state->queuedReceivedBytes < state->swsLimit || state->swsAvoidanceInvoked == true)
    {
        arwnd = 1;
        if (state->swsLimit > 0)
            state->swsAvoidanceInvoked = true;
        sctpEV3<<"arwnd=1; createSack : SWS Avoidance ACTIVE !!!\n";
    }
    else
    {
        arwnd = state->localRwnd - state->queuedReceivedBytes;
        sctpEV3<<simTime()<<" arwnd = "<<state->localRwnd<<" - "<<state->queuedReceivedBytes<<" = "<<arwnd<<"\n";
    }
    advRwnd->record(arwnd);
    SCTPSackChunk* sackChunk=new SCTPSackChunk("SACK");
    sackChunk->setChunkType(SACK);
    sackChunk->setCumTsnAck(state->cTsnAck);
    sackChunk->setA_rwnd(arwnd);
    uint32 numGaps=state->numGaps;
    uint32 numDups=state->dupList.size();
    uint16 sackLength=SCTP_SACK_CHUNK_LENGTH + numGaps*4 + numDups*4;
    uint32 mtu = getPath(remoteAddr)->pmtu;

    if (sackLength > mtu-32) // FIXME
    {
        if (SCTP_SACK_CHUNK_LENGTH + numGaps*4 > mtu-32)
        {
            numDups = 0;
            numGaps = (uint32)((mtu-32-SCTP_SACK_CHUNK_LENGTH)/4);
        }
        else
        {
            numDups = (uint32)((mtu-32-SCTP_SACK_CHUNK_LENGTH - numGaps*4)/4);
        }
        sackLength=SCTP_SACK_CHUNK_LENGTH + numGaps*4 + numDups*4;
    }
    sackChunk->setNumGaps(numGaps);
    sackChunk->setNumDupTsns(numDups);
    sackChunk->setBitLength(sackLength*8);

    sctpEV3<<"Sack arwnd="<<sackChunk->getA_rwnd()<<" ctsnAck="<<state->cTsnAck<<" numGaps="<<numGaps<<" numDups="<<numDups<<"\n";

    if (numGaps > 0)
    {
        sackChunk->setGapStartArraySize(numGaps);
        sackChunk->setGapStopArraySize(numGaps);

        uint32 last = state->cTsnAck;
        for (key=0; key<numGaps; key++)
        {
            // ====== Validity check ===========================================
            assert(tsnGt(state->gapStartList[key], last + 1));
            assert(tsnGe(state->gapStopList[key], state->gapStartList[key]));
            last = state->gapStopList[key];

            sackChunk->setGapStart(key, state->gapStartList[key]);
            sackChunk->setGapStop(key, state->gapStopList[key]);
        }
    }
    if (numDups > 0)
    {
        sackChunk->setDupTsnsArraySize(numDups);
        key=0;
        for(std::list<uint32>::iterator iter=state->dupList.begin(); iter!=state->dupList.end(); iter++)
        {
            sackChunk->setDupTsns(key, (*iter));
            key++;
            if (key == numDups)
                break;
        }
        state->dupList.clear();
    }
    sctpEV3<<endl;
    for (uint32 i=0; i<numGaps; i++)
        sctpEV3<<sackChunk->getGapStart(i)<<" - "<<sackChunk->getGapStop(i)<<"\n";

    sctpEV3<<"send "<<sackChunk->getName()<<" from "<<localAddr<<" to "<<state->lastDataSourceAddress<<"\n";
    return sackChunk;
}

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

Definition at line 272 of file SCTPCCFunctions.cc.

{
    // When the association does not transmit data on a given transport address
    // within an RTO, the cwnd of the transport address SHOULD be adjusted to 2*MTU.

        sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterCwndTimeout]\t" << path->remoteAddress
                  << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd;
        path->cwnd = (int32)min(4 * path->pmtu, max(2 * path->pmtu, 4380));
        sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl;
    recordCwndUpdate(path);
}

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

Definition at line 236 of file SCTPCCFunctions.cc.

{
        sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterRtxTimeout]\t" << path->remoteAddress
                    << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd;

        path->ssthresh = (int32)max(path->cwnd / 2, 4 * path->pmtu);
        path->cwnd = path->pmtu;

        sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl;
    path->partialBytesAcked         = 0;
    recordCwndUpdate(path);

    // Leave Fast Recovery mode
    if (path->fastRecoveryActive == true) {
        path->fastRecoveryActive     = false;
        path->fastRecoveryExitPoint = 0;
    }
}

void SCTPAssociation::cwndUpdateAfterSack (  )  [protected]

Definition at line 50 of file SCTPCCFunctions.cc.

{
    for (SCTPPathMap::iterator iter = sctpPathMap.begin(); iter != sctpPathMap.end(); iter++) {
        SCTPPathVariables* path = iter->second;
        if(path->fastRecoveryActive == false) {

            // ====== Retransmission required -> reduce congestion window ======
            if(path->requiresRtx) {
                double decreaseFactor = 0.5;

                      sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterSack]\t" << path->remoteAddress
                                 << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd;

                      path->ssthresh = max((int32)path->cwnd - (int32)rint(decreaseFactor * (double)path->cwnd),
                                                  4 * (int32)path->pmtu);
                      path->cwnd = path->ssthresh;

                      sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl;
                 recordCwndUpdate(path);
                 path->partialBytesAcked = 0;


                 // ====== Fast Recovery ========================================
                 if(state->fastRecoverySupported) {
                    uint32 highestAckOnPath = state->lastTsnAck;
                    for(SCTPQueue::PayloadQueue::iterator pq = retransmissionQ->payloadQueue.begin();
                         pq != retransmissionQ->payloadQueue.end(); pq++) {
                         if( (chunkHasBeenAcked(pq->second) == true) &&
                              (tsnGt(pq->second->tsn, highestAckOnPath)) &&
                              (pq->second->getLastDestinationPath() == path) ) {
                             // T.D. 21.11.09: Only take care of TSNs on the same path!
                             highestAckOnPath = pq->second->tsn;
                         }
                    }
                    /* this can ONLY become TRUE, when Fast Recovery IS supported */
                    path->fastRecoveryActive         = true;
                    path->fastRecoveryExitPoint  = highestAckOnPath;
                    path->fastRecoveryEnteringTime = simTime();

                    sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterSack] Entering Fast Recovery on path "
                              << path->remoteAddress
                              << ", exit point is " << path->fastRecoveryExitPoint << endl;
                }
            }
        }
        else {
            for (SCTPPathMap::iterator iter = sctpPathMap.begin(); iter != sctpPathMap.end(); iter++) {
                SCTPPathVariables* path = iter->second;
                if(path->fastRecoveryActive) {
                    sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterSack] Still in Fast Recovery on path "
                              << path->remoteAddress
                              << ", exit point is " << path->fastRecoveryExitPoint << endl;
                }
            }
        }
    }
}

void SCTPAssociation::cwndUpdateBytesAcked ( SCTPPathVariables path,
const uint32  ackedBytes,
const bool  ctsnaAdvanced 
) [protected]

Definition at line 130 of file SCTPCCFunctions.cc.

{
    sctpEV3 << simulation.getSimTime() << "====> cwndUpdateBytesAcked:"
              << " path="                     << path->remoteAddress
              << " ackedBytes="           << ackedBytes
              << " ctsnaAdvanced="        << ((ctsnaAdvanced == true) ? "yes" : "no")
              << " cwnd="                     << path->cwnd
              << " ssthresh="                 << path->ssthresh
              << " ackedBytes="           << ackedBytes
              << " pathOsbBeforeUpdate=" << path->outstandingBytesBeforeUpdate
              << " pathOsb="                  << path->outstandingBytes
              << endl;

    if (path->fastRecoveryActive == false) {
        // T.D. 21.11.09: Increasing cwnd is only allowed when not being in
        //                      Fast Recovery mode!

        // ====== Slow Start ==================================================
        if (path->cwnd <= path->ssthresh)  {
            // ------ Clear PartialBytesAcked counter --------------------------
            path->partialBytesAcked = 0;

            // ------ Increase Congestion Window -------------------------------
            if ((ctsnaAdvanced == true) &&
                 (path->outstandingBytesBeforeUpdate >= path->cwnd)) {
                    sctpEV3 << simTime() << ":\tCC [cwndUpdateBytesAcked-SlowStart]\t" << path->remoteAddress
                              << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << " acked=" << ackedBytes;

                    path->cwnd += (int32)min(path->pmtu, ackedBytes);

                    sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl;
                recordCwndUpdate(path);
            }

            // ------ No need to increase Congestion Window --------------------
            else {
                sctpEV3 << simTime() << ":\tCC "
                        << "Not increasing cwnd of path " << path->remoteAddress << " in slow start:\t"
                        << "ctsnaAdvanced="       << ((ctsnaAdvanced == true) ? "yes" : "no") << "\t"
                        << "cwnd="                    << path->cwnd                              << "\t"
                        << "ssthresh="                << path->ssthresh                          << "\t"
                        << "ackedBytes="              << ackedBytes                              << "\t"
                        << "pathOsbBeforeUpdate=" << path->outstandingBytesBeforeUpdate << "\t"
                        << "pathOsb="                 << path->outstandingBytes              << "\t"
                        << "(pathOsbBeforeUpdate >= path->cwnd)="
                        << (path->outstandingBytesBeforeUpdate >= path->cwnd) << endl;
            }
        }

        // ====== Congestion Avoidance ========================================
        else
        {
            // ------ Increase PartialBytesAcked counter -----------------------
            path->partialBytesAcked += ackedBytes;

            double increaseFactor = 1.0;

            // ------ Increase Congestion Window -------------------------------
            if ( (path->partialBytesAcked >= path->cwnd) &&
                  (ctsnaAdvanced == true) &&
                  (path->outstandingBytesBeforeUpdate >= path->cwnd) ) {
                    sctpEV3 << simTime() << ":\tCC [cwndUpdateBytesAcked-CgAvoidance]\t" << path->remoteAddress
                              << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << " acked=" << ackedBytes;

                    path->cwnd += (int32)rint(increaseFactor * path->pmtu);

                    sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl;
                recordCwndUpdate(path);
                path->partialBytesAcked =
                    ((path->cwnd < path->partialBytesAcked) ?
                        (path->partialBytesAcked - path->cwnd) : 0);
            }

            // ------ No need to increase Congestion Window -------------------
            else {
                sctpEV3 << simTime() << ":\tCC "
                        << "Not increasing cwnd of path " << path->remoteAddress << " in congestion avoidance: "
                        << "ctsnaAdvanced="       << ((ctsnaAdvanced == true) ? "yes" : "no") << "\t"
                        << "cwnd="                    << path->cwnd                              << "\t"
                        << "ssthresh="                << path->ssthresh                          << "\t"
                        << "ackedBytes="              << ackedBytes                              << "\t"
                        << "pathOsbBeforeUpdate=" << path->outstandingBytesBeforeUpdate << "\t"
                        << "pathOsb="                 << path->outstandingBytes              << "\t"
                        << "(pathOsbBeforeUpdate >= path->cwnd)="
                            << (path->outstandingBytesBeforeUpdate >= path->cwnd)            << "\t"
                        << "partialBytesAcked="   << path->partialBytesAcked                 << "\t"
                        << "(path->partialBytesAcked >= path->cwnd)="
                            << (path->partialBytesAcked >= path->cwnd) << endl;
            }
        }

        // ====== Reset PartialBytesAcked counter if no more outstanding bytes
        if(path->outstandingBytes == 0) {
            path->partialBytesAcked = 0;
        }
    }
    else {
        sctpEV3 << simTime() << ":\tCC "
                << "Not increasing cwnd of path " << path->remoteAddress
                << " during Fast Recovery" << endl;
    }
}

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

Definition at line 256 of file SCTPCCFunctions.cc.

{
        if(path->cwnd > ((path->outstandingBytes + state->maxBurst * path->pmtu))) {
            sctpEV3 << simTime()      << ":\tCC [cwndUpdateMaxBurst]\t" << path->remoteAddress
                    << "\tsst="       << path->ssthresh << " cwnd=" << path->cwnd
                    << "\tosb="       << path->outstandingBytes
                    << "\tmaxBurst=" << state->maxBurst * path->pmtu << endl;

            path->cwnd = path->outstandingBytes + (state->maxBurst * path->pmtu);
            recordCwndUpdate(path);

            sctpEV3 << "\t=>\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl;
        }
}

void SCTPAssociation::decreaseOutstandingBytes ( SCTPDataVariables chunk  )  [private]

Definition at line 32 of file SCTPAssociationRcvMessage.cc.

Referenced by dequeueAckedChunks(), handleChunkReportedAsAcked(), handleChunkReportedAsMissing(), moveChunkToOtherPath(), and tsnWasReneged().

{
    SCTPPathVariables* lastPath = chunk->getLastDestinationPath();

    assert(lastPath->outstandingBytes >= chunk->booksize);
    lastPath->outstandingBytes -= chunk->booksize;
    state->outstandingBytes -= chunk->booksize;
    assert((int64)state->outstandingBytes >= 0);

    chunk->countsAsOutstanding = false;

    CounterMap::iterator iterator = qCounter.roomRetransQ.find(lastPath->remoteAddress);
        iterator->second -= ADD_PADDING(chunk->booksize + SCTP_DATA_CHUNK_LENGTH);

}

void SCTPAssociation::deleteStreams (  ) 

Definition at line 1193 of file SCTPAssociationUtil.cc.

Referenced by SCTP::removeAssociation().

{
    for (SCTPSendStreamMap::iterator it=sendStreams.begin(); it != sendStreams.end(); it++)
    {
        it->second->deleteQueue();
    }
    for (SCTPReceiveStreamMap::iterator it=receiveStreams.begin(); it != receiveStreams.end(); it++)
    {
        delete it->second;
    }
}

uint32 SCTPAssociation::dequeueAckedChunks ( const uint32  tsna,
SCTPPathVariables path,
simtime_t &  rttEstimation 
) [protected]

Definition at line 1151 of file SCTPAssociationRcvMessage.cc.

Referenced by process_RCV_Message(), and processSackArrived().

{
    SCTP::AssocStat* assocStat                   = sctpMain->getAssocStat(assocId);
    uint32            newlyAckedBytes            = 0;
    uint64            sendBufferBeforeUpdate = state->sendBuffer;

    // Set it ridiculously high
    rttEstimation = MAXTIME;

    // Are there chunks in the retransmission queue ? If Yes -> check for dequeue.
    SCTPQueue::PayloadQueue::iterator iterator = retransmissionQ->payloadQueue.begin();
    while (iterator != retransmissionQ->payloadQueue.end()) {
        SCTPDataVariables* chunk = iterator->second;
        if (tsnGe(tsna, chunk->tsn)) {
            // Dequeue chunk, cause it has been acked
            if (transmissionQ->getChunk(chunk->tsn)) {
                transmissionQ->removeMsg(chunk->tsn);
                chunk->enqueuedInTransmissionQ = false;
                CounterMap::iterator q = qCounter.roomTransQ.find(chunk->getNextDestination());
                q->second -= ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH);
                CounterMap::iterator qb = qCounter.bookedTransQ.find(chunk->getNextDestination());
                qb->second -= chunk->booksize;
            }

            chunk = retransmissionQ->getAndExtractChunk(chunk->tsn);
            state->sendBuffer -= chunk->len/8;

            SCTPPathVariables* lastPath = chunk->getLastDestinationPath();
            assert(lastPath != NULL);

            if (!chunkHasBeenAcked(chunk)) {
                newlyAckedBytes += (chunk->booksize);

                sctpEV3 << simTime() << ": CumAcked TSN " << chunk->tsn
                          << " on path " << chunk->getLastDestination() << endl;

                lastPath->newlyAckedBytes += (chunk->booksize);

                // T.D. 05.12.09: CumAck affects lastPath -> reset its T3 timer later.
                lastPath->newCumAck = true;
            }


            if(assocStat) {
                assocStat->ackedBytes += chunk->len/8;
            }

            if ((chunkHasBeenAcked(chunk) == false) && (chunk->countsAsOutstanding)) {
                ackChunk(chunk);
                if ((chunk->numberOfTransmissions == 1) && (chunk->getLastDestinationPath() == sackPath)) {
                    const simtime_t timeDifference = simTime() - chunk->sendTime;
                    if ((timeDifference < rttEstimation) || (rttEstimation == MAXTIME)) {
                        rttEstimation = timeDifference;
                    }
                }
                decreaseOutstandingBytes(chunk);
            }
            if (chunk->userData != NULL) {
                delete chunk->userData;
            }
            delete chunk;
        }
        else {
            break;
        }
        iterator = retransmissionQ->payloadQueue.begin();
    }

    if(sendBufferBeforeUpdate != state->sendBuffer && state->sendBuffer < state->sendQueueLimit) {
        // T.D. 06.02.2010: Just send SCTP_I_SENDQUEUE_ABATED once, after all newly acked
        //                        chunks have been dequeued.
        // I.R. only send indication if the sendBuffer size has dropped below the sendQueueLimit
        assert(state->lastSendQueueAbated < simTime());
        state->appSendAllowed = true;
        sctpEV3 << simTime() << ":\tSCTP_I_SENDQUEUE_ABATED("
                  << sendBufferBeforeUpdate - state->sendBuffer << ") to refill buffer "
                  << state->sendBuffer << "/" << state->sendQueueLimit << endl;
        sendIndicationToApp(SCTP_I_SENDQUEUE_ABATED, sendBufferBeforeUpdate - state->sendBuffer);
        state->lastSendQueueAbated = simTime();
    }

    sctpEV3 << "dequeueAckedChunks(): newlyAckedBytes=" << newlyAckedBytes
              << ", rttEstimation=" << rttEstimation << endl;

    return (newlyAckedBytes);
}

SCTPDataMsg * SCTPAssociation::dequeueOutboundDataMsg ( const int32  availableSpace,
const int32  availableCwnd 
) [protected]

Definition at line 1646 of file SCTPAssociationUtil.cc.

Referenced by sendOnPath().

{
    SCTPDataMsg* datMsg=NULL;
    int32 nextStream = -1;

    sctpEV3<<"dequeueOutboundDataMsg: " << availableSpace <<" bytes left to be sent" << endl;
    /* Only change stream if we don't have to finish a fragmented message */
    if (state->lastMsgWasFragment)
        nextStream = state->lastStreamScheduled;
    else
        nextStream = (this->*ssFunctions.ssGetNextSid)(false);

    if (nextStream == -1)
        return NULL;

    sctpEV3<<"dequeueOutboundDataMsg: now stream "<< nextStream << endl;

    for (SCTPSendStreamMap::iterator iter=sendStreams.begin(); iter!=sendStreams.end(); ++iter)
    {
        if ((int32)iter->first==nextStream)
        {
            SCTPSendStream* stream=iter->second;
            cQueue* streamQ = NULL;

            if (!stream->getUnorderedStreamQ()->empty())
            {
                streamQ = stream->getUnorderedStreamQ();
                sctpEV3<<"DequeueOutboundDataMsg() found chunks in stream "<<iter->first<<" unordered queue, queue size="<<stream->getUnorderedStreamQ()->getLength()<<"\n";
            }
            else if (!stream->getStreamQ()->empty())
            {
                streamQ = stream->getStreamQ();
                sctpEV3<<"DequeueOutboundDataMsg() found chunks in stream "<<iter->first<<" ordered queue, queue size="<<stream->getStreamQ()->getLength()<<"\n";
            }

            if (streamQ)
            {
                int32 b=ADD_PADDING( (check_and_cast<SCTPSimpleMessage*>(((SCTPDataMsg*)streamQ->front())->getEncapsulatedMsg())->getByteLength()+SCTP_DATA_CHUNK_LENGTH));

                /* check if chunk found in queue has to be fragmented */
                if (b > (int32)state->assocPmtu - IP_HEADER_LENGTH - SCTP_COMMON_HEADER)
                {
                    /* START FRAGMENTATION */
                    SCTPDataMsg* datMsgQueued = (SCTPDataMsg*)streamQ->pop();
                    SCTPSimpleMessage *datMsgQueuedSimple = check_and_cast<SCTPSimpleMessage*>(datMsgQueued->getEncapsulatedMsg());

                    SCTPDataMsg* datMsgLastFragment = NULL;
                    uint32 offset = 0;

                    sctpEV3<<"Fragmentation: chunk " << &datMsgQueued << ", size = " << datMsgQueued->getByteLength() << endl;

                    while (datMsgQueued)
                    {
                        /* detemine size of fragment, either max payload or what's left */
                        uint32 msgbytes = state->assocPmtu - IP_HEADER_LENGTH - SCTP_COMMON_HEADER - SCTP_DATA_CHUNK_LENGTH;
                        if (msgbytes > datMsgQueuedSimple->getDataLen() - offset)
                            msgbytes = datMsgQueuedSimple->getDataLen() - offset;

                        /* new DATA msg */
                        SCTPDataMsg* datMsgFragment = new SCTPDataMsg();
                        datMsgFragment->setSid(datMsgQueued->getSid());
                        datMsgFragment->setPpid(datMsgQueued->getPpid());
                        datMsgFragment->setInitialDestination(datMsgQueued->getInitialDestination());
                        datMsgFragment->setEnqueuingTime(datMsgQueued->getEnqueuingTime());
                        datMsgFragment->setMsgNum(datMsgQueued->getMsgNum());
                        datMsgFragment->setOrdered(datMsgQueued->getOrdered());
                        datMsgFragment->setExpiryTime(datMsgQueued->getExpiryTime());
                        datMsgFragment->setRtx(datMsgQueued->getRtx());
                        datMsgFragment->setFragment(true);
                            datMsgFragment->setBooksize(msgbytes + state->header);

                        /* is this the first fragment? */
                        if (offset == 0)
                            datMsgFragment->setBBit(true);

                        /* new msg */
                        SCTPSimpleMessage *datMsgFragmentSimple = new SCTPSimpleMessage();

                        datMsgFragmentSimple->setName(datMsgQueuedSimple->getName());
                        datMsgFragmentSimple->setCreationTime(datMsgQueuedSimple->getCreationTime());

                        datMsgFragmentSimple->setDataArraySize(msgbytes);
                        datMsgFragmentSimple->setDataLen(msgbytes);
                        datMsgFragmentSimple->setByteLength(msgbytes);

                        /* copy data */
                        for (uint32 i = offset; i < offset + msgbytes; i++)
                            datMsgFragmentSimple->setData(i - offset, datMsgQueuedSimple->getData(i));

                        offset += msgbytes;
                        datMsgFragment->encapsulate(datMsgFragmentSimple);

                        /* insert fragment into queue */
                        if (!streamQ->empty())
                        {
                            if (!datMsgLastFragment)
                            {
                                /* insert first fragment at the begining of the queue*/
                                streamQ->insertBefore((SCTPDataMsg*)streamQ->front(), datMsgFragment);
                            }
                            else
                            {
                                /* insert fragment after last inserted   */
                                streamQ->insertAfter(datMsgLastFragment, datMsgFragment);
                            }
                        }
                        else
                            streamQ->insert(datMsgFragment);

                        state->queuedMessages++;
                        qCounter.roomSumSendStreams += ADD_PADDING(datMsgFragment->getByteLength() + SCTP_DATA_CHUNK_LENGTH);
                        qCounter.bookedSumSendStreams += datMsgFragment->getBooksize();
                        sctpEV3<<"Fragmentation: fragment " << &datMsgFragment << " created, length = " << datMsgFragmentSimple->getByteLength() << ", queue size = " << streamQ->getLength() << endl;

                        datMsgLastFragment = datMsgFragment;

                        /* all fragments done? */
                        if (datMsgQueuedSimple->getDataLen() == offset)
                        {
                            datMsgFragment->setEBit(true);

                            /* remove original element */
                            sctpEV3<<"Fragmentation: delete " << &datMsgQueued << endl;
                            //streamQ->pop();
                            qCounter.roomSumSendStreams -= ADD_PADDING(datMsgQueued->getByteLength() + SCTP_DATA_CHUNK_LENGTH);
                            qCounter.bookedSumSendStreams -= datMsgQueued->getBooksize();
                            delete datMsgQueued;
                            datMsgQueued = NULL;
                            state->queuedMessages--;
                        }
                    }

                    /* the next chunk returned will always be a fragment */
                    state->lastMsgWasFragment = true;

                    b=ADD_PADDING( (check_and_cast<SCTPSimpleMessage*>(((SCTPDataMsg*)streamQ->front())->getEncapsulatedMsg())->getBitLength()/8+SCTP_DATA_CHUNK_LENGTH));
                    /* FRAGMENTATION DONE */
                }

                if ((b <= availableSpace) &&
                     ( (int32)((SCTPDataMsg*)streamQ->front())->getBooksize() <= availableCwnd)) {
                    datMsg = (SCTPDataMsg*)streamQ->pop();
                    /*if (!state->appSendAllowed && streamQ->getLength()<=state->sendQueueLimit)
                    {
                        state->appSendAllowed = true;
                        sendIndicationToApp(SCTP_I_SENDQUEUE_ABATED);
                    }*/
                    sendQueue->record(streamQ->getLength());

                    if (!datMsg->getFragment())
                    {
                        datMsg->setBBit(true);
                        datMsg->setEBit(true);
                        state->lastMsgWasFragment = false;
                    }
                    else
                    {
                        if (datMsg->getEBit())
                            state->lastMsgWasFragment = false;
                        else
                            state->lastMsgWasFragment = true;
                    }

                    sctpEV3<<"DequeueOutboundDataMsg() found chunk ("<<&datMsg<<") in the stream queue "<<&iter->first<<"("<<streamQ<<") queue size="<<streamQ->getLength()<<"\n";
                 }
            }
            break;
        }
    }
    if (datMsg != NULL)
    {
        qCounter.roomSumSendStreams -= ADD_PADDING( (check_and_cast<SCTPSimpleMessage*>(datMsg->getEncapsulatedMsg())->getBitLength()/8+SCTP_DATA_CHUNK_LENGTH));
        qCounter.bookedSumSendStreams -= datMsg->getBooksize();
    }
    return (datMsg);
}

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

Definition at line 2085 of file SCTPAssociationUtil.cc.

Referenced by process_RCV_Message().

{
    SCTPChunk* chunk;
    uint32 numberOfChunks = sctpmsg->getChunksArraySize();
    if (numberOfChunks>0)
    for (uint32 i=0; i<numberOfChunks; i++)
    {
        chunk = (SCTPChunk*)(sctpmsg->removeChunk());
        if (chunk->getChunkType()==DATA)
            delete (SCTPSimpleMessage*)chunk->decapsulate();
        delete chunk;
    }
    delete sctpmsg;
}

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

Definition at line 599 of file SCTPAssociation.h.

{ return fsm; };

int32 SCTPAssociation::getFsmState (  )  const [inline]

Definition at line 593 of file SCTPAssociation.h.

{ return fsm->getState(); };

cMessage* SCTPAssociation::getInitTimer (  )  const [inline]

Definition at line 600 of file SCTPAssociation.h.

{ return T1_InitTimer; };

const IPvXAddress& SCTPAssociation::getNextAddress ( const SCTPPathVariables oldPath  )  const [inline, protected]

Definition at line 766 of file SCTPAssociation.h.

                                                                                         {
            const SCTPPathVariables* nextPath = getNextPath(oldPath);
            if(nextPath != NULL) {
                return(nextPath->remoteAddress);
            }
            return(SCTPDataVariables::zeroAddress);
        }

SCTPPathVariables * SCTPAssociation::getNextDestination ( SCTPDataVariables chunk  )  const [protected]

Definition at line 1898 of file SCTPAssociationUtil.cc.

Referenced by handleChunkReportedAsMissing(), and process_TIMEOUT_RTX().

{
    SCTPPathVariables* next;
    SCTPPathVariables* last;

    sctpEV3 << "Running getNextDestination()" << endl;
    if (chunk->numberOfTransmissions == 0) {
        if (chunk->getInitialDestinationPath() == NULL) {
            next = state->getPrimaryPath();
        }
        else {
            next = chunk->getInitialDestinationPath();
        }
    }
    else {
        if (chunk->hasBeenFastRetransmitted) {
            sctpEV3 << "Chunk is scheduled for FastRetransmission. Next destination = "
                      << chunk->getLastDestination() << endl;
            return(chunk->getLastDestinationPath());
        }
        // If this is a retransmission, we should choose another, active path.
        last = chunk->getLastDestinationPath();
        next = getNextPath(last);
        if( (next == NULL) || (next->confirmed == false) ) {
            next = last;
        }
    }

    sctpEV3 << "getNextDestination(): chunk was last sent to " << last->remoteAddress
              << ", will next be sent to path " << next->remoteAddress << endl;
    return (next);
}

SCTPPathVariables * SCTPAssociation::getNextPath ( const SCTPPathVariables oldPath  )  const [protected]

Definition at line 1876 of file SCTPAssociationUtil.cc.

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

{
    int32 hit = 0;
    if (sctpPathMap.size() > 1) {
        for (SCTPPathMap::const_iterator iterator = sctpPathMap.begin();
              iterator != sctpPathMap.end(); iterator++) {
            if (iterator->second == oldPath) {
                if (++hit == 1) {
                    continue;
                }
                else {
                    break;
                }
            }
            if (iterator->second->activePath) {
                return iterator->second;
            }
        }
    }
    return(NULL);
}

SCTPDataVariables * SCTPAssociation::getOutboundDataChunk ( const SCTPPathVariables path,
const int32  availableSpace,
const int32  availableCwnd 
) [protected]

Definition at line 1552 of file SCTPAssociationUtil.cc.

Referenced by sendOnPath().

{
    /* are there chunks in the transmission queue ? If Yes -> dequeue and return it */
    sctpEV3 << "getOutboundDataChunk(" << path->remoteAddress << "):"
              << " availableSpace=" << availableSpace
              << " availableCwnd="  << availableCwnd
              << endl;
    if (!transmissionQ->payloadQueue.empty()) {
        for(SCTPQueue::PayloadQueue::iterator it = transmissionQ->payloadQueue.begin();
             it != transmissionQ->payloadQueue.end(); it++) {
            SCTPDataVariables* chunk = it->second;
            if( (chunkHasBeenAcked(chunk) == false) &&
                 (chunk->getNextDestinationPath() == path) ) {
                const int32 len = ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH);
                sctpEV3 << "getOutboundDataChunk() found chunk " << chunk->tsn
                          <<" in the transmission queue, length=" << len << endl;
                if ((len <= availableSpace) &&
                     ((int32)chunk->booksize <= availableCwnd)) {
                    // T.D. 05.01.2010: The bookkeeping counters may only be decreased when
                    //                        this chunk is actually dequeued. Therefore, the check
                    //                        for "chunkHasBeenAcked==false" has been moved into the
                    //                        "if" statement above!
                    transmissionQ->payloadQueue.erase(it);
                    chunk->enqueuedInTransmissionQ = false;
                    CounterMap::iterator i = qCounter.roomTransQ.find(path->remoteAddress);
                    i->second -= ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH);
                    CounterMap::iterator ib = qCounter.bookedTransQ.find(path->remoteAddress);
                    ib->second -= chunk->booksize;
                    return chunk;
                }
            }
        }
    }
    return NULL;
}

int32 SCTPAssociation::getOutstandingBytes (  )  const [protected]

Definition at line 2000 of file SCTPAssociationUtil.cc.

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

{
    int32 osb = 0;
    for (SCTPPathMap::const_iterator pm = sctpPathMap.begin(); pm != sctpPathMap.end(); pm++) {
        osb += pm->second->outstandingBytes;
    }
    return osb;
}

SCTPPathVariables* SCTPAssociation::getPath ( const IPvXAddress pathId  )  const [inline]
SCTPQueue* SCTPAssociation::getRetransmissionQueue (  )  const [inline]

Definition at line 596 of file SCTPAssociation.h.

Referenced by SCTP::removeAssociation().

{ return retransmissionQ; };

cMessage* SCTPAssociation::getSackTimer (  )  const [inline]

Definition at line 602 of file SCTPAssociation.h.

{ return SackTimer; };

SCTPAlgorithm* SCTPAssociation::getSctpAlgorithm (  )  const [inline]

Definition at line 597 of file SCTPAssociation.h.

{ return sctpAlgorithm; };

SCTP* SCTPAssociation::getSctpMain (  )  const [inline]

Definition at line 598 of file SCTPAssociation.h.

Referenced by SCTPPathVariables::SCTPPathVariables().

{ return sctpMain; };

cMessage* SCTPAssociation::getShutdownTimer (  )  const [inline]

Definition at line 601 of file SCTPAssociation.h.

{ return T2_ShutdownTimer; };

SCTPStateVariables* SCTPAssociation::getState (  )  const [inline]

Definition at line 594 of file SCTPAssociation.h.

{ return state; };

SCTPQueue* SCTPAssociation::getTransmissionQueue (  )  const [inline]

Definition at line 595 of file SCTPAssociation.h.

Referenced by SCTP::removeAssociation(), and SCTPAlgorithm::setAssociation().

{ return transmissionQ; };

void SCTPAssociation::handleChunkReportedAsAcked ( uint32 &  highestNewAck,
simtime_t &  rttEstimation,
SCTPDataVariables myChunk,
SCTPPathVariables sackPath 
) [private]

Definition at line 1011 of file SCTPAssociationRcvMessage.cc.

Referenced by processSackArrived().

{
    SCTPPathVariables* myChunkLastPath = myChunk->getLastDestinationPath();
    if ( (myChunk->numberOfTransmissions == 1) &&
          (myChunk->hasBeenReneged == false) ) {
        if (myChunkLastPath == sackPath) {
            const simtime_t timeDifference = simTime() - myChunk->sendTime;
            if((timeDifference < rttEstimation) || (rttEstimation == -1.0)) {
                rttEstimation = timeDifference;
            }
            sctpEV3 << simTime()          << " processSackArrived: computed rtt time diff == "
                      << timeDifference << " for TSN "<< myChunk->tsn << endl;
        }
    }
    if ( (myChunk->hasBeenAbandoned == false)    &&
          (myChunk->hasBeenReneged == false) ) {
        myChunkLastPath->newlyAckedBytes += (myChunk->booksize);

        sctpEV3 << simTime() << ": GapAcked TSN " << myChunk->tsn
                  << " on path " << myChunkLastPath->remoteAddress << endl;

        if (myChunk->tsn > highestNewAck) {
            highestNewAck = myChunk->tsn;
        }
        ackChunk(myChunk);
        if (myChunk->countsAsOutstanding) {
            decreaseOutstandingBytes(myChunk);
        }
        if (transmissionQ->getChunk(myChunk->tsn)) {      // I.R. 02.01.07
            sctpEV3 << "Found TSN " << myChunk->tsn << " in transmissionQ -> remote it" << endl;
            transmissionQ->removeMsg(myChunk->tsn);
            myChunk->enqueuedInTransmissionQ = false;
            CounterMap::iterator q = qCounter.roomTransQ.find(myChunk->getNextDestination());
            q->second -= ADD_PADDING(myChunk->len/8+SCTP_DATA_CHUNK_LENGTH);
            CounterMap::iterator qb = qCounter.bookedTransQ.find(myChunk->getNextDestination());
            qb->second -= myChunk->booksize;
        }
        myChunk->gapReports = 0;
    }
}

void SCTPAssociation::handleChunkReportedAsMissing ( const SCTPSackChunk *  sackChunk,
const uint32  highestNewAck,
SCTPDataVariables myChunk,
const SCTPPathVariables sackPath 
) [private]

Definition at line 1056 of file SCTPAssociationRcvMessage.cc.

Referenced by processSackArrived().

{
    SCTPPathVariables* myChunkLastPath = myChunk->getLastDestinationPath();
    sctpEV3 << "TSN " << myChunk->tsn << " is missing in gap reports (last "
              << myChunkLastPath->remoteAddress << ") ";
    if (!chunkHasBeenAcked(myChunk)) {
        sctpEV3 << "has not been acked, highestNewAck=" << highestNewAck
                  << " countsAsOutstanding=" << myChunk->countsAsOutstanding << endl;
        const uint32 chunkReportedAsMissing = (highestNewAck > myChunk->tsn) ? 1 : 0;
        if (chunkReportedAsMissing > 0) {
            // T.D. 15.04.09: Increase gapReports by chunkReportedAsMissing.
            // Fixed bug here: gapReports += chunkReportedAsMissing instead of gapReports = chunkReportedAsMissing.
            /*
            printf("GapReports for TSN %u [ret=%d,fast=%s] at t=%s:  %d --> %d by %d\n",
                        myChunk->tsn,
                        myChunk->numberOfRetransmissions,
                        (myChunk->hasBeenFastRetransmitted == true) ? "YES" : "no",
                        simTime().str().c_str(),
                        myChunk->gapReports,
                        myChunk->gapReports + chunkReportedAsMissing,
                        chunkReportedAsMissing);
            */
            myChunk->gapReports += chunkReportedAsMissing;

            myChunkLastPath->gapNAcksInLastSACK++;

            if (myChunk->gapReports >= state->numGapReports) {
                bool fastRtx = false;
                fastRtx = ((myChunk->hasBeenFastRetransmitted == false) &&
                              (myChunk->numberOfRetransmissions == 0));
                if (fastRtx) {

                    // ====== Add chunk to transmission queue ========
                    SCTPQueue::PayloadQueue::iterator it = transmissionQ->payloadQueue.find(myChunk->tsn);
                    if (transmissionQ->getChunk(myChunk->tsn) == NULL) {
                        SCTP::AssocStat* assocStat = sctpMain->getAssocStat(assocId);
                        if(assocStat) {
                            assocStat->numFastRtx++;
                        }
                        myChunk->hasBeenFastRetransmitted = true;

                        sctpEV3 << simTime() << ": Fast RTX for TSN "
                                  << myChunk->tsn << " on path " << myChunk->getLastDestination() << endl;
                        myChunkLastPath->numberOfFastRetransmissions++;

                        myChunk->setNextDestination(getNextDestination(myChunk));
                        SCTPPathVariables* myChunkNextPath = myChunk->getNextDestinationPath();
                        assert(myChunkNextPath != NULL);

                        if (myChunk->countsAsOutstanding) {
                            decreaseOutstandingBytes(myChunk);
                        }
                        if (!transmissionQ->checkAndInsertChunk(myChunk->tsn, myChunk)) {
                            sctpEV3 << "Fast RTX: cannot add message/chunk (TSN="
                                      << myChunk->tsn << ") to the transmissionQ" << endl;
                        }
                        else    {
                            myChunk->enqueuedInTransmissionQ = true;
                            CounterMap::iterator q = qCounter.roomTransQ.find(myChunk->getNextDestination());
                            q->second += ADD_PADDING(myChunk->len/8+SCTP_DATA_CHUNK_LENGTH);
                            CounterMap::iterator qb = qCounter.bookedTransQ.find(myChunk->getNextDestination());
                            qb->second += myChunk->booksize;
                        }
                        myChunkNextPath->requiresRtx = true;
                        if(myChunkNextPath->findLowestTSN == true) {
                            // TD 08.12.09: fixed detection of lowest TSN retransmitted
                            myChunkNextPath->lowestTSNRetransmitted = true;
                        }
                    }
                }
            }
        }
        else {
            myChunk->hasBeenFastRetransmitted = false;
            sctpEV3 << "TSN " << myChunk->tsn << " countsAsOutstanding="
                        << myChunk->countsAsOutstanding << endl;
            if (highestNewAck > myChunk->tsn) {
                myChunk->gapReports++;
            }
            myChunkLastPath->gapAcksInLastSACK++;
        }
        myChunkLastPath->findLowestTSN = false;
    }
    else {
        // Reneging, type 1:
        // A chunk in the gap blocks has been un-acked => reneg it.
                    tsnWasReneged(myChunk,
                                      1);
    }
}

void SCTPAssociation::increaseOutstandingBytes ( SCTPDataVariables chunk,
SCTPPathVariables path 
) [private]

Definition at line 28 of file SCTPAssociationSendAll.cc.

Referenced by sendOnPath().

{
    path->outstandingBytes += chunk->booksize;
    state->outstandingBytes += chunk->booksize;

    CounterMap::iterator iterator = qCounter.roomRetransQ.find(path->remoteAddress);
        iterator->second += ADD_PADDING(chunk->booksize + SCTP_DATA_CHUNK_LENGTH);
}

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

Utility: returns name of SCTP_I_xxx constants

Definition at line 107 of file SCTPAssociationUtil.cc.

Referenced by sendEstabIndicationToApp(), and sendIndicationToApp().

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

Utility: creates send/receive queues and sctpAlgorithm

Definition at line 318 of file SCTPAssociationUtil.cc.

Referenced by process_ASSOCIATE(), and process_OPEN_PASSIVE().

{
    sctpEV3<<"SCTPAssociationUtil:initAssociation\n";
    // create send/receive queues
    const char *queueClass = openCmd->getQueueClass();
    transmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass));

    retransmissionQ = check_and_cast<SCTPQueue *>(createOne(queueClass));
    outboundStreams = openCmd->getOutboundStreams();
    // create algorithm
    const char *sctpAlgorithmClass = openCmd->getSctpAlgorithmClass();
    if (!sctpAlgorithmClass || !sctpAlgorithmClass[0])
        sctpAlgorithmClass = sctpMain->par("sctpAlgorithmClass");
    sctpAlgorithm = check_and_cast<SCTPAlgorithm *>(createOne(sctpAlgorithmClass));
    sctpAlgorithm->setAssociation(this);
    sctpAlgorithm->initialize();
    // create state block
    state = sctpAlgorithm->createStateVariables();
}

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

SCTPCCFunctions

Definition at line 39 of file SCTPCCFunctions.cc.

Referenced by pmStartPathManagement().

{
        path->cwnd = (int32)min(4 * path->pmtu, max(2 * path->pmtu, 4380));
    path->ssthresh = state->peerRwnd;
    recordCwndUpdate(path);

    sctpEV3 << simTime() << ":\tCC [initCCParameters]\t" << path->remoteAddress
              << "\tsst=" << path->ssthresh << " cwnd=" << path->cwnd << endl;
}

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

Definition at line 37 of file SCTPSSFunctions.cc.

{
    uint32 i;

    sctpEV3<<"initStreams instreams="<<inStreams<<"  outstream="<<outStreams<<"\n";
    if (receiveStreams.size()==0 && sendStreams.size()==0)
    {
        for (i=0; i<inStreams; i++)
        {
            SCTPReceiveStream* rcvStream = new SCTPReceiveStream();

            this->receiveStreams[i]=rcvStream;
            rcvStream->setStreamId(i);
            this->state->numMsgsReq[i]=0;
        }
        for (i=0; i<outStreams; i++)
        {
            SCTPSendStream* sendStream = new SCTPSendStream(i);
            this->sendStreams[i]=sendStream;
            sendStream->setStreamId(i);
        }
    }
}

void SCTPAssociation::loadPacket ( SCTPPathVariables pathVar,
SCTPMessage **  sctpMsg,
uint16 *  chunksAdded,
uint16 *  dataChunksAdded,
uint32 *  packetBytes,
bool *  authAdded 
) [private]

Definition at line 84 of file SCTPAssociationSendAll.cc.

Referenced by sendOnPath().

{
    *sctpMsg = state->sctpMsg;
    *chunksAdded = state->chunksAdded;
    *dataChunksAdded = state->dataChunksAdded;
    *packetBytes = state->packetBytes;
    sctpEV3 << "loadPacket: path=" << pathVar->remoteAddress << " osb=" << pathVar->outstandingBytes << " -> " << pathVar->outstandingBytes + state->packetBytes << endl;
    pathVar->outstandingBytes += state->packetBytes;
    qCounter.bookedSumSendStreams -= state->packetBytes;

    for (uint16 i = 0; i < (*sctpMsg)->getChunksArraySize(); i++)
        retransmissionQ->payloadQueue.find(((SCTPDataChunk*)(*sctpMsg)->getChunks(i))->getTsn())->second->countsAsOutstanding = true;

}

SCTPDataVariables * SCTPAssociation::makeDataVarFromDataMsg ( SCTPDataMsg *  datMsg,
SCTPPathVariables path 
) [private]

Definition at line 106 of file SCTPAssociationSendAll.cc.

Referenced by sendOnPath().

{
    SCTPDataVariables* datVar = new SCTPDataVariables();

    datMsg->setInitialDestination(path->remoteAddress);
    datVar->setInitialDestination(path);

    datVar->bbit                            = datMsg->getBBit();
    datVar->ebit                            = datMsg->getEBit();
    datVar->enqueuingTime               = datMsg->getEnqueuingTime();
    datVar->expiryTime                  = datMsg->getExpiryTime();
    datVar->ppid                            = datMsg->getPpid();
    datVar->len                             = datMsg->getBitLength();
    datVar->sid                             = datMsg->getSid();
    datVar->allowedNoRetransmissions = datMsg->getRtx();
    datVar->booksize                        = datMsg->getBooksize();

    // ------ Stream handling ---------------------------------------
    SCTPSendStreamMap::iterator iterator = sendStreams.find(datMsg->getSid());
    SCTPSendStream*              stream  = iterator->second;
    uint32                           nextSSN     = stream->getNextStreamSeqNum();
    datVar->userData = datMsg->decapsulate();
    if (datMsg->getOrdered()) {
        // ------ Ordered mode: assign SSN ---------
        if (datMsg->getEBit())
        {
            datVar->ssn = nextSSN++;
        }
        else
        {
            datVar->ssn = nextSSN;
        }

        datVar->ordered = true;
        if (nextSSN > 65535) {
            stream->setNextStreamSeqNum(0);
        }
        else {
            stream->setNextStreamSeqNum(nextSSN);
        }
    }
    else {
        // ------ Ordered mode: no SSN needed ------
        datVar->ssn      = 0;
        datVar->ordered = false;
    }


    return(datVar);
}

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

Definition at line 1205 of file SCTPAssociationUtil.cc.

Referenced by processDataArrived().

{
    SCTPQueue* stream, dStream;
    uint32 sum  = 0;
    uint32 comp = 0;
    bool     delQ = false;
    uint32 high = state->highestTsnStored;

    sctpEV3 << "makeRoomForTsn: tsn=" << tsn
              << ", length=" << length << " high=" << high << endl;
    while ((sum < length) && (state->highestTsnReceived>state->lastTsnAck)) {
        comp = sum;
        for (SCTPReceiveStreamMap::iterator iter = receiveStreams.begin();
              iter!=receiveStreams.end(); iter++) {
            if (tsn > high) {
                return false;
            }
            if (uBit) {
                stream = iter->second->getUnorderedQ();
            }
            else {
                stream = iter->second->getOrderedQ();
            }
            SCTPDataVariables* chunk = stream->getChunk(high);
            if (chunk == NULL) {      //12.06.08
                sctpEV3 << high << " not found in orderedQ. Try deliveryQ" << endl;
                stream = iter->second->getDeliveryQ();
                chunk = stream->getChunk(high);
                delQ = true;
            }
            if (chunk != NULL) {
                sum+=chunk->len;
                if (stream->deleteMsg(high)) {
                    sctpEV3 << high << " found and deleted" << endl;

                    state->queuedReceivedBytes-=chunk->len/8; //12.06.08
                    if (ssnGt(iter->second->getExpectedStreamSeqNum(),chunk->ssn)) {
                        iter->second->setExpectedStreamSeqNum(chunk->ssn);
                    }
                }
                qCounter.roomSumRcvStreams -= ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH);
                if (high == state->highestTsnReceived) {
                    state->highestTsnReceived--;
                }
                removeFromGapList(high);

                if (tsn > state->highestTsnReceived) {
                    state->highestTsnReceived = tsn;
                }
                high--;
                break;
            }
            else {
                sctpEV3 << "TSN " << high << " not found in stream "
                          << iter->second->getStreamId() << endl;
            }
        }

        if (comp == sum) {
            sctpEV3 << high << " not found in any stream" << endl;
            high--;
        }
        state->highestTsnStored = high;

        if (tsn > state->highestTsnReceived) {
            return false;
        }
    }
    return true;
}

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

Definition at line 1524 of file SCTPAssociationUtil.cc.

Referenced by processDataArrived().

{
    SCTPDataVariables* chunk = new SCTPDataVariables();

    chunk->bbit = dataChunk->getBBit();
    chunk->ebit = dataChunk->getEBit();
    chunk->sid  = dataChunk->getSid();
    chunk->ssn  = dataChunk->getSsn();
    chunk->ppid = dataChunk->getPpid();
    chunk->tsn  = dataChunk->getTsn();
    if (!dataChunk->getUBit()) {
        chunk->ordered = true;
    }
    else {
        chunk->ordered = false;
    }
    SCTPSimpleMessage* smsg=check_and_cast<SCTPSimpleMessage*>(dataChunk->decapsulate());

    chunk->userData = smsg;
    chunk->len = smsg->getDataLen()*8;

    sctpEV3 << "makeVarFromMsg: queuedBytes has been increased to "
              << state->queuedReceivedBytes << endl;
    return chunk;
}

void SCTPAssociation::moveChunkToOtherPath ( SCTPDataVariables chunk,
SCTPPathVariables newPath 
) [private]

Definition at line 1687 of file SCTPAssociationRcvMessage.cc.

Referenced by process_TIMEOUT_RTX().

{
    // ====== Prepare next destination =======================================
    SCTPPathVariables* lastPath = chunk->getLastDestinationPath();
    chunk->hasBeenFastRetransmitted = false;
    chunk->gapReports                     = 0;
    chunk->setNextDestination(newPath);
    sctpEV3 << simTime() << ": Timer-Based RTX for TSN " << chunk->tsn
              << ": lastDestination=" << chunk->getLastDestination()
              << " nextDestination="  << chunk->getNextDestination() << endl;

    // ======= Remove chunk's booksize from outstanding bytes ================
    // T.D. 12.02.2010: This case may happen when using sender queue control!
    if(chunk->countsAsOutstanding) {
        assert(lastPath->outstandingBytes >= chunk->booksize);
        lastPath->outstandingBytes -= chunk->booksize;
        assert((int32)lastPath->outstandingBytes >= 0);
        state->outstandingBytes -= chunk->booksize;
        assert((int64)state->outstandingBytes >= 0);
        chunk->countsAsOutstanding = false;
        // T.D. 12.02.2010: No Timer-Based RTX is necessary any more when there
        //                        are no outstanding bytes!
        if(lastPath->outstandingBytes == 0) {
            stopTimer(lastPath->T3_RtxTimer);
        }
    }


    // ====== Perform bookkeeping ============================================
    // Check, if chunk_ptr->tsn is already in transmission queue.
    // This can happen in case multiple timeouts occur in succession.
    if (!transmissionQ->checkAndInsertChunk(chunk->tsn, chunk)) {
        sctpEV3 << "TSN " << chunk->tsn << " already in transmissionQ" << endl;
        return;
    }
    else {
        chunk->enqueuedInTransmissionQ = true;
        sctpEV3 << "Inserting TSN " << chunk->tsn << " into transmissionQ" << endl;
        CounterMap::iterator q = qCounter.roomTransQ.find(chunk->getNextDestination());
        q->second += ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH);
        CounterMap::iterator qb = qCounter.bookedTransQ.find(chunk->getNextDestination());
        qb->second += chunk->booksize;

        if (chunk->countsAsOutstanding) {
            decreaseOutstandingBytes(chunk);
        }
        state->peerRwnd += (chunk->booksize);
    }
    if (state->peerRwnd > state->initialPeerRwnd) {
        state->peerRwnd = state->initialPeerRwnd;
    }
    sctpEV3 << "T3 Timeout: Chunk (TSN=" << chunk->tsn
                << ") has been requeued in transmissionQ, rwnd was set to "
                << state->peerRwnd << endl;
}

bool SCTPAssociation::nextChunkFitsIntoPacket ( int32  bytes  )  [protected]

Definition at line 1825 of file SCTPAssociationUtil.cc.

Referenced by sendOnPath().

{
    int32 nextStream = -1;
    SCTPSendStream* stream;

    /* Only change stream if we don't have to finish a fragmented message */
    if (state->lastMsgWasFragment)
        nextStream = state->lastStreamScheduled;
    else
        nextStream = (this->*ssFunctions.ssGetNextSid)(true);

    if (nextStream == -1)
        return false;

    stream = sendStreams.find(nextStream)->second;

    if (stream)
    {
        cQueue* streamQ = NULL;

        if (!stream->getUnorderedStreamQ()->empty())
            streamQ = stream->getUnorderedStreamQ();
        else if (!stream->getStreamQ()->empty())
            streamQ = stream->getStreamQ();

        if (streamQ)
        {
            int32 b=ADD_PADDING( (check_and_cast<SCTPSimpleMessage*>(((SCTPDataMsg*)streamQ->front())->getEncapsulatedMsg())->getByteLength()+SCTP_DATA_CHUNK_LENGTH));

            /* Check if next message would be fragmented */
            if (b > (int32) state->assocPmtu - IP_HEADER_LENGTH - SCTP_COMMON_HEADER)
            {
                /* Test if fragment fits */
                if (bytes >= (int32) state->assocPmtu - IP_HEADER_LENGTH - SCTP_COMMON_HEADER - SCTP_DATA_CHUNK_LENGTH)
                    return true;
                else
                    return false;
            }

            /* Message doesn't need to be fragmented, just try if it fits */
            if (b <= bytes)
                return true;
            else
                return false;
        }
    }

    return false;
}

int32 SCTPAssociation::numUsableStreams ( void   )  [protected]

Definition at line 106 of file SCTPSSFunctions.cc.

{
    int32 count=0;

    for (SCTPSendStreamMap::iterator iter=sendStreams.begin(); iter!=sendStreams.end(); iter++)
        if (iter->second->getStreamQ()->length()>0 || iter->second->getUnorderedStreamQ()->length()>0)
        {
            count++;
        }
    return count;
}

void SCTPAssociation::pathStatusIndication ( const SCTPPathVariables path,
const bool  status 
) [protected]

Definition at line 2020 of file SCTPAssociationUtil.cc.

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

{
    cPacket* msg = new cPacket("StatusInfo");
    msg->setKind(SCTP_I_STATUS);
    SCTPStatusInfo* cmd = new SCTPStatusInfo();
    cmd->setPathId(path->remoteAddress);
    cmd->setAssocId(assocId);
    cmd->setActive(status);
    msg->setControlInfo(cmd);
    if (!status) {
        SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId);
        iter->second.numPathFailures++;
    }
    sendToApp(msg);
}

SCTPDataVariables * SCTPAssociation::peekAbandonedChunk ( const SCTPPathVariables path  )  [protected]

Definition at line 1591 of file SCTPAssociationUtil.cc.

{
    // Are there chunks in the retransmission queue? If Yes -> dequeue and return it.
    if (!retransmissionQ->payloadQueue.empty())
    {
        for(SCTPQueue::PayloadQueue::iterator it = retransmissionQ->payloadQueue.begin();
             it != retransmissionQ->payloadQueue.end(); it++) {
            SCTPDataVariables* chunk = it->second;
            sctpEV3<<"peek Chunk "<<chunk->tsn<<"\n";
            if (chunk->getLastDestinationPath() == path && chunk->hasBeenAbandoned) {
                sctpEV3<<"peekAbandonedChunk() found chunk in the retransmission queue\n";
                return chunk;
            }
        }
    }
    return NULL;
}

SCTPDataMsg * SCTPAssociation::peekOutboundDataMsg (  )  [protected]

Definition at line 1610 of file SCTPAssociationUtil.cc.

Referenced by calculateBytesToSendOnPath().

{
    SCTPDataMsg* datMsg=NULL;
    int32 nextStream = -1;
    nextStream = (this->*ssFunctions.ssGetNextSid)(true);

    if (nextStream == -1)
    {

        sctpEV3<<"peekOutboundDataMsg(): no valid stream found -> returning NULL !\n";

        return NULL;
    }


    for (SCTPSendStreamMap::iterator iter=sendStreams.begin(); iter!=sendStreams.end(); ++iter)
    {
        if ((int32)iter->first==nextStream)
        {
            SCTPSendStream* stream=iter->second;
            if (!stream->getUnorderedStreamQ()->empty())
            {
                    return (datMsg);

            }
            if (!stream->getStreamQ()->empty())
            {
                    return (datMsg);

            }
        }
    }
    return NULL;

}

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

Implemements the pure SCTP state machine

Definition at line 538 of file SCTPAssociationBase.cc.

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

{
    sctpEV3<<"performStateTransition\n";
    if (event==SCTP_E_IGNORE)   // e.g. discarded segment
    {
        ev << "Staying in state: " << stateName(fsm->getState()) << " (no FSM event)\n";
        return true;
    }

    // state machine
    int32 oldState = fsm->getState();
    switch (fsm->getState())
    {
        case SCTP_S_CLOSED:
            switch (event)
            {
                case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_OPEN_PASSIVE: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_ASSOCIATE: FSM_Goto((*fsm), SCTP_S_COOKIE_WAIT); break;
                case SCTP_E_RCV_INIT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_RCV_VALID_COOKIE_ECHO: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break;
                    case SCTP_E_CLOSE: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                default:;
            }
            break;

        case SCTP_S_COOKIE_WAIT:
            switch (event)
            {
                case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_RCV_INIT_ACK: FSM_Goto((*fsm), SCTP_S_COOKIE_ECHOED); break;
                case SCTP_E_RCV_VALID_COOKIE_ECHO: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break;
                default:;
            }
            break;

        case SCTP_S_COOKIE_ECHOED:
            switch (event)
            {
                case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_RCV_COOKIE_ACK:FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break;
                default:;
            }
            break;
        case SCTP_S_ESTABLISHED:
            switch (event)
            {
                case SCTP_E_SEND: FSM_Goto((*fsm), SCTP_S_ESTABLISHED); break;
                case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_PENDING);    break;
                case SCTP_E_STOP_SENDING: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_PENDING); state->stopSending = true; state->lastTSN = state->nextTSN-1; break;    //I.R.
                case SCTP_E_RCV_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_RECEIVED); break;
                case SCTP_E_CLOSE: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                default:;
            }
            break;

        case SCTP_S_SHUTDOWN_PENDING:
            switch (event)
            {
                case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_NO_MORE_OUTSTANDING: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_SENT); break;
                case SCTP_E_RCV_SHUTDOWN: FSM_Goto((*fsm), SCTP_S_SHUTDOWN_RECEIVED); break;
                case SCTP_E_RCV_SHUTDOWN_ACK: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                default:;
            }
            break;

        case SCTP_S_SHUTDOWN_RECEIVED:
            switch (event)
            {
                case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_NO_MORE_OUTSTANDING:
                            FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT);
                    break;
                case SCTP_E_SHUTDOWN: sendShutdownAck(remoteAddr); /*FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT);*/ break;
                default:;
            }
            break;

        case SCTP_S_SHUTDOWN_SENT:
            switch (event)
            {
                case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_RCV_SHUTDOWN_ACK: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_RCV_SHUTDOWN: sendShutdownAck(remoteAddr); FSM_Goto((*fsm), SCTP_S_SHUTDOWN_ACK_SENT); break;
                default:;
            }
            break;

        case SCTP_S_SHUTDOWN_ACK_SENT:
            switch (event)
            {
                case SCTP_E_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_RCV_ABORT: FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                case SCTP_E_RCV_SHUTDOWN_COMPLETE:      FSM_Goto((*fsm), SCTP_S_CLOSED); break;
                default:;
            }
            break;

    }

    if (oldState!=fsm->getState())
    {
        ev << "Transition: " << stateName(oldState) << " --> " << stateName(fsm->getState()) << "    (event was: " << eventName(event) << ")\n";
        sctpEV3 << sctpMain->getName() << ": " << stateName(oldState) << " --> " << stateName(fsm->getState()) << "  (on " << eventName(event) << ")\n";
        stateEntered(fsm->getState());
    }
    else
    {
        ev<< "Staying in state: " << stateName(fsm->getState()) << " (event was: " << eventName(event) << ")\n";
    }
    if (event==SCTP_E_ABORT && oldState==fsm->getState() && fsm->getState()==SCTP_S_CLOSED)
        return true;

    if (oldState!=fsm->getState() && fsm->getState()==SCTP_S_CLOSED)
    {
        sctpEV3<<"return false because oldState="<<oldState<<" and new state is closed\n";
        return false;
    }
    else
        return true;
}

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

Definition at line 2009 of file SCTPAssociationUtil.cc.

Referenced by processHeartbeatAckArrived(), and processSackArrived().

{
    path->pathErrorCount = 0;
    if (path->activePath == false) {
        /* notify the application */
        pathStatusIndication(path, true);
        sctpEV3 << "Path " << path->remoteAddress
                  << " state changes from INACTIVE to ACTIVE !!!" << endl;
    }
}

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

Definition at line 1932 of file SCTPAssociationUtil.cc.

Referenced by sendOnPath().

{
    /* restart hb_timer on this path */
    stopTimer(path->HeartbeatTimer);
    if (state->enableHeartbeats)
    {
        path->heartbeatTimeout = path->pathRto + (double)sctpMain->par("hbInterval");
        startTimer(path->HeartbeatTimer, path->heartbeatTimeout);
        sctpEV3 << "Restarting HB timer on path "<< path->remoteAddress
                  << " to expire at time " << path->heartbeatTimeout << endl;
    }

    path->cwndTimeout = path->pathRto;
    stopTimer(path->CwndTimer);
    startTimer(path->CwndTimer, path->cwndTimeout);

    sctpEV3 << "Restarting CWND timer on path "<< path->remoteAddress
              << " to expire at time " << path->cwndTimeout << endl;
}

void SCTPAssociation::pmRttMeasurement ( SCTPPathVariables path,
const simtime_t &  rttEstimation 
) [protected]

Definition at line 2037 of file SCTPAssociationUtil.cc.

Referenced by processHeartbeatAckArrived(), and processSackArrived().

{
    if (rttEstimation < MAXTIME) {
        if (simTime() > path->updateTime) {
            if (path->updateTime == SIMTIME_ZERO) {
                path->rttvar  = rttEstimation.dbl() / 2;
                path->srtt    = rttEstimation;
                path->pathRto = 3.0 * rttEstimation.dbl();
                path->pathRto = max(min(path->pathRto.dbl(), (double)sctpMain->par("rtoMax")),
                                          (double)sctpMain->par("rtoMin"));
            }
            else {
                path->rttvar  = (1.0 - (double)sctpMain->par("rtoBeta")) * path->rttvar.dbl() +
                                         (double)sctpMain->par("rtoBeta") * fabs(path->srtt.dbl() - rttEstimation.dbl());
                path->srtt    = (1.0 - (double)sctpMain->par("rtoAlpha")) * path->srtt.dbl() +
                                         (double)sctpMain->par("rtoAlpha") * rttEstimation.dbl();
                path->pathRto = path->srtt.dbl() + 4.0 * path->rttvar.dbl();
                path->pathRto = max(min(path->pathRto.dbl(), (double)sctpMain->par("rtoMax")),
                                          (double)sctpMain->par("rtoMin"));
            }
/*
            std::cout << simTime() << ": Updating timer values for path " << path->remoteAddress << ":"
                      << " RTO="              << path->pathRto
                      << " rttEstimation=" << rttEstimation
                      << " SRTT="             << path->srtt
                      << " -->  RTTVAR="      << path->rttvar << endl;
*/
            // RFC 2960, sect. 6.3.1: new RTT measurements SHOULD be made no more
            //                                than once per round-trip.
            path->updateTime = simTime() + path->srtt;
            path->statisticsPathRTO->record(path->pathRto);
            path->statisticsPathRTT->record(rttEstimation);
        }
    }
}

void SCTPAssociation::pmStartPathManagement (  )  [protected]

Flow control

Definition at line 1952 of file SCTPAssociationUtil.cc.

Referenced by stateEntered().

{
    RoutingTableAccess routingTableAccess;
    SCTPPathVariables* path;
    int32 i=0;
    /* populate path structures !!! */
    /* set a high start value...this is appropriately decreased later (below) */
    state->assocPmtu = state->localRwnd;
    for(SCTPPathMap::iterator piter=sctpPathMap.begin(); piter!=sctpPathMap.end(); piter++)
    {
        path=piter->second;
        path->pathErrorCount = 0;
        InterfaceEntry *rtie = routingTableAccess.get()->getInterfaceForDestAddr(path->remoteAddress.get4());
        path->pmtu = rtie->getMTU();
        sctpEV3 << "Path MTU of Interface "<< i << " = " << path->pmtu <<"\n";
        if (path->pmtu < state->assocPmtu)
        {
            state->assocPmtu = path->pmtu;
        }
        initCCParameters(path);
        path->pathRto = (double)sctpMain->par("rtoInitial");
        path->srtt = path->pathRto;
        path->rttvar = SIMTIME_ZERO;
        /* from now on we may have one update per RTO/SRTT */
        path->updateTime = SIMTIME_ZERO;


        path->partialBytesAcked = 0;
        path->outstandingBytes = 0;
        path->activePath = true;
        // Timer probably not running, but stop it anyway I.R.
        stopTimer(path->T3_RtxTimer);

        if (path->remoteAddress == state->initialPrimaryPath && !path->confirmed) {
            path->confirmed = true;
        }
        sctpEV3<<getFullPath()<<" numberOfLocalAddresses="<<state->localAddresses.size()<<"\n";
             path->heartbeatTimeout= (double)sctpMain->par("hbInterval")+i*path->pathRto;
             stopTimer(path->HeartbeatTimer);
             sendHeartbeat(path);
             startTimer(path->HeartbeatTimer, path->heartbeatTimeout);
             startTimer(path->HeartbeatIntervalTimer, path->heartbeatIntervalTimeout);
        path->statisticsPathRTO->record(path->pathRto);
        i++;
    }
}

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

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

Definition at line 472 of file SCTPAssociationBase.cc.

Referenced by processAppCommand().

{
    switch (commandCode) {
    case SCTP_C_ASSOCIATE:           return SCTP_E_ASSOCIATE;
    case SCTP_C_OPEN_PASSIVE:        return SCTP_E_OPEN_PASSIVE;
    case SCTP_C_SEND:                return SCTP_E_SEND;
    case SCTP_C_CLOSE:               return SCTP_E_CLOSE;
    case SCTP_C_ABORT:               return SCTP_E_ABORT;
    case SCTP_C_RECEIVE:             return SCTP_E_RECEIVE;
    case SCTP_C_SEND_UNORDERED:      return SCTP_E_SEND;
    case SCTP_C_SEND_ORDERED:        return SCTP_E_SEND;
    case SCTP_C_PRIMARY:             return SCTP_E_PRIMARY;
    case SCTP_C_QUEUE_MSGS_LIMIT:    return SCTP_E_QUEUE_MSGS_LIMIT;
    case SCTP_C_QUEUE_BYTES_LIMIT:   return SCTP_E_QUEUE_BYTES_LIMIT;
    case SCTP_C_SHUTDOWN:            return SCTP_E_SHUTDOWN;
    case SCTP_C_NO_OUTSTANDING:      return SCTP_E_SEND_SHUTDOWN_ACK;
    default:
        sctpEV3<<"commandCode="<<commandCode<<"\n";
        opp_error("Unknown message kind in app command");
                      return (SCTPEventCode)0; // to satisfy compiler
    }
}

void SCTPAssociation::printConnBrief (  )  [protected]

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

Definition at line 151 of file SCTPAssociationUtil.cc.

Referenced by processAppCommand(), and processSCTPMessage().

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

void SCTPAssociation::printOutstandingTsns (  )  [protected]
void SCTPAssociation::printSctpPathMap (  )  const

Definition at line 40 of file SCTPAssociationUtil.cc.

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

{
    sctpEV3 <<"SCTP PathMap:" << endl;
    for (SCTPPathMap::const_iterator iterator = sctpPathMap.begin();
          iterator != sctpPathMap.end(); ++iterator) {
        const SCTPPathVariables* path = iterator->second;
        sctpEV3 << " - " << path->remoteAddress << ":  osb=" << path->outstandingBytes
                  << " cwnd=" << path->cwnd << endl;
    }
}

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

Utility: prints important header fields

Definition at line 159 of file SCTPAssociationUtil.cc.

{
    sctpEV3 << "." << sctpmsg->getSrcPort() << " > ";
    sctpEV3 << "." << sctpmsg->getDestPort() << ": ";
    sctpEV3 << "initTag "<< sctpmsg->getTag() << "\n";
}

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

Definition at line 265 of file SCTPAssociationEventProc.cc.

Referenced by processAppCommand().

{
    sctpEV3 << "SCTPAssociationEventProc:process_ABORT; assoc=" << assocId << endl;
    switch(fsm->getState()) {
        case SCTP_S_ESTABLISHED:
            sendOnAllPaths(state->getPrimaryPath());
            sendAbort();
            break;
    }
}

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

Definition at line 31 of file SCTPAssociationEventProc.cc.

Referenced by processAppCommand().

{
    IPvXAddress lAddr, rAddr;

    SCTPOpenCommand *openCmd = check_and_cast<SCTPOpenCommand *>(sctpCommand);

    ev<<"SCTPAssociationEventProc:process_ASSOCIATE\n";

    switch(fsm->getState())
    {
        case SCTP_S_CLOSED:
        initAssociation(openCmd);
        state->active = true;
        localAddressList = openCmd->getLocalAddresses();
        lAddr = openCmd->getLocalAddresses().front();
        if (!(openCmd->getRemoteAddresses().empty()))
        {
            remoteAddressList = openCmd->getRemoteAddresses();
            rAddr = openCmd->getRemoteAddresses().front();
        }
        else
            rAddr = openCmd->getRemoteAddr();
        localPort = openCmd->getLocalPort();
        remotePort = openCmd->getRemotePort();
        state->numRequests = openCmd->getNumRequests();
        if (rAddr.isUnspecified() || remotePort==0)
        opp_error("Error processing command OPEN_ACTIVE: remote address and port must be specified");

        if (localPort==0)
        {
        localPort = sctpMain->getEphemeralPort();
        }
        ev << "OPEN: " << lAddr << ":" << localPort << " --> " << rAddr << ":" << remotePort << "\n";

        sctpMain->updateSockPair(this, lAddr, rAddr, localPort, remotePort);
        state->localRwnd = (long)sctpMain->par("arwnd");
        sendInit();
        startTimer(T1_InitTimer,state->initRexmitTimeout);
        break;

    default:
        opp_error("Error processing command OPEN_ACTIVE: connection already exists");
    }

}

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

Definition at line 249 of file SCTPAssociationEventProc.cc.

Referenced by processAppCommand().

{
    sctpEV3 << "SCTPAssociationEventProc:process_CLOSE; assoc=" << assocId << endl;
    switch(fsm->getState()) {
        case SCTP_S_ESTABLISHED:
            sendOnAllPaths(state->getPrimaryPath());
            sendShutdown();
            break;
        case SCTP_S_SHUTDOWN_RECEIVED:
            if (getOutstandingBytes() == 0) {
                sendShutdownAck(remoteAddr);
            }
            break;
     }
}

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

Definition at line 77 of file SCTPAssociationEventProc.cc.

Referenced by processAppCommand().

{
    IPvXAddress lAddr;
    int16 localPort;

    SCTPOpenCommand *openCmd = check_and_cast<SCTPOpenCommand *>(sctpCommand);

    sctpEV3<<"SCTPAssociationEventProc:process_OPEN_PASSIVE\n";

    switch(fsm->getState())
    {
        case SCTP_S_CLOSED:
            initAssociation(openCmd);
            state->fork = openCmd->getFork();
            localAddressList = openCmd->getLocalAddresses();
            sctpEV3<<"process_OPEN_PASSIVE: number of local addresses="<<localAddressList.size()<<"\n";
            lAddr = openCmd->getLocalAddresses().front();
            localPort = openCmd->getLocalPort();
            inboundStreams = openCmd->getInboundStreams();
            outboundStreams = openCmd->getOutboundStreams();
            state->localRwnd = (long)sctpMain->par("arwnd");
            state->numRequests = openCmd->getNumRequests();
            state->messagesToPush = openCmd->getMessagesToPush();

            if (localPort==0)
                opp_error("Error processing command OPEN_PASSIVE: local port must be specified");
            sctpEV3 << "Assoc "<<assocId<<"::Starting to listen on: " << lAddr << ":" << localPort << "\n";

            sctpMain->updateSockPair(this, lAddr, IPvXAddress(), localPort, 0);
            break;
        default:
        opp_error("Error processing command OPEN_PASSIVE: connection already exists");
    }
}

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

Definition at line 229 of file SCTPAssociationEventProc.cc.

Referenced by processAppCommand().

{
    SCTPPathInfo *pinfo = check_and_cast<SCTPPathInfo *>(sctpCommand);
    state->setPrimaryPath(getPath(pinfo->getRemoteAddress()));
}

void SCTPAssociation::process_QUEUE_BYTES_LIMIT ( const SCTPCommand *  sctpCommand  )  [protected]

Definition at line 243 of file SCTPAssociationEventProc.cc.

Referenced by processAppCommand().

{
    const SCTPInfo* qinfo = check_and_cast<const SCTPInfo*>(sctpCommand);
    state->sendQueueLimit = qinfo->getText();
}

void SCTPAssociation::process_QUEUE_MSGS_LIMIT ( const SCTPCommand *  sctpCommand  )  [protected]

Queue Management

Definition at line 236 of file SCTPAssociationEventProc.cc.

Referenced by processAppCommand().

{
    const SCTPInfo* qinfo = check_and_cast<const SCTPInfo*>(sctpCommand);
    state->queueLimit = qinfo->getText();
    sctpEV3<<"state->queueLimit set to "<<state->queueLimit<<"\n";
}

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

Definition at line 49 of file SCTPAssociationRcvMessage.cc.

Referenced by processSCTPMessage().

{
    // ====== Header checks ==================================================
    sctpEV3 << getFullPath()  << " SCTPAssociationRcvMessage:process_RCV_Message"
              << " localAddr="  << localAddr
              << " remoteAddr=" << remoteAddr << endl;
    if ((sctpmsg->hasBitError() || !sctpmsg->getChecksumOk()))
    {
        if (((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType() == INIT_ACK) {
            stopTimer(T1_InitTimer);
            sctpEV3 << "InitAck with bit-error. Retransmit Init" << endl;
            retransmitInit();
            startTimer(T1_InitTimer,state->initRexmitTimeout);
        }
        if (((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType() == COOKIE_ACK) {
            stopTimer(T1_InitTimer);
            sctpEV3 << "CookieAck with bit-error. Retransmit CookieEcho" << endl;
            retransmitCookieEcho();
            startTimer(T1_InitTimer,state->initRexmitTimeout);
        }
    }

    SCTPPathVariables* path      = getPath(src);
    const uint16 srcPort         = sctpmsg->getDestPort();
    const uint16 destPort        = sctpmsg->getSrcPort();
    const uint32 numberOfChunks = sctpmsg->getChunksArraySize();
    sctpEV3 << "numberOfChunks=" <<numberOfChunks << endl;

    state->sctpmsg = (SCTPMessage*)sctpmsg->dup();

    // ====== Handle chunks ==================================================
    bool trans              = true;
    bool sendAllowed        = false;
    bool dupReceived        = false;
    bool dataChunkReceived  = false;
    bool dataChunkDelivered = false;
    bool shutdownCalled     = false;
    for (uint32 i = 0; i < numberOfChunks; i++) {
        const SCTPChunk* header = (const SCTPChunk*)(sctpmsg->removeChunk());
        const uint8       type  = header->getChunkType();

        if ((type != INIT) &&
             (type != ABORT) &&
             (type != ERRORTYPE) &&
             (sctpmsg->getTag() != peerVTag)) {
            sctpEV3 << " VTag "<< sctpmsg->getTag() << " incorrect. Should be "
                      << peerVTag << " localVTag=" << localVTag << endl;
            return true;
        }

        switch (type) {
        case INIT:
            sctpEV3 << "SCTPAssociationRcvMessage: INIT received" << endl;
            SCTPInitChunk* initChunk;
            initChunk = check_and_cast<SCTPInitChunk*>(header);
            if ((initChunk->getNoInStreams() != 0) &&
                 (initChunk->getNoOutStreams() != 0) &&
                 (initChunk->getInitTag() != 0)) {
                trans = processInitArrived(initChunk, srcPort, destPort);
            }
            i = numberOfChunks-1;
            delete initChunk;
            break;
        case INIT_ACK:
            sctpEV3 << "SCTPAssociationRcvMessage: INIT_ACK received" << endl;
            if (fsm->getState() == SCTP_S_COOKIE_WAIT) {
                SCTPInitAckChunk* initAckChunk;
                initAckChunk = check_and_cast<SCTPInitAckChunk*>(header);
                if ((initAckChunk->getNoInStreams() != 0) &&
                    (initAckChunk->getNoOutStreams() != 0) &&
                    (initAckChunk->getInitTag() != 0)) {
                    trans = processInitAckArrived(initAckChunk);
                }
                else if (initAckChunk->getInitTag() == 0) {
                    sendAbort();
                    sctpMain->removeAssociation(this);
                }
                i = numberOfChunks-1;
                delete initAckChunk;
            }
            else {
                sctpEV3 << "INIT_ACK will be ignored" << endl;
            }
            break;
        case COOKIE_ECHO:
            sctpEV3 << "SCTPAssociationRcvMessage: COOKIE_ECHO received" << endl;
            SCTPCookieEchoChunk* cookieEchoChunk;
            cookieEchoChunk = check_and_cast<SCTPCookieEchoChunk*>(header);
            trans = processCookieEchoArrived(cookieEchoChunk,src);
            delete cookieEchoChunk;
            break;
        case COOKIE_ACK:
            sctpEV3 << "SCTPAssociationRcvMessage: COOKIE_ACK received" << endl;
            if (fsm->getState() == SCTP_S_COOKIE_ECHOED) {
                SCTPCookieAckChunk* cookieAckChunk;
                cookieAckChunk = check_and_cast<SCTPCookieAckChunk*>(header);
                trans = processCookieAckArrived();
                delete cookieAckChunk;
            }
            break;
        case DATA:
            sctpEV3 << "SCTPAssociationRcvMessage: DATA received" << endl;
            if (fsm->getState() == SCTP_S_COOKIE_ECHOED) {
                trans = performStateTransition(SCTP_E_RCV_COOKIE_ACK);
            }
            if (!(fsm->getState() == SCTP_S_SHUTDOWN_RECEIVED || fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)) {
                SCTPDataChunk* dataChunk;
                dataChunk = check_and_cast<SCTPDataChunk*>(header);
                if ((dataChunk->getByteLength()- 16) > 0) {
                    const SCTPEventCode event = processDataArrived(dataChunk);
                    if (event == SCTP_E_DELIVERED) {
                        dataChunkReceived    = true;
                        dataChunkDelivered = true;
                        state->sackAllowed = true;
                    }
                    else if (event==SCTP_E_SEND || event==SCTP_E_IGNORE) {
                        dataChunkReceived    = true;
                        state->sackAllowed = true;
                    }
                    else if (event==SCTP_E_DUP_RECEIVED) {
                        dupReceived = true;
                    }
                }
                else {
                    sendAbort();
                    sctpMain->removeAssociation(this);
                }
                delete dataChunk;
            }
            trans = true;
            break;
        case SACK:
        {
            sctpEV3 << "SCTPAssociationRcvMessage: SACK received" << endl;
            const int32 scount = qCounter.roomSumSendStreams;
            SCTPSackChunk* sackChunk;
            sackChunk = check_and_cast<SCTPSackChunk*>(header);
            processSackArrived(sackChunk);
            trans           = true;
            sendAllowed = true;
            delete sackChunk;
            if (getOutstandingBytes()==0 && transmissionQ->getQueueSize()==0 && scount==0) {
                if (fsm->getState() == SCTP_S_SHUTDOWN_PENDING) {
                    sctpEV3 << "No more packets: send SHUTDOWN" << endl;
                    sendShutdown();
                    trans               = performStateTransition(SCTP_E_NO_MORE_OUTSTANDING);
                    shutdownCalled = true;
                }
                else if (fsm->getState() == SCTP_S_SHUTDOWN_RECEIVED) {
                    sctpEV3 << "No more outstanding" << endl;
                    sendShutdownAck(remoteAddr);
                }
            }
            break;
        }
        case ABORT:
            SCTPAbortChunk* abortChunk;
            abortChunk = check_and_cast<SCTPAbortChunk*>(header);
            sctpEV3 << "SCTPAssociationRcvMessage: ABORT with T-Bit "
                      << abortChunk->getT_Bit() << " received" << endl;
            if (sctpmsg->getTag() == localVTag || sctpmsg->getTag() == peerVTag) {
                sendIndicationToApp(SCTP_I_ABORT);
                trans = performStateTransition(SCTP_E_ABORT);
            }
            delete abortChunk;
            break;
        case HEARTBEAT:
            sctpEV3 << "SCTPAssociationRcvMessage: HEARTBEAT received" << endl;
            SCTPHeartbeatChunk* heartbeatChunk;
            heartbeatChunk = check_and_cast<SCTPHeartbeatChunk*>(header);
            if (!(fsm->getState() == SCTP_S_CLOSED)) {
                sendHeartbeatAck(heartbeatChunk, dest, src);
            }
            trans = true;
            delete heartbeatChunk;
            if (path) {
                path->numberOfHeartbeatsRcvd++;
                path->pathRcvdHb->record(path->numberOfHeartbeatsRcvd);
            }
            break;
        case HEARTBEAT_ACK:
            sctpEV3 << "SCTPAssociationRcvMessage: HEARTBEAT_ACK received" << endl;
            if (fsm->getState() == SCTP_S_COOKIE_ECHOED) {
                trans = performStateTransition(SCTP_E_RCV_COOKIE_ACK);
            }
            SCTPHeartbeatAckChunk* heartbeatAckChunk;
            heartbeatAckChunk = check_and_cast<SCTPHeartbeatAckChunk*>(header);
            if (path) {
                processHeartbeatAckArrived(heartbeatAckChunk, path);
            }
            trans = true;
            delete heartbeatAckChunk;
            break;
        case SHUTDOWN:
            sctpEV3 << "SCTPAssociationRcvMessage: SHUTDOWN received" << endl;
            SCTPShutdownChunk* shutdownChunk;
            shutdownChunk = check_and_cast<SCTPShutdownChunk*>(header);
            if (shutdownChunk->getCumTsnAck()>state->lastTsnAck) {
                simtime_t rttEstimation = MAXTIME;
                dequeueAckedChunks(shutdownChunk->getCumTsnAck(),
                                         getPath(remoteAddr), rttEstimation);
                state->lastTsnAck = shutdownChunk->getCumTsnAck();
            }
            trans = performStateTransition(SCTP_E_RCV_SHUTDOWN);
            sendIndicationToApp(SCTP_I_SHUTDOWN_RECEIVED);
            trans = true;
            delete shutdownChunk;
            break;
        case SHUTDOWN_ACK:
            sctpEV3 << "SCTPAssociationRcvMessage: SHUTDOWN_ACK received" << endl;
            if (fsm->getState()!=SCTP_S_ESTABLISHED) {
                SCTPShutdownAckChunk* shutdownAckChunk;
                shutdownAckChunk = check_and_cast<SCTPShutdownAckChunk*>(header);
                sendShutdownComplete();
                stopTimers();
                stopTimer(T2_ShutdownTimer);
                stopTimer(T5_ShutdownGuardTimer);
                sctpEV3 << "state=" << stateName(fsm->getState()) << endl;
                if ((fsm->getState() == SCTP_S_SHUTDOWN_SENT) ||
                     (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)) {
                    trans = performStateTransition(SCTP_E_RCV_SHUTDOWN_ACK);
                    sendIndicationToApp(SCTP_I_CLOSED);
                    delete state->shutdownChunk;
                }
                delete shutdownAckChunk;
            }
            break;
        case SHUTDOWN_COMPLETE:
            sctpEV3<<"Shutdown Complete arrived" << endl;
            SCTPShutdownCompleteChunk* shutdownCompleteChunk;
            shutdownCompleteChunk = check_and_cast<SCTPShutdownCompleteChunk*>(header);
            trans = performStateTransition(SCTP_E_RCV_SHUTDOWN_COMPLETE);
            sendIndicationToApp(SCTP_I_PEER_CLOSED);     // necessary for NAT-Rendezvous
            if (trans == true) {
                stopTimers();
            }
            stopTimer(T2_ShutdownTimer);
            stopTimer(T5_ShutdownGuardTimer);
            delete state->shutdownAckChunk;
            delete shutdownCompleteChunk;
            break;
        default: sctpEV3<<"different type" << endl;
            break;
        }

        if (i==numberOfChunks-1 && (dataChunkReceived || dupReceived)) {
            sendAllowed=true;
            sctpEV3 << "i=" << i << " sendAllowed=true; scheduleSack" << endl;
            scheduleSack();
            if (fsm->getState() == SCTP_S_SHUTDOWN_SENT && state->ackState>=sackFrequency) {
                sendSack();
            }
        }

        // Send any new DATA chunks, SACK chunks, HEARTBEAT chunks etc.
        sctpEV3 << "SCTPAssociationRcvMessage: send new data? state=" << stateName(fsm->getState())
                  << " sendAllowed="        << sendAllowed
                  << " shutdownCalled=" << shutdownCalled << endl;
        if (((fsm->getState() == SCTP_S_ESTABLISHED) ||
              (fsm->getState() == SCTP_S_SHUTDOWN_PENDING) ||
              (fsm->getState() == SCTP_S_SHUTDOWN_RECEIVED)) &&
             (sendAllowed) &&
             (!shutdownCalled)) {
            sendOnAllPaths(state->getPrimaryPath());
        }
    }

    // ====== Clean-up =======================================================
    disposeOf(state->sctpmsg);
    return trans;
}

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

Definition at line 218 of file SCTPAssociationEventProc.cc.

Referenced by processAppCommand().

{
     SCTPSendCommand *sendCommand = check_and_cast<SCTPSendCommand *>(sctpCommand);
    if ((uint32)sendCommand->getSid() > inboundStreams || sendCommand->getSid() < 0)
    {
        sctpEV3<<"Application tries to read from invalid stream id....\n";
    }
    state->numMsgsReq[sendCommand->getSid()]+= sendCommand->getNumMsgs();
    pushUlp();
}

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

Definition at line 112 of file SCTPAssociationEventProc.cc.

Referenced by processAppCommand().

{
    SCTPSendCommand* sendCommand = check_and_cast<SCTPSendCommand*>(sctpCommand);

    if(fsm->getState() != SCTP_S_ESTABLISHED) {
        // TD 12.03.2009: since SCTP_S_ESTABLISHED is the only case, the
        // switch(...)-block has been removed for enhanced readability.
        sctpEV3 << "process_SEND: state is not SCTP_S_ESTABLISHED -> returning" << endl;
        return;
    }

    sctpEV3 << "process_SEND:"
              << " assocId="      << assocId
              << " localAddr="    << localAddr
              << " remoteAddr="   << remoteAddr
              << " cmdRemoteAddr="<< sendCommand->getRemoteAddr()
              << " cmdPrimary="   << (sendCommand->getPrimary() ? "true" : "false")
              << " appGateIndex=" << appGateIndex
              << " streamId="     << sendCommand->getSid() << endl;

    SCTPSimpleMessage* smsg = check_and_cast<SCTPSimpleMessage*>((msg->decapsulate()));
    SCTP::AssocStatMap::iterator iter = sctpMain->assocStatMap.find(assocId);
    iter->second.sentBytes += smsg->getBitLength() / 8;

  // ------ Prepare SCTPDataMsg -----------------------------------------
  const uint32 streamId       = sendCommand->getSid();
  const uint32 sendUnordered = sendCommand->getSendUnordered();
  const uint32 ppid           = sendCommand->getPpid();
  SCTPSendStream* stream = NULL;
  SCTPSendStreamMap::iterator associter = sendStreams.find(streamId);
  if (associter != sendStreams.end()) {
     stream = associter->second;
  }
  else {
     opp_error("stream with id %d not found", streamId);
  }

  char name[64];
  snprintf(name, sizeof(name), "SDATA-%d-%d", streamId, state->msgNum);
  smsg->setName(name);

  SCTPDataMsg* datMsg = new SCTPDataMsg();
  datMsg->encapsulate(smsg);
  datMsg->setSid(streamId);
  datMsg->setPpid(ppid);
  datMsg->setEnqueuingTime(simulation.getSimTime());

  // ------ Set initial destination address -----------------------------
  if (sendCommand->getPrimary()) {
     if (sendCommand->getRemoteAddr() == IPvXAddress("0.0.0.0")) {
            datMsg->setInitialDestination(remoteAddr);
     }
     else {
        datMsg->setInitialDestination(sendCommand->getRemoteAddr());
     }
  }
  else {
     datMsg->setInitialDestination(state->getPrimaryPathIndex());
  }

  // ------ Optional padding and size calculations ----------------------
     datMsg->setBooksize(smsg->getBitLength() / 8 + state->header);
     qCounter.roomSumSendStreams += ADD_PADDING(smsg->getBitLength() / 8 + SCTP_DATA_CHUNK_LENGTH);
     qCounter.bookedSumSendStreams += datMsg->getBooksize();
     state->sendBuffer += smsg->getByteLength();

  datMsg->setMsgNum(++state->msgNum);

  // ------ Ordered/Unordered modes -------------------------------------
  if (sendUnordered == 1) {
     datMsg->setOrdered(false);
     stream->getUnorderedStreamQ()->insert(datMsg);
  }
  else {
     datMsg->setOrdered(true);
     stream->getStreamQ()->insert(datMsg);

     if ((state->appSendAllowed)        &&
          (state->sendQueueLimit > 0) &&
          ((uint64)state->sendBuffer >= state->sendQueueLimit) ) {
        sendIndicationToApp(SCTP_I_SENDQUEUE_FULL);
        state->appSendAllowed = false;
     }
     sendQueue->record(stream->getStreamQ()->getLength());
  }

  state->queuedMessages++;
  if ((state->queueLimit > 0) && (state->queuedMessages > state->queueLimit)) {
     state->queueUpdate = false;
  }
  sctpEV3 << "process_SEND:"
             << " last="         << sendCommand->getLast()
             <<"    queueLimit=" << state->queueLimit << endl;

  // ------ Call sendCommandInvoked() to send message -------------------
  // sendCommandInvoked() itself will call sendOnAllPaths() ...
  if (sendCommand->getLast() == true) {
     if (sendCommand->getPrimary()) {
        sctpAlgorithm->sendCommandInvoked(NULL);
     }
     else {
        sctpAlgorithm->sendCommandInvoked(getPath(datMsg->getInitialDestination()));
     }
  }
}

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

Definition at line 276 of file SCTPAssociationEventProc.cc.

{
    SCTPStatusInfo *statusInfo = new SCTPStatusInfo();
    statusInfo->setState(fsm->getState());
    statusInfo->setStateName(stateName(fsm->getState()));
    statusInfo->setPathId(remoteAddr);
    statusInfo->setActive(getPath(remoteAddr)->activePath);
    msg->setControlInfo(statusInfo);
    sendToApp(msg);
}

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

Definition at line 1464 of file SCTPAssociationRcvMessage.cc.

Referenced by processTimer().

{
    bool oldState;

    /* check if error counters must be increased */
      if (path->activePath)
      {
             state->errorCount++;
             path->pathErrorCount++;

             sctpEV3<<"HB timeout timer expired for path "<<path->remoteAddress<<" --> Increase Error Counters (Assoc: "<<state->errorCount<<", Path: "<<path->pathErrorCount<<")\n";
      }

    /* RTO must be doubled for this path ! */
    path->pathRto = (simtime_t)min(2 * path->pathRto.dbl(), sctpMain->par("rtoMax"));
    path->statisticsPathRTO->record(path->pathRto);
    /* check if any thresholds are exceeded, and if so, check if ULP must be notified */
    if (state->errorCount > (uint32)sctpMain->par("assocMaxRetrans"))
    {
        sendIndicationToApp(SCTP_I_CONN_LOST);
        sendAbort();
        sctpMain->removeAssociation(this);
        return;
    }
    else
    {
        /* set path state to INACTIVE, if the path error counter is exceeded */
        if (path->pathErrorCount >   (uint32)sctpMain->par("pathMaxRetrans"))
        {
            oldState = path->activePath;
            path->activePath = false;
            if (path == state->getPrimaryPath()) {
                state->setPrimaryPath(getNextPath(path));
            }
            sctpEV3 << "pathErrorCount now "<< path->pathErrorCount
                      << "; PP now " << state->getPrimaryPathIndex() << endl;
        }
        /* then: we can check, if all paths are INACTIVE ! */
        if (allPathsInactive())
        {
            sctpEV3<<"sctp_do_hb_to_timer() : ALL PATHS INACTIVE --> closing ASSOC\n";
            sendIndicationToApp(SCTP_I_CONN_LOST);
            return;

        } else if (path->activePath == false && oldState == true)
        {
            /* notify the application, in case the PATH STATE has changed from ACTIVE to INACTIVE */
            pathStatusIndication(path, false);
        }

    }
}

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

Definition at line 1444 of file SCTPAssociationRcvMessage.cc.

Referenced by processTimer().

{

    sctpEV3<<"HB Interval timer expired -- sending new HB REQ on path "<<path->remoteAddress<<"\n";
    /* restart hb_send_timer on this path */
    stopTimer(path->HeartbeatIntervalTimer);
    stopTimer(path->HeartbeatTimer);
    path->heartbeatIntervalTimeout = (double)sctpMain->par("hbInterval") +  path->pathRto;
    path->heartbeatTimeout = path->pathRto;
    startTimer(path->HeartbeatIntervalTimer, path->heartbeatIntervalTimeout);
    if ((simTime() - path->lastAckTime > path->heartbeatIntervalTimeout/2) || path->forceHb)
    {
        sendHeartbeat(path);
        startTimer(path->HeartbeatTimer, path->heartbeatTimeout);

        path->forceHb = false;
    }
}

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

Definition at line 1395 of file SCTPAssociationRcvMessage.cc.

Referenced by processTimer().

{
    if (++state->initRetransCounter > (int32)sctpMain->par("maxInitRetrans"))
    {
        sctpEV3 << "Retransmission count during connection setup exceeds " << (int32)sctpMain->par("maxInitRetrans") << ", giving up\n";
        sendIndicationToApp(SCTP_I_CLOSED);
        sendAbort();
        sctpMain->removeAssociation(this);
        return;
    }
    sctpEV3<< "Performing retransmission #" << state->initRetransCounter << "\n";
    switch(fsm->getState())
    {
        case SCTP_S_COOKIE_WAIT: retransmitInit(); break;
        case SCTP_S_COOKIE_ECHOED: retransmitCookieEcho(); break;
        default:     opp_error("Internal error: INIT-REXMIT timer expired while in state %s", stateName(fsm->getState()));
    }
    state->initRexmitTimeout *= 2;
    if (state->initRexmitTimeout > SCTP_TIMEOUT_INIT_REXMIT_MAX)
        state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT_MAX;
    startTimer(T1_InitTimer,state->initRexmitTimeout);
}

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

Definition at line 1588 of file SCTPAssociationRcvMessage.cc.

Referenced by processTimer().

{
    sctpEV3 << "Processing retransmission timeout ..." << endl;

    // ====== Increase the RTO (by doubling it) ==============================
    path->pathRto = min(2 * path->pathRto.dbl(), sctpMain->par("rtoMax"));
    path->statisticsPathRTO->record(path->pathRto);
    sctpEV3 << "Schedule T3 based retransmission for path "<< path->remoteAddress << endl;

    // ====== Update congestion window =======================================
    (this->*ccFunctions.ccUpdateAfterRtxTimeout)(path);


    // ====== Error Counter Handling =========================================
    if (!state->zeroWindowProbing) {
        state->errorCount++;
        path->pathErrorCount++;
        sctpEV3 << "RTX-Timeout: errorCount increased to "<<path->pathErrorCount<<"  state->errorCount="<<state->errorCount<<"\n";
    }
    if (state->errorCount >= (uint32)sctpMain->par("assocMaxRetrans")) {
        /* error counter exceeded terminate the association -- create an SCTPC_EV_CLOSE event and send it to myself */

        sctpEV3 << "process_TIMEOUT_RTX : ASSOC ERROR COUNTER EXCEEDED, closing ASSOC" << endl;
        sendIndicationToApp(SCTP_I_CONN_LOST);
        sendAbort();
        sctpMain->removeAssociation(this);
        return 0;

    }
    else {
        if (path->pathErrorCount > (uint32)sctpMain->par("pathMaxRetrans")) {
            bool notifyUlp = false;

            sctpEV3 << "pathErrorCount exceeded\n";
            if (path->activePath) {
                /* tell the source */
                notifyUlp = true;
            }
            path->activePath = false;
            if (path->remoteAddress == state->getPrimaryPathIndex()) {
                SCTPPathVariables* nextPath = getNextPath(path);
                if (nextPath != NULL) {
                    state->setPrimaryPath(nextPath);
                }
            }
            sctpEV3 << "process_TIMEOUT_RTX(" << path->remoteAddress
                      << ") : PATH ERROR COUNTER EXCEEDED, path status is INACTIVE" << endl;
            if (allPathsInactive()) {
                sctpEV3 << "process_TIMEOUT_RTX: ALL PATHS INACTIVE --> connection LOST!" << endl;
                sendIndicationToApp(SCTP_I_CONN_LOST);
                sendAbort();
                sctpMain->removeAssociation(this);
                return 0;
            }
            else if (notifyUlp) {
                // Send notification to the application
                pathStatusIndication(path, false);
            }
        }
        sctpEV3 << "process_TIMEOUT_RTX(" << path->remoteAddress
                  << ") : PATH ERROR COUNTER now " << path->pathErrorCount << endl;
    }


    // ====== Do Retransmission ==============================================
    // dequeue all chunks not acked so far and put them in the TransmissionQ
    if (!retransmissionQ->payloadQueue.empty()) {
        sctpEV3 << "Still " << retransmissionQ->payloadQueue.size()
                  << " chunks in retransmissionQ" << endl;

        for (SCTPQueue::PayloadQueue::iterator iterator = retransmissionQ->payloadQueue.begin();
            iterator != retransmissionQ->payloadQueue.end(); iterator++) {
            SCTPDataVariables* chunk = iterator->second;
            assert(chunk != NULL);

            // ====== Insert chunks into TransmissionQ ============================
            // Only insert chunks that were sent to the path that has timed out
            if ( ((chunkHasBeenAcked(chunk) == false && chunk->countsAsOutstanding) || chunk->hasBeenReneged) &&
                  (chunk->getLastDestinationPath() == path) ) {
                sctpEV3 << simTime() << ": Timer-Based RTX for TSN "
                          << chunk->tsn << " on path " << chunk->getLastDestination() << endl;
                chunk->getLastDestinationPath()->numberOfTimerBasedRetransmissions++;
                SCTP::AssocStatMap::iterator iter = sctpMain->assocStatMap.find(assocId);
                iter->second.numT3Rtx++;

                moveChunkToOtherPath(chunk, getNextDestination(chunk));
            }
        }
    }


    SCTPPathVariables* nextPath = getNextPath(path);
    sctpEV3 << "TimeoutRTX: sendOnAllPaths()" << endl;
    sendOnAllPaths(nextPath);

    return 0;
}

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

Definition at line 1418 of file SCTPAssociationRcvMessage.cc.

Referenced by processTimer().

{

    if (++state->errorCount > (uint32)sctpMain->par("assocMaxRetrans"))
    {
        sendIndicationToApp(SCTP_I_CONN_LOST);
        sendAbort();
        sctpMain->removeAssociation(this);
        return;
    }

    sctpEV3 << "Performing shutdown retransmission. Assoc error count now "<<state->errorCount<<" \n";
    if(fsm->getState() == SCTP_S_SHUTDOWN_SENT)
    {
        retransmitShutdown();
    }
    else if (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)
        retransmitShutdownAck();

    state->initRexmitTimeout *= 2;
    if (state->initRexmitTimeout > SCTP_TIMEOUT_INIT_REXMIT_MAX)
        state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT_MAX;
    startTimer(T2_ShutdownTimer,state->initRexmitTimeout);
}

bool SCTPAssociation::processAppCommand ( cPacket *  msg  ) 

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

Definition at line 495 of file SCTPAssociationBase.cc.

Referenced by SCTP::handleMessage().

{
    printConnBrief();

    // first do actions
    SCTPCommand *sctpCommand = (SCTPCommand *)(msg->removeControlInfo());
    SCTPEventCode event = preanalyseAppCommandEvent(msg->getKind());

    sctpEV3 << "App command: " << eventName(event) << "\n";
    switch (event)
    {
        case SCTP_E_ASSOCIATE: process_ASSOCIATE(event, sctpCommand, msg); break;
        case SCTP_E_OPEN_PASSIVE: process_OPEN_PASSIVE(event, sctpCommand, msg); break;
        case SCTP_E_SEND: process_SEND(event, sctpCommand, msg); break;
        case SCTP_E_CLOSE: process_CLOSE(event); break;
        case SCTP_E_ABORT: process_ABORT(event); break;
        case SCTP_E_RECEIVE: process_RECEIVE_REQUEST(event, sctpCommand); break;
        case SCTP_E_PRIMARY: process_PRIMARY(event, sctpCommand); break;
        case SCTP_E_QUEUE_BYTES_LIMIT: process_QUEUE_BYTES_LIMIT(sctpCommand); break;
        case SCTP_E_QUEUE_MSGS_LIMIT:    process_QUEUE_MSGS_LIMIT(sctpCommand); break;
        case SCTP_E_SHUTDOWN: /*sendShutdown*/
        sctpEV3<<"SCTP_E_SHUTDOWN in state "<<stateName(fsm->getState())<<"\n";
            if (fsm->getState()==SCTP_S_SHUTDOWN_RECEIVED) {
            sctpEV3<<"send shutdown ack\n";
                sendShutdownAck(remoteAddr);
                }
            break;  //I.R.
        case SCTP_E_STOP_SENDING: break;
        case SCTP_E_SEND_SHUTDOWN_ACK:
                /*if (fsm->getState()==SCTP_S_SHUTDOWN_RECEIVED && getOutstandingBytes()==0
                    && qCounter.roomSumSendStreams==0 && transmissionQ->getQueueSize()==0)
                {
                    sendShutdownAck(state->primaryPathIndex);
                }*/
                break;
        default: opp_error("wrong event code");
    }
    delete sctpCommand;
    // then state transitions
    return performStateTransition(event);
}

bool SCTPAssociation::processCookieAckArrived (  )  [protected]

Definition at line 645 of file SCTPAssociationRcvMessage.cc.

Referenced by process_RCV_Message().

{
    bool trans=false;

    if (fsm->getState() == SCTP_S_COOKIE_ECHOED)
    {
        stopTimer(T1_InitTimer);
        trans=performStateTransition(SCTP_E_RCV_COOKIE_ACK);
        if (state->cookieChunk->getCookieArraySize()==0)
        {
                delete state->cookieChunk->getStateCookie();
        }
        delete state->cookieChunk;
        return trans;
    }
    else
        sctpEV3<<"State="<<fsm->getState()<<"\n";

    return trans;
}

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

Definition at line 554 of file SCTPAssociationRcvMessage.cc.

Referenced by process_RCV_Message().

{
    bool trans = false;
    SCTPCookie* cookie = check_and_cast<SCTPCookie*>(cookieEcho->getStateCookie());
    if (cookie->getCreationTime()+(int32)sctpMain->par("validCookieLifetime")<simTime())
    {
        sctpEV3<<"stale Cookie: sendAbort\n";
        sendAbort();
        delete cookie;
        return trans;
    }
    if (fsm->getState() == SCTP_S_CLOSED)
    {
        if (cookie->getLocalTag()!=localVTag || cookie->getPeerTag() != peerVTag)
        {
            bool same=true;
            for (int32 i=0; i<32; i++)
            {
                if (cookie->getLocalTieTag(i)!=state->localTieTag[i])
                {
                    same = false;
                    break;
                }
                if (cookie->getPeerTieTag(i)!=state->peerTieTag[i])
                {
                    same = false;
                    break;
                }
            }
            if (!same)
            {
                sendAbort();
                delete cookie;
                return trans;
            }
        }
        sctpEV3<<"State is CLOSED, Cookie_Ack has to be sent\n";
        trans=performStateTransition(SCTP_E_RCV_VALID_COOKIE_ECHO);
        if (trans)
            sendCookieAck(addr);//send to address
    }
    else if (fsm->getState() == SCTP_S_ESTABLISHED || fsm->getState() == SCTP_S_COOKIE_WAIT || fsm->getState() == SCTP_S_COOKIE_ECHOED)
    {
        sctpEV3<<"State is not CLOSED, but COOKIE_ECHO received. Compare the Tags\n";
        // case A: Peer restarted, retrieve information from cookie
        if (cookie->getLocalTag()!=localVTag && cookie->getPeerTag() != peerVTag )
        {
            bool same=true;
            for (int32 i=0; i<32; i++)
            {
                if (cookie->getLocalTieTag(i)!=state->localTieTag[i])
                {
                    same = false;
                    break;
                }
                if (cookie->getPeerTieTag(i)!=state->peerTieTag[i])
                {
                    same = false;
                    break;
                }
            }
            if (same)
            {
                localVTag = cookie->getLocalTag();
                peerVTag = cookie->getPeerTag();
                sendCookieAck(addr);
            }
        }
        // case B: Setup collision, retrieve information from cookie
        else if (cookie->getPeerTag()==peerVTag && (cookie->getLocalTag()!=localVTag || cookie->getLocalTag()==0))
        {
            localVTag = cookie->getLocalTag();
            peerVTag = cookie->getPeerTag();
            performStateTransition(SCTP_E_RCV_VALID_COOKIE_ECHO);
            sendCookieAck(addr);
        }
        else if (cookie->getPeerTag()==peerVTag && cookie->getLocalTag()==localVTag)
        {
            sendCookieAck(addr); //send to address src
        }
        trans=true;
    }
    else
    {
        sctpEV3<<"State="<<fsm->getState()<<"\n";
        trans = true;
    }
    delete cookie;
    return trans;
}

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

Definition at line 1242 of file SCTPAssociationRcvMessage.cc.

Referenced by process_RCV_Message().

{
    bool                     checkCtsnaChange = false;
    const uint32         tsn                    = dataChunk->getTsn();
    SCTPPathVariables* path                 = getPath(remoteAddr);

    state->newChunkReceived       = false;
    state->lastTsnReceived        = tsn;
    state->lastDataSourceAddress = remoteAddr;

    sctpEV3 << simTime() << " SCTPAssociation::processDataArrived TSN=" << tsn << endl;
    path->pathRcvdTSN->record(tsn);

    SCTPSimpleMessage* smsg = check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate());
    dataChunk->setBitLength(SCTP_DATA_CHUNK_LENGTH*8);
    dataChunk->encapsulate(smsg);
    const uint32 payloadLength = dataChunk->getBitLength()/8-SCTP_DATA_CHUNK_LENGTH;
    sctpEV3 << "state->bytesRcvd=" << state->bytesRcvd << endl;
    state->bytesRcvd+=payloadLength;
    sctpEV3 << "state->bytesRcvd now=" << state->bytesRcvd << endl;
    SCTP::AssocStatMap::iterator iter=sctpMain->assocStatMap.find(assocId);
    iter->second.rcvdBytes+=dataChunk->getBitLength()/8-SCTP_DATA_CHUNK_LENGTH;

    if (state->numGaps == 0) {
        state->highestTsnReceived = state->cTsnAck;
    }
    else {
        state->highestTsnReceived = state->gapStopList[state->numGaps-1];
    }
    if (state->stopReceiving) {
        return SCTP_E_IGNORE;
    }

    if (tsnLe(tsn, state->cTsnAck)) {
            sctpEV3 << "Duplicate TSN " << tsn << " (smaller than CumAck)" << endl;
            state->dupList.push_back(tsn);
            state->dupList.unique();
            delete check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate());
            return SCTP_E_DUP_RECEIVED;
    }


    if ((int32)(state->localRwnd-state->queuedReceivedBytes) <= 0) {
        if (tsnGt(tsn, state->highestTsnReceived)) {
            return SCTP_E_IGNORE;
        }
        // changed 06.07.05 I.R.
        else if ((!tsnIsDuplicate(tsn)) &&
                    (tsn < state->highestTsnStored)) {
            if (!makeRoomForTsn(tsn, dataChunk->getBitLength()-SCTP_DATA_CHUNK_LENGTH*8, dataChunk->getUBit())) {
                delete check_and_cast <SCTPSimpleMessage*>(dataChunk->decapsulate());
                return SCTP_E_IGNORE;
            }
        }
    }
    if (tsnGt(tsn, state->highestTsnReceived)) {
        sctpEV3 << "highestTsnReceived=" << state->highestTsnReceived
                  << " tsn=" << tsn << endl;
        state->highestTsnReceived = state->highestTsnStored = tsn;
        if (tsn == initPeerTsn) {
            state->cTsnAck = tsn;
        }
        else {
            sctpEV3 << "Update fragment list" << endl;
            checkCtsnaChange = updateGapList(tsn);
        }
        state->newChunkReceived = true;
    }
    else if (tsnIsDuplicate(tsn)) {
        // TSN value is duplicate within a fragment
        sctpEV3 << "Duplicate TSN " << tsn << " (copy)" << endl;
        state->dupList.push_back(tsn);
        state->dupList.unique();
        return SCTP_E_IGNORE;
    }
    else {
        checkCtsnaChange = updateGapList(tsn);
    }
    if (state->swsAvoidanceInvoked) {
        // swsAvoidanceInvoked => schedule a SACK to be sent at once in this case
        sctpEV3 << "swsAvoidanceInvoked" << endl;
        state->ackState = sackFrequency;
    }

    if (checkCtsnaChange) {
        advanceCtsna();
    }
    sctpEV3 << "cTsnAck=" << state->cTsnAck
              << " highestTsnReceived=" << state->highestTsnReceived << endl;

    SCTPEventCode event = SCTP_E_SEND;
    if (state->newChunkReceived) {
        SCTPReceiveStreamMap::iterator iter = receiveStreams.find(dataChunk->getSid());
        const int ret = iter->second->enqueueNewDataChunk(makeVarFromMsg(dataChunk));
        if (ret > 0) {
            state->queuedReceivedBytes+=payloadLength;

            event = SCTP_E_DELIVERED;
            if (ret < 3) {
                sendDataArrivedNotification(dataChunk->getSid());
                putInDeliveryQ(dataChunk->getSid());
            }
        }
        state->newChunkReceived = false;
    }

    return(event);
}

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

Definition at line 1352 of file SCTPAssociationRcvMessage.cc.

Referenced by process_RCV_Message().

{
    path->numberOfHeartbeatAcksRcvd++;
    path->pathRcvdHbAck->record(path->numberOfHeartbeatAcksRcvd);
    /* hb-ack goes to pathmanagement, reset error counters, stop timeout timer */
    const IPvXAddress addr          = hback->getRemoteAddr();
    const simtime_t hbTimeField = hback->getTimeField();
    stopTimer(path->HeartbeatTimer);
    /* assume a valid RTT measurement on this path */
    simtime_t rttEstimation = simTime() - hbTimeField;
    pmRttMeasurement(path, rttEstimation);
    pmClearPathCounter(path);
    path->confirmed = true;
    path->lastAckTime = simTime();
    if (path->primaryPathCandidate == true) {
        state->setPrimaryPath(getPath(addr));
        path->primaryPathCandidate = false;
        if (path->pmtu < state->assocPmtu) {
            state->assocPmtu = path->pmtu;
        }
        path->ssthresh = state->peerRwnd;
        recordCwndUpdate(path);
        path->heartbeatTimeout = (double)sctpMain->par("hbInterval") + path->pathRto;
    }

    if (path->activePath == false) {
        sctpEV3 << "HB ACK arrived activePath=false. remoteAddress=" <<path->remoteAddress
                  << " initialPP=" << state->initialPrimaryPath << endl;
        path->activePath = true;
        if (state->reactivatePrimaryPath && path->remoteAddress == state->initialPrimaryPath) {
            state->setPrimaryPath(path);
        }
        sctpEV3 << "primaryPath now " << state->getPrimaryPathIndex() << endl;
    }
    sctpEV3 << "Received HB ACK chunk...resetting error counters on path " << addr
              <<", rttEstimation=" << rttEstimation << endl;
    path->pathErrorCount = 0;
    return SCTP_E_IGNORE;
}

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

Definition at line 492 of file SCTPAssociationRcvMessage.cc.

Referenced by process_RCV_Message().

{
    bool trans = false;
    if (fsm->getState() == SCTP_S_COOKIE_WAIT)
    {
        sctpEV3<<"State is COOKIE_WAIT, Cookie_Echo has to be sent\n";
        stopTimer(T1_InitTimer);
        state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT;
        trans=performStateTransition(SCTP_E_RCV_INIT_ACK);
        //delete state->initChunk; will be deleted when state ESTABLISHED is entered
        if (trans)
        {
            state->initialPrimaryPath = remoteAddr;
            state->setPrimaryPath(getPath(remoteAddr));
            initPeerTsn=initAckChunk->getInitTSN();
            localVTag= initAckChunk->getInitTag();
            state->cTsnAck = initPeerTsn - 1;
            state->initialPeerRwnd = initAckChunk->getA_rwnd();
            state->peerRwnd = state->initialPeerRwnd;
            remoteAddressList.clear();
            numberOfRemoteAddresses =initAckChunk->getAddressesArraySize();
            sctpEV3<<"number of remote addresses in initAck="<<numberOfRemoteAddresses<<"\n";
            for (uint32 j=0; j<numberOfRemoteAddresses; j++)
            {
                if (initAckChunk->getAddresses(j).isIPv6())
                    continue;
                for (AddressVector::iterator k=state->localAddresses.begin(); k!=state->localAddresses.end(); ++k)
                {
                    if (!((*k).isUnspecified()))
                    {
                        sctpEV3<<"addPath "<<initAckChunk->getAddresses(j)<<"\n";
                        sctpMain->addRemoteAddress(this,(*k), initAckChunk->getAddresses(j));
                        this->remoteAddressList.push_back(initAckChunk->getAddresses(j));
                        addPath(initAckChunk->getAddresses(j));
                    }
                }
            }
            SCTPPathMap::iterator ite=sctpPathMap.find(remoteAddr);
            if (ite==sctpPathMap.end())
            {
                sctpEV3<<__LINE__<<" get new path for "<<remoteAddr<<"\n";
                SCTPPathVariables* path = new SCTPPathVariables(remoteAddr, this);
                sctpPathMap[remoteAddr] = path;
                qCounter.roomTransQ[remoteAddr]  = 0;
                qCounter.roomRetransQ[remoteAddr] = 0;
                qCounter.bookedTransQ[remoteAddr] = 0;
            }
            inboundStreams   = ((initAckChunk->getNoOutStreams()<inboundStreams)?initAckChunk->getNoOutStreams():inboundStreams);
            outboundStreams = ((initAckChunk->getNoInStreams()<outboundStreams)?initAckChunk->getNoInStreams():outboundStreams);
            (this->*ssFunctions.ssInitStreams)(inboundStreams, outboundStreams);
            sendCookieEcho(initAckChunk);
        }
        startTimer(T1_InitTimer, state->initRexmitTimeout);
    }
    else
        sctpEV3<<"State="<<fsm->getState()<<"\n";
    printSctpPathMap();
    return trans;
}

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

Process incoming SCTP packets. Invoked from process_RCV_Message

Definition at line 323 of file SCTPAssociationRcvMessage.cc.

Referenced by process_RCV_Message().

{
    SCTPAssociation* assoc;
    char timerName[128];
    bool trans = false;
    InterfaceTableAccess interfaceTableAccess;
    AddressVector adv;
    sctpEV3<<"processInitArrived\n";
    if (fsm->getState() == SCTP_S_CLOSED)
    {
        sctpEV3<<"fork="<<state->fork<<" initReceived="<<state->initReceived<<"\n";
        if (state->fork && !state->initReceived)
        {
            sctpEV3<<"cloneAssociation\n";
            assoc = cloneAssociation();
            sctpEV3<<"addForkedAssociation\n";
            sctpMain->addForkedAssociation(this, assoc, localAddr, remoteAddr, srcPort, destPort);

            sctpEV3 << "Connection forked: this connection got new assocId=" << assocId << ", "
                "spinoff keeps LISTENing with assocId=" << assoc->assocId << "\n";
            snprintf(timerName, sizeof(timerName), "T2_SHUTDOWN of assoc %d", assocId);
            T2_ShutdownTimer->setName(timerName);
            snprintf(timerName, sizeof(timerName), "T5_SHUTDOWN_GUARD of assoc %d", assocId);
            T5_ShutdownGuardTimer->setName(timerName);
            snprintf(timerName, sizeof(timerName), "SACK_TIMER of assoc %d", assocId);
            SackTimer->setName(timerName);
            snprintf(timerName, sizeof(timerName), "T1_INIT of assoc %d", assocId);
            T1_InitTimer->setName(timerName);
        }
        else
        {
            sctpMain->updateSockPair(this, localAddr, remoteAddr, srcPort, destPort);

        }
        if (!state->initReceived)
        {
            state->initReceived = true;
            state->initialPrimaryPath = remoteAddr;
            state->setPrimaryPath(getPath(remoteAddr));
            if (initchunk->getAddressesArraySize()==0)
            {
                sctpEV3<<__LINE__<<" get new path for "<<remoteAddr<<"\n";
                SCTPPathVariables* rPath = new SCTPPathVariables(remoteAddr, this);
                sctpPathMap[rPath->remoteAddress] = rPath;
                qCounter.roomTransQ[rPath->remoteAddress]     = 0;
                qCounter.bookedTransQ[rPath->remoteAddress] = 0;
                qCounter.roomRetransQ[rPath->remoteAddress] = 0;
            }
            initPeerTsn=initchunk->getInitTSN();
            state->cTsnAck = initPeerTsn - 1;
            state->initialPeerRwnd = initchunk->getA_rwnd();
            state->peerRwnd = state->initialPeerRwnd;
            localVTag= initchunk->getInitTag();
            numberOfRemoteAddresses =initchunk->getAddressesArraySize();
            IInterfaceTable *ift = interfaceTableAccess.get();
            state->localAddresses.clear();
            if (localAddressList.front() == IPvXAddress("0.0.0.0"))
            {
                for (int32 i=0; i<ift->getNumInterfaces(); ++i)
                {
                    if (ift->getInterface(i)->ipv4Data()!=NULL)
                    {
                        adv.push_back(ift->getInterface(i)->ipv4Data()->getIPAddress());
                    }
                    else if (ift->getInterface(i)->ipv6Data()!=NULL)
                    {
                        adv.push_back(ift->getInterface(i)->ipv6Data()->getAddress(0));
                    }
                }
            }
            else
            {
                adv = localAddressList;
            }
            uint32 rlevel = getLevel(remoteAddr);
            if (rlevel>0)
                for (AddressVector::iterator i=adv.begin(); i!=adv.end(); ++i)
                {
                    if (getLevel((*i))>=rlevel)
                    {
                        sctpMain->addLocalAddress(this, (*i));
                        state->localAddresses.push_back((*i));
                    }
                }
            for (uint32 j=0; j<initchunk->getAddressesArraySize(); j++)
            {
                // skip IPv6 because we can't send to them yet
                if (initchunk->getAddresses(j).isIPv6())
                    continue;
                // set path variables for this pathlocalAddresses
                if (!getPath(initchunk->getAddresses(j)))
                {
                    SCTPPathVariables* path = new SCTPPathVariables(initchunk->getAddresses(j), this);
                    sctpEV3<<__LINE__<<" get new path for "<<initchunk->getAddresses(j)<<" ptr="<<path<<"\n";
                    for (AddressVector::iterator k=state->localAddresses.begin(); k!=state->localAddresses.end(); ++k)
                    {
                        sctpMain->addRemoteAddress(this,(*k), initchunk->getAddresses(j));
                        this->remoteAddressList.push_back(initchunk->getAddresses(j));
                    }
                    sctpPathMap[path->remoteAddress] = path;
                    qCounter.roomTransQ[path->remoteAddress]     = 0;
                    qCounter.bookedTransQ[path->remoteAddress] = 0;
                    qCounter.roomRetransQ[path->remoteAddress] = 0;
                }
            }
            SCTPPathMap::iterator ite=sctpPathMap.find(remoteAddr);
            if (ite==sctpPathMap.end())
            {
                SCTPPathVariables* path = new SCTPPathVariables(remoteAddr, this);
                sctpEV3<<__LINE__<<" get new path for "<<remoteAddr<<" ptr="<<path<<"\n";
                sctpPathMap[remoteAddr] = path;
                qCounter.roomTransQ[remoteAddr]  = 0;
                qCounter.bookedTransQ[remoteAddr] = 0;
                qCounter.roomRetransQ[remoteAddr] = 0;
            }
            trans = performStateTransition(SCTP_E_RCV_INIT);
            if (trans) {
                sendInitAck(initchunk);
            }
        }
        else if (fsm->getState() == SCTP_S_CLOSED)
        {
            trans=performStateTransition(SCTP_E_RCV_INIT);
            if (trans) {
                sendInitAck(initchunk);
            }
        }
        else {
            trans = true;
        }
    }
    else if (fsm->getState() == SCTP_S_COOKIE_WAIT) //INIT-Collision
    {
        sctpEV3<<"INIT collision: send Init-Ack\n";
        sendInitAck(initchunk);
        trans=true;
    }
    else if (fsm->getState() == SCTP_S_COOKIE_ECHOED || fsm->getState() == SCTP_S_ESTABLISHED)
    {
        // check, whether a new address has been added
        bool addressPresent = false;
        for (uint32 j=0; j<initchunk->getAddressesArraySize(); j++)
        {
            if (initchunk->getAddresses(j).isIPv6())
                continue;
            for (AddressVector::iterator k=remoteAddressList.begin(); k!=remoteAddressList.end(); ++k)
            {
                if ((*k)==(initchunk->getAddresses(j)))
                {
                    addressPresent = true;
                    break;
                }
            }
            if (!addressPresent)
            {
                sendAbort();
                return true;
            }
        }
        sendInitAck(initchunk);
        trans=true;
    }
    else if (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)
        trans = true;
    printSctpPathMap();
    return trans;
}

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

Definition at line 709 of file SCTPAssociationRcvMessage.cc.

Referenced by process_RCV_Message().

{
    simtime_t            rttEstimation            = MAXTIME;
    bool                     ctsnaAdvanced            = false;
    SCTPPathVariables* path                       = getPath(remoteAddr);    // Path for *this* SACK!
    const uint64         arwnd                    = sackChunk->getA_rwnd();
    const uint32         tsna                         = sackChunk->getCumTsnAck();
    uint32               highestNewAck            = tsna;   // Highest newly acked TSN
    const uint16         numGaps                      = sackChunk->getNumGaps();
    bool                     getChunkFastFirstTime = true;

    // ====== Print some information =========================================
    sctpEV3 << "##### SACK Processing: TSNa=" << tsna << " #####" << endl;
    for(SCTPPathMap::iterator piter = sctpPathMap.begin(); piter != sctpPathMap.end(); piter++) {
        SCTPPathVariables* myPath = piter->second;
        sctpEV3 << "Path " << myPath->remoteAddress << ":\t"
                  << "outstanding="          << path->outstandingBytes << "\t"
                  << "T3scheduled="          << path->T3_RtxTimer->getArrivalTime() << " "
                  << (path->T3_RtxTimer->isScheduled() ? "[ok]" : "[NOT SCHEDULED]") << "\t"
                  << endl;
    }



    // ====== Initialize some variables ======================================
    for(SCTPPathMap::iterator piter = sctpPathMap.begin(); piter != sctpPathMap.end(); piter++) {
        SCTPPathVariables* myPath = piter->second;
        // T.D. 26.03.09: Remember outstanding bytes before this update
        // Values are necessary for updating the congestion window!
        myPath->outstandingBytesBeforeUpdate = myPath->outstandingBytes;     // T.D. 14.11.09: Bugfix - copy from myPath, not from path!
        myPath->requiresRtx                      = false;
        myPath->lowestTSNRetransmitted       = false;
        myPath->findLowestTSN                    = true;
        myPath->gapAcksInLastSACK                = 0;
        myPath->gapNAcksInLastSACK               = 0;
        myPath->newlyAckedBytes                  = 0;
        if (myPath == path) {
            myPath->lastAckTime = simTime();
        }
    }


    // ====== Zero Window Probing ============================================
    if ( (state->zeroWindowProbing) && (arwnd > 0) ) {
        state->zeroWindowProbing = false;
    }


    // #######################################################################
    // #### Processing of CumAck                                                         ####
    // #######################################################################

    if (tsnGt(tsna, state->lastTsnAck)) {    // Handle new CumAck
        sctpEV3 << "===== Handling new CumAck for TSN " << tsna << " =====" << endl;


        // We have got new chunks acked, and our cum ack point is advanced ...
        // Depending on the parameter osbWithHeader ackedBytes are with or without the header bytes.
        // T.D. 23.03.09: path->newlyAckedBytes is updated in dequeueAckedChunks()!
        dequeueAckedChunks(tsna, path, rttEstimation); // chunks with tsn between lastTsnAck and tsna are removed from the transmissionQ and the retransmissionQ; outstandingBytes are decreased

        state->lastTsnAck = tsna;
        ctsnaAdvanced = true;
    }
    else if (tsnLt(tsna, state->lastTsnAck)) {
        sctpEV3 << "Stale CumAck (" << tsna << " < " << state->lastTsnAck << ")"
                  << endl;
        return SCTP_E_IGNORE;
    }


    // ====== Handle reneging ================================================
    if ((numGaps == 0) && (tsnLt(tsna, state->highestTsnAcked))) {
        // Reneging, type 0:
        // In a previous SACK, chunks up to highestTsnAcked have been acked.
        // This SACK contains a CumAck < highestTsnAcked
        //      => rereg TSNs from CumAck+1 to highestTsnAcked
        //      => new highestTsnAcked = CumAck
        sctpEV3 << "numGaps=0 && tsna " << tsna
                  << " < highestTsnAcked " << state->highestTsnAcked << endl;
        uint32 i = state->highestTsnAcked;
        while (i >= tsna + 1) {
            SCTPDataVariables* myChunk = retransmissionQ->getChunk(i);
            if(myChunk) {
                if(chunkHasBeenAcked(myChunk)) {
                    tsnWasReneged(myChunk,
                                      0);
                }
            }
            i--;
        }
        state->highestTsnAcked = tsna;
    }


    // #######################################################################
    // #### Processing of GapAcks                                                        ####
    // #######################################################################

    if ((numGaps > 0) && (!retransmissionQ->payloadQueue.empty()) ) {
        sctpEV3 << "===== Handling GapAcks after CumTSNAck " << tsna << " =====" << endl;
        sctpEV3 << "We got " << numGaps << " gap reports" << endl;

        // We got fragment reports... check for newly acked chunks.
        const uint32 queuedChunks = retransmissionQ->payloadQueue.size();
        sctpEV3 << "Number of chunks in retransmissionQ: " << queuedChunks
                  <<" highestGapStop: "  << sackChunk->getGapStop(numGaps-1)
                  <<" highestTsnAcked: " << state->highestTsnAcked << endl;

        // ====== Handle reneging =============================================
        // highest gapStop smaller than highestTsnAcked: there might have been reneging
        if (tsnLt(sackChunk->getGapStop(numGaps-1), state->highestTsnAcked)) {
            // Reneging, type 2:
            // In a previous SACK, chunks up to highestTsnAcked have been acked.
            // This SACK contains a last gap ack < highestTsnAcked
            //      => rereg TSNs from last gap ack to highestTsnAcked
            //      => new highestTsnAcked = last gap ack
            uint32 i = state->highestTsnAcked;
            while (i >= sackChunk->getGapStop(numGaps - 1) + 1) {
                // ====== Looking up TSN in retransmission queue ================
                SCTPDataVariables* myChunk = retransmissionQ->getChunk(i);
                if(myChunk) {
                    if (chunkHasBeenAcked(myChunk)) {
                        sctpEV3 << "TSN " << i << " was found. It has been un-acked." << endl;
                        tsnWasReneged(myChunk,
                                          2);
                        sctpEV3 << "highestTsnAcked now " << state->highestTsnAcked << endl;
                    }
                }
                else {
                    sctpEV3 << "TSN " << i << " not found in retransmissionQ" << endl;
                }
                i--;
            }
            state->highestTsnAcked = sackChunk->getGapStop(numGaps - 1);
        }

        // ====== Looking for changes in the gap reports ======================
        sctpEV3 << "Looking for changes in gap reports" << endl;
        for (int32 key = 0;key < numGaps; key++) {
            const uint32 lo = sackChunk->getGapStart(key);
            const uint32 hi = sackChunk->getGapStop(key);


            // ====== Iterate over TSNs in gap reports =========================
            sctpEV3 << "Examine TSNs between " << lo << " and " << hi << endl;
            for (uint32 pos = lo; pos <= hi; pos++) {
                SCTPDataVariables* myChunk = retransmissionQ->getChunkFast(pos, getChunkFastFirstTime);
                if (myChunk) {
                    if(chunkHasBeenAcked(myChunk) == false) {
                        SCTPPathVariables* myChunkLastPath = myChunk->getLastDestinationPath();
                        assert(myChunkLastPath != NULL);
                        // T.D. 02.02.2010: This chunk has been acked newly.
                        //                        Let's process this new acknowledgement!
                        handleChunkReportedAsAcked(highestNewAck, rttEstimation, myChunk,
                                                            path /* i.e. the SACK path for RTT measurement! */);
                    }
                }
            }
        }
        state->highestTsnAcked = sackChunk->getGapStop(numGaps-1);

        // ====== Examine chunks between the gap reports ======================
        // They might have to be retransmitted or they could have been removed
        uint32 lo = tsna;
        for (int32 key = 0; key < numGaps; key++) {
            const uint32 hi = sackChunk->getGapStart(key);
            for (uint32 pos = lo+1; pos <= hi - 1; pos++) {
                SCTPDataVariables* myChunk = retransmissionQ->getChunkFast(pos, getChunkFastFirstTime);
                if(myChunk) {
                    handleChunkReportedAsMissing(sackChunk, highestNewAck, myChunk,
                                                          path /* i.e. the SACK path for RTT measurement! */);
                }
                else {
                    sctpEV3 << "TSN " << pos << " not found in retransmissionQ" << endl;
                }
            }
            lo = sackChunk->getGapStop(key);
        }


        // ====== Validity checks =============================================
    }


    // ====== Update Fast Recovery status, according to SACK =================
    updateFastRecoveryStatus(state->lastTsnAck);

    // ====== Update RTT measurement for newly acked data chunks =============
    sctpEV3 << simTime() << ": SACK: rtt=" << rttEstimation
              << ", path=" << path->remoteAddress << endl;
    pmRttMeasurement(path, rttEstimation);



    // #######################################################################
    // #### Receiver Window Management                                               ####
    // #######################################################################

    const uint32 osb = getOutstandingBytes();
    state->peerRwnd = arwnd - osb;

    // position of statement changed 20.07.05 I.R.
    if ((int32)(state->peerRwnd) < 0) {
        state->peerRwnd = 0;
    }
    if (state->peerRwnd > state->initialPeerRwnd) {
        state->peerRwnd = state->initialPeerRwnd;
    }
    if (arwnd == 1 || state->peerRwnd < state->swsLimit || arwnd == 0) {
        sctpEV3 << "processSackArrived: arwnd=" << arwnd
                  << " state->peerRwnd=" << state->peerRwnd
                  << " set peerWindowFull" << endl;
        state->peerWindowFull = true;
    }
    else
    {
        state->peerWindowFull    = false;
        state->zeroWindowProbing = false;
    }
#ifdef PVIATE
    advancePeerTsn();
#endif

    // ====== Need for zero-window probing? ==================================
    if(osb == 0) {
        if (arwnd == 0)
            state->zeroWindowProbing = true;
    }


    // #######################################################################
    // #### Congestion Window Management                                             ####
    // #######################################################################

    sctpEV3 << "Before ccUpdateBytesAcked: ";
    for(SCTPPathMap::iterator piter = sctpPathMap.begin(); piter != sctpPathMap.end(); piter++) {
        SCTPPathVariables* myPath    = piter->second;
        const IPvXAddress& myPathId = myPath->remoteAddress;


        if(myPath->newlyAckedBytes > 0) {
            // T.D. 07.10.2009: Only call ccUpdateBytesAcked() when there are
            //                        acked bytes on this path!
            const bool advanceWindow = myPath->newCumAck;

            sctpEV3 << simTime() << ":\tCC " << myPath->newlyAckedBytes
                      << " newly acked on path " << myPathId << ";"
                      << "\t->\tadvanceWindow="       << advanceWindow << endl;

            (this->*ccFunctions.ccUpdateBytesAcked)(myPath, myPath->newlyAckedBytes, advanceWindow);
        }
    }

    // ====== Update congestion windows on paths (handling decreases) ========
    sctpEV3 << "Before ccUpdateAfterSack with tsna=" << tsna << endl;
    // ccUpdateAfterSack() will iterate over all paths.
    (this->*ccFunctions.ccUpdateAfterSack)();


    // #######################################################################
    // #### Path Management                                                              ####
    // #######################################################################

    // ====== Need to stop or restart T3 timer? ==============================
    for(SCTPPathMap::iterator piter = sctpPathMap.begin(); piter != sctpPathMap.end(); piter++) {
        SCTPPathVariables* myPath    = piter->second;
        const IPvXAddress& myPathId = myPath->remoteAddress;

        if (myPath->outstandingBytes == 0) {
            // T.D. 07.01.2010: Only stop T3 timer when there is nothing more to send on this path!
            if(qCounter.roomTransQ.find(myPath->remoteAddress)->second == 0) {
                // Stop T3 timer, if there are no more outstanding bytes.
                stopTimer(myPath->T3_RtxTimer);
            }
        }
        else if (myPath->newCumAck) {
            stopTimer(myPath->T3_RtxTimer);
            startTimer(myPath->T3_RtxTimer, myPath->pathRto);
        }
        else {
            /* Also restart T3 timer, when lowest TSN is rtx'ed */
            if(myPath->lowestTSNRetransmitted == true) {
                sctpEV3 << "Lowest TSN retransmitted => restart of T3 timer for path "
                            << myPathId << endl;
                stopTimer(myPath->T3_RtxTimer);
                startTimer(myPath->T3_RtxTimer, myPath->pathRto);
            }
        }

        // ====== Clear error counter if TSNs on path have been acked =========
        if (myPath->newlyAckedBytes > 0) {
            pmClearPathCounter(myPath);
        }
    }



    return SCTP_E_IGNORE;
}

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

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

Definition at line 458 of file SCTPAssociationBase.cc.

Referenced by SCTP::handleMessage().

{
    printConnBrief();

    localAddr  = msgDestAddr;
    localPort  = sctpmsg->getDestPort();
    remoteAddr = msgSrcAddr;
    remotePort = sctpmsg->getSrcPort();

    return process_RCV_Message(sctpmsg, msgSrcAddr, msgDestAddr);
}

bool SCTPAssociation::processTimer ( cMessage *  msg  ) 

Definition at line 390 of file SCTPAssociationBase.cc.

Referenced by SCTP::handleMessage().

{
    SCTPPathVariables* path = NULL;

    sctpEV3 << msg->getName() << " timer expired at "<<simulation.getSimTime()<<"\n";

    SCTPPathInfo* pinfo = check_and_cast<SCTPPathInfo*>(msg->getControlInfo());
    IPvXAddress addr = pinfo->getRemoteAddress();

    if (addr != IPvXAddress("0.0.0.0"))
        path = getPath(addr);
     // first do actions
    SCTPEventCode event;
    event = SCTP_E_IGNORE;
    if (msg==T1_InitTimer)
    {
        process_TIMEOUT_INIT_REXMIT(event);
    }
    else if (msg==SackTimer)
    {
    sctpEV3<<simulation.getSimTime()<<" delayed Sack: cTsnAck="<<state->cTsnAck<<" highestTsnReceived="<<state->highestTsnReceived<<" lastTsnReceived="<<state->lastTsnReceived<<" ackState="<<state->ackState<<" numGaps="<<state->numGaps<<"\n";
        sendSack();
    }
    else if (msg==T2_ShutdownTimer)
    {
        stopTimer(T2_ShutdownTimer);
        process_TIMEOUT_SHUTDOWN(event);
    }
    else if (msg==T5_ShutdownGuardTimer)
    {
        stopTimer(T5_ShutdownGuardTimer);
        delete state->shutdownChunk;
        sendIndicationToApp(SCTP_I_CONN_LOST);
        sendAbort();
        sctpMain->removeAssociation(this);
    }
    else if (path!=NULL && msg==path->HeartbeatIntervalTimer)
    {
        process_TIMEOUT_HEARTBEAT_INTERVAL(path, path->forceHb);
    }
    else if (path!=NULL && msg==path->HeartbeatTimer)
    {
        process_TIMEOUT_HEARTBEAT(path);
    }
    else if (path!=NULL && msg==path->T3_RtxTimer)
    {
        process_TIMEOUT_RTX(path);
    }
    else if (path!=NULL && msg==path->CwndTimer)
    {
        (this->*ccFunctions.ccUpdateAfterCwndTimeout)(path);
    }
    else if (strcmp(msg->getName(), "StartTesting")==0)
    {
        if (sctpMain->testing == false)
        {
            sctpMain->testing = true;
            sctpEV3<<"set testing to true\n";
        }
    }
    else
    {
        sctpAlgorithm->processTimer(msg, event);
    }
     // then state transitions
     return performStateTransition(event);
}

void SCTPAssociation::pushUlp (  )  [protected]

Definition at line 1051 of file SCTPAssociationUtil.cc.

Referenced by process_RECEIVE_REQUEST().

{
    int32                    count = 0;

    for (unsigned int i = 0; i < inboundStreams; i++) { //12.06.08
        putInDeliveryQ(i);
    }
    if (state->pushMessagesLeft <= 0) {
        state->pushMessagesLeft = state->messagesToPush;
    }
    bool restrict = false;
    if (state->pushMessagesLeft > 0) {
        restrict = true;
    }


    sctpEV3 << simTime() << " Calling pushUlp(" << state->queuedReceivedBytes
              << " bytes queued) ..." << endl;
    uint32 i = state->nextRSid;
    do {
        SCTPReceiveStreamMap::iterator iter = receiveStreams.find(i);
        SCTPReceiveStream* rStream = iter->second;
        sctpEV3 << "Size of stream " << iter->first << ": "
                  << rStream->getDeliveryQ()->getQueueSize() << endl;

        while ( (!rStream->getDeliveryQ()->payloadQueue.empty()) &&
                  (!restrict || (restrict && state->pushMessagesLeft>0)) ) {
            SCTPDataVariables* chunk = rStream->getDeliveryQ()->extractMessage();
            qCounter.roomSumRcvStreams -= ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH);

            if (state->pushMessagesLeft >0)
                state->pushMessagesLeft--;

            state->queuedReceivedBytes-=chunk->len/8;
            if (state->swsAvoidanceInvoked) {
                if ((int32)(state->localRwnd - state->queuedReceivedBytes) >= (int32)(state->swsLimit) &&
                     (int32)(state->localRwnd - state->queuedReceivedBytes) <= (int32)(state->swsLimit+state->assocPmtu)) {
                    /* only if the window has opened up more than one MTU we will send a SACK */
                    state->swsAvoidanceInvoked = false;
                    sctpEV3<<"pushUlp: Window opens up to "<<(int32)state->localRwnd-state->queuedReceivedBytes<<" bytes: sending a SACK. SWS Avoidance INACTIVE\n";

                    sendSack();
                }
            }
            else if ((int32)(state->swsLimit) == 0) {
                sendSack();
            }
            sctpEV3 << "Push TSN " << chunk->tsn
                      << ": sid="     << chunk->sid << " ssn=" << chunk->ssn << endl;
            cPacket* msg= (cPacket *)chunk->userData;
            msg->setKind(SCTP_I_DATA);
            SCTPRcvCommand *cmd = new SCTPRcvCommand("push");
            cmd->setAssocId(assocId);
            cmd->setGate(appGateIndex);
            cmd->setSid(chunk->sid);
            cmd->setSsn(chunk->ssn);
            cmd->setSendUnordered(!chunk->ordered);
            cmd->setLocalAddr(localAddr);
            cmd->setRemoteAddr(remoteAddr);
            cmd->setPpid(chunk->ppid);
            cmd->setTsn(chunk->tsn);
            cmd->setCumTsn(state->lastTsnAck);
            msg->setControlInfo(cmd);
            state->numMsgsReq[count]--;
            delete chunk;
            sendToApp(msg);
        }
        i = (i + 1) % inboundStreams;
        count++;
    } while (i != state->nextRSid);

    state->nextRSid = (state->nextRSid + 1) % inboundStreams;
    if ( (state->queuedReceivedBytes == 0) && (fsm->getState() == SCTP_S_SHUTDOWN_ACK_SENT)) {
        sctpEV3 << "SCTP_E_CLOSE" << endl;
        performStateTransition(SCTP_E_CLOSE);
    }
}

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

Definition at line 1009 of file SCTPAssociationUtil.cc.

Referenced by processDataArrived(), and pushUlp().

{
    SCTPReceiveStreamMap::iterator iter=receiveStreams.find(sid);
    SCTPReceiveStream* rStream = iter->second;
    sctpEV3 << "putInDeliveryQ: SSN=" << rStream->getExpectedStreamSeqNum()
              << " SID=" << sid
              << " QueueSize="<< rStream->getOrderedQ()->getQueueSize() << endl;
    while (rStream->getOrderedQ()->getQueueSize()>0)
    {
        /* dequeue first from reassembly Q */
        SCTPDataVariables* chunk =
            rStream->getOrderedQ()-> dequeueChunkBySSN(rStream->getExpectedStreamSeqNum());
        if (chunk) {
            sctpEV3 << "putInDeliveryQ::chunk " <<chunk->tsn
                      <<", sid " << chunk->sid <<" and ssn " << chunk->ssn
                      <<" dequeued from ordered queue. queuedReceivedBytes="
                      << state->queuedReceivedBytes << " will be reduced by "
                      << chunk->len/8 << endl;
            state->queuedReceivedBytes-=chunk->len/8;


            qCounter.roomSumRcvStreams -= ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH);
            if (rStream->getDeliveryQ()->checkAndInsertChunk(chunk->tsn, chunk)) {
                state->queuedReceivedBytes += chunk->len/8;

                sctpEV3 << "data put in deliveryQ; queuedBytes now "
                          << state->queuedReceivedBytes << endl;
                qCounter.roomSumRcvStreams += ADD_PADDING(chunk->len/8 + SCTP_DATA_CHUNK_LENGTH);
                int32 seqnum=rStream->getExpectedStreamSeqNum();
                rStream->setExpectedStreamSeqNum(++seqnum);
                if (rStream->getExpectedStreamSeqNum() > 65535) {
                    rStream->setExpectedStreamSeqNum(0);
                }
                sendDataArrivedNotification(sid);
            }
        }
        else {
            break;
        }
    }
}

void SCTPAssociation::putInTransmissionQ ( uint32  tsn,
SCTPDataVariables chunk 
) [protected]
void SCTPAssociation::recordCwndUpdate ( SCTPPathVariables path  )  [private]
void SCTPAssociation::recordInPathVectors ( SCTPMessage pMsg,
const IPvXAddress rDest 
) [protected]

Definition at line 190 of file SCTPAssociationUtil.cc.

Referenced by sendToIP().

{
    uint32 n_chunks = pMsg->getChunksArraySize();
    if (n_chunks == 0)
       return;

    SCTPPathVariables* p_path = getPath(rDest);

    for (uint32 i = 0 ; i < n_chunks ; i++) {
        const SCTPChunk* p_chunk = check_and_cast<const SCTPChunk *>(pMsg->getChunks(i));
        if (p_chunk->getChunkType() == DATA) {
            const SCTPDataChunk* p_data_chunk = check_and_cast<const SCTPDataChunk *>(p_chunk);
            p_path->pathTSN->record(p_data_chunk->getTsn());
        } else if (p_chunk->getChunkType() == HEARTBEAT) {
            p_path->numberOfHeartbeatsSent++;
            p_path->pathHb->record(p_path->numberOfHeartbeatsSent);
        } else if (p_chunk->getChunkType() == HEARTBEAT_ACK) {
            p_path->numberOfHeartbeatAcksSent++;
            p_path->pathHbAck->record(p_path->numberOfHeartbeatAcksSent);
        }
    }
}

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

Definition at line 1292 of file SCTPAssociationUtil.cc.

Referenced by makeRoomForTsn().

{
    int32 gapsize, numgaps;

    numgaps = state->numGaps;
    sctpEV3<<"remove TSN "<<removedTsn<<" from GapList. "<<numgaps<<" gaps present, cumTsnAck="<<state->cTsnAck<<"\n";
    for (int32 j=0; j<numgaps; j++)
        sctpEV3<<state->gapStartList[j]<<" - "<<state->gapStopList[j]<<"\n";
    for (int32 i=numgaps-1; i>=0; i--)
    {
        sctpEV3<<"gapStartList["<<i<<"]="<<state->gapStartList[i]<<", state->gapStopList["<<i<<"]="<<state->gapStopList[i]<<"\n";
        if (tsnBetween(state->gapStartList[i], removedTsn, state->gapStopList[i]))
        {
            gapsize = (int32)(state->gapStopList[i] - state->gapStartList[i]+1);
            if (gapsize>1)
            {
                if (state->gapStopList[i]==removedTsn)
                {
                    state->gapStopList[i]--;
                }
                else if (state->gapStartList[i]==removedTsn)
                {
                    state->gapStartList[i]++;
                }
                else //gap is split in two
                {
                    for (int32 j=numgaps-1; j>=i; j--)
                    {
                        state->gapStopList[j+1] = state->gapStopList[j];
                        state->gapStartList[j+1] = state->gapStartList[j];
                    }
                    state->gapStopList[i] = removedTsn-1;
                    state->gapStartList[i+1] = removedTsn+1;
                    state->numGaps = min(state->numGaps + 1, MAX_GAP_COUNT);      // T.D. 18.12.09: Enforce upper limit!
                }
            }
            else
            {
                for (int32 j=i; j<=numgaps-1; j++)
                {
                    state->gapStopList[j] = state->gapStopList[j+1];
                    state->gapStartList[j] = state->gapStartList[j+1];
                }
                state->gapStartList[numgaps-1]=0;
                state->gapStopList[numgaps-1]=0;
                state->numGaps--;
                if (state->numGaps == 0)
                {
                    if (removedTsn == state->lastTsnAck+1)
                    {
                        state->lastTsnAck = removedTsn;
                    }
                }
            }
        }
    }
    if (state->numGaps>0)
        state->highestTsnReceived = state->gapStopList[state->numGaps-1];
    else
        state->highestTsnReceived = state->cTsnAck;
}

void SCTPAssociation::removePath (  ) 

Definition at line 768 of file SCTPAssociationBase.cc.

Referenced by SCTP::removeAssociation().

{
    SCTPPathMap::iterator pathIterator;
    while((pathIterator = sctpPathMap.begin()) != sctpPathMap.end())
    {
        SCTPPathVariables* path = pathIterator->second;
        sctpEV3 << getFullPath() << " remove path " << path->remoteAddress << endl;
        stopTimer(path->HeartbeatTimer);
        delete path->HeartbeatTimer;
        stopTimer(path->HeartbeatIntervalTimer);
        sctpEV3 << "delete timer " << path->HeartbeatIntervalTimer->getName() << endl;
        delete path->HeartbeatIntervalTimer;
        stopTimer(path->T3_RtxTimer);
        delete path->T3_RtxTimer;
        stopTimer(path->CwndTimer);
        delete path->CwndTimer;
        delete path;
        sctpPathMap.erase(pathIterator);
    }
}

void SCTPAssociation::removePath ( const IPvXAddress addr  ) 

Definition at line 1170 of file SCTPAssociationUtil.cc.

{
    SCTPPathMap::iterator pathIterator = sctpPathMap.find(addr);
    if (pathIterator != sctpPathMap.end())
    {
        SCTPPathVariables* path = pathIterator->second;
        path->cwnd      = 0;
        path->ssthresh = 0;
        recordCwndUpdate(path);

        stopTimer(path->HeartbeatTimer);
        delete path->HeartbeatTimer;
        stopTimer(path->HeartbeatIntervalTimer);
        delete path->HeartbeatIntervalTimer;
        stopTimer(path->T3_RtxTimer);
        delete path->T3_RtxTimer;
        stopTimer(path->CwndTimer);
        delete path->CwndTimer;
        sctpPathMap.erase(pathIterator);
        delete path;
    }
}

void SCTPAssociation::retransmitCookieEcho (  )  [protected]

Definition at line 660 of file SCTPAssociationUtil.cc.

Referenced by process_RCV_Message(), and process_TIMEOUT_INIT_REXMIT().

{
    SCTPMessage*                 sctpmsg = new SCTPMessage();
    sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
    SCTPCookieEchoChunk* cookieEchoChunk=check_and_cast<SCTPCookieEchoChunk*>(state->cookieChunk->dup());
    if (cookieEchoChunk->getCookieArraySize()==0)
    {
        cookieEchoChunk->setStateCookie(state->cookieChunk->getStateCookie()->dup());
    }
    sctpmsg->addChunk(cookieEchoChunk);

    sctpEV3<<"retransmitCookieEcho localAddr="<<localAddr<<"     remoteAddr"<<remoteAddr<<"\n";

    sendToIP(sctpmsg);
}

void SCTPAssociation::retransmitInit (  )  [protected]

Retransmitting chunks

Definition at line 471 of file SCTPAssociationUtil.cc.

Referenced by process_RCV_Message(), and process_TIMEOUT_INIT_REXMIT().

{
    SCTPMessage *sctpmsg = new SCTPMessage();
    sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
    SCTPInitChunk *sctpinit;// = new SCTPInitChunk("INIT");

    sctpEV3<<"Retransmit InitChunk="<<&sctpinit<<"\n";

    sctpinit=check_and_cast<SCTPInitChunk *>(state->initChunk->dup());
    sctpinit->setChunkType(INIT);
    sctpmsg->addChunk(sctpinit);

    sendToIP(sctpmsg);
}

void SCTPAssociation::retransmitShutdown (  )  [protected]

Definition at line 824 of file SCTPAssociationUtil.cc.

Referenced by process_TIMEOUT_SHUTDOWN().

{
    SCTPMessage *sctpmsg = new SCTPMessage();
    sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
    SCTPShutdownChunk* shutdownChunk;
    shutdownChunk=check_and_cast<SCTPShutdownChunk*>(state->shutdownChunk->dup());
    sctpmsg->addChunk(shutdownChunk);

    sctpEV3<<"retransmitShutdown localAddr="<<localAddr<<"  remoteAddr"<<remoteAddr<<"\n";

    sendToIP(sctpmsg);
}

void SCTPAssociation::retransmitShutdownAck (  )  [protected]

Definition at line 837 of file SCTPAssociationUtil.cc.

Referenced by process_TIMEOUT_SHUTDOWN().

{
    SCTPMessage *sctpmsg = new SCTPMessage();
    sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
    SCTPShutdownAckChunk* shutdownAckChunk;
    shutdownAckChunk=check_and_cast<SCTPShutdownAckChunk*>(state->shutdownAckChunk->dup());
    sctpmsg->addChunk(shutdownAckChunk);

    sctpEV3<<"retransmitShutdownAck localAddr="<<localAddr<<"  remoteAddr"<<remoteAddr<<"\n";

    sendToIP(sctpmsg);
}

void SCTPAssociation::scheduleSack (  )  [protected]

Definition at line 851 of file SCTPAssociationUtil.cc.

Referenced by process_RCV_Message().

{
    /* increase SACK counter, we received another data PACKET */
    if (state->firstChunkReceived)
        state->ackState++;
    else
    {
        state->ackState = sackFrequency;
        state->firstChunkReceived = true;
    }

    sctpEV3<<"scheduleSack() : ackState is now: "<<state->ackState<<"\n";

    if (state->ackState <= sackFrequency - 1)
    {
        /* start a SACK timer if none is running, to expire 200 ms (or parameter) from now */
        if (!SackTimer->isScheduled())
        {
             startTimer(SackTimer, sackPeriod);
        }
        /* else: leave timer running, and do nothing... */ else {
            /* is this possible at all ? Check this... */

            sctpEV3<<"SACK timer running, but scheduleSack() called\n";

        }
    }
}

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

Utility: start a timer

Definition at line 735 of file SCTPAssociation.h.

Referenced by SCTPAssociation(), and startTimer().

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

void SCTPAssociation::sendAbort (  )  [protected]

Definition at line 780 of file SCTPAssociationUtil.cc.

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

{
    SCTPMessage *msg = new SCTPMessage();
    msg->setBitLength(SCTP_COMMON_HEADER*8);

    sctpEV3<<"SCTPAssociationUtil:sendABORT localPort="<<localPort<<"    remotePort="<<remotePort<<"\n";

    msg->setSrcPort(localPort);
    msg->setDestPort(remotePort);
    SCTPAbortChunk* abortChunk = new SCTPAbortChunk("ABORT");
    abortChunk->setChunkType(ABORT);
    abortChunk->setT_Bit(0);
    abortChunk->setBitLength(SCTP_ABORT_CHUNK_LENGTH*8);
    msg->addChunk(abortChunk);
    sendToIP(msg, remoteAddr);
}

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

Definition at line 719 of file SCTPAssociationUtil.cc.

Referenced by processCookieEchoArrived().

{
    SCTPMessage *sctpcookieack = new SCTPMessage();
    sctpcookieack->setBitLength(SCTP_COMMON_HEADER*8);

    sctpEV3<<"SCTPAssociationUtil:sendCookieACK\n";

    sctpcookieack->setSrcPort(localPort);
    sctpcookieack->setDestPort(remotePort);
    SCTPCookieAckChunk* cookieAckChunk=new SCTPCookieAckChunk("COOKIE_ACK");
    cookieAckChunk->setChunkType(COOKIE_ACK);
    cookieAckChunk->setBitLength(SCTP_COOKIE_ACK_LENGTH*8);
    sctpcookieack->addChunk(cookieAckChunk);
    sendToIP(sctpcookieack, dest);
}

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

Definition at line 615 of file SCTPAssociationUtil.cc.

Referenced by processInitAckArrived().

{
    SCTPMessage *sctpcookieecho = new SCTPMessage();
    sctpcookieecho->setBitLength(SCTP_COMMON_HEADER*8);

    sctpEV3<<"SCTPAssociationUtil:sendCookieEcho\n";

    sctpcookieecho->setSrcPort(localPort);
    sctpcookieecho->setDestPort(remotePort);
    SCTPCookieEchoChunk* cookieEchoChunk=new SCTPCookieEchoChunk("COOKIE_ECHO");
    cookieEchoChunk->setChunkType(COOKIE_ECHO);
    int32 len = initAckChunk->getCookieArraySize();
    cookieEchoChunk->setCookieArraySize(len);
    if (len>0)
    {
        for (int32 i=0; i<len; i++)
            cookieEchoChunk->setCookie(i, initAckChunk->getCookie(i));
        cookieEchoChunk->setBitLength((SCTP_COOKIE_ACK_LENGTH+len)*8);
    }
    else
    {
        SCTPCookie* cookie = check_and_cast <SCTPCookie*> (initAckChunk->getStateCookie());
        cookieEchoChunk->setStateCookie(cookie);
        cookieEchoChunk->setBitLength(SCTP_COOKIE_ACK_LENGTH*8 + cookie->getBitLength());
    }
    uint32 unknownLen = initAckChunk->getUnrecognizedParametersArraySize();
    if (unknownLen>0)
    {
        sctpEV3<<"Found unrecognized Parameters in INIT-ACK chunk with a length of "<<unknownLen<<" bytes.\n";
        cookieEchoChunk->setUnrecognizedParametersArraySize(unknownLen);
        for (uint32 i=0; i<unknownLen; i++)
            cookieEchoChunk->setUnrecognizedParameters(i,initAckChunk->getUnrecognizedParameters(i));
    }
    else
        cookieEchoChunk->setUnrecognizedParametersArraySize(0);
    state->cookieChunk=check_and_cast<SCTPCookieEchoChunk*>(cookieEchoChunk->dup());
    if (len==0)
    {
        state->cookieChunk->setStateCookie(initAckChunk->getStateCookie()->dup());
            }
    sctpcookieecho->addChunk(cookieEchoChunk);
        sendToIP(sctpcookieecho);
}

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

Definition at line 992 of file SCTPAssociationUtil.cc.

Referenced by processDataArrived(), and putInDeliveryQ().

{

    sctpEV3<<"SendDataArrivedNotification\n";

    cPacket* cmsg = new cPacket("DataArrivedNotification");
    cmsg->setKind(SCTP_I_DATA_NOTIFICATION);
    SCTPCommand *cmd = new SCTPCommand("notification");
    cmd->setAssocId(assocId);
    cmd->setSid(sid);
    cmd->setNumMsgs(1);
    cmsg->setControlInfo(cmd);

    sendToApp(cmsg);
}

void SCTPAssociation::sendEstabIndicationToApp (  )  [protected]

Utility: sends SCTP_I_ESTABLISHED indication with SCTPConnectInfo to application

Definition at line 290 of file SCTPAssociationUtil.cc.

Referenced by stateEntered().

{
    sctpEV3 << "sendEstabIndicationToApp: localPort="
              << localPort << " remotePort=" << remotePort << endl;

    cPacket* msg = new cPacket(indicationName(SCTP_I_ESTABLISHED));
    msg->setKind(SCTP_I_ESTABLISHED);

    SCTPConnectInfo* establishIndication = new SCTPConnectInfo("CI");
    establishIndication->setAssocId(assocId);
    establishIndication->setLocalAddr(localAddr);
    establishIndication->setRemoteAddr(remoteAddr);
    establishIndication->setLocalPort(localPort);
    establishIndication->setRemotePort(remotePort);
    establishIndication->setRemoteAddresses(remoteAddressList);
    establishIndication->setInboundStreams(inboundStreams);
    establishIndication->setOutboundStreams(outboundStreams);
    establishIndication->setNumMsgs(state->sendQueueLimit);
    msg->setControlInfo(establishIndication);
    sctpMain->send(msg, "to_appl", appGateIndex);

}

void SCTPAssociation::sendHeartbeat ( const SCTPPathVariables path  )  [protected]

Definition at line 676 of file SCTPAssociationUtil.cc.

Referenced by pmStartPathManagement(), and process_TIMEOUT_HEARTBEAT_INTERVAL().

{
    SCTPMessage* sctpHeartbeatbeat = new SCTPMessage();
    sctpHeartbeatbeat->setBitLength(SCTP_COMMON_HEADER*8);

    sctpHeartbeatbeat->setSrcPort(localPort);
    sctpHeartbeatbeat->setDestPort(remotePort);
    SCTPHeartbeatChunk* heartbeatChunk = new SCTPHeartbeatChunk("HEARTBEAT");
    heartbeatChunk->setChunkType(HEARTBEAT);
    heartbeatChunk->setRemoteAddr(path->remoteAddress);
    heartbeatChunk->setTimeField(simTime());
    heartbeatChunk->setBitLength((SCTP_HEARTBEAT_CHUNK_LENGTH+12)*8);
    sctpHeartbeatbeat->addChunk(heartbeatChunk);
    sctpEV3 << "sendHeartbeat: sendToIP to " << path->remoteAddress << endl;
    sendToIP(sctpHeartbeatbeat, path->remoteAddress);
}

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

Definition at line 693 of file SCTPAssociationUtil.cc.

Referenced by process_RCV_Message().

{
    SCTPMessage*                 sctpHeartbeatAck = new SCTPMessage();
    sctpHeartbeatAck->setBitLength(SCTP_COMMON_HEADER*8);
    sctpHeartbeatAck->setSrcPort(localPort);
    sctpHeartbeatAck->setDestPort(remotePort);
    SCTPHeartbeatAckChunk* heartbeatAckChunk=new SCTPHeartbeatAckChunk("HEARTBEAT_ACK");
    heartbeatAckChunk->setChunkType(HEARTBEAT_ACK);
    heartbeatAckChunk->setRemoteAddr(heartbeatChunk->getRemoteAddr());
    heartbeatAckChunk->setTimeField(heartbeatChunk->getTimeField());
    const int32 len = heartbeatChunk->getInfoArraySize();
    if (len > 0){
        heartbeatAckChunk->setInfoArraySize(len);
        for (int32 i=0; i<len; i++)
            heartbeatAckChunk->setInfo(i,heartbeatChunk->getInfo(i));
    }

    heartbeatAckChunk->setBitLength(heartbeatChunk->getBitLength());
    sctpHeartbeatAck->addChunk(heartbeatAckChunk);

    sctpEV3 << "sendHeartbeatAck: sendToIP from " << src << " to " << dest << endl;
    sendToIP(sctpHeartbeatAck, dest);
}

void SCTPAssociation::sendIndicationToApp ( const int32  code,
const int32  value = 0 
) [protected]

Utility: sends status indication (SCTP_I_xxx) to application

Definition at line 272 of file SCTPAssociationUtil.cc.

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

{
    sctpEV3<<"sendIndicationToApp: " << indicationName(code) << endl;

    cPacket* msg = new cPacket(indicationName(code));
    msg->setKind(code);

    SCTPCommand* indication = new SCTPCommand(indicationName(code));
    indication->setAssocId(assocId);
    indication->setLocalAddr(localAddr);
    indication->setRemoteAddr(remoteAddr);
    if (code == SCTP_I_SENDQUEUE_ABATED) {
        indication->setNumMsgs(value);
    }
    msg->setControlInfo(indication);
    sctpMain->send(msg, "to_appl", appGateIndex);
}

void SCTPAssociation::sendInit (  )  [protected]

Methods for creating and sending chunks

Definition at line 339 of file SCTPAssociationUtil.cc.

Referenced by process_ASSOCIATE().

{
    //RoutingTableAccess routingTableAccess;
    InterfaceTableAccess interfaceTableAccess;
    AddressVector adv;
    uint32 length = SCTP_INIT_CHUNK_LENGTH;

    if (remoteAddr.isUnspecified() || remotePort==0)
        opp_error("Error processing command ASSOCIATE: foreign socket unspecified");
    if (localPort==0)
        opp_error("Error processing command ASSOCIATE: local port unspecified");
    state->setPrimaryPath(getPath(remoteAddr));
    // create message consisting of INIT chunk
    SCTPMessage *sctpmsg = new SCTPMessage();
    sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
    SCTPInitChunk *initChunk = new SCTPInitChunk("INIT");
    initChunk->setChunkType(INIT);
    initChunk->setInitTag((uint32)(fmod(intrand(INT32_MAX), 1.0+(double)(unsigned)0xffffffffUL)) & 0xffffffffUL);

    peerVTag = initChunk->getInitTag();
    sctpEV3<<"INIT from "<<localAddr<<":InitTag="<<peerVTag<<"\n";
    initChunk->setA_rwnd(sctpMain->par("arwnd"));
    state->localRwnd = (long)sctpMain->par("arwnd");
    initChunk->setNoOutStreams(outboundStreams);
    initChunk->setNoInStreams(inboundStreams);
    initChunk->setInitTSN(1000);
    state->nextTSN=initChunk->getInitTSN();
    state->lastTSN = initChunk->getInitTSN() + state->numRequests - 1;
    initTsn=initChunk->getInitTSN();
    IInterfaceTable *ift = interfaceTableAccess.get();
    sctpEV3<<"add local address\n";
    if (localAddressList.front() == IPvXAddress("0.0.0.0"))
    {
        for (int32 i=0; i<ift->getNumInterfaces(); ++i)
        {
            if (ift->getInterface(i)->ipv4Data()!=NULL)
            {
                adv.push_back(ift->getInterface(i)->ipv4Data()->getIPAddress());
            }
            else if (ift->getInterface(i)->ipv6Data()!=NULL)
            {
                for (int32 j=0; j<ift->getInterface(i)->ipv6Data()->getNumAddresses(); j++)
                {
                    sctpEV3<<"add address "<<ift->getInterface(i)->ipv6Data()->getAddress(j)<<"\n";
                    adv.push_back(ift->getInterface(i)->ipv6Data()->getAddress(j));
                }
            }
        }
    }
    else
    {
        adv = localAddressList;
        sctpEV3<<"gebundene Adresse "<<localAddr<<" wird hinzugefuegt\n";
    }
    uint32 addrNum=0;
    bool friendly = false;
    if (remoteAddr.isIPv6())
    {
        for (AddressVector::iterator i=adv.begin(); i!=adv.end(); ++i)
        {
            if (!friendly)
            {
                initChunk->setAddressesArraySize(addrNum+1);
                initChunk->setAddresses(addrNum++,(*i));
                length+=20;
            }
            sctpMain->addLocalAddress(this, (*i));
            state->localAddresses.push_back((*i));
            if (localAddr.isUnspecified())
                localAddr=(*i);
        }
    }
    else
    {
        uint32 rlevel = getLevel(remoteAddr);
        sctpEV3<<"level of remote address="<<rlevel<<"\n";
        for (AddressVector::iterator i=adv.begin(); i!=adv.end(); ++i)
        {
            sctpEV3<<"level of address "<<(*i)<<" = "<<getLevel((*i))<<"\n";
            if (getLevel((*i))>=rlevel)
            {
                initChunk->setAddressesArraySize(addrNum+1);
                initChunk->setAddresses(addrNum++,(*i));
                length+=8;
                sctpMain->addLocalAddress(this, (*i));
                state->localAddresses.push_back((*i));
                if (localAddr.get4().getInt()==0)
                    localAddr=(*i);
            }
            else if (rlevel==4 && getLevel((*i))==3 && friendly)
            {
                sctpMain->addLocalAddress(this, (*i));
                state->localAddresses.push_back((*i));
                if (localAddr.get4().getInt()==0)
                    localAddr=(*i);
            }
        }
    }
    sctpMain->printInfoConnMap();
    initChunk->setBitLength(length*8);
    sctpmsg->addChunk(initChunk);
    // set path variables
    if (remoteAddressList.size()>0)
    {
        for (AddressVector::iterator it=remoteAddressList.begin(); it!=remoteAddressList.end(); it++)
        {
            sctpEV3<<__LINE__<<" get new path for "<<(*it)<<"\n";
            SCTPPathVariables* path = new SCTPPathVariables((*it), this);
            sctpPathMap[(*it)] = path;
            qCounter.roomTransQ[(*it)]    = 0;
            qCounter.bookedTransQ[(*it)] = 0;
            qCounter.roomRetransQ[(*it)] = 0;
        }
    }
    else
    {
        sctpEV3<<__LINE__<<" get new path for "<<remoteAddr<<"\n";
        SCTPPathVariables* path = new SCTPPathVariables(remoteAddr, this);
        sctpPathMap[remoteAddr] = path;
        qCounter.roomTransQ[remoteAddr]  = 0;
        qCounter.bookedTransQ[remoteAddr] = 0;
        qCounter.roomRetransQ[remoteAddr] = 0;
    }
    // send it
    state->initChunk=check_and_cast<SCTPInitChunk *>(initChunk->dup());
    state->initChunk->setName("StateInitChunk");
    printSctpPathMap();
    sctpEV3<<getFullPath()<<" sendInit: localVTag="<<localVTag<<" peerVTag="<<peerVTag<<"\n";
    sendToIP(sctpmsg);
    sctpMain->assocList.push_back(this);
}

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

Definition at line 487 of file SCTPAssociationUtil.cc.

Referenced by processInitArrived().

{
    uint32 length = SCTP_INIT_CHUNK_LENGTH;

    state->setPrimaryPath(getPath(remoteAddr));
    // create segment
    SCTPMessage *sctpinitack = new SCTPMessage();
    sctpinitack->setBitLength(SCTP_COMMON_HEADER*8);

    sctpinitack->setSrcPort(localPort);
    sctpinitack->setDestPort(remotePort);
    sctpEV3<<"sendInitAck at "<<localAddr<<". Provided InitTag="<<initChunk->getInitTag()<<"\n";
    SCTPInitAckChunk *initAckChunk = new SCTPInitAckChunk("INIT_ACK");
    initAckChunk->setChunkType(INIT_ACK);
    SCTPCookie *cookie = new SCTPCookie("CookieUtil");
    cookie->setCreationTime(simTime());
    cookie->setLocalTieTagArraySize(32);
    cookie->setPeerTieTagArraySize(32);
    if (fsm->getState()==SCTP_S_CLOSED)
    {
        while (peerVTag==0)
        {
            peerVTag = (uint32)intrand(INT32_MAX);
        }
        initAckChunk->setInitTag(peerVTag);
        initAckChunk->setInitTSN(2000);
        state->nextTSN=initAckChunk->getInitTSN();
        state->lastTSN = initAckChunk->getInitTSN() + state->numRequests - 1;
        cookie->setLocalTag(localVTag);
        cookie->setPeerTag(peerVTag);
        for (int32 i=0; i<32; i++)
        {
            cookie->setLocalTieTag(i,0);
            cookie->setPeerTieTag(i,0);
        }
        sctpinitack->setTag(localVTag);
        sctpEV3<<"state=closed: localVTag="<<localVTag<<" peerVTag="<<peerVTag<<"\n";
    }
    else if (fsm->getState()==SCTP_S_COOKIE_WAIT || fsm->getState()==SCTP_S_COOKIE_ECHOED)
    {
        initAckChunk->setInitTag(peerVTag);
        sctpEV3<<"different state:set InitTag in InitAck: "<<initAckChunk->getInitTag()<<"\n";
        initAckChunk->setInitTSN(state->nextTSN);
        initPeerTsn=initChunk->getInitTSN();
        state->cTsnAck = initPeerTsn - 1;
        cookie->setLocalTag(initChunk->getInitTag());
        cookie->setPeerTag(peerVTag);
        for (int32 i=0; i<32; i++)
        {
            cookie->setPeerTieTag(i,(uint8)(intrand(256)));
            state->peerTieTag[i] = cookie->getPeerTieTag(i);
            if (fsm->getState()==SCTP_S_COOKIE_ECHOED)
            {
                cookie->setLocalTieTag(i,(uint8)(intrand(256)));
                state->localTieTag[i] = cookie->getLocalTieTag(i);
            }
            else
                cookie->setLocalTieTag(i,0);
        }
        sctpinitack->setTag(initChunk->getInitTag());
        sctpEV3<<"VTag in InitAck: "<<sctpinitack->getTag()<<"\n";
    }
    else
    {
        sctpEV3<<"other state\n";
        uint32 tag=0;
        while (tag==0)
        {
            tag = (uint32)(fmod(intrand(INT32_MAX), 1.0+(double)(unsigned)0xffffffffUL)) & 0xffffffffUL;
        }
        initAckChunk->setInitTag(tag);
        initAckChunk->setInitTSN(state->nextTSN);
        cookie->setLocalTag(localVTag);
        cookie->setPeerTag(peerVTag);
        for (int32 i=0; i<32; i++)
        {
            cookie->setPeerTieTag(i,state->peerTieTag[i]);
            cookie->setLocalTieTag(i,state->localTieTag[i]);
        }
        sctpinitack->setTag(initChunk->getInitTag());
    }
    cookie->setBitLength(SCTP_COOKIE_LENGTH*8);
    initAckChunk->setStateCookie(cookie);
    initAckChunk->setCookieArraySize(0);
    initAckChunk->setA_rwnd(sctpMain->par("arwnd"));
    state->localRwnd = (long)sctpMain->par("arwnd");
    initAckChunk->setNoOutStreams((unsigned int)min(outboundStreams,initChunk->getNoInStreams()));
    initAckChunk->setNoInStreams((unsigned int)min(inboundStreams,initChunk->getNoOutStreams()));
    initTsn=initAckChunk->getInitTSN();
    uint32 addrNum=0;
    bool friendly = false;
    if (!friendly)
    for (AddressVector::iterator k=state->localAddresses.begin(); k!=state->localAddresses.end(); ++k)
    {
        initAckChunk->setAddressesArraySize(addrNum+1);
        initAckChunk->setAddresses(addrNum++,(*k));
        length+=8;
    }
    uint32 unknownLen = initChunk->getUnrecognizedParametersArraySize();
    if (unknownLen>0)
    {
        sctpEV3<<"Found unrecognized Parameters in INIT chunk with a length of "<<unknownLen<<" bytes.\n";
        initAckChunk->setUnrecognizedParametersArraySize(unknownLen);
        for (uint32 i=0; i<unknownLen; i++)
            initAckChunk->setUnrecognizedParameters(i,initChunk->getUnrecognizedParameters(i));
        length+=unknownLen;
    }
    else
        initAckChunk->setUnrecognizedParametersArraySize(0);

    initAckChunk->setBitLength((length+initAckChunk->getCookieArraySize())*8 + cookie->getBitLength());
    inboundStreams = ((initChunk->getNoOutStreams()<initAckChunk->getNoInStreams())?initChunk->getNoOutStreams():initAckChunk->getNoInStreams());
    outboundStreams = ((initChunk->getNoInStreams()<initAckChunk->getNoOutStreams())?initChunk->getNoInStreams():initAckChunk->getNoOutStreams());
    (this->*ssFunctions.ssInitStreams)(inboundStreams, outboundStreams);
    sctpinitack->addChunk(initAckChunk);
    if (fsm->getState()==SCTP_S_CLOSED)
    {
        sendToIP(sctpinitack, state->initialPrimaryPath);
    }
    else
    {
        sendToIP(sctpinitack);

    }
    sctpMain->assocList.push_back(this);
    printSctpPathMap();
}

void SCTPAssociation::sendOnAllPaths ( SCTPPathVariables firstPath  ) 

Definition at line 193 of file SCTPAssociationSendAll.cc.

Referenced by process_ABORT(), process_CLOSE(), process_RCV_Message(), process_TIMEOUT_RTX(), sendShutdownAck(), and stateEntered().

{
        // ------ Send on provided path first ... -----------------------------
        if(firstPath != NULL) {
            sendOnPath(firstPath);
        }

        // ------ ... then, try sending on all other paths --------------------
        for (SCTPPathMap::iterator iterator = sctpPathMap.begin(); iterator != sctpPathMap.end(); ++iterator) {
            SCTPPathVariables* path = iterator->second;
            if(path != firstPath) {
                sendOnPath(path);
            }
        }

}

void SCTPAssociation::sendOnPath ( SCTPPathVariables pathId,
const bool  firstPass = true 
)

Utility: Send data from sendQueue.

Definition at line 305 of file SCTPAssociationSendAll.cc.

Referenced by SCTPAlg::sendCommandInvoked(), and sendOnAllPaths().

{
    // ====== Variables ======================================================
    SCTPPathVariables*  path             = NULL;      // Path to send next message to
    SCTPMessage*            sctpMsg      = NULL;
    SCTPSackChunk*          sackChunk    = NULL;
    SCTPDataChunk*          chunkPtr         = NULL;

    uint16 chunksAdded      = 0;
    uint16 dataChunksAdded  = 0;
    uint32 totalChunksSent  = 0;
    uint32 totalPacketsSent = 0;
    uint32 packetBytes      = 0;
    uint32 outstandingBytes = 0;

    uint32 tcount               = 0;     // Bytes in transmission queue on the selected path
    uint32 scount               = 0;     // Bytes in send streams
    int32 bytesToSend           = 0;

    bool headerCreated      = false;
    bool rtxActive              = false;
    bool sendOneMorePacket  = false;
    bool sendingAllowed     = true;
    bool authAdded              = false;
    bool sackAdded              = false;

    // ====== Obtain path ====================================================
    sctpEV3 << endl << "##### sendAll(";
    if(pathId) {
        sctpEV3 << pathId->remoteAddress;
    }
    sctpEV3 << ") #####" << endl;
    while(sendingAllowed)
    {
        headerCreated = false;
        if (state->bytesToRetransmit > 0) {
            // There are bytes in the transmissionQ. They have to be sent first.
            path = choosePathForRetransmission();
            assert(path != NULL);
            rtxActive = true;
        }
        else {
            if (pathId == NULL) {   // No path given => use primary path.
                path = state->getPrimaryPath();
            }
            else {
                path = pathId;
            }
        }

        outstandingBytes = path->outstandingBytes;
        assert((int32)outstandingBytes >= 0);
        CounterMap::iterator tq = qCounter.roomTransQ.find(path->remoteAddress);
        tcount = tq->second;
        scount = qCounter.roomSumSendStreams;     // includes header and padding
        sctpEV3 << "\nsendAll: on " << path->remoteAddress << ":"
                  << " tcount="      << tcount
                  << " scount="      << scount
                  << " nextTSN="         << state->nextTSN << endl;

        bool sackOnly;
        bool sackWithData;
        timeForSack(sackOnly, sackWithData);
        if (tcount == 0 && scount == 0) {
            // ====== No DATA chunks to send ===================================
            sctpEV3 << "No DATA chunk available!" << endl;
            if (!sackOnly) {     // SACK?, no data to send
                sctpEV3 << "No SACK to send either" << endl;
                return;
            }
            else {
                bytes.bytesToSend = 0;
            }
        }
        else {
            bytesAllowedToSend(path, firstPass);
        }
        bytesToSend = bytes.bytesToSend;

        // As there is at least a SACK to be sent, a header can be created

        if (state->sctpMsg)  // ??? Robin: Ist das in Ordnung???
        {
            loadPacket(path, &sctpMsg, &chunksAdded, &dataChunksAdded, &packetBytes, &authAdded);
            headerCreated = true;
        }
        else if (bytesToSend > 0 || bytes.chunk || bytes.packet || sackWithData || sackOnly) {
            sctpMsg = new SCTPMessage("send");
            //printf("%d Name=%s Pointer=%p\n", __LINE__, sctpMsg->getName(), sctpMsg);
            sctpMsg->setByteLength(SCTP_COMMON_HEADER);
            packetBytes = 0;
            headerCreated = true;
        }


        if (sackWithData || sackOnly)
        {
            // SACK can be sent
            assert(headerCreated==true);
            sackChunk = createSack();
            chunksAdded++;
            totalChunksSent++;
            // ------ Create AUTH chunk, if necessary --------------------------

            // ------ Add SACK chunk -------------------------------------------
            sctpMsg->addChunk(sackChunk);
            sackAdded = true;
            if (sackOnly)     // ????? Robin: SACK mit FORWARD_TSN????
            {
                // send the packet and leave
                //printf("%d Name=%s Pointer=%p, sctpMsg\n", __LINE__, sctpMsg->getName(), sctpMsg);
                state->ackState = 0;
                // Stop SACK timer if it is running...
                stopTimer(SackTimer);
                sctpAlgorithm->sackSent();
                state->sackAllowed = false;
                sendToIP(sctpMsg, state->lastDataSourceAddress);
                if ((bytesToSend > 0) || (bytes.chunk) || (bytes.packet)) {
                    sctpMsg = new SCTPMessage("send");
                    sctpMsg->setByteLength(SCTP_COMMON_HEADER);
                    packetBytes = 0;
                    headerCreated = true;
                    sackAdded = false;
                }
                else
                    return;
            }
        }


        // ####################################################################
        // #### Data Transmission                                                        ####
        // ####################################################################

        bool packetFull = false;

        while(!packetFull && headerCreated) {
            assert(headerCreated == true);
            sctpEV3 << "bytesToSend="    << bytesToSend
                      << " bytes.chunk="     << bytes.chunk
                      << " bytes.packet=" << bytes.packet << endl;

            // ====== How many bytes may be transmitted in next packet? ========
            int32 allowance = path->pmtu;     // Default behaviour: send 1 path MTU
                if ((bytesToSend > 0) || (bytes.chunk) || (bytes.packet)) {
                    // Allow 1 more MTU
                }
                else {
                    // No more sending allowed.
                    allowance   = 0;
                    bytesToSend = 0;
                }

            if ((allowance > 0) || (bytes.chunk) || (bytes.packet)) {
                bool firstTime = false;   // Is DATA chunk send for the first time?

                // ====== Retransmission ========================================
                // T.D. 05.01.2010: If bytes.packet is true, one packet is allowed
                //                        to be retransmitted!
                SCTPDataVariables* datVar = getOutboundDataChunk(path,
                                                                                 path->pmtu - sctpMsg->getByteLength() - 20,
                                                                                 (bytes.packet == true) ? path->pmtu : allowance);
                if (chunksAdded==1 && sackAdded && !sackOnly && datVar==NULL) {
                    sctpMsg->removeChunk();
                    delete sackChunk;
                    datVar = getOutboundDataChunk(path,
                                                            path->pmtu - sctpMsg->getByteLength() - 20,
                                                            (bytes.packet == true) ? path->pmtu : allowance);
                }
                if (datVar != NULL) {
                    assert(datVar->getNextDestinationPath() == path);
                    datVar->numberOfRetransmissions++;
                    if (chunkHasBeenAcked(datVar) == false) {
                        sctpEV3 << simTime() << ": Retransmission #" << datVar->numberOfRetransmissions
                                  << " of TSN " << datVar->tsn
                                  << " on path " << datVar->getNextDestination()
                                  << " (last was " << datVar->getLastDestination() << ")" << endl;

                        datVar->countsAsOutstanding = true;
                        datVar->hasBeenReneged       = false;
                        increaseOutstandingBytes(datVar, path); // NOTE: path == datVar->getNextDestinationPath()
                    }
                }

                // ====== First Transmission ====================================
                else if ( ((scount > 0) && (!state->nagleEnabled)) ||                                         // Data to send and Nagle off
                             ((uint32)scount >= path->pmtu - 32 - 20) ||                                          // Data to fill at least one path MTU
                             ((scount > 0) && (state->nagleEnabled) && (outstandingBytes == 0)) ) {   // Data to send, Nagle on and no outstanding bytes

                    if(path == state->getPrimaryPath()) {

                        // ------ Dequeue data message ----------------------------
                        sctpEV3 << "sendAll:     sctpMsg->length=" << sctpMsg->getByteLength()
                                  << " length datMsg=" << path->pmtu-sctpMsg->getByteLength() - 20 << endl;
                        SCTPDataMsg* datMsg = dequeueOutboundDataMsg(path->pmtu-sctpMsg->getByteLength() - 20,
                                                                                    allowance);
                        if (chunksAdded==1 && sackAdded && !sackOnly && datMsg==NULL)
                        {
                            sctpMsg->removeChunk();
                            delete sackChunk;
                            datMsg = dequeueOutboundDataMsg(path->pmtu-sctpMsg->getByteLength() - 20,
                                                                    allowance);
                        }
                        // ------ Handle data message -----------------------------
                        if (datMsg) {
                            firstTime = true;

                            state->queuedMessages--;
                            if ((state->queueLimit > 0) &&
                                (state->queuedMessages < state->queueLimit) &&
                                (state->queueUpdate == false)) {
                                // Tell upper layer readiness to accept more data
                                sendIndicationToApp(SCTP_I_SEND_MSG);
                                state->queueUpdate = true;
                            }

                            datVar = makeDataVarFromDataMsg(datMsg, path);
                            delete datMsg;

                            sctpEV3 << "sendAll: chunk " << datVar << " dequeued from StreamQ "
                                    << datVar->sid << ": tsn=" << datVar->tsn
                                    << ", bytes now " << qCounter.roomSumSendStreams << "\n";
                        }

                        // ------ No data message has been dequeued ---------------
                        else {
                            // ------ Are there any chunks to send? ----------------
                            if (chunksAdded == 0) {
                                // No -> nothing more to do.
                                if (state->sctpMsg == sctpMsg)
                                {
                                    state->sctpMsg = NULL;
                                    state->packetBytes = 0;
                                }
                                packetFull = true;  // chunksAdded==0, packetFull==true => leave inner while loop
                            }
                            else {
                                // Yes.
                                if (state->nagleEnabled && (outstandingBytes > 0) &&
                                    nextChunkFitsIntoPacket(path->pmtu-sctpMsg->getByteLength() - 20) &&
                                    (sctpMsg->getByteLength() < path->pmtu - 32 - 20) && (tcount == 0))
                                {
                                    storePacket(path, sctpMsg, chunksAdded, dataChunksAdded, packetBytes, authAdded);
                                    packetBytes = 0;
                                }
                                //chunksAdded = 0;
                                packetFull = true;  // chunksAdded==0, packetFull==true => leave inner while loop
                                sctpEV3 << "sendAll: packetFull: msg length = " << sctpMsg->getBitLength() / 8 + 20 << "\n";
                            }
                        }
                    }
                }


                // ------ Handle DATA chunk -------------------------------------
                if (datVar != NULL && !packetFull) {
                    // ------ Assign TSN -----------------------------------------
                    if (firstTime) {
                        assert(datVar->tsn == 0);
                        datVar->tsn = state->nextTSN;
                        sctpEV3 << "sendAll: set TSN=" << datVar->tsn
                                << " sid=" << datVar->sid << ", ssn=" << datVar->ssn << "\n";
                        state->nextTSN++;
                    }

                    SCTP::AssocStatMap::iterator iterator = sctpMain->assocStatMap.find(assocId);
                    iterator->second.transmittedBytes += datVar->len / 8;

                    datVar->setLastDestination(path);
                    datVar->countsAsOutstanding = true;
                    datVar->hasBeenReneged       = false;
                    datVar->sendTime                 = simTime(); //I.R. to send Fast RTX just once a RTT

                    // ------ First transmission of datVar -----------------------
                    if (datVar->numberOfTransmissions == 0) {

                        sctpEV3 << "sendAll: " << simTime() << " firstTime, TSN "
                                  << datVar->tsn    << ": lastDestination set to "
                                  << datVar->getLastDestination() << endl;

                        if (!state->firstDataSent) {
                            state->firstDataSent = true;
                        }
                        sctpEV3 << "sendAll: insert in retransmissionQ tsn=" << datVar->tsn << "\n";
                        if(!retransmissionQ->checkAndInsertChunk(datVar->tsn, datVar)) {
                            opp_error("Cannot add datVar to retransmissionQ!");
                            // Falls es hier aufschlaegt, muss ueberlegt werden, ob es OK ist, dass datVars nicht eingefuegt werden koennen.
                        }
                        else {
                            sctpEV3 << "sendAll: size of retransmissionQ=" << retransmissionQ->getQueueSize() << "\n";
                            unackChunk(datVar);
                            increaseOutstandingBytes(datVar, path);
                        }
                    }

                    /* datVar is already in the retransmissionQ */
                    datVar->numberOfTransmissions++;
                    datVar->gapReports                  = 0;
                    datVar->hasBeenFastRetransmitted = false;
                    sctpEV3<<"sendAll(): adding new outbound data datVar to packet (tsn="<<datVar->tsn<<")...!!!\n";

                    chunkPtr = transformDataChunk(datVar);

                    /* update counters */
                    totalChunksSent++;
                    chunksAdded++;
                    dataChunksAdded++;
                    sctpMsg->addChunk(chunkPtr);
                    if(nextChunkFitsIntoPacket(path->pmtu - sctpMsg->getByteLength() - 20) == false) {
                        // ???? Robin: Ist diese Annahme so richtig?
                        packetFull = true;
                    }

                    state->peerRwnd -= datVar->booksize;
                    if ((bytes.chunk == false) && (bytes.packet == false)) {
                        bytesToSend -= datVar->booksize;
                    }
                    else if (bytes.chunk) {
                        bytes.chunk = false;
                    }
                    else if ((bytes.packet) && (packetFull)) {
                        bytes.packet = false;
                    }

                    if (bytesToSend <= 0) {
                        if ((!packetFull) && (qCounter.roomSumSendStreams > path->pmtu - 32 - 20 || tcount > 0)) {
                            sendOneMorePacket = true;
                            bytes.packet        = true;
                            sctpEV3 << "sendAll: one more packet allowed\n";
                        }
                        else {
                            if (state->nagleEnabled && (outstandingBytes > 0) &&
                                nextChunkFitsIntoPacket(path->pmtu-sctpMsg->getByteLength() - 20) &&
                                (sctpMsg->getByteLength() < path->pmtu - 32 - 20) && (tcount == 0))
                            {
                                storePacket(path, sctpMsg, chunksAdded, dataChunksAdded, packetBytes, authAdded);
                                packetBytes = 0;
                                chunksAdded = 0;
                                packetFull  = true;  // chunksAdded==0, packetFull==true => leave inner while loop
                            }
                            else {
                                packetFull            = true;
                            }
                        }
                        bytesToSend = 0;
                    }
                    else if ((qCounter.roomSumSendStreams == 0) && (tq->second==0)) {
                        packetFull            = true;
                        sctpEV3 << "sendAll: no data in send and transQ: packet full\n";
                    }
                    sctpEV3 << "sendAll: bytesToSend after reduction: " << bytesToSend << "\n";
                }

                // ------ There is no DATA chunk, only control chunks possible --
                else {
                    // ????? Robin: Kann dieser Fall wirklich eintreten?
                    if (chunksAdded == 0) {   // Nothing to do -> return
                        packetFull = true;  // chunksAdded==0, packetFull==true => leave inner while loop
                    }
                    else {
                        packetFull = true;
                        sctpEV3 << "sendAll: packetFull: msg length = " << sctpMsg->getBitLength() / 8 + 20 << "\n";
                        datVar = NULL;
                    }
                }


                // ====== Send packet ===========================================
                if (packetFull) {
                    if(chunksAdded == 0) {   // Nothing to send
                        delete sctpMsg;
                        sendingAllowed = false;   // sendingAllowed==false => leave outer while loop
                    }
                    else {
                        sctpEV3 << "sendAll: " << simTime() << "    packet full:"
                                << "    totalLength=" << sctpMsg->getBitLength() / 8 + 20
                                << ",    path="   << path->remoteAddress
                                << "     "                << dataChunksAdded << " chunks added, outstandingBytes now "
                                << path->outstandingBytes << "\n";

                        /* new chunks would exceed MTU, so we send old packet and build a new one */
                        /* this implies that at least one data chunk is send here */
                        if (dataChunksAdded > 0) {
                            if (!path->T3_RtxTimer->isScheduled()) {
                                // Start retransmission timer, if not scheduled before
                                startTimer(path->T3_RtxTimer, path->pathRto);
                            }
                            else {
                                sctpEV3 << "sendAll: RTX Timer already scheduled -> no need to schedule it\n";
                            }
                        }
                        if (sendOneMorePacket) {
                            sendOneMorePacket = false;
                            bytesToSend         = 0;
                            bytes.packet        = false;
                        }


                        sendToIP(sctpMsg, path->remoteAddress);
                        pmDataIsSentOn(path);
                        totalPacketsSent++;

                        // ------ Reset status ------------------------------------
                        if (state->sctpMsg == sctpMsg)
                        {
                            state->sctpMsg = NULL;
                            path->outstandingBytes += packetBytes;
                            packetBytes = 0;
                        }
                        headerCreated    = false;
                        chunksAdded      = 0;
                        dataChunksAdded = 0;
                        firstTime        = false;

                        sctpEV3 << "sendAll: sending Packet to path " << path->remoteAddress
                                  << "  scount=" << scount
                                  << "  tcount=" << tcount
                                  << "  bytesToSend=" << bytesToSend << endl;
                    }
                }
                sctpEV3 << "sendAll: still " << bytesToSend
                          << " bytes to send, headerCreated=" << headerCreated << endl;

            }    // if (bytesToSend > 0 || bytes.chunk || bytes.packet)
            else {
                packetFull = true;  // Leave inner while loop
                delete sctpMsg;     // T.D. 19.01.2010: Free unsent message
            }

            sctpEV3 << "packetFull=" << packetFull << endl;
        }    // while(!packetFull)

        sctpEV3 << "bytesToSend="    << bytesToSend
                  << " bytes.chunk="     << bytes.chunk
                  << " bytes.packet=" << bytes.packet << endl;
        if (!(bytesToSend > 0 || bytes.chunk || bytes.packet)) {
            sendingAllowed = false;
        }
    }    // while(sendingAllowed)

    sctpEV3 << "sendAll: nothing more to send... BYE!\n";
}

void SCTPAssociation::sendSack (  )  [protected]

Definition at line 973 of file SCTPAssociationUtil.cc.

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

{
    SCTPSackChunk*               sackChunk;

    sctpEV3 << "Sending SACK" << endl;

    /* sack timer has expired, reset flag, and send SACK */
    stopTimer(SackTimer);
    state->ackState = 0;
    sackChunk = createSack();

    SCTPMessage* sctpmsg = new SCTPMessage();
    sctpmsg->setBitLength(SCTP_COMMON_HEADER*8);
    sctpmsg->addChunk(sackChunk);

    // Return the SACK to the address where we last got a data chunk from
    sendToIP(sctpmsg, state->lastDataSourceAddress);
}

void SCTPAssociation::sendShutdown (  )  [protected]

Definition at line 797 of file SCTPAssociationUtil.cc.

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

{
    SCTPMessage *msg = new SCTPMessage();
    msg->setBitLength(SCTP_COMMON_HEADER*8);

    sctpEV3<<"SCTPAssociationUtil:sendShutdown localPort="<<localPort<<"     remotePort="<<remotePort<<"\n";

    msg->setSrcPort(localPort);
    msg->setDestPort(remotePort);
    SCTPShutdownChunk* shutdownChunk = new SCTPShutdownChunk("SHUTDOWN");
    shutdownChunk->setChunkType(SHUTDOWN);
    //shutdownChunk->setCumTsnAck(state->lastTsnAck);
    shutdownChunk->setCumTsnAck(state->cTsnAck);
    shutdownChunk->setBitLength(SCTP_SHUTDOWN_CHUNK_LENGTH*8);
    state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT;
    state->initRetransCounter = 0;
    stopTimer(T5_ShutdownGuardTimer);
    startTimer(T5_ShutdownGuardTimer,SHUTDOWN_GUARD_TIMEOUT);
    stopTimer(T2_ShutdownTimer);
    startTimer(T2_ShutdownTimer,state->initRexmitTimeout);
    state->shutdownChunk=check_and_cast<SCTPShutdownChunk*>(shutdownChunk->dup());
    msg->addChunk(shutdownChunk);
    sendToIP(msg, remoteAddr);
    performStateTransition(SCTP_E_NO_MORE_OUTSTANDING);
}

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

Definition at line 735 of file SCTPAssociationUtil.cc.

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

{
    sendOnAllPaths(getPath(dest));
    if (getOutstandingBytes() == 0) {
        performStateTransition(SCTP_E_NO_MORE_OUTSTANDING);
        SCTPMessage *sctpshutdownack = new SCTPMessage();
        sctpshutdownack->setBitLength(SCTP_COMMON_HEADER*8);

        sctpEV3 << "SCTPAssociationUtil:sendShutdownACK" << endl;

        sctpshutdownack->setSrcPort(localPort);
        sctpshutdownack->setDestPort(remotePort);
        SCTPShutdownAckChunk* shutdownAckChunk=new SCTPShutdownAckChunk("SHUTDOWN_ACK");
        shutdownAckChunk->setChunkType(SHUTDOWN_ACK);
        shutdownAckChunk->setBitLength(SCTP_COOKIE_ACK_LENGTH*8);
        sctpshutdownack->addChunk(shutdownAckChunk);
        state->initRexmitTimeout = SCTP_TIMEOUT_INIT_REXMIT;
        state->initRetransCounter = 0;
        stopTimer(T2_ShutdownTimer);
        startTimer(T2_ShutdownTimer,state->initRexmitTimeout);
        stopTimer(T5_ShutdownGuardTimer);
        startTimer(T5_ShutdownGuardTimer,SHUTDOWN_GUARD_TIMEOUT);
        state->shutdownAckChunk=check_and_cast<SCTPShutdownAckChunk*>(shutdownAckChunk->dup());
        sendToIP(sctpshutdownack, dest);
    }
}

void SCTPAssociation::sendShutdownComplete (  )  [protected]

Definition at line 762 of file SCTPAssociationUtil.cc.

Referenced by process_RCV_Message().

{
    SCTPMessage *sctpshutdowncomplete = new SCTPMessage();
    sctpshutdowncomplete->setBitLength(SCTP_COMMON_HEADER*8);

    sctpEV3<<"SCTPAssociationUtil:sendShutdownComplete\n";

    sctpshutdowncomplete->setSrcPort(localPort);
    sctpshutdowncomplete->setDestPort(remotePort);
    SCTPShutdownCompleteChunk* shutdownCompleteChunk=new SCTPShutdownCompleteChunk("SHUTDOWN_COMPLETE");
    shutdownCompleteChunk->setChunkType(SHUTDOWN_COMPLETE);
    shutdownCompleteChunk->setTBit(0);
    shutdownCompleteChunk->setBitLength(SCTP_SHUTDOWN_ACK_LENGTH*8);
    sctpshutdowncomplete->addChunk(shutdownCompleteChunk);
    sendToIP(sctpshutdowncomplete);
}

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

Utility: sends packet to application

Definition at line 313 of file SCTPAssociationUtil.cc.

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

{
    sctpMain->send(msg, "to_appl", appGateIndex);
}

void SCTPAssociation::sendToIP ( SCTPMessage sctpmsg,
const IPvXAddress dest,
const bool  qs = false 
) [protected]

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

Definition at line 214 of file SCTPAssociationUtil.cc.

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

{
    // Final touches on the segment before sending
    sctpmsg->setSrcPort(localPort);
    sctpmsg->setDestPort(remotePort);
    sctpmsg->setChecksumOk(true);
    const SCTPChunk* chunk = (const SCTPChunk*)(sctpmsg->peekFirstChunk());
    if (chunk->getChunkType() == ABORT) {
        const SCTPAbortChunk* abortChunk = check_and_cast<const SCTPAbortChunk *>(chunk);
        if (abortChunk->getT_Bit() == 1) {
            sctpmsg->setTag(peerVTag);
        }
        else {
            sctpmsg->setTag(localVTag);
        }
    }
    else if (sctpmsg->getTag() == 0) {
        sctpmsg->setTag(localVTag);
    }

    if ((bool)sctpMain->par("udpEncapsEnabled")) {
        sctpmsg->setKind(UDP_C_DATA);
        UDPControlInfo* controlInfo = new UDPControlInfo();
        controlInfo->setSrcPort(9899);
        controlInfo->setDestAddr(remoteAddr.get4());
        controlInfo->setDestPort(9899);
        sctpmsg->setControlInfo(controlInfo);
    }
    else {
        if (dest.isIPv6()) {
            IPv6ControlInfo* controlInfo = new IPv6ControlInfo();
            controlInfo->setProtocol(IP_PROT_SCTP);
            controlInfo->setSrcAddr(IPv6Address());
            controlInfo->setDestAddr(dest.get6());
            sctpmsg->setControlInfo(controlInfo);
            sctpMain->send(sctpmsg, "to_ipv6");
        }
        else {
            IPControlInfo* controlInfo = new IPControlInfo();
            controlInfo->setProtocol(IP_PROT_SCTP);
            controlInfo->setSrcAddr(IPAddress("0.0.0.0"));
            controlInfo->setDestAddr(dest.get4());
            sctpmsg->setControlInfo(controlInfo);
            sctpMain->send(sctpmsg, "to_ip");
        }
        recordInPathVectors(sctpmsg, dest);
    }
    sctpEV3 << "Sent to " << dest << endl;
}

void SCTPAssociation::sendToIP ( SCTPMessage sctpmsg,
const bool  qs = false 
) [inline, protected]

Definition at line 726 of file SCTPAssociation.h.

                                                                          {
            sendToIP(sctpmsg, remoteAddr, qs);
        }

void SCTPAssociation::signalConnectionTimeout (  )  [protected]

Utility: signal to user that connection timed out

Definition at line 267 of file SCTPAssociationUtil.cc.

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

Definition at line 837 of file SCTPAssociation.h.

Referenced by makeRoomForTsn().

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

void SCTPAssociation::startTimer ( cMessage *  timer,
const simtime_t &  timeout 
) [protected]
void SCTPAssociation::stateEntered ( int32  state  )  [protected]

Definition at line 669 of file SCTPAssociationBase.cc.

Referenced by performStateTransition().

{
    switch (status)
    {
        case SCTP_S_COOKIE_WAIT:
            break;
        case SCTP_S_ESTABLISHED:
        {
            sctpEV3 << "State ESTABLISHED entered" << endl;
            stopTimer(T1_InitTimer);
            if (state->initChunk) {
                delete state->initChunk;
            }
            state->nagleEnabled                   = (bool)sctpMain->par("nagleEnabled");
            state->enableHeartbeats               = (bool)sctpMain->par("enableHeartbeats");
            state->numGapReports                  = sctpMain->par("numGapReports");
            state->maxBurst                       = (uint32)sctpMain->par("maxBurst");
                state->header = 0;
            state->swsLimit                      = (uint32)sctpMain->par("swsLimit");
            state->fastRecoverySupported         = (bool)sctpMain->par("fastRecoverySupported");
            state->reactivatePrimaryPath         = (bool)sctpMain->par("reactivatePrimaryPath");
            sackPeriod                           = (double)sctpMain->par("sackPeriod");
            sackFrequency                        = sctpMain->par("sackFrequency");
            SCTP::AssocStat stat;
            stat.assocId                         = assocId;
            stat.start                           = simulation.getSimTime();
            stat.stop                            = 0;
            stat.rcvdBytes                       = 0;
            stat.ackedBytes                      = 0;
            stat.sentBytes                       = 0;
            stat.transmittedBytes                = 0;
            stat.numFastRtx                      = 0;
            stat.numT3Rtx                        = 0;
            stat.numDups                         = 0;
            stat.numPathFailures                 = 0;
            stat.numForwardTsn                   = 0;
            stat.lifeTime                        = 0;
            stat.throughput                      = 0;
            sctpMain->assocStatMap[stat.assocId] = stat;
            ccModule = sctpMain->par("ccModule");
            switch (ccModule)
            {
                case RFC4960:
                {
                    ccFunctions.ccInitParams                 = &SCTPAssociation::initCCParameters;
                    ccFunctions.ccUpdateAfterSack            = &SCTPAssociation::cwndUpdateAfterSack;
                    ccFunctions.ccUpdateAfterCwndTimeout     = &SCTPAssociation::cwndUpdateAfterCwndTimeout;
                    ccFunctions.ccUpdateAfterRtxTimeout      = &SCTPAssociation::cwndUpdateAfterRtxTimeout;
                    ccFunctions.ccUpdateMaxBurst             = &SCTPAssociation::cwndUpdateMaxBurst;
                    ccFunctions.ccUpdateBytesAcked           = &SCTPAssociation::cwndUpdateBytesAcked;
                    break;
                }
            }
            pmStartPathManagement();
            state->sendQueueLimit = (uint32)sctpMain->par("sendQueueLimit");
            sendEstabIndicationToApp();
            char str[128];
            snprintf(str, sizeof(str), "Cumulated TSN Ack of Association %d", assocId);
            cumTsnAck = new cOutVector(str);
            snprintf(str, sizeof(str), "Number of Gap Blocks in Last SACK of Association %d", assocId);
            numGapBlocks = new cOutVector(str);
            snprintf(str, sizeof(str), "SendQueue of Association %d", assocId);
            sendQueue = new cOutVector(str);
            state->sendQueueLimit = (uint32)sctpMain->par("sendQueueLimit");
            SCTP::VTagPair vtagPair;
            vtagPair.peerVTag     = peerVTag;
            vtagPair.localVTag  = localVTag;
            vtagPair.localPort  = localPort;
            vtagPair.remotePort = remotePort;
            sctpMain->sctpVTagMap[assocId] = vtagPair;
            break;
        }
        case SCTP_S_CLOSED:
        {
            sendIndicationToApp(SCTP_I_CLOSED);
            break;
        }
        case SCTP_S_SHUTDOWN_PENDING:
        {
            if (getOutstandingBytes()==0 && transmissionQ->getQueueSize()==0 && qCounter.roomSumSendStreams==0)
                sendShutdown();
            break;
        }
        case SCTP_S_SHUTDOWN_RECEIVED:
        {
            sctpEV3 << "Entered state SHUTDOWN_RECEIVED, osb=" << getOutstandingBytes()
                      << ", transQ=" << transmissionQ->getQueueSize()
                      << ", scount=" << qCounter.roomSumSendStreams << endl;
            if (getOutstandingBytes()==0 && transmissionQ->getQueueSize()==0 && qCounter.roomSumSendStreams==0) {
                sendShutdownAck(remoteAddr);
            }
            else {
                sendOnAllPaths(state->getPrimaryPath());
            }
            break;
        }
    }
}

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

Utility: returns name of SCTP_S_xxx constants

Definition at line 51 of file SCTPAssociationUtil.cc.

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

{
#define CASE(x) case x: s=#x+7; break
    const char* s = "unknown";
    switch (state) {
        CASE(SCTP_S_CLOSED);
        CASE(SCTP_S_COOKIE_WAIT);
        CASE(SCTP_S_COOKIE_ECHOED);
        CASE(SCTP_S_ESTABLISHED);
        CASE(SCTP_S_SHUTDOWN_PENDING);
        CASE(SCTP_S_SHUTDOWN_SENT);
        CASE(SCTP_S_SHUTDOWN_RECEIVED);
        CASE(SCTP_S_SHUTDOWN_ACK_SENT);
    }
    return s;
#undef CASE
}

void SCTPAssociation::stopTimer ( cMessage *  timer  ) 
void SCTPAssociation::stopTimers (  ) 

Definition at line 1517 of file SCTPAssociationRcvMessage.cc.

Referenced by process_RCV_Message().

{
    for (SCTPPathMap::iterator j = sctpPathMap.begin(); j != sctpPathMap.end(); j++) {
        stopTimer(j->second->HeartbeatTimer);
        stopTimer(j->second->HeartbeatIntervalTimer);
    }
}

void SCTPAssociation::storePacket ( SCTPPathVariables pathVar,
SCTPMessage sctpMsg,
const uint16  chunksAdded,
const uint16  dataChunksAdded,
const uint32  packetBytes,
const bool  authAdded 
) [private]

Definition at line 60 of file SCTPAssociationSendAll.cc.

Referenced by sendOnPath().

{
    for (uint16 i = 0; i < sctpMsg->getChunksArraySize(); i++) {
        retransmissionQ->payloadQueue.find(((SCTPDataChunk*)sctpMsg->getChunks(i))->getTsn())->second->countsAsOutstanding = false;
    }
    state->sctpMsg            = sctpMsg;
    state->chunksAdded    = chunksAdded;
    state->dataChunksAdded = dataChunksAdded;
    state->packetBytes    = packetBytes;
    sctpEV3 << "storePacket: path=" << pathVar->remoteAddress
              << " osb=" << pathVar->outstandingBytes << " -> "
              << pathVar->outstandingBytes - state->packetBytes << endl;
    assert(pathVar->outstandingBytes >= state->packetBytes);
    pathVar->outstandingBytes -= state->packetBytes;
        qCounter.roomSumSendStreams += state->packetBytes + (dataChunksAdded * SCTP_DATA_CHUNK_LENGTH);
    qCounter.bookedSumSendStreams += state->packetBytes;

}

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

Dealing with streams

Definition at line 62 of file SCTPSSFunctions.cc.

{
    int32 sid, testsid;

    sctpEV3<<"Stream Scheduler: RoundRobin\n";

    sid = -1;

    if ((state->ssLastDataChunkSizeSet == false || state->ssNextStream == false) &&
         (sendStreams.find(state->lastStreamScheduled)->second->getUnorderedStreamQ()->length() > 0 ||
         sendStreams.find(state->lastStreamScheduled)->second->getStreamQ()->length() > 0))
    {
        sid = state->lastStreamScheduled;
        sctpEV3<<"Stream Scheduler: again sid " << sid << ".\n";
        state->ssNextStream = true;
    }
    else
    {
        testsid = state->lastStreamScheduled;

        do {
            testsid = (testsid + 1) % outboundStreams;

            if (sendStreams.find(testsid)->second->getUnorderedStreamQ()->length() > 0 ||
                sendStreams.find(testsid)->second->getStreamQ()->length() > 0)
            {
                sid = testsid;
                sctpEV3<<"Stream Scheduler: chose sid " << sid << ".\n";

                if (!peek)
                    state->lastStreamScheduled = sid;
            }
        } while (sid == -1 && testsid != (int32) state->lastStreamScheduled);

    }

    sctpEV3<<"streamScheduler sid="<<sid<<" lastStream="<<state->lastStreamScheduled<<" outboundStreams="<<outboundStreams<<" next="<<state->ssNextStream<<"\n";

    state->ssLastDataChunkSizeSet = false;

    return sid;
}

void SCTPAssociation::timeForSack ( bool &  sackOnly,
bool &  sackWithData 
) [private]

Definition at line 174 of file SCTPAssociationSendAll.cc.

Referenced by sendOnPath().

{
    sackOnly = sackWithData = false;
        if (((state->numGaps > 0) || (state->dupList.size() > 0)) &&
             (state->sackAllowed)) {
        // Schedule sending of SACKs at once, when we have fragments to report
        state->ackState = sackFrequency;
        sackOnly = sackWithData = true;  // SACK necessary, regardless of data available
    }
    if (state->ackState >= sackFrequency) {
        sackOnly = sackWithData = true;  // SACK necessary, regardless of data available
    }
    else if (SackTimer->isScheduled()) {
        sackOnly         = false;
        sackWithData = true;      // Only send SACK when data is present.
    }
}

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

Manipulating chunks

Definition at line 1129 of file SCTPAssociationUtil.cc.

Referenced by sendOnPath().

{
    SCTPDataChunk*       dataChunk = new SCTPDataChunk("DATA");
    SCTPSimpleMessage* msg        = check_and_cast<SCTPSimpleMessage*>(chunk->userData->dup());
    dataChunk->setChunkType(DATA);
    dataChunk->setBBit(chunk->bbit);
    dataChunk->setEBit(chunk->ebit);
    if (chunk->ordered) {
        dataChunk->setUBit(0);
    }
    else {
        dataChunk->setUBit(1);
    }
    dataChunk->setTsn(chunk->tsn);
    dataChunk->setSid(chunk->sid);
    dataChunk->setSsn(chunk->ssn);
    dataChunk->setPpid(chunk->ppid);
    dataChunk->setEnqueuingTime(chunk->enqueuingTime);
    dataChunk->setBitLength(SCTP_DATA_CHUNK_LENGTH*8);
    msg->setBitLength(chunk->len);
    dataChunk->encapsulate(msg);
    return dataChunk;
}

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

Definition at line 835 of file SCTPAssociation.h.

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

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

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

Definition at line 833 of file SCTPAssociation.h.

Referenced by createSack(), and dequeueAckedChunks().

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

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

Definition at line 834 of file SCTPAssociation.h.

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

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

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

Methods dealing with the handling of TSNs

Definition at line 1276 of file SCTPAssociationUtil.cc.

Referenced by processDataArrived().

{
    for (std::list<uint32>::const_iterator iterator = state->dupList.begin();
          iterator != state->dupList.end(); iterator++)
    {
        if ((*iterator) == tsn)
            return true;
    }
    for (uint32 i=0; i < state->numGaps; i++) {
        if (tsnBetween(state->gapStartList[i], tsn, state->gapStopList[i])) {
            return true;
        }
    }
    return false;
}

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

Definition at line 832 of file SCTPAssociation.h.

Referenced by processDataArrived().

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

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

Compare TSNs

Definition at line 831 of file SCTPAssociation.h.

Referenced by processSackArrived().

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

void SCTPAssociation::tsnWasReneged ( SCTPDataVariables chunk,
const int  type 
) [protected]

Definition at line 666 of file SCTPAssociationRcvMessage.cc.

Referenced by handleChunkReportedAsMissing(), and processSackArrived().

{

#ifdef PKT
    if (transmissionQ->getQueueSize() > 0) {
        for (SCTPQueue::PayloadQueue::iterator tq = transmissionQ->payloadQueue.begin();
              tq != transmissionQ->payloadQueue.end(); tq++) {
            if (tq->second->tsn > chunk->tsn) {
                if (!transmissionQ->checkAndInsertChunk(chunk->tsn, chunk)) {
                    sctpEV3 << "tsnWasReneged: cannot add message/chunk (TSN="
                              << chunk->tsn <<") to the transmissionQ" << endl;
                }
                else {
                    chunk->enqueuedInTransmissionQ = true;
                    chunk->setNextDestination(chunk->getLastDestinationPath());
                    CounterMap::iterator q = qCounter.roomTransQ.find(chunk->getNextDestination());
                    q->second+=ADD_PADDING(chunk->len/8+SCTP_DATA_CHUNK_LENGTH);
                    CounterMap::iterator qb=qCounter.bookedTransQ.find(chunk->getNextDestination());
                    qb->second+=chunk->booksize;
                    return;
                }
            }
        }
    }
#endif
    sctpEV3 << "TSN " << chunk->tsn << " has been reneged (type "
              << type << ")" << endl;
    unackChunk(chunk);
    if (chunk->countsAsOutstanding) {
        decreaseOutstandingBytes(chunk);
    }
    chunk->hasBeenReneged = true;
    chunk->gapReports        = 1;
    if (!chunk->getLastDestinationPath()->T3_RtxTimer->isScheduled()) {
        startTimer(chunk->getLastDestinationPath()->T3_RtxTimer,
                      chunk->getLastDestinationPath()->pathRto);
    }
}

void SCTPAssociation::unackChunk ( SCTPDataVariables chunk  )  [inline, private]

Definition at line 890 of file SCTPAssociation.h.

Referenced by sendOnPath(), and tsnWasReneged().

                                                         {
            chunk->hasBeenAcked = false;
        }

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

Definition at line 1543 of file SCTPAssociationRcvMessage.cc.

{
    bool notifyUlp = false;
    if (++state->errorCount >=   (uint32)sctpMain->par("assocMaxRetrans"))
    {
        sctpEV3 << "Retransmission count during connection setup exceeds " << (int32)sctpMain->par("assocMaxRetrans") << ", giving up\n";
        sendIndicationToApp(SCTP_I_CLOSED);
        sendAbort();
        sctpMain->removeAssociation(this);
        return 0;
    }
    else if (++path->pathErrorCount >=  (uint32)sctpMain->par("pathMaxRetrans"))
    {
        if (path->activePath)
        {
            /* tell the source */
            notifyUlp = true;
        }

        path->activePath = false;
        if (path == state->getPrimaryPath()) {
            state->setPrimaryPath(getNextPath(path));
        }
        sctpEV3<<"process_TIMEOUT_RESET("<<(path->remoteAddress)<<") : PATH ERROR COUNTER EXCEEDED, path status is INACTIVE\n";
        if (allPathsInactive())
        {
            sctpEV3<<"process_TIMEOUT_RESET : ALL PATHS INACTIVE --> closing ASSOC\n";
            sendIndicationToApp(SCTP_I_CONN_LOST);
            sendAbort();
            sctpMain->removeAssociation(this);
            return 0;
        }
        else if (notifyUlp)
        {
            /* notify the application */
            pathStatusIndication(path, false);
        }
        sctpEV3<<"process_TIMEOUT_RESET("<<(path->remoteAddress)<<") : PATH ERROR COUNTER now "<<path->pathErrorCount<<"\n";
        return 2;
    }
    return 1;
}

void SCTPAssociation::updateFastRecoveryStatus ( const uint32  lastTsnAck  )  [protected]

Definition at line 109 of file SCTPCCFunctions.cc.

Referenced by processSackArrived().

{
    for (SCTPPathMap::iterator iter = sctpPathMap.begin(); iter != sctpPathMap.end(); iter++) {
        SCTPPathVariables* path = iter->second;

        if (path->fastRecoveryActive) {
            if ( (tsnGt(lastTsnAck, path->fastRecoveryExitPoint)) ||
                  (lastTsnAck == path->fastRecoveryExitPoint)
            ) {
                path->fastRecoveryActive     = false;
                path->fastRecoveryExitPoint = 0;

                sctpEV3 << simTime() << ":\tCC [cwndUpdateAfterSack] Leaving Fast Recovery on path "
                              << path->remoteAddress
                              << ", lastTsnAck=" << lastTsnAck << endl;
            }
        }
    }
}

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

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

Definition at line 1354 of file SCTPAssociationUtil.cc.

Referenced by processDataArrived().

{
    sctpEV3 << "Entering updateGapList (tsn=" << receivedTsn
              << " cTsnAck=" <<state->cTsnAck << " Number of Gaps="
              << state->numGaps << endl;

    uint32 lo = state->cTsnAck + 1;
    if ((int32)(state->localRwnd-state->queuedReceivedBytes) <= 0)
    {
        sctpEV3 << "Window full" << endl;
        // Only check if cumTsnAck can be advanced
        if (receivedTsn == lo) {
            sctpEV3 << "Window full, but cumTsnAck can be advanced:" << lo << endl;
        }
        else
            return false;
    }

    if (tsnGt(receivedTsn, state->highestTsnStored)) {    // 17.06.08
        state->highestTsnStored = receivedTsn;
    }

    for (uint32 i = 0; i<state->numGaps; i++) {
        if (state->gapStartList[i] > 0) {
            const uint32 hi = state->gapStartList[i] - 1;
            if (tsnBetween(lo, receivedTsn, hi)) {
                const uint32 gapsize = hi - lo + 1;
                if (gapsize > 1) {
                    if (receivedTsn == hi) {
                        state->gapStartList[i] = receivedTsn;
                        state->newChunkReceived = true;
                        return true;
                    }
                    else if (receivedTsn == lo) {
                        if (receivedTsn == (state->cTsnAck + 1)) {
                            state->cTsnAck++;
                            state->newChunkReceived = true;
                            return true;
                        }
                        /* some gap must increase its upper bound */
                        state->gapStopList[i-1] = receivedTsn;
                        state->newChunkReceived = true;
                        return true;
                    }
                    else {  /* a gap in between */
                        state->numGaps = min(state->numGaps + 1, MAX_GAP_COUNT);      // T.D. 18.12.09: Enforce upper limit!

                        for (uint32 j = state->numGaps - 1; j > i; j--) {    // T.D. 18.12.09: Fixed invalid start value.
                            state->gapStartList[j] = state->gapStartList[j-1];
                            state->gapStopList[j] = state->gapStopList[j-1];
                        }
                        state->gapStartList[i]=receivedTsn;
                        state->gapStopList[i]=receivedTsn;
                        state->newChunkReceived = true;
                        return true;
                    }
                }
                else {  /* alright: gapsize is 1: our received tsn may close gap between fragments */
                    if (lo == state->cTsnAck + 1) {
                        state->cTsnAck = state->gapStopList[i];
                        if (i == state->numGaps-1) {
                            state->gapStartList[i] = 0;
                            state->gapStopList[i] = 0;
                        }
                        else {
                            for (uint32 j = i; j < state->numGaps - 1; j++) {        // T.D. 18.12.09: Fixed invalid end value.
                                state->gapStartList[j] = state->gapStartList[j + 1];
                                state->gapStopList[j]  = state->gapStopList[j + 1];
                            }
                        }
                        state->numGaps--;
                        state->newChunkReceived = true;
                        return true;
                    }
                    else {
                        state->gapStopList[i-1] = state->gapStopList[i];
                        if (i == state->numGaps-1) {
                            state->gapStartList[i] = 0;
                            state->gapStopList[i] = 0;
                        }
                        else {
                            for (uint32 j = i; j < state->numGaps - 1; j++) {        // T.D. 18.12.09: Fixed invalid end value.
                                state->gapStartList[j] = state->gapStartList[j + 1];
                                state->gapStopList[j]  = state->gapStopList[j + 1];
                            }
                        }
                        state->numGaps--;
                        state->newChunkReceived = true;
                        return true;
                    }
                }
            }
            else {  /* receivedTsn is not in the gap between these fragments... */
                lo = state->gapStopList[i] + 1;
            }
        } /* end: for */
    }/* end: for */

    /* (NULL LIST)   OR  (End of Gap List passed) */
    if (receivedTsn == lo) {    // just increase ctsna, handle further update of ctsna later
        if (receivedTsn == state->cTsnAck + 1) {
            state->cTsnAck              = receivedTsn;
            state->newChunkReceived = true;
            return true;
        }
        /* Update last fragment....increase stop_tsn by one */
        state->gapStopList[state->numGaps-1]++;

        state->newChunkReceived = true;
        return true;

    }
    else {  // A new fragment altogether, past the end of the list
        if(state->numGaps + 1 <= MAX_GAP_COUNT) {     // T.D. 18.12.09: Enforce upper limit!
            state->gapStartList[state->numGaps] = receivedTsn;
            state->gapStopList[state->numGaps]  = receivedTsn;
            state->numGaps++;
            state->newChunkReceived = true;
        }
        return true;
    }

    return false;
}


Friends And Related Function Documentation

friend class SCTP [friend]

Definition at line 490 of file SCTPAssociation.h.

friend class SCTPPathVariables [friend]

Definition at line 491 of file SCTPAssociation.h.

Referenced by addPath(), processInitAckArrived(), processInitArrived(), and sendInit().


Member Data Documentation

cOutVector* SCTPAssociation::advRwnd [protected]

Definition at line 555 of file SCTPAssociation.h.

Referenced by createSack(), SCTPAssociation(), and ~SCTPAssociation().

Definition at line 562 of file SCTPAssociation.h.

Referenced by bytesAllowedToSend(), SCTPAssociation(), and sendOnPath().

uint16 SCTPAssociation::ccModule [protected]

Definition at line 553 of file SCTPAssociation.h.

Referenced by stateEntered().

cOutVector* SCTPAssociation::cumTsnAck [protected]

Definition at line 556 of file SCTPAssociation.h.

Referenced by SCTPAssociation(), stateEntered(), and ~SCTPAssociation().

cFSM* SCTPAssociation::fsm [protected]
uint32 SCTPAssociation::inboundStreams [protected]
uint32 SCTPAssociation::initPeerTsn [protected]
uint32 SCTPAssociation::initTsn [protected]

Definition at line 548 of file SCTPAssociation.h.

Referenced by sendInit(), and sendInitAck().

Definition at line 531 of file SCTPAssociation.h.

Definition at line 543 of file SCTPAssociation.h.

Referenced by processInitAckArrived(), processInitArrived(), and SCTPAssociation().

cOutVector* SCTPAssociation::numGapBlocks [protected]

Definition at line 558 of file SCTPAssociation.h.

Referenced by SCTPAssociation(), stateEntered(), and ~SCTPAssociation().

uint32 SCTPAssociation::sackFrequency [protected]
double SCTPAssociation::sackPeriod [protected]

Definition at line 551 of file SCTPAssociation.h.

Referenced by scheduleSack(), SCTPAssociation(), and stateEntered().

cOutVector* SCTPAssociation::sendQueue [protected]
uint16 SCTPAssociation::ssModule [protected]

Definition at line 800 of file SCTPAssociation.h.

Referenced by SCTPAssociation().

Definition at line 538 of file SCTPAssociation.h.

Referenced by SCTPAssociation().

Definition at line 561 of file SCTPAssociation.h.

Referenced by advanceCtsna(), bytesAllowedToSend(), calculateBytesToSendOnPath(), cloneAssociation(), createSack(), cwndUpdateAfterSack(), cwndUpdateMaxBurst(), decreaseOutstandingBytes(), dequeueAckedChunks(), dequeueOutboundDataMsg(), getNextDestination(), handleChunkReportedAsMissing(), increaseOutstandingBytes(), initAssociation(), initCCParameters(), initStreams(), loadPacket(), makeRoomForTsn(), makeVarFromMsg(), moveChunkToOtherPath(), nextChunkFitsIntoPacket(), performStateTransition(), pmDataIsSentOn(), pmStartPathManagement(), process_ABORT(), process_ASSOCIATE(), process_CLOSE(), process_OPEN_PASSIVE(), process_PRIMARY(), process_QUEUE_BYTES_LIMIT(), process_QUEUE_MSGS_LIMIT(), process_RCV_Message(), process_RECEIVE_REQUEST(), process_SEND(), process_TIMEOUT_HEARTBEAT(), process_TIMEOUT_INIT_REXMIT(), process_TIMEOUT_RTX(), process_TIMEOUT_SHUTDOWN(), processCookieAckArrived(), processCookieEchoArrived(), processDataArrived(), processHeartbeatAckArrived(), processInitAckArrived(), processInitArrived(), processSackArrived(), processTimer(), pushUlp(), putInDeliveryQ(), removeFromGapList(), retransmitCookieEcho(), retransmitInit(), retransmitShutdown(), retransmitShutdownAck(), scheduleSack(), SCTPAssociation(), sendCookieEcho(), sendEstabIndicationToApp(), sendInit(), sendInitAck(), sendOnPath(), sendSack(), sendShutdown(), sendShutdownAck(), stateEntered(), storePacket(), streamScheduler(), timeForSack(), tsnIsDuplicate(), updateCounters(), updateGapList(), and ~SCTPAssociation().

int32 SCTPAssociation::status [protected]

Definition at line 547 of file SCTPAssociation.h.


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