INET Framework for OMNeT++/OMNEST
SCTP Class Reference

#include <SCTP.h>

List of all members.

Classes

struct  AppConnKey
struct  AssocStat
struct  SockPair
struct  VTagPair

Public Types

typedef std::map< int32,
AssocStat
AssocStatMap
typedef std::map< int32, VTagPairSctpVTagMap
typedef std::map< AppConnKey,
SCTPAssociation * > 
SctpAppConnMap
typedef std::map< SockPair,
SCTPAssociation * > 
SctpConnMap

Public Member Functions

void printInfoConnMap ()
void printVTagMap ()
void removeAssociation (SCTPAssociation *assoc)
virtual ~SCTP ()
virtual void initialize ()
virtual void handleMessage (cMessage *msg)
virtual void finish ()
AssocStatgetAssocStat (uint32 assocId)
void updateSockPair (SCTPAssociation *assoc, IPvXAddress localAddr, IPvXAddress remoteAddr, int32 localPort, int32 remotePort)
void addLocalAddress (SCTPAssociation *conn, IPvXAddress address)
void addLocalAddressToAllRemoteAddresses (SCTPAssociation *conn, IPvXAddress address, std::vector< IPvXAddress > remAddresses)
void addRemoteAddress (SCTPAssociation *conn, IPvXAddress localAddress, IPvXAddress remoteAddress)
void removeLocalAddressFromAllRemoteAddresses (SCTPAssociation *conn, IPvXAddress address, std::vector< IPvXAddress > remAddresses)
void removeRemoteAddressFromAllConnections (SCTPAssociation *conn, IPvXAddress address, std::vector< IPvXAddress > locAddresses)
void addForkedAssociation (SCTPAssociation *assoc, SCTPAssociation *newAssoc, IPvXAddress localAddr, IPvXAddress remoteAddr, int32 localPort, int32 remotePort)
uint16 getEphemeralPort ()
SCTPAssociationgetAssoc (int32 assocId)
SCTPAssociationfindAssocWithVTag (uint32 peerVTag, uint32 remotePort, uint32 localPort)
SctpVTagMap getVTagMap ()
void bindPortForUDP ()

Static Public Member Functions

static int32 getNewConnId ()

Public Attributes

AssocStatMap assocStatMap
SctpVTagMap sctpVTagMap
SctpAppConnMap sctpAppConnMap
SctpConnMap sctpConnMap
std::list< SCTPAssociation * > assocList
simtime_t testTimeout
uint32 numGapReports
uint32 numPacketsReceived
uint32 numPacketsDropped

Static Public Attributes

static bool testing
static bool logverbose

Protected Member Functions

SCTPAssociationfindAssocForMessage (IPvXAddress srcAddr, IPvXAddress destAddr, uint32 srcPort, uint32 destPort, bool findListen)
SCTPAssociationfindAssocForApp (int32 appGateIndex, int32 assocId)
void sendAbortFromMain (SCTPMessage *sctpmsg, IPvXAddress srcAddr, IPvXAddress destAddr)
void sendShutdownCompleteFromMain (SCTPMessage *sctpmsg, IPvXAddress srcAddr, IPvXAddress destAddr)
void updateDisplayString ()

Protected Attributes

int32 sizeConnMap
uint16 nextEphemeralPort

Static Protected Attributes

static int32 nextConnId = 0

Detailed Description

Implements the SCTP protocol. This section describes the internal architecture of the SCTP model.

You may want to check the SCTPSocket class which makes it easier to use SCTP from applications.

The SCTP protocol implementation is composed of several classes (discussion follows below):

  • SCTP: the module class
  • SCTPAssociation: manages a connection
  • SCTPSendQueue, SCTPReceiveQueue: abstract base classes for various types of send and receive queues
  • SCTPAlgorithm: abstract base class for SCTP algorithms

SCTP subclassed from cSimpleModule. It manages socketpair-to-connection mapping, and dispatches segments and user commands to the appropriate SCTPAssociation object.

SCTPAssociation manages the connection, with the help of other objects. SCTPAssociation itself implements the basic SCTP "machinery": takes care of the state machine, stores the state variables (TCB), sends/receives etc.

SCTPAssociation internally relies on 3 objects. The first two are subclassed from SCTPSendQueue and SCTPReceiveQueue. They manage the actual data stream, so SCTPAssociation itself only works with sequence number variables. This makes it possible to easily accomodate need for various types of simulated data transfer: real byte stream, "virtual" bytes (byte counts only), and sequence of cMessage objects (where every message object is mapped to a SCTP sequence number range).

Currently implemented send queue and receive queue classes are SCTPVirtualDataSendQueue and SCTPVirtualDataRcvQueue which implement queues with "virtual" bytes (byte counts only).

The third object is subclassed from SCTPAlgorithm. Control over retransmissions, congestion control and ACK sending are "outsourced" from SCTPAssociation into SCTPAlgorithm: delayed acks, slow start, fast rexmit, etc. are all implemented in SCTPAlgorithm subclasses.

The concrete SCTPAlgorithm class to use can be chosen per connection (in OPEN) or in a module parameter.


Member Typedef Documentation

typedef std::map<int32,AssocStat> SCTP::AssocStatMap
typedef std::map<int32, VTagPair> SCTP::SctpVTagMap

