INET Framework for OMNeT++/OMNEST
SCTPSocket Class Reference

#include <SCTPSocket.h>

List of all members.

Classes

class  CallbackInterface

Public Types

enum  State {
  NOT_BOUND, CLOSED, LISTENING, CONNECTING,
  CONNECTED, PEER_CLOSED, LOCALLY_CLOSED, SOCKERROR
}

Public Member Functions

 SCTPSocket (bool type=true)
 SCTPSocket (cPacket *msg)
 ~SCTPSocket ()
int getConnectionId () const
int getState ()
void setState (int state)
Getter functions
AddressVector getLocalAddresses ()
int getLocalPort ()
AddressVector getRemoteAddresses ()
int getRemotePort ()
IPvXAddress getRemoteAddr ()
Opening and closing connections, sending data
void setOutputGate (cGate *toSctp)
void setOutboundStreams (int streams)
void setInboundStreams (int streams)
int getOutboundStreams ()
int getLastStream ()
void bind (int localPort)
void bind (IPvXAddress localAddr, int localPort)
void bindx (AddressVector localAddr, int localPort)
void addAddress (IPvXAddress addr)
void listen (bool fork=false, uint32 requests=0, uint32 messagesToPush=0)
void connect (IPvXAddress remoteAddress, int32 remotePort, uint32 numRequests)
void connectx (AddressVector remoteAddresses, int32 remotePort, uint32 numRequests=0)
void send (cPacket *msg, bool last=true, bool primary=true)
void sendNotification (cPacket *msg)
void sendRequest (cPacket *msg)
void close ()
void abort ()
void shutdown ()
void requestStatus ()

Static Public Member Functions

static const char * stateName (int state)

Public Attributes

cGate * gateToSctp

Protected Member Functions

void sendToSCTP (cPacket *msg)

Protected Attributes

int assocId
int sockId
int sockstate
bool oneToOne
IPvXAddress localAddr
AddressVector localAddresses
int localPrt
IPvXAddress remoteAddr
AddressVector remoteAddresses
int remotePrt
int fsmStatus
int inboundStreams
int outboundStreams
int lastStream
CallbackInterfacecb
void * yourPtr

Handling of messages arriving from SCTP

bool belongsToSocket (cPacket *msg)
void setCallbackObject (CallbackInterface *cb, void *yourPtr=NULL)
void processMessage (cPacket *msg)
static bool belongsToAnySCTPSocket (cPacket *msg)

Member Enumeration Documentation

Enumerator:
NOT_BOUND 
CLOSED 
LISTENING 
CONNECTING 
CONNECTED 
PEER_CLOSED 
LOCALLY_CLOSED 
SOCKERROR 

Constructor & Destructor Documentation

SCTPSocket::SCTPSocket ( bool  type = true)

Constructor. The connectionId() method returns a valid Id right after constructor call.

{
    sockstate = NOT_BOUND;
    localPrt = remotePrt = 0;
    cb = NULL;
    yourPtr = NULL;
    gateToSctp = NULL;
    lastStream=-1;
    oneToOne = type;
    if (oneToOne)
        assocId = SCTP::getNewConnId();
    else
        assocId = 0;
    sctpEV3<<"sockstate="<<sockstate<<"\n";
}
SCTPSocket::SCTPSocket ( cPacket *  msg)

Constructor, to be used with forked sockets (see listen()). The assocId will be picked up from the message: it should have arrived from SCTPMain and contain SCTPCommmand control info.

SCTPSocket::~SCTPSocket ( )

Destructor

{
    localAddresses.clear();
}

Member Function Documentation

void SCTPSocket::abort ( )

Aborts the association.

Referenced by SCTPClient::handleTimer().

{
    if (sockstate!=NOT_BOUND && sockstate!=CLOSED && sockstate!=SOCKERROR)
    {
        cPacket *msg = new cPacket("ABORT", SCTP_C_ABORT);
        SCTPCommand *cmd = new SCTPCommand();
        //sctpEV3<<"Message cmd="<<&cmd<<"\n";
        cmd->setAssocId(assocId);
        msg->setControlInfo(cmd);
        sendToSCTP(msg);
    }
    sockstate = CLOSED;
}
void SCTPSocket::addAddress ( IPvXAddress  addr)
{
    sctpEV3<<"add address "<<addr<<"\n";
    localAddresses.push_back(addr);
}
bool SCTPSocket::belongsToAnySCTPSocket ( cPacket *  msg) [static]

Returns true if the message belongs to any SCTPSocket instance. (This basically checks if the message has a SCTPCommand attached to it as controlInfo().)

{
    return dynamic_cast<SCTPCommand *>(msg->getControlInfo());
}
bool SCTPSocket::belongsToSocket ( cPacket *  msg)

Returns true if the message belongs to this socket instance (message has a SCTPCommand as controlInfo(), and the assocId in it matches that of the socket.)

{
    bool ret= dynamic_cast<SCTPCommand *>(msg->getControlInfo()) &&
           ((SCTPCommand *)(msg->getControlInfo()))->getAssocId()==assocId;
    sctpEV3<<"assoc="<<((SCTPCommand *)(msg->getControlInfo()))->getAssocId()<<"\n";
    return ret;
}
void SCTPSocket::bind ( int  localPort)

Bind the socket to a local port number.

Referenced by SCTPServer::initialize(), SCTPPeer::initialize(), and SCTPClient::initialize().

{
    if (sockstate!=NOT_BOUND)
        opp_error("SCTPSocket::bind(): socket already bound");
    localAddresses.push_back(IPvXAddress("0.0.0.0"));
    localPrt = lPort;
    sockstate = CLOSED;
}
void SCTPSocket::bind ( IPvXAddress  localAddr,
int  localPort 
)

Bind the socket to a local port number and IP address (useful with multi-homing).

{
    sctpEV3<<"bind address "<<lAddr<<"\n";
    if (sockstate!=NOT_BOUND)
        opp_error("SCTPSocket::bind(): socket already bound");
    localAddresses.push_back(lAddr);
    localPrt = lPort;
    sockstate = CLOSED;
}
void SCTPSocket::bindx ( AddressVector  localAddr,
int  localPort 
)

Referenced by SCTPServer::initialize(), SCTPPeer::initialize(), and SCTPClient::initialize().

{
    IPvXAddress lAddr;
    for (AddressVector::iterator i=lAddresses.begin(); i!=lAddresses.end(); ++i)
    {
        ev<<"bindx: bind address "<<(*i)<<"\n";
        localAddresses.push_back((*i));
    }
    localPrt = lPort;
    sockstate = CLOSED;
}
void SCTPSocket::close ( )

Closes the local end of the connection. With SCTP, a CLOSE operation means "I have no more data to send", and thus results in a one-way connection until the remote SCTP closes too (or the FIN_WAIT_1 timeout expires)

Referenced by SCTPClient::close(), SCTPClient::handleTimer(), SCTPPeer::socketDataArrived(), and SCTPPeer::socketPeerClosed().

{
    sctpEV3<<"SCTPSocket: close\n";

    cPacket *msg = new cPacket("CLOSE", SCTP_C_CLOSE);
    SCTPCommand *cmd = new SCTPCommand();
    cmd->setAssocId(assocId);
    msg->setControlInfo(cmd);
    sendToSCTP(msg);
    sockstate = sockstate==CONNECTED ? LOCALLY_CLOSED : CLOSED;
}
void SCTPSocket::connect ( IPvXAddress  remoteAddress,
int32  remotePort,
uint32  numRequests 
)

Active OPEN to the given remote socket.

Referenced by SCTPPeer::connect(), and SCTPClient::connect().