Constructor & Destructor Documentation

SCTP::~SCTP ( ) [virtual]
{
    sctpEV3<<"delete SCTPMain\n";
    if (!(sctpAppConnMap.empty()))
    {
        sctpEV3<<"clear appConnMap ptr="<<&sctpAppConnMap<<"\n";
        sctpAppConnMap.clear();
    }
    if (!(assocStatMap.empty()))
    {
        sctpEV3<<"clear assocStatMap ptr="<<&assocStatMap<<"\n";
        assocStatMap.clear();
    }
    if (!(sctpVTagMap.empty()))
    {
        sctpVTagMap.clear();
    }
    sctpEV3<<"after clearing maps\n";
}

Member Function Documentation

void SCTP::addForkedAssociation ( SCTPAssociation assoc,
SCTPAssociation newAssoc,
IPvXAddress  localAddr,
IPvXAddress  remoteAddr,
int32  localPort,
int32  remotePort 
)

Update assocs socket pair, and register newAssoc (which'll keep LISTENing). Also, assoc will get a new assocId (and newAssoc will live on with its old assocId).

Referenced by SCTPAssociation::processInitArrived().

{
    SockPair keyAssoc;

    ev<<"addForkedConnection assocId="<<assoc->assocId<<"    newId="<<newAssoc->assocId<<"\n";

    for (SctpConnMap::iterator j=sctpConnMap.begin(); j!=sctpConnMap.end(); ++j)
        if (assoc->assocId==j->second->assocId)
            keyAssoc = j->first;
    // update conn's socket pair, and register newConn (which'll keep LISTENing)
    updateSockPair(assoc, localAddr, remoteAddr, localPort, remotePort);
    updateSockPair(newAssoc, keyAssoc.localAddr, keyAssoc.remoteAddr, keyAssoc.localPort, keyAssoc.remotePort);
    // conn will get a new assocId...
    AppConnKey key;
    key.appGateIndex = assoc->appGateIndex;
    key.assocId = assoc->assocId;
    sctpAppConnMap.erase(key);
    key.assocId = assoc->assocId = getNewConnId();
    sctpAppConnMap[key] = assoc;

    // ...and newConn will live on with the old assocId
    key.appGateIndex = newAssoc->appGateIndex;
    key.assocId = newAssoc->assocId;
    sctpAppConnMap[key] = newAssoc;
    /*ev<<"assocId="<<assoc->assocId<<" remoteAddr="<<assoc->remoteAddr<<"\n";
    assoc->removeOldPath();*/
    printInfoConnMap();
}
void SCTP::addLocalAddress ( SCTPAssociation conn,
IPvXAddress  address 
)

Referenced by SCTPAssociation::processInitArrived(), and SCTPAssociation::sendInit().

{

        //sctpEV3<<"Add local address: "<<address<<"\n";

        SockPair key;

        key.localAddr = conn->localAddr;
        key.remoteAddr = conn->remoteAddr;
        key.localPort = conn->localPort;
        key.remotePort = conn->remotePort;

        SctpConnMap::iterator i = sctpConnMap.find(key);
        if (i!=sctpConnMap.end())
        {
            ASSERT(i->second==conn);
            if (key.localAddr.isUnspecified())
            {
                sctpConnMap.erase(i);
                sizeConnMap--;
            }
        }
        else
            sctpEV3<<"no actual sockPair found\n";
        key.localAddr = address;
        //key.localAddr = address.get4().getInt();
        // //sctpEV3<<"laddr="<<key.localAddr<<"    lp="<<key.localPort<<"  raddr="<<key.remoteAddr<<" rPort="<<key.remotePort<<"\n";
        sctpConnMap[key] = conn;
        sizeConnMap = sctpConnMap.size();
        sctpEV3<<"number of connections="<<sizeConnMap<<"\n";

        printInfoConnMap();
}
void SCTP::addLocalAddressToAllRemoteAddresses ( SCTPAssociation conn,
IPvXAddress  address,
std::vector< IPvXAddress remAddresses 
)
{

        //sctpEV3<<"Add local address: "<<address<<"\n";

        SockPair key;

        for (AddressVector::iterator i=remAddresses.begin(); i!=remAddresses.end(); ++i)
        {
            //sctpEV3<<"remote address="<<(*i)<<"\n";
            key.localAddr = conn->localAddr;
            key.remoteAddr = (*i);
            key.localPort = conn->localPort;
            key.remotePort = conn->remotePort;

            SctpConnMap::iterator j = sctpConnMap.find(key);
            if (j!=sctpConnMap.end())
            {
            ASSERT(j->second==conn);
            if (key.localAddr.isUnspecified())
                    {
                    sctpConnMap.erase(j);
                    sizeConnMap--;
                }

            }
            else
                sctpEV3<<"no actual sockPair found\n";
            key.localAddr = address;
            sctpConnMap[key] = conn;

            sizeConnMap++;
            sctpEV3<<"number of connections="<<sctpConnMap.size()<<"\n";

            printInfoConnMap();
        }
}
void SCTP::addRemoteAddress ( SCTPAssociation conn,
IPvXAddress  localAddress,
IPvXAddress  remoteAddress 
)

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

{

    sctpEV3<<"Add remote Address: "<<remoteAddress<<" to local Address "<<localAddress<<"\n";

    SockPair key;
    key.localAddr = localAddress;
    key.remoteAddr = remoteAddress;
    key.localPort = conn->localPort;
    key.remotePort = conn->remotePort;

    SctpConnMap::iterator i = sctpConnMap.find(key);
    if (i!=sctpConnMap.end())
    {
        ASSERT(i->second==conn);
    }
    else
    {

        //sctpEV3<<"no actual sockPair found\n";

        sctpConnMap[key] = conn;
        sizeConnMap++;
    }

    //sctpEV3<<"number of connections="<<sctpConnMap.size()<<"\n";
    printInfoConnMap();
}
void SCTP::bindPortForUDP ( )

Referenced by initialize().

{
    EV << "Binding to UDP port " << 9899 << endl;

    cMessage *msg = new cMessage("UDP_C_BIND", UDP_C_BIND);
    UDPControlInfo *ctrl = new UDPControlInfo();
    ctrl->setSrcPort(9899);
    ctrl->setSockId(UDPSocket::generateSocketId());
    msg->setControlInfo(ctrl);
    send(msg, "to_ip");
}
SCTPAssociation * SCTP::findAssocForApp ( int32  appGateIndex,
int32  assocId 
) [protected]

Referenced by handleMessage().

{
    AppConnKey key;
    key.appGateIndex = appGateIndex;
    key.assocId = assocId;
    sctpEV3<<"findAssoc for appGateIndex "<<appGateIndex<<" and assoc "<<assocId<<"\n";
    SctpAppConnMap::iterator i = sctpAppConnMap.find(key);
    return i==sctpAppConnMap.end() ? NULL : i->second;
}
SCTPAssociation * SCTP::findAssocForMessage ( IPvXAddress  srcAddr,
IPvXAddress  destAddr,
uint32  srcPort,
uint32  destPort,
bool  findListen 
) [protected]

Referenced by handleMessage().

{
    SockPair key;

    key.localAddr = destAddr;
    key.remoteAddr = srcAddr;
    key.localPort = destPort;
    key.remotePort = srcPort;
    SockPair save = key;
    sctpEV3<<"findAssocForMessage: srcAddr="<<destAddr<<" destAddr="<<srcAddr<<" srcPort="<<destPort<<"  destPort="<<srcPort<<"\n";
    printInfoConnMap();

    // try with fully qualified SockPair
    SctpConnMap::iterator i;
    i = sctpConnMap.find(key);
    if (i!=sctpConnMap.end())
        return i->second;


    // try with localAddr missing (only localPort specified in passive/active open)
    key.localAddr.set("0.0.0.0");

    i = sctpConnMap.find(key);
    if (i!=sctpConnMap.end())
    {

        //sctpEV3<<"try with localAddr missing (only localPort specified in passive/active open)\n";

        return i->second;
    }

    if (findListen==true)
    {
        /*key = save;
        key.localPort = 0;
        key.localAddr.set("0.0.0.0");
        i = sctpConnMap.find(key);
        if (i!=sctpConnMap.end())
        {
            return i->second;
        }*/


        // try fully qualified local socket + blank remote socket (for incoming SYN)
        key = save;
        key.remoteAddr.set("0.0.0.0");
        key.remotePort = 0;
        i = sctpConnMap.find(key);
        if (i!=sctpConnMap.end())
        {

            //sctpEV3<<"try fully qualified local socket + blank remote socket \n";

            return i->second;
        }


        // try with blank remote socket, and localAddr missing (for incoming SYN)
        key.localAddr.set("0.0.0.0");
        i = sctpConnMap.find(key);
        if (i!=sctpConnMap.end())
        {

            //sctpEV3<<"try with blank remote socket, and localAddr missing \n";

            return i->second;
        }
    }
    // given up

    sctpEV3<<"giving up on trying to find assoc for localAddr="<<srcAddr<<" remoteAddr="<<destAddr<<" localPort="<<srcPort<<" remotePort="<<destPort<<"\n";
    return NULL;
}
SCTPAssociation * SCTP::findAssocWithVTag ( uint32  peerVTag,
uint32  remotePort,
uint32  localPort 
)

Referenced by handleMessage().

{

    printVTagMap();
    sctpEV3<<"findAssocWithVTag: peerVTag="<<peerVTag<<" srcPort="<<remotePort<<"    destPort="<<localPort<<"\n";
    printInfoConnMap();

    // try with fully qualified SockPair
    for (SctpVTagMap::iterator i=sctpVTagMap.begin(); i!=sctpVTagMap.end();i++)
    {
        if ((i->second.peerVTag==peerVTag && i->second.localPort==localPort
            && i->second.remotePort==remotePort)
            || (i->second.localVTag==peerVTag && i->second.localPort==localPort
            && i->second.remotePort==remotePort))
            return getAssoc(i->first);
    }
    return NULL;
}
void SCTP::finish ( ) [virtual]
{
    SctpConnMap::iterator connMapIterator = sctpConnMap.begin();
    while (connMapIterator != sctpConnMap.end()) {
        removeAssociation(connMapIterator->second);
        connMapIterator = sctpConnMap.begin();
    }
    ev << getFullPath() << ": finishing SCTP with "
        << sctpConnMap.size() << " connections open." << endl;

    for (AssocStatMap::const_iterator iterator = assocStatMap.begin();
          iterator != assocStatMap.end(); iterator++) {
        const SCTP::AssocStat& assoc = iterator->second;

        ev << "Association " << assoc.assocId << ": started at " << assoc.start
            << " and finished at " << assoc.stop << " --> lifetime: " << assoc.lifeTime << endl;
        ev << "Association " << assoc.assocId << ": sent bytes=" << assoc.sentBytes
            << ", acked bytes=" << assoc.ackedBytes<< ", throughput=" << assoc.throughput<< " bit/s" << endl;
        ev << "Association " << assoc.assocId << ": transmitted Bytes="
            << assoc.transmittedBytes<< ", retransmitted Bytes=" << assoc.transmittedBytes-assoc.ackedBytes<< endl;
        ev << "Association " << assoc.assocId << ": number of Fast RTX="
            << assoc.numFastRtx << ", number of Timer-Based RTX=" << assoc.numT3Rtx
            << ", path failures=" << assoc.numPathFailures<< ", ForwardTsns=" << assoc.numForwardTsn<< endl;
        ev << "AllMessages=" <<numPacketsReceived<< " BadMessages=" <<numPacketsDropped<< endl;

        recordScalar("Association Lifetime", assoc.lifeTime);
        recordScalar("Acked Bytes",          assoc.ackedBytes);
        recordScalar("Throughput [bit/s]",   assoc.throughput);
        recordScalar("Transmitted Bytes",    assoc.transmittedBytes);
        recordScalar("Fast RTX",                 assoc.numFastRtx);
        recordScalar("Timer-Based RTX",      assoc.numT3Rtx);
        recordScalar("Duplicate Acks",       assoc.numDups);
        recordScalar("Packets Received",         numPacketsReceived);
        recordScalar("Packets Dropped",      numPacketsDropped);

    }
}
SCTPAssociation * SCTP::getAssoc ( int32  assocId)

Referenced by findAssocWithVTag().

{
    for (SctpAppConnMap::iterator i = sctpAppConnMap.begin(); i!=sctpAppConnMap.end(); i++)
    {
        if (i->first.assocId==assocId)
            return i->second;
    }
    return NULL;
}
AssocStat* SCTP::getAssocStat ( uint32  assocId) [inline]

Referenced by SCTPAssociation::dequeueAckedChunks(), and SCTPAssociation::handleChunkReportedAsMissing().

                                                       {
            SCTP::AssocStatMap::iterator found = assocStatMap.find(assocId);
            if(found != assocStatMap.end()) {
              return(&found->second);
            }
            return(NULL);
        }
uint16 SCTP::getEphemeralPort ( )

To be called from SCTPAssociation: reserves an ephemeral port for the connection.

Referenced by SCTPAssociation::process_ASSOCIATE().

{
    if (nextEphemeralPort==5000)
        error("Ephemeral port range 1024..4999 exhausted (email SCTP model "
                "author that he should implement reuse of ephemeral ports!!!)");
    return nextEphemeralPort++;
}
static int32 SCTP::getNewConnId ( ) [inline, static]

Generates a new integer, to be used as assocId. (assocId is part of the key which associates connections with their apps).

Referenced by addForkedAssociation(), SCTPSocket::connect(), SCTPSocket::listen(), and SCTPSocket::SCTPSocket().

{return ++nextConnId;}
SctpVTagMap SCTP::getVTagMap ( ) [inline]
{return sctpVTagMap;};
void SCTP::handleMessage ( cMessage *  msg) [virtual]
{
    IPvXAddress destAddr;
    IPvXAddress srcAddr;
    IPControlInfo *controlInfo =NULL;
    IPv6ControlInfo *controlInfoV6 =NULL;
    bool findListen = false;
    bool bitError = false;

    sctpEV3<<"\n\nSCTPMain handleMessage at "<<getFullPath()<<"\n";

    if (msg->isSelfMessage())
    {

        sctpEV3<<"selfMessage\n";

         SCTPAssociation *assoc = (SCTPAssociation *) msg->getContextPointer();
        bool ret = assoc->processTimer(msg);

        if (!ret)
            removeAssociation(assoc);
    }
    else if (msg->arrivedOn("from_ip") || msg->arrivedOn("from_ipv6"))
    {
        sctpEV3<<"Message from IP\n";
        printInfoConnMap();
        if (!dynamic_cast<SCTPMessage *>(msg))
        {
            sctpEV3<<"no sctp message, delete it\n";
            delete msg;
            return;
        }
        SCTPMessage *sctpmsg = check_and_cast<SCTPMessage *>(msg);

        numPacketsReceived++;

        if ((sctpmsg->hasBitError() || !(sctpmsg->getChecksumOk()))) {
            sctpEV3<<"Packet has bit-error. delete it\n";

            bitError = true;
            numPacketsDropped++;
            delete msg;
            return;
        }
        if (msg->arrivedOn("from_ip"))
        {
            if (par("udpEncapsEnabled"))
            {
                std::cout<<"Laenge SCTPMSG="<<sctpmsg->getByteLength()<<"\n";
                UDPControlInfo *ctrl = check_and_cast<UDPControlInfo *>(msg->removeControlInfo());
                srcAddr = ctrl->getSrcAddr();
                destAddr = ctrl->getDestAddr();
                std::cout<<"controlInfo srcAddr="<<srcAddr<<"  destAddr="<<destAddr<<"\n";
                std::cout<<"VTag="<<sctpmsg->getTag()<<"\n";
            }
            else
            {
                controlInfo = check_and_cast<IPControlInfo *>(msg->removeControlInfo());
                IPDatagram *datagram = controlInfo->removeOrigDatagram();
                delete datagram;
                sctpEV3<<"controlInfo srcAddr="<<controlInfo->getSrcAddr()<<"   destAddr="<<controlInfo->getDestAddr()<<"\n";
                srcAddr = controlInfo->getSrcAddr();
                destAddr = controlInfo->getDestAddr();
            }
        }
        else
        {
            controlInfoV6 = check_and_cast<IPv6ControlInfo *>(msg->removeControlInfo());
            srcAddr = controlInfoV6->getSrcAddr();
            destAddr = controlInfoV6->getDestAddr();
        }


        sctpEV3<<"srcAddr="<<srcAddr<<" destAddr="<<destAddr<<"\n";
        if (sctpmsg->getBitLength()>(SCTP_COMMON_HEADER*8))
        {
            if (((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType()==INIT || ((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType()==INIT_ACK )
                findListen = true;

            SCTPAssociation *assoc = findAssocForMessage(srcAddr, destAddr, sctpmsg->getSrcPort(),sctpmsg->getDestPort(), findListen);
            if (!assoc && sctpConnMap.size()>0)
                assoc = findAssocWithVTag(sctpmsg->getTag(),sctpmsg->getSrcPort(), sctpmsg->getDestPort());
            if (!assoc)
            {
                sctpEV3<<"no assoc found msg="<<sctpmsg->getName()<<"\n";
                if (bitError)
                {
                    delete sctpmsg;
                    return;
                }
                if (((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType()==SHUTDOWN_ACK)
                    sendShutdownCompleteFromMain(sctpmsg, destAddr, srcAddr);
                else if (((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType()!=ABORT  &&
                    ((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType()!=SHUTDOWN_COMPLETE)
                {
                    sendAbortFromMain(sctpmsg, destAddr, srcAddr);
                }
                delete sctpmsg;
            }
            else
            {
                bool ret = assoc->processSCTPMessage(sctpmsg, srcAddr, destAddr);
                if (!ret)
                {
                    sctpEV3<<"SCTPMain:: removeAssociation \n";
                    removeAssociation(assoc);
                    delete sctpmsg;
                }
                else
                {
                    delete sctpmsg;
                }
            }
        }
        else
        {
            delete sctpmsg;
        }
    }
    else // must be from app
    {
        sctpEV3<<"must be from app\n";
        SCTPCommand *controlInfo = check_and_cast<SCTPCommand *>(msg->getControlInfo());

        int32 appGateIndex;
        if (controlInfo->getGate()!=-1)
            appGateIndex = controlInfo->getGate();
        else
            appGateIndex = msg->getArrivalGate()->getIndex();
        int32 assocId = controlInfo->getAssocId();
        sctpEV3<<"msg arrived from app for assoc "<<assocId<<"\n";
        SCTPAssociation *assoc = findAssocForApp(appGateIndex, assocId);

        if (!assoc)
        {
            sctpEV3 << "no assoc found. msg="<<msg->getName()<<" number of assocs = "<<assocList.size()<<"\n";

            if (strcmp(msg->getName(),"PassiveOPEN")==0 || strcmp(msg->getName(),"Associate")==0)
            {
                if (assocList.size()>0)
                {
                    assoc = NULL;
                    SCTPOpenCommand* open = check_and_cast<SCTPOpenCommand*>(controlInfo);
                    sctpEV3<<"Looking for assoc with remoteAddr="<<open->getRemoteAddr()<<", remotePort="<<open->getRemotePort()<<", localPort="<<open->getLocalPort()<<"\n";
                    for (std::list<SCTPAssociation*>::iterator iter=assocList.begin(); iter!=assocList.end(); iter++)
                    {
                        sctpEV3<<"remoteAddr="<<(*iter)->remoteAddr<<", remotePort="<<(*iter)->remotePort<<", localPort="<<(*iter)->localPort<<"\n";
                        if ((*iter)->remoteAddr == open->getRemoteAddr() && (*iter)->localPort==open->getLocalPort() && (*iter)->remotePort==open->getRemotePort())
                        {
                            assoc = (*iter);
                            break;
                        }
                    }
                }
                if (assoc==NULL)
                {
                    assoc = new SCTPAssociation(this,appGateIndex,assocId);

                    AppConnKey key;
                    key.appGateIndex = appGateIndex;
                    key.assocId = assocId;
                    sctpAppConnMap[key] = assoc;
                    sctpEV3 << "SCTP association created for appGateIndex " << appGateIndex << " and assoc "<<assocId<<"\n";
                    bool ret = assoc->processAppCommand(PK(msg));
                    if (!ret)
                    {
                        removeAssociation(assoc);
                    }
                }
            }
        }
        else
        {
            sctpEV3<<"assoc found\n";
            bool ret = assoc->processAppCommand(PK(msg));

            if (!ret)
                removeAssociation(assoc);
        }
        delete msg;
    }
    if (ev.isGUI())
        updateDisplayString();
}
void SCTP::initialize ( ) [virtual]
{
    nextEphemeralPort = (uint16)(intrand(10000) + 30000);

    //sctpEV3<<"SCTPMain initialize\n";

    cModule *netw = simulation.getSystemModule();

    testing = netw->hasPar("testing") && netw->par("testing").boolValue();
    if(testing) {
    }
    if (netw->hasPar("testTimeout"))
    {
        testTimeout = (simtime_t)netw->par("testTimeout");
    }
    numPacketsReceived = 0;
    numPacketsDropped    = 0;
    sizeConnMap          = 0;
    if ((bool)par("udpEncapsEnabled"))
        bindPortForUDP();
}
void SCTP::printInfoConnMap ( )

Referenced by addForkedAssociation(), addLocalAddress(), addLocalAddressToAllRemoteAddresses(), addRemoteAddress(), SCTPAssociation::cloneAssociation(), findAssocForMessage(), findAssocWithVTag(), handleMessage(), removeAssociation(), removeLocalAddressFromAllRemoteAddresses(), removeRemoteAddressFromAllConnections(), SCTPAssociation::sendInit(), and updateSockPair().

{
    SCTPAssociation* assoc;
    SockPair      key;
    sctpEV3<<"Number of Assocs: "<<sizeConnMap<<"\n";
    if (sizeConnMap>0)
    {
        for (SctpConnMap::iterator i = sctpConnMap.begin(); i!=sctpConnMap.end(); ++i)
        {
            assoc = i->second;
            key = i->first;

                sctpEV3<<"assocId: "<<assoc->assocId<<"  assoc: "<<assoc<<" src: "<<IPvXAddress(key.localAddr)<<" dst: "<<IPvXAddress(key.remoteAddr)<<" lPort: "<<key.localPort<<" rPort: "<<key.remotePort<<"\n";

        }

        sctpEV3<<"\n";
    }

}
void SCTP::printVTagMap ( )

Referenced by findAssocWithVTag().

{
    int32 assocId;
    VTagPair      key;
    sctpEV3<<"Number of Assocs: "<<sctpVTagMap.size()<<"\n";
    if (sctpVTagMap.size()>0)
    {
        for (SctpVTagMap::iterator i = sctpVTagMap.begin(); i!=sctpVTagMap.end(); ++i)
        {
            assocId = i->first;
            key = i->second;

                sctpEV3<<"assocId: "<<assocId<<" peerVTag: "<<key.peerVTag<<
                " localVTag: "<<key.localVTag<<
                " localPort: "<<key.localPort<<" rPort: "<<key.remotePort<<"\n";
        }

        sctpEV3<<"\n";
    }
}
void SCTP::removeAssociation ( SCTPAssociation assoc)

Referenced by finish(), handleMessage(), SCTPAssociation::process_RCV_Message(), SCTPAssociation::process_TIMEOUT_HEARTBEAT(), SCTPAssociation::process_TIMEOUT_INIT_REXMIT(), SCTPAssociation::process_TIMEOUT_RTX(), SCTPAssociation::process_TIMEOUT_SHUTDOWN(), SCTPAssociation::processTimer(), and SCTPAssociation::updateCounters().

{
    bool            ok    = false;
    bool            find = false;
    const int32 id    = conn->assocId;

    sctpEV3 << "Deleting SCTP connection " << conn << " id= "<< id << endl;

    printInfoConnMap();
    if (sizeConnMap > 0) {
        AssocStatMap::iterator assocStatMapIterator = assocStatMap.find(conn->assocId);
        if (assocStatMapIterator != assocStatMap.end()) {
            assocStatMapIterator->second.stop        = simulation.getSimTime();
            assocStatMapIterator->second.lifeTime    = assocStatMapIterator->second.stop - assocStatMapIterator->second.start;
            assocStatMapIterator->second.throughput = assocStatMapIterator->second.ackedBytes*8 / assocStatMapIterator->second.lifeTime.dbl();
        }
        while (!ok) {
            if (sizeConnMap == 0) {
                ok = true;
            }
            else {
                for (SctpConnMap::iterator sctpConnMapIterator = sctpConnMap.begin();
                      sctpConnMapIterator != sctpConnMap.end(); sctpConnMapIterator++) {
                    if (sctpConnMapIterator->second != NULL) {
                        SCTPAssociation* assoc = sctpConnMapIterator->second;
                        if (assoc->assocId == conn->assocId) {
                            if (assoc->T1_InitTimer) {
                                assoc->stopTimer(assoc->T1_InitTimer);
                            }
                            if (assoc->T2_ShutdownTimer) {
                                assoc->stopTimer(assoc->T2_ShutdownTimer);
                            }
                            if (assoc->T5_ShutdownGuardTimer) {
                                assoc->stopTimer(assoc->T5_ShutdownGuardTimer);
                            }
                            if (assoc->SackTimer) {
                                assoc->stopTimer(assoc->SackTimer);
                            }
                            sctpConnMap.erase(sctpConnMapIterator);
                            sizeConnMap--;
                            find = true;
                            break;
                        }
                    }
                }
            }

            if (!find) {
                ok = true;
            }
            else {
                find = false;
            }
        }
    }

    // T.D. 26.11.09: Write statistics
    char str[128];
    for (SCTPAssociation::SCTPPathMap::iterator pathMapIterator = conn->sctpPathMap.begin();
          pathMapIterator != conn->sctpPathMap.end(); pathMapIterator++) {
        const SCTPPathVariables* path = pathMapIterator->second;
        snprintf((char*)&str, sizeof(str), "Number of Fast Retransmissions %d:%s",
                 conn->assocId, path->remoteAddress.str().c_str());
        recordScalar(str, path->numberOfFastRetransmissions);
        snprintf((char*)&str, sizeof(str), "Number of Timer-Based Retransmissions %d:%s",
                 conn->assocId, path->remoteAddress.str().c_str());
        recordScalar(str, path->numberOfTimerBasedRetransmissions);
        snprintf((char*)&str, sizeof(str), "Number of Heartbeats Sent %d:%s",
                 conn->assocId, path->remoteAddress.str().c_str());
        recordScalar(str, path->numberOfHeartbeatsSent);
        snprintf((char*)&str, sizeof(str), "Number of Heartbeats Received %d:%s",
                 conn->assocId, path->remoteAddress.str().c_str());
        recordScalar(str, path->numberOfHeartbeatsRcvd);
        snprintf((char*)&str, sizeof(str), "Number of Heartbeat ACKs Sent %d:%s",
                 conn->assocId, path->remoteAddress.str().c_str());
        recordScalar(str, path->numberOfHeartbeatAcksSent);
        snprintf((char*)&str, sizeof(str), "Number of Heartbeat ACKs Received %d:%s",
                 conn->assocId, path->remoteAddress.str().c_str());
        recordScalar(str, path->numberOfHeartbeatAcksRcvd);
    }


    conn->removePath();
    conn->deleteStreams();

    // TD 20.11.09: Chunks may be in the transmission and retransmission queues simultaneously.
    //                   Remove entry from transmission queue if it is already in the retransmission queue.
    for (SCTPQueue::PayloadQueue::iterator i = conn->getRetransmissionQueue()->payloadQueue.begin();
          i != conn->getRetransmissionQueue()->payloadQueue.end(); i++) {
        SCTPQueue::PayloadQueue::iterator j = conn->getTransmissionQueue()->payloadQueue.find(i->second->tsn);
        if(j != conn->getTransmissionQueue()->payloadQueue.end()) {
            conn->getTransmissionQueue()->payloadQueue.erase(j);
        }
    }
     // TD 20.11.09: Now, both queues can be safely deleted.
    delete conn->getRetransmissionQueue();
    delete conn->getTransmissionQueue();

    AppConnKey key;
    key.appGateIndex = conn->appGateIndex;
    key.assocId       = conn->assocId;
    sctpAppConnMap.erase(key);
    assocList.remove(conn);
    delete conn;
}
void SCTP::removeLocalAddressFromAllRemoteAddresses ( SCTPAssociation conn,
IPvXAddress  address,
std::vector< IPvXAddress remAddresses 
)
{

        //sctpEV3<<"Remove local address: "<<address<<"\n";

        SockPair key;

        for (AddressVector::iterator i=remAddresses.begin(); i!=remAddresses.end(); ++i)
        {
            //sctpEV3<<"remote address="<<(*i)<<"\n";
            key.localAddr = address;
            key.remoteAddr = (*i);
            key.localPort = conn->localPort;
            key.remotePort = conn->remotePort;

            SctpConnMap::iterator j = sctpConnMap.find(key);
            if (j!=sctpConnMap.end())
            {
                ASSERT(j->second==conn);
                sctpConnMap.erase(j);
                sizeConnMap--;
            }
            else
                sctpEV3<<"no actual sockPair found\n";

            //sctpEV3<<"number of connections="<<sctpConnMap.size()<<"\n";

            printInfoConnMap();
        }
}
void SCTP::removeRemoteAddressFromAllConnections ( SCTPAssociation conn,
IPvXAddress  address,
std::vector< IPvXAddress locAddresses 
)
{

        //sctpEV3<<"Remove remote address: "<<address<<"\n";

        SockPair key;

        for (AddressVector::iterator i=locAddresses.begin(); i!=locAddresses.end(); i++)
        {
            //sctpEV3<<"local address="<<(*i)<<"\n";
            key.localAddr = (*i);
            key.remoteAddr = address;
            key.localPort = conn->localPort;
            key.remotePort = conn->remotePort;

            SctpConnMap::iterator j = sctpConnMap.find(key);
            if (j!=sctpConnMap.end())
            {
                ASSERT(j->second==conn);
                sctpConnMap.erase(j);
                sizeConnMap--;
            }
            else
                sctpEV3<<"no actual sockPair found\n";

            //sctpEV3<<"number of connections="<<sctpConnMap.size()<<"\n";

            printInfoConnMap();
        }
}
void SCTP::sendAbortFromMain ( SCTPMessage sctpmsg,
IPvXAddress  srcAddr,
IPvXAddress  destAddr 
) [protected]

Referenced by handleMessage().

{
    SCTPMessage *msg = new SCTPMessage();

    sctpEV3<<"\n\nSCTPMain:sendABORT \n";

    msg->setSrcPort(sctpmsg->getDestPort());
    msg->setDestPort(sctpmsg->getSrcPort());
    msg->setBitLength(SCTP_COMMON_HEADER*8);
    msg->setChecksumOk(true);

    SCTPAbortChunk* abortChunk = new SCTPAbortChunk("ABORT");
    abortChunk->setChunkType(ABORT);
    if (sctpmsg->getChunksArraySize()>0 && ((SCTPChunk*)(sctpmsg->getChunks(0)))->getChunkType()==INIT)
    {

        SCTPInitChunk* initChunk = check_and_cast<SCTPInitChunk *>(sctpmsg->getChunks(0));
        abortChunk->setT_Bit(0);
        msg->setTag(initChunk->getInitTag());
    }
    else
    {
        abortChunk->setT_Bit(1);
        msg->setTag(sctpmsg->getTag());
    }
    abortChunk->setBitLength(SCTP_ABORT_CHUNK_LENGTH*8);
    msg->addChunk(abortChunk);
    if ((bool)par("udpEncapsEnabled"))
    {
        msg->setKind(UDP_C_DATA);
        std::cout<<"VTag="<<msg->getTag()<<"\n";
        UDPControlInfo *ctrl = new UDPControlInfo();
        ctrl->setSrcPort(9899);
        ctrl->setDestAddr(destAddr.get4());
        ctrl->setDestPort(9899);
        msg->setControlInfo(ctrl);
    }
    else
    {
        IPControlInfo *controlInfo = new IPControlInfo();
        controlInfo->setProtocol(IP_PROT_SCTP);
        controlInfo->setSrcAddr(srcAddr.get4());
        controlInfo->setDestAddr(destAddr.get4());
        msg->setControlInfo(controlInfo);
    }
    send(msg,"to_ip");
}
void SCTP::sendShutdownCompleteFromMain ( SCTPMessage sctpmsg,
IPvXAddress  srcAddr,
IPvXAddress  destAddr 
) [protected]

Referenced by handleMessage().

{
    SCTPMessage *msg = new SCTPMessage();

    sctpEV3<<"\n\nSCTP:sendABORT \n";

    msg->setSrcPort(sctpmsg->getDestPort());
    msg->setDestPort(sctpmsg->getSrcPort());
    msg->setBitLength(SCTP_COMMON_HEADER*8);
    msg->setChecksumOk(true);

    SCTPShutdownCompleteChunk* scChunk = new SCTPShutdownCompleteChunk("SHUTDOWN_COMPLETE");
    scChunk->setChunkType(SHUTDOWN_COMPLETE);
    scChunk->setTBit(1);
    msg->setTag(sctpmsg->getTag());

    scChunk->setBitLength(SCTP_SHUTDOWN_ACK_LENGTH*8);
    msg->addChunk(scChunk);
    IPControlInfo *controlInfo = new IPControlInfo();
    controlInfo->setProtocol(IP_PROT_SCTP);
    controlInfo->setSrcAddr(srcAddr.get4());
    controlInfo->setDestAddr(destAddr.get4());
    msg->setControlInfo(controlInfo);
    send(msg,"to_ip");
}
void SCTP::updateDisplayString ( ) [protected]

Referenced by handleMessage().

{
    if (ev.disable_tracing)
    {
        // in express mode, we don't bother to update the display
        // (std::map's iteration is not very fast if map is large)
        getDisplayString().setTagArg("t",0,"");
        return;
    }

}
void SCTP::updateSockPair ( SCTPAssociation assoc,
IPvXAddress  localAddr,
IPvXAddress  remoteAddr,
int32  localPort,
int32  remotePort 
)

To be called from SCTPAssociation when socket pair changes

Referenced by addForkedAssociation(), SCTPAssociation::process_ASSOCIATE(), SCTPAssociation::process_OPEN_PASSIVE(), and SCTPAssociation::processInitArrived().

{
    SockPair key;
    sctpEV3<<"updateSockPair:   localAddr: "<<localAddr<<"   remoteAddr="<<remoteAddr<<"    localPort="<<localPort<<" remotePort="<<remotePort<<"\n";

    key.localAddr = (conn->localAddr = localAddr);
    key.remoteAddr = (conn->remoteAddr = remoteAddr);
    key.localPort = conn->localPort = localPort;
    key.remotePort = conn->remotePort = remotePort;

    for (SctpConnMap::iterator i=sctpConnMap.begin(); i!=sctpConnMap.end(); i++)
    {
        if (i->second == conn)
        {
            sctpConnMap.erase(i);
            break;
        }
    }

    sctpEV3<<"updateSockPair conn="<<conn<<"    localAddr="<<key.localAddr<<"            remoteAddr="<<key.remoteAddr<<"     localPort="<<key.localPort<<"  remotePort="<<remotePort<<"\n";

    sctpConnMap[key] = conn;
    sizeConnMap = sctpConnMap.size();
    //sctpEV3<<"number of connections="<<sctpConnMap.size()<<"\n";
    sctpEV3<<"assoc inserted in sctpConnMap\n";
    printInfoConnMap();
}

Member Data Documentation

bool SCTP::logverbose [static]
int32 SCTP::nextConnId = 0 [static, protected]
uint16 SCTP::nextEphemeralPort [protected]

Referenced by getEphemeralPort(), and initialize().

bool SCTP::testing [static]

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