{
sctpEV3<<"Socket connect. Assoc="<<assocId<<", sockstate="<<sockstate<<"\n";
    if (oneToOne && sockstate!=NOT_BOUND && sockstate!=CLOSED)
        opp_error( "SCTPSocket::connect(): connect() or listen() already called");
    else if (!oneToOne && sockstate!=LISTENING)
        opp_error( "SCTPSocket::connect: One-to-many style socket must be listening");
    cPacket *msg = new cPacket("Associate", SCTP_C_ASSOCIATE);
    remoteAddr = remoteAddress;
    remotePrt = remotePort;
    SCTPOpenCommand *openCmd = new SCTPOpenCommand();
    if (oneToOne)
        openCmd->setAssocId(assocId);
    else
        openCmd->setAssocId(SCTP::getNewConnId());
    sctpEV3<<"Socket connect. Assoc="<<openCmd->getAssocId()<<", sockstate="<<stateName(sockstate)<<"\n";
    //openCmd->setAssocId(assocId);
    openCmd->setLocalAddresses(localAddresses);
    openCmd->setLocalPort(localPrt);
    openCmd->setRemoteAddr(remoteAddr);
    openCmd->setRemotePort(remotePrt);
    openCmd->setOutboundStreams(outboundStreams);
   openCmd->setOutboundStreams(inboundStreams);
    openCmd->setNumRequests(numRequests);
    msg->setControlInfo(openCmd);
    sendToSCTP(msg);
    if (oneToOne)
        sockstate = CONNECTING;
}
void SCTPSocket::connectx ( AddressVector  remoteAddresses,
int32  remotePort,
uint32  numRequests = 0 
)
{
    sctpEV3<<"Socket connectx.  sockstate="<<sockstate<<"\n";
    /*if (sockstate!=NOT_BOUND && sockstate!=CLOSED)
        opp_error( "SCTPSocket::connect(): connect() or listen() already called");*/
    if (oneToOne && sockstate!=NOT_BOUND && sockstate!=CLOSED)
        opp_error( "SCTPSocket::connect(): connect() or listen() already called");
    else if (!oneToOne && sockstate!=LISTENING)
        opp_error( "SCTPSocket::connect: One-to-many style socket must be listening");
    cPacket *msg = new cPacket("Associate", SCTP_C_ASSOCIATE);
    remoteAddresses = remoteAddressList;
    remoteAddr = remoteAddresses.front();
    remotePrt = remotePort;
    SCTPOpenCommand *openCmd = new SCTPOpenCommand();
    openCmd->setAssocId(assocId);
    openCmd->setLocalAddresses(localAddresses);
    openCmd->setLocalPort(localPrt);
    openCmd->setRemoteAddr(remoteAddr);
    openCmd->setRemoteAddresses(remoteAddresses);
    openCmd->setRemotePort(remotePrt);
    openCmd->setOutboundStreams(outboundStreams);
    openCmd->setNumRequests(numRequests);
    msg->setControlInfo(openCmd);
    sendToSCTP(msg);
    if (oneToOne)
        sockstate = CONNECTING;
}
int SCTPSocket::getConnectionId ( ) const [inline]

Returns the internal connection Id. SCTP uses the (gate index, assocId) pair to identify the connection when it receives a command from the application (or SCTPSocket).

Referenced by SCTPPeer::connect(), SCTPPeer::sendQueueRequest(), SCTPClient::sendQueueRequest(), and SCTPClient::setPrimaryPath().

{return assocId;}
int SCTPSocket::getLastStream ( ) [inline]
{return lastStream;};
AddressVector SCTPSocket::getLocalAddresses ( ) [inline]
{return localAddresses;}
int SCTPSocket::getLocalPort ( ) [inline]
{return localPrt;}
int SCTPSocket::getOutboundStreams ( ) [inline]
{return outboundStreams;};
IPvXAddress SCTPSocket::getRemoteAddr ( ) [inline]
{return remoteAddr;}
AddressVector SCTPSocket::getRemoteAddresses ( ) [inline]
{return remoteAddresses;}
int SCTPSocket::getRemotePort ( ) [inline]
{return remotePrt;}
int SCTPSocket::getState ( ) [inline]

Returns the socket state, one of NOT_BOUND, CLOSED, LISTENING, CONNECTING, CONNECTED, etc. Messages received from SCTP must be routed through processMessage() in order to keep socket state up-to-date.

Referenced by SCTPPeer::handleMessage(), SCTPPeer::socketPeerClosed(), and SCTPClient::socketPeerClosed().

{return sockstate;}
void SCTPSocket::listen ( bool  fork = false,
uint32  requests = 0,
uint32  messagesToPush = 0 
)

Initiates passive OPEN. If fork=true, you'll have to create a new SCTPSocket object for each incoming connection, and this socket will keep listening on the port. If fork=false, the first incoming connection will be accepted, and SCTP will refuse subsequent ones. See SCTPOpenCommand documentation (neddoc) for more info.

Referenced by SCTPServer::initialize(), and SCTPPeer::initialize().

{
    if (sockstate!=CLOSED)
        opp_error(sockstate==NOT_BOUND ? "SCTPSocket: must call bind() before listen()"
                                       : "SCTPSocket::listen(): connect() or listen() already called");

    cPacket *msg = new cPacket("PassiveOPEN", SCTP_C_OPEN_PASSIVE);

    SCTPOpenCommand *openCmd = new SCTPOpenCommand();
    //openCmd->setLocalAddr(localAddr);
    openCmd->setLocalAddresses(localAddresses);
    openCmd->setLocalPort(localPrt);
    if (oneToOne)
        openCmd->setAssocId(assocId);
    else
        openCmd->setAssocId(SCTP::getNewConnId());
    openCmd->setFork(fork);
   openCmd->setInboundStreams(inboundStreams);
    openCmd->setOutboundStreams(outboundStreams);
    openCmd->setNumRequests(requests);
    openCmd->setMessagesToPush(messagesToPush);
    msg->setControlInfo(openCmd);
    sctpEV3<<"Assoc "<<openCmd->getAssocId()<<"::send PassiveOPEN to SCTP from socket:listen \n";

    sendToSCTP(msg);
    sockstate = LISTENING;
}
void SCTPSocket::processMessage ( cPacket *  msg)

Examines the message (which should have arrived from SCTPMain), updates socket state, and if there is a callback object installed (see setCallbackObject(), class CallbackInterface), dispatches to the appropriate method of it with the same yourPtr that you gave in the setCallbackObject() call.

The method deletes the message, unless (1) there is a callback object installed AND (2) the message is payload (message kind SCTP_I_DATA or SCTP_I_URGENT_DATA) when the responsibility of destruction is on the socketDataArrived() callback method.

IMPORTANT: for performance reasons, this method doesn't check that the message belongs to this socket, i.e. belongsToSocket(msg) would return true!

Referenced by SCTPPeer::handleMessage(), and SCTPClient::handleMessage().

{
    SCTPStatusInfo *status;
    switch (msg->getKind())
    {
        case SCTP_I_DATA:
            sctpEV3<<"SCTP_I_DATA\n";
            if (cb)
                cb->socketDataArrived(assocId, yourPtr, msg, false);
            break;
        case SCTP_I_DATA_NOTIFICATION:
            sctpEV3<<"SCTP_I_NOTIFICATION\n";
            if (cb)
                cb->socketDataNotificationArrived(assocId, yourPtr, msg);
            break;
        case SCTP_I_SEND_MSG:
            if (cb)
                cb->sendRequestArrived();
            break;
        case SCTP_I_ESTABLISHED:
        {
            if (oneToOne)
                sockstate = CONNECTED;
            SCTPConnectInfo *connectInfo = check_and_cast<SCTPConnectInfo *>(msg->removeControlInfo());
            localAddr = connectInfo->getLocalAddr();
            remoteAddr = connectInfo->getRemoteAddr();
            localPrt = connectInfo->getLocalPort();
            remotePrt = connectInfo->getRemotePort();;
            fsmStatus = connectInfo->getStatus();
            inboundStreams = connectInfo->getInboundStreams();
            outboundStreams = connectInfo->getOutboundStreams();

            if (cb)
                cb->socketEstablished(assocId, yourPtr, connectInfo->getNumMsgs());
            delete connectInfo;
            break;
        }
        case SCTP_I_PEER_CLOSED:
            sctpEV3<<"peer closed\n";
            if (oneToOne)
                sockstate = sockstate==CONNECTED ? PEER_CLOSED : CLOSED;

            if (cb)
                cb->socketPeerClosed(assocId, yourPtr);
            break;
        case SCTP_I_ABORT:
        case SCTP_I_CONN_LOST:
        case SCTP_I_CLOSED:
            sctpEV3<<"SCTP_I_CLOSED called\n";
            sockstate = CLOSED;

            if (cb)
                cb->socketClosed(assocId, yourPtr);
            break;
        case SCTP_I_CONNECTION_REFUSED:
        case SCTP_I_CONNECTION_RESET:
        case SCTP_I_TIMED_OUT:
            sockstate = SOCKERROR;
            if (cb)
                cb->socketFailure(assocId, yourPtr, msg->getKind());

            break;
        case SCTP_I_STATUS:
            status = check_and_cast<SCTPStatusInfo *>(msg->removeControlInfo());

            if (cb)
                cb->socketStatusArrived(assocId, yourPtr, status);
            delete status;
            break;
        case SCTP_I_SHUTDOWN_RECEIVED:
            sctpEV3<<"SCTP_I_SHUTDOWN_RECEIVED\n";
        if (cb)
                cb->shutdownReceivedArrived(assocId);
            break;
        case SCTP_I_SENDQUEUE_FULL:
            if (cb)
                cb->sendqueueFullArrived(assocId);
            break;
        case SCTP_I_SENDQUEUE_ABATED:
        {
            SCTPCommand *cmd = check_and_cast<SCTPCommand *>(msg->removeControlInfo());
            if (cb)
            {
                cb->sendqueueAbatedArrived(assocId, cmd->getNumMsgs());
            }
            delete cmd;
            break;
        }
        default:
            opp_error("SCTPSocket: invalid msg kind %d, one of the SCTP_I_xxx constants expected", msg->getKind());
    }

    delete msg;
}
void SCTPSocket::requestStatus ( )

Causes SCTP to reply with a fresh SCTPStatusInfo, attached to a dummy message as controlInfo(). The reply message can be recognized by its message kind SCTP_I_STATUS, or (if a callback object is used) the socketStatusArrived() method of the callback object will be called.

{
    cPacket *msg = new cPacket("STATUS", SCTP_C_STATUS);
    SCTPCommand *cmd = new SCTPCommand();
    cmd->setAssocId(assocId);
    msg->setControlInfo(cmd);
    sendToSCTP(msg);
}
void SCTPSocket::send ( cPacket *  msg,
bool  last = true,
bool  primary = true 
)

Sends data packet.

Referenced by SCTPPeer::sendRequest(), SCTPClient::sendRequest(), sendToSCTP(), SCTPPeer::socketDataArrived(), and SCTPClient::socketDataArrived().

{
    if (oneToOne && sockstate!=CONNECTED && sockstate!=CONNECTING && sockstate!=PEER_CLOSED) {
        opp_error("SCTPSocket::send(): not connected or connecting");
   }
    else if (!oneToOne && sockstate!=LISTENING) {
        opp_error( "SCTPSocket::send: One-to-many style socket must be listening");
   }
    SCTPSendCommand *cmd = new SCTPSendCommand();
    cmd->setAssocId(assocId);
    if (msg->getKind() == SCTP_C_SEND_ORDERED)
        cmd->setSendUnordered(COMPLETE_MESG_ORDERED);
    else
        cmd->setSendUnordered(COMPLETE_MESG_UNORDERED);
    lastStream=(lastStream+1)%outboundStreams;
    cmd->setSid(lastStream);
    cmd->setLast(last);
    cmd->setPrimary(primary);
    msg->setKind(SCTP_C_SEND);
    msg->setControlInfo(cmd);
    sendToSCTP(msg);
}
void SCTPSocket::sendNotification ( cPacket *  msg)

Referenced by SCTPClient::setPrimaryPath(), SCTPPeer::shutdownReceivedArrived(), SCTPClient::shutdownReceivedArrived(), SCTPPeer::socketDataNotificationArrived(), and SCTPClient::socketDataNotificationArrived().

{
    if (oneToOne && sockstate!=CONNECTED && sockstate!=CONNECTING && sockstate!=PEER_CLOSED) {
        opp_error("SCTPSocket::sendNotification(%s): not connected or connecting", msg->getName());
   }
    else if (!oneToOne && sockstate!=LISTENING) {
        opp_error( "SCTPSocket::send: One-to-many style socket must be listening");
   }
    sendToSCTP(msg);
}
void SCTPSocket::sendRequest ( cPacket *  msg)
void SCTPSocket::sendToSCTP ( cPacket *  msg) [protected]

Referenced by abort(), close(), connect(), connectx(), listen(), requestStatus(), send(), sendNotification(), sendRequest(), and shutdown().

{
    if (!gateToSctp)
        opp_error("SCTPSocket: setOutputGate() must be invoked before socket can be used");
    check_and_cast<cSimpleModule *>(gateToSctp->getOwnerModule())->send(msg, gateToSctp);
}
void SCTPSocket::setCallbackObject ( CallbackInterface cb,
void *  yourPtr = NULL 
)

Sets a callback object, to be used with processMessage(). This callback object may be your simple module itself (if it multiply inherits from CallbackInterface too, that is you declared it as

 class MyAppModule : public cSimpleModule, public SCTPSocket::CallbackInterface
 

and redefined the necessary virtual functions; or you may use dedicated class (and objects) for this purpose.

SCTPSocket doesn't delete the callback object in the destructor or on any other occasion.

YourPtr is an optional pointer. It may contain any value you wish -- SCTPSocket will not look at it or do anything with it except passing it back to you in the CallbackInterface calls. You may find it useful if you maintain additional per-connection information: in that case you don't have to look it up by assocId in the callbacks, you can have it passed to you as yourPtr.

Referenced by SCTPPeer::initialize(), and SCTPClient::initialize().

{
    cb = callback;
    yourPtr = yourPointer;
}
void SCTPSocket::setInboundStreams ( int  streams) [inline]
void SCTPSocket::setOutboundStreams ( int  streams) [inline]
void SCTPSocket::setOutputGate ( cGate *  toSctp) [inline]

Sets the gate on which to send to SCTP. Must be invoked before socket can be used. Example: socket.setOutputGate(gate("sctpOut"));

Referenced by SCTPServer::initialize(), SCTPPeer::initialize(), and SCTPClient::initialize().

{gateToSctp = toSctp;};
void SCTPSocket::setState ( int  state) [inline]
{sockstate = state; };
void SCTPSocket::shutdown ( )

Referenced by SCTPClient::handleTimer(), SCTPClient::sendqueueAbatedArrived(), SCTPPeer::sendRequestArrived(), SCTPClient::sendRequestArrived(), SCTPPeer::socketEstablished(), and SCTPClient::socketEstablished().

{
    ev<<"SCTPSocket: shutdown\n";

    cPacket *msg = new cPacket("Shutdown", SCTP_C_SHUTDOWN);
    SCTPCommand *cmd = new SCTPCommand();
    cmd->setAssocId(assocId);
    msg->setControlInfo(cmd);
    sendToSCTP(msg);
}
const char * SCTPSocket::stateName ( int  state) [static]

Returns name of socket state code returned by state().

Referenced by connect().

{
#define CASE(x) case x: s=#x; break
    const char *s = "unknown";
    switch (state)
    {
        CASE(NOT_BOUND);
        CASE(CLOSED);
        CASE(LISTENING);
        CASE(CONNECTING);
        CASE(CONNECTED);
        CASE(PEER_CLOSED);
        CASE(LOCALLY_CLOSED);
        CASE(SOCKERROR);
    }
    return s;
#undef CASE
}

Member Data Documentation

int SCTPSocket::fsmStatus [protected]

Referenced by processMessage().

Referenced by SCTPSocket(), and sendToSCTP().

int SCTPSocket::inboundStreams [protected]

Referenced by connect(), listen(), and processMessage().

int SCTPSocket::lastStream [protected]

Referenced by SCTPSocket(), and send().

int SCTPSocket::sockId [protected]
void* SCTPSocket::yourPtr [protected]

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