/* ------------------------------------------------------------------
 * Copyright (C) 1998-2010 PacketVideo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * -------------------------------------------------------------------
 */

#include "pvmf_socket_node.h"
#include "oscl_byte_order.h"
#include "pvmf_protocol_engine_command_format_ids.h"
#include "pvmf_media_cmd.h"
#include "pvmf_media_msg_format_ids.h"
#include "oscl_rand.h"
#include "oscl_time.h"
#include "pvmf_socket_node_tunables.h"
#include "oscl_bin_stream.h"
// Use default DLL entry point for Symbian
#include "oscl_dll.h"

//////////////////////////////////////////////////
// PVMFSocketNodeMemPool
//////////////////////////////////////////////////

PVMFSocketNodeMemPool::PVMFSocketNodeMemPool(uint32 aMemPoolNumBufs)
        : iMediaDataMemPool(NULL)
{
    iMediaDataMemPool = OSCL_NEW(OsclMemPoolFixedChunkAllocator, (aMemPoolNumBufs, MEDIA_DATA_CLASS_SIZE));
    iInternalAlloc = NULL;
    iSharedBufferAlloc = NULL;
    iMediaMsgAllocator = NULL;
    iMediaFragGroupAlloc = NULL;
    iMediaFragGroupAllocMempool = NULL;
}

void PVMFSocketNodeMemPool::CreateAllocators(const OSCL_HeapString<OsclMemAllocator>& iMime, uint32 aSize, uint32 aExpectedNumberOfBlocksPerBuffer, uint32 aResizeSize, uint32 aMaxNumResizes)
{
    if (!iSharedBufferAlloc)
    {
        iSharedDataBufferInfo.Init(aSize, aExpectedNumberOfBlocksPerBuffer, aResizeSize, aMaxNumResizes);
        const uint32 maxAllocatorNameLen = 255;
        char allocatorName[maxAllocatorNameLen];
        const uint32 strLenForMimeName  = maxAllocatorNameLen - oscl_strlen("InternalSocketBuffer");
        oscl_strncpy(allocatorName, iMime.get_cstr(), strLenForMimeName);
        allocatorName[strLenForMimeName] = '\0';
        oscl_strcat(allocatorName, "InternalSocketBuffer");
        CreateDefaultDataBufferAllocator(allocatorName);
    }
#if SNODE_ENABLE_UDP_MULTI_PACKET
    CreateUDPMultipleRecvAllocator();
#endif
}

OsclMemPoolResizableAllocator* PVMFSocketNodeMemPool::CreateResizableDataBufferAllocator(const char* allocatorName)
{
    OSCL_UNUSED_ARG(allocatorName);
    if (iMediaMsgAllocator)
    {
        /*
         * It may be possible that the allocator was binded to iInternalAlloc/iSharedBufferAlloc
         * So destruct it.
         * Deallocation of iInternalAlloc/iSharedBufferAlloc will be done as part of Reset/Destruction of node
         */
        OSCL_DELETE(iMediaMsgAllocator);
        iMediaMsgAllocator = NULL;
    }

    OSCL_ASSERT(iSharedBufferAlloc == NULL);
    if (iSharedBufferAlloc)
        return NULL;

    int32 err;
    OSCL_TRY(err,
             iSharedBufferAlloc = OSCL_NEW(OsclMemPoolResizableAllocator, (iSharedDataBufferInfo.iSize, (1 + iSharedDataBufferInfo.iMaxNumResizes),
                                           iSharedDataBufferInfo.iExpectedNumberOfBlocksPerBuffer));
            );
    if (err != OsclErrNone || !iSharedBufferAlloc)
        return NULL;

    iSharedBufferAlloc->setMaxSzForNewMemPoolBuffer(iSharedDataBufferInfo.iResizeSize);
    iMediaMsgAllocator = OSCL_NEW(PVMFResizableSimpleMediaMsgAlloc, (iSharedBufferAlloc));
    return iSharedBufferAlloc;
}

void PVMFSocketNodeMemPool::CreateDefaultDataBufferAllocator(const char* allocatorName)
{
    OSCL_UNUSED_ARG(allocatorName);
    if (iMediaMsgAllocator)
    {
        /*
         * It may be possible that the allocator was binded to iInternalAlloc/iSharedBufferAlloc
         * So destruct it.
         * Deallocation of iInternalAlloc/iSharedBufferAlloc will be done as part of Reset/Destruction of node
         */
        OSCL_DELETE(iMediaMsgAllocator);
        iMediaMsgAllocator = NULL;
    }

    OSCL_ASSERT(iInternalAlloc == NULL);
    if (iInternalAlloc)
        return;

    iInternalAlloc = OSCL_NEW(OsclMemPoolResizableAllocator, (iSharedDataBufferInfo.iSize, (1 + iSharedDataBufferInfo.iMaxNumResizes),
                              iSharedDataBufferInfo.iExpectedNumberOfBlocksPerBuffer));
    iInternalAlloc->setMaxSzForNewMemPoolBuffer(iSharedDataBufferInfo.iResizeSize);
    iMediaMsgAllocator = OSCL_NEW(PVMFResizableSimpleMediaMsgAlloc, (iInternalAlloc));
}

void PVMFSocketNodeMemPool::CreateUDPMultipleRecvAllocator()
{
#if SNODE_ENABLE_UDP_MULTI_PACKET
    //Create the multiple-receive allocator
    iMediaFragGroupAllocMempool
    = OSCL_NEW(OsclMemPoolFixedChunkAllocator
               , (SNODE_UDP_MULTI_FRAG_ALLOCATOR_MAX_MSGS)
              );
    iMediaFragGroupAlloc
    = OSCL_NEW(PVMFMediaFragGroupCombinedAlloc<PVMFSocketNodeAllocator>
               , (SNODE_UDP_MULTI_FRAG_ALLOCATOR_MAX_MSGS
                  , SNODE_UDP_MULTI_FRAG_ALLOCATOR_MAX_FRAGS_PER_MSG
                  , iMediaFragGroupAllocMempool)
              );
    iMediaFragGroupAlloc->create();
#endif
}

uint32 PVMFSocketNodeMemPool::GetMaxSizeMediaMsgLen()
{
    OsclMemPoolResizableAllocator* resizableAllocator = NULL;

    const uint32 wrappingOverhead = iMediaMsgAllocator->GetMediaMsgAllocationOverheadBytes();

    if (iSharedBufferAlloc)
    {
        resizableAllocator = OSCL_STATIC_CAST(OsclMemPoolResizableAllocator*, iSharedBufferAlloc);
    }
    else if (iInternalAlloc)
    {
        resizableAllocator = OSCL_STATIC_CAST(OsclMemPoolResizableAllocator*, iInternalAlloc);
    }

    if (resizableAllocator)
    {
        return (resizableAllocator->getLargestContiguousFreeBlockSize() - wrappingOverhead);
    }

    return 0;
}

void PVMFSocketNodeMemPool::DestroyAllocators()
{
    if (iInternalAlloc != NULL)
    {
        iInternalAlloc->CancelFreeChunkAvailableCallback();
        iInternalAlloc->removeRef();
    }
    if (iSharedBufferAlloc != NULL)
    {
        iSharedBufferAlloc->CancelFreeChunkAvailableCallback();
        iSharedBufferAlloc->removeRef();
    }
    if (iMediaMsgAllocator)
    {
        OSCL_DELETE(iMediaMsgAllocator);
        iMediaMsgAllocator = NULL;
    }
#if SNODE_ENABLE_UDP_MULTI_PACKET
    DestroyUDPMultipleRecvAllocator();
#endif
}

void PVMFSocketNodeMemPool::DestroyUDPMultipleRecvAllocator()
{
#if SNODE_ENABLE_UDP_MULTI_PACKET
    if (iMediaFragGroupAlloc)
    {
        iMediaFragGroupAlloc->removeRef();
        iMediaFragGroupAlloc = NULL;
    }
    if (iMediaFragGroupAllocMempool)
    {
        iMediaFragGroupAllocMempool->removeRef();
        iMediaFragGroupAllocMempool = NULL;
    }
#endif
}

//////////////////////////////////////////////////
// SocketNodeStats
//////////////////////////////////////////////////

#if(ENABLE_SOCKET_NODE_STATS)
void SocketNodeStats::Log(PVMFPortVector<PVMFSocketPort, PVMFSocketNodeAllocator>& aPortVec)
{
    if (iLogged)
        return;//prevent multiple logging.
    if (!iLogger)
        return;//prevent logging after thread logoff.
    iLogged = true;

    PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iLogger, PVLOGMSG_ERR,
                    (0, "SocketNodeStats:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"));

    PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iLogger, PVLOGMSG_ERR,
                    (0, "SocketNodeStats: %8d Num Run", iNumRun));
    PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iLogger, PVLOGMSG_ERR,
                    (0, "SocketNodeStats: %8d Num QueueNodeCmd", iNumQueueNodeCmd));

    PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iLogger, PVLOGMSG_ERR,
                    (0, "SocketNodeStats: %8d Num Bind", iNumBind));

    for (uint32 i = 0; i < aPortVec.size(); i++)
    {
        if (aPortVec[i]->iConfig)
            aPortVec[i]->iConfig->iPortStats.Log(iLogger, aPortVec[i]->iConfig->iMime);
    }

    PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iLogger, PVLOGMSG_ERR,
                    (0, "SocketNodeStats:@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"));
}
#endif //ENABLE_SOCKET_NODE_STATS

//////////////////////////////////////////////////
// SocketPortConfig
//////////////////////////////////////////////////
SocketPortConfig::SocketPortConfig()
{
    iPVMFPort = NULL;
    iSockId = 0;
    iUDPSocket = NULL;
    iTCPSocket = NULL;
    iDNS = NULL;
    iMemPool    = NULL;
    iContainer = NULL;
    iTag = PVMF_SOCKET_NODE_PORT_TYPE_UNKNOWN;
    iRTP = false;
    iRTCP = false;

    iMaxTcpRecvBufferSize = SNODE_DEFAULT_SOCKET_TCP_BUFFER_SIZE;
    iMaxTcpRecvBufferCount = SNODE_DEFAULT_SOCKET_TCP_BUFFER_COUNT;
}

void SocketPortConfig::CreateAllocators(uint32 aSize, uint32 aExpectedNumberOfBlocksPerBuffer, uint32 aResizeSize, uint32 aMaxNumResizes)
{
    iMemPool->CreateAllocators(iMime, aSize, aExpectedNumberOfBlocksPerBuffer, aResizeSize, aMaxNumResizes);
}

void SocketPortConfig::CleanupMemPools(Oscl_DefAlloc& aAlloc)
{
    if (iMemPool)
    {
        iMemPool->DestroyAllocators();
        iMemPool->~PVMFSocketNodeMemPool();
        aAlloc.deallocate((OsclAny*)(iMemPool));
        iMemPool = NULL;
    }
}

//////////////////////////////////////////////////
// End SocketPortConfig
//////////////////////////////////////////////////

//////////////////////////////////////////////////
// Standard Node APIs
//////////////////////////////////////////////////

OSCL_EXPORT_REF PVMFSocketNode::PVMFSocketNode(int32 aPriority)
        : PVMFNodeInterfaceImpl(aPriority, "PVMFSocketNode")
        , TIMEOUT_CONNECT(30000)
        , TIMEOUT_SEND(3000)
        , TIMEOUT_SENDTO(3000)
        , TIMEOUT_RECV(-1)
        , TIMEOUT_RECVFROM(-1)
        , TIMEOUT_SHUTDOWN(10000)
        , MAX_UDP_PACKET_SIZE(MAX_SOCKET_BUFFER_SIZE)
        , MIN_UDP_PACKET_SIZE(MIN_SOCKET_BUFFER_SIZE)
        , iMaxTCPRecvBufferSizeToConfigure(-1)
        , iMaxTCPRecvBufferCntToConfigure(-1)
{
    iLogger = NULL;
    iDataPathLogger = NULL;
    iDataPathLoggerRTP = NULL;
    iDataPathLoggerRTCP = NULL;
    iOsclErrorTrapImp = NULL;
    iSockServ = NULL;
    iSocketID = 0;
    iCommandErrorCode = PVMFSocketNodeErrorEventStart;
    iErrorEventErrorCode = PVMFSocketNodeErrorEventStart;
    iExtensionInterface = NULL;
    iInSocketCallback = false;
    iNumStopPortActivityPending = (-1);//inactive.
    iUdpPortRange = 2000;
    int32 err;
    OSCL_TRY(err,
             //Create the port vector.
             iPortVector.Construct(PVMF_SOCKET_NODE_PORT_VECTOR_RESERVE);

             //Set the node capability data.
             //This node can support an unlimited number of ports.
             iNodeCapability.iCanSupportMultipleInputPorts = true;
             iNodeCapability.iCanSupportMultipleOutputPorts = true;
             iNodeCapability.iHasMaxNumberOfPorts = false;
             iNodeCapability.iMaxNumberOfPorts = 0;//no maximum

             iNodeCapability.iInputFormatCapability.push_back(PVMF_MIME_INET_UDP);
             iNodeCapability.iInputFormatCapability.push_back(PVMF_MIME_INET_TCP);

             iNodeCapability.iOutputFormatCapability.push_back(PVMF_MIME_INET_TCP);
             iNodeCapability.iOutputFormatCapability.push_back(PVMF_MIME_INET_UDP);

             iDnsCache.NewL();

            );

    if (err != OsclErrNone)
    {
        //if a leave happened, cleanup and re-throw the error
        iPortVector.clear();
        iNodeCapability.iInputFormatCapability.clear();
        iNodeCapability.iOutputFormatCapability.clear();
        OSCL_CLEANUP_BASE_CLASS(PVMFNodeInterfaceImpl);
        OSCL_LEAVE(err);
    }

    iLogger = PVLogger::GetLoggerObject("PVMFSocketNode");
    iDataPathLogger = PVLogger::GetLoggerObject("datapath.socketnode");
    iDataPathLoggerRTP = PVLogger::GetLoggerObject("datapath.socketnode.rtp");
    iDataPathLoggerRTCP = PVLogger::GetLoggerObject("datapath.socketnode.rtcp");
    iOsclErrorTrapImp = OsclErrorTrap::GetErrorTrapImp();
}


OSCL_EXPORT_REF PVMFSocketNode::~PVMFSocketNode()
{
#if(ENABLE_SOCKET_NODE_STATS)
    iSocketNodeStats.Log(iPortVector);
    iSocketNodeStats.Logoff();
#endif

    Cancel();

    //thread logoff
    if (IsAdded())
        RemoveFromScheduler();

    if (iExtensionInterface)
    {
        iExtensionInterface->removeRef();
    }

    /* Cleanup allocated ports */
    CleanupPorts();
    iPortVector.clear();
    CleanupClosedTCPSockets();
    CleanupClosedUDPSockets();
    CleanupClosedDNS();

    PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode:~PVMFSocketNode - Going to delete Sock Serv"));
    if (iSockServ)
    {
        iSockServ->Close();
        iSockServ->~OsclSocketServ();
        iAlloc.deallocate(iSockServ);
        iSockServ = NULL;
    }
    PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode:~PVMFSocketNode out"));
}

//retrieve a port iterator.
OSCL_EXPORT_REF PVMFPortIter* PVMFSocketNode::GetPorts(const PVMFPortFilter* aFilter)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode:GetPorts"));

    OSCL_UNUSED_ARG(aFilter);//port filter is not implemented.
    iPortVector.Reset();
    return &iPortVector;
}

//Port activity handler
void PVMFSocketNode::HandlePortActivity(const PVMFPortActivity &aActivity)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "0x%x PVMFSocketNode::HandlePortActivity IN: port=0x%x, type=%d",
                     this, aActivity.iPort, aActivity.iType));

    switch (aActivity.iType)
    {

        case PVMF_PORT_ACTIVITY_CONNECT:
        {
            PVMFSocketPort* sockPort = OSCL_STATIC_CAST(PVMFSocketPort*, aActivity.iPort);
            OSCL_ASSERT(sockPort && sockPort->iConfig);
            SocketPortConfig& aSockConfig = *sockPort->iConfig;
            aSockConfig.CreateAllocators(aSockConfig.iMaxTcpRecvBufferSize *(aSockConfig.iMaxTcpRecvBufferCount - 1), aSockConfig.iMaxTcpRecvBufferCount - 1, aSockConfig.iMaxTcpRecvBufferSize, 1);
#if(ENABLE_SOCKET_NODE_STATS)
            aSockConfig.iPortStats.iNumPortEventConnect++;
#endif

            //Receives may have been blocked waiting on the port to be connected, so check here.
            //Note: This is a known use case for HTTP streaming, where the port request and connect
            //can happen after the node start
            if (CanReceive(aSockConfig))
                StartRecvOperation(aSockConfig);
        }
        break;

        case PVMF_PORT_ACTIVITY_INCOMING_MSG:
        {
            PVMFSocketPort* sockPort = (PVMFSocketPort*)(aActivity.iPort);
            OSCL_ASSERT(sockPort && sockPort->iConfig);
            SocketPortConfig& aSockConfig = *sockPort->iConfig;

#if(ENABLE_SOCKET_NODE_STATS)
            aSockConfig.iPortStats.iNumPortEventIncomingMsg++;
#endif

            //Try to process this message now.
            if (CanProcessIncomingMsg(aSockConfig))
                ProcessIncomingMsg(aSockConfig);
            //Otherwise, ignore this event now.  Other code will check
            //the input queue as needed.
        }
        break;

        case PVMF_PORT_ACTIVITY_CONNECTED_PORT_READY:
        {
            PVMFSocketPort* sockPort = (PVMFSocketPort*)(aActivity.iPort);
            OSCL_ASSERT(sockPort && sockPort->iConfig);
            SocketPortConfig& aSockConfig = *sockPort->iConfig;

#if(ENABLE_SOCKET_NODE_STATS)
            aSockConfig.iPortStats.iNumPortEventConnectedPortReady++;
#endif

            //See if the port was waiting on this event, and if so, continue processing.

            if (aSockConfig.iState.iConnectOperation == EPVSocketPortConnectOperation_WaitOnConnectedPort)
            {
#if(ENABLE_SOCKET_NODE_STATS)
                aSockConfig.iPortStats.EndConnectTime(aSockConfig.iState.iConnectOperation);
#endif
                ConnectOperationComplete(aSockConfig, PVMFSuccess, NULL);
            }

            if (aSockConfig.iState.iRecvOperation == EPVSocketPortRecvOperation_WaitOnConnectedPort)
            {
#if(ENABLE_SOCKET_NODE_STATS)
                aSockConfig.iPortStats.EndRecvTime(aSockConfig.iState.iRecvOperation);
#endif
                RecvOperationComplete(aSockConfig, PVMFSuccess, NULL);
            }

            //Otherwise ignore this event now.  Other code will check connected
            //port status as needed.
        }
        break;

        default:
            //all other events can be ignored.
            break;
    }
}

//////////////////////////////////////////////////
// End Standard Node APIs
//////////////////////////////////////////////////

//////////////////////////////////////////////////
// Additional Public APIs unique to Socket Node
//////////////////////////////////////////////////

OSCL_EXPORT_REF bool PVMFSocketNode::GetPortConfig(PVMFPortInterface &aPort, OsclNetworkAddress &aLocalAdd, OsclNetworkAddress &aRemoteAdd)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::GetPortConfig IN"));
    aLocalAdd.ipAddr.Set("0.0.0.0");
    aLocalAdd.port = 0;

    aRemoteAdd.ipAddr.Set("");
    aRemoteAdd.port = 0;

    for (uint32 i = 0; i < iPortVector.size(); i++)
    {
        if (iPortVector[i]->iConfig
                && iPortVector[i]->iConfig->iPVMFPort == &aPort)
        {
            aLocalAdd = iPortVector[i]->iConfig->iAddr.iLocalAdd;
            aRemoteAdd = iPortVector[i]->iConfig->iAddr.iRemoteAdd;
            return true;
        }
    }
    return false;
}

OSCL_EXPORT_REF bool PVMFSocketNode::SetPortConfig(PVMFPortInterface &aPort, OsclNetworkAddress aLocalAdd, OsclNetworkAddress aRemoteAdd)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::SetPortConfig IN"));
    for (uint32 i = 0; i < iPortVector.size(); i++)
    {
        if (iPortVector[i]->iConfig
                && iPortVector[i]->iConfig->iPVMFPort == &aPort)
        {
            iPortVector[i]->iConfig->iAddr.iLocalAdd = aLocalAdd;
            iPortVector[i]->iConfig->iAddr.iRemoteAdd = aRemoteAdd;
            return true;
        }
    }
    return false;
}

OSCL_EXPORT_REF PVMFStatus PVMFSocketNode::SetMaxUDPPortNum(uint32& aMaxUdpPortNum, uint32& aMinUdpPortNum)
{
    iUdpPortRange = aMaxUdpPortNum - aMinUdpPortNum;
    return PVMFSuccess;
}
//////////////////////////////////////////////////
// End Additional Public APIs unique to Socket Node
//////////////////////////////////////////////////


//Create UDP sockets on consecutive ports.
//This is needed because 3GPP streaming servers require consecutive ports.
//If successfully created, the sockets are saved in the "allocated port" vector.
//The created sockets will be associated with PVMF ports later during RequestPort
//commands.
PVMFStatus PVMFSocketNode::AllocateConsecutivePorts(PvmfMimeString* aPortConfig,
        uint32& aLowerPortNum,
        uint32& aHigherPortNum, uint32& aStartPortNum)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::AllocateConsecutivePorts IN"));

    //used in case of 3GPP streaming to allocate consecutive udp ports
    //for rtp and rtcp.
    //lower port number = rtp => PVMF_SOCKET_NODE_PORT_TYPE_SOURCE
    //higher port number = rtcp => PVMF_SOCKET_NODE_PORT_TYPE_SINK
    aLowerPortNum = 0;
    aHigherPortNum = 0;

    uint32 startSockID = iSocketID;

    PVMFStatus status = PVMFFailure;

    SocketPortConfig* lower_sock_config = OSCL_NEW(SocketPortConfig, ());
    SocketPortConfig* higher_sock_config = OSCL_NEW(SocketPortConfig, ());

    for (int maxNumOfBind = iUdpPortRange; maxNumOfBind >= 0; maxNumOfBind--)
    {
        OSCL_HeapString<OsclMemAllocator> rtpportConfigWithMime;
        rtpportConfigWithMime += aPortConfig->get_cstr();
        rtpportConfigWithMime += _STRLIT_CHAR("/rtp");
        ParseTransportConfig(&rtpportConfigWithMime,
                             lower_sock_config->iAddr,
                             lower_sock_config->iMime);
        //this should only be UDP
        if (lower_sock_config->iAddr.iProtocol != INET_UDP)
        {
            status = PVMFErrArgument;
            goto Exit;
        }
        lower_sock_config->iContainer = this;
        lower_sock_config->iAddr.iLocalAdd.port = aStartPortNum;
        lower_sock_config->iSockId = startSockID++;
        lower_sock_config->iRTP = true;

        if (NULL == (lower_sock_config->iUDPSocket = (OsclUDPSocket*)CreateOsclSocketAndBind(lower_sock_config->iAddr, lower_sock_config->iSockId)))
        {
            status = PVMFFailure;
            goto Exit;
        }

        OSCL_HeapString<OsclMemAllocator> rtcpportConfigWithMime;
        rtcpportConfigWithMime += aPortConfig->get_cstr();
        rtcpportConfigWithMime += _STRLIT_CHAR("/rtcp");

        ParseTransportConfig(&rtcpportConfigWithMime,
                             higher_sock_config->iAddr,
                             higher_sock_config->iMime);
        //this should only be UDP
        if (higher_sock_config->iAddr.iProtocol != INET_UDP)
        {
            status = PVMFErrArgument;
            goto Exit;
        }
        higher_sock_config->iContainer = this;
        higher_sock_config->iAddr.iLocalAdd.port =
            lower_sock_config->iAddr.iLocalAdd.port + 1;
        higher_sock_config->iSockId = startSockID++;
        higher_sock_config->iRTCP = true;

        if (NULL == (higher_sock_config->iUDPSocket = (OsclUDPSocket*)CreateOsclSocketAndBind(higher_sock_config->iAddr, higher_sock_config->iSockId)))
        {
            status = PVMFFailure;
            goto Exit;
        }

        //We were able to create and bind, now see whether we got consecutive ports or not.
        if (higher_sock_config->iAddr.iLocalAdd.port ==
                (lower_sock_config->iAddr.iLocalAdd.port + 1))
        {
            aLowerPortNum = lower_sock_config->iAddr.iLocalAdd.port;
            lower_sock_config->iPVMFPort = NULL;
            lower_sock_config->iTag = PVMF_SOCKET_NODE_PORT_TYPE_SOURCE;
            iAllocatedPortVector.push_back(lower_sock_config);

            aHigherPortNum = higher_sock_config->iAddr.iLocalAdd.port;
            higher_sock_config->iPVMFPort = NULL;
            higher_sock_config->iTag = PVMF_SOCKET_NODE_PORT_TYPE_SINK;
            iAllocatedPortVector.push_back(higher_sock_config);

            iSocketID = startSockID;
            aStartPortNum = higher_sock_config->iAddr.iLocalAdd.port + 1;

            status = PVMFSuccess;
            goto Exit;
        }
        else
        {
            //Delete and try again
            OsclUDPSocket* udpSocket1 = lower_sock_config->iUDPSocket;
            udpSocket1->~OsclUDPSocket();
            iAlloc.deallocate(udpSocket1);
            lower_sock_config->iUDPSocket = NULL;

            OsclUDPSocket* udpSocket2 = higher_sock_config->iUDPSocket;
            udpSocket2->~OsclUDPSocket();
            iAlloc.deallocate(udpSocket2);
            higher_sock_config->iUDPSocket = NULL;
            aStartPortNum = higher_sock_config->iAddr.iLocalAdd.port + 1;
            startSockID = iSocketID;
        }
    }//for max port bind attempts


    status = PVMFFailure;

Exit:
    if (status != PVMFSuccess)
    {
        OSCL_DELETE(lower_sock_config);
        OSCL_DELETE(higher_sock_config);
    }
    return status;
}

OSCL_EXPORT_REF PVMFStatus PVMFSocketNode::SetMaxTCPRecvBufferSize(uint32 aBufferSize, PVMFPortInterface* aPort)
{
    PVMFStatus status =  PVMFErrArgument;
    if (aPort)
    {
        for (uint32 ii = 0; ii < iPortVector.size(); ii++)
        {
            PVMFSocketPort* sockPort = iPortVector[ii];
            SocketPortConfig* sockConfig = sockPort->iConfig;
            if (sockConfig && sockConfig->iPVMFPort && aPort == sockConfig->iPVMFPort)
            {
                sockConfig->iMaxTcpRecvBufferSize = aBufferSize;
                status =  PVMFSuccess;
                break;
            }
        }
    }
    else
    {
        for (uint32 ii = 0; ii < iPortVector.size(); ii++)
        {
            PVMFSocketPort* sockPort = iPortVector[ii];
            SocketPortConfig* sockConfig = sockPort->iConfig;
            if (sockConfig)
            {
                sockConfig->iMaxTcpRecvBufferSize = aBufferSize;
            }
            else
            {
                iMaxTCPRecvBufferSizeToConfigure = aBufferSize;
            }
        }
        if (0 == iPortVector.size())
        {
            iMaxTCPRecvBufferSizeToConfigure = aBufferSize;
        }
        status =  PVMFSuccess;
    }

    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::SetMaxTCPRecvBufferSize status --- [%d]", status));
    return status;
}

OSCL_EXPORT_REF PVMFStatus PVMFSocketNode::GetMaxTCPRecvBufferSize(uint32& aSize, PVMFPortInterface* aPort) const
{
    PVMFStatus status =  PVMFErrArgument;
    if (aPort)
    {
        for (uint32 ii = 0; ii < iPortVector.size(); ii++)
        {
            PVMFSocketPort* sockPort = iPortVector[ii];
            SocketPortConfig* sockConfig = sockPort->iConfig;
            if (sockConfig->iPVMFPort && aPort == sockConfig->iPVMFPort)
            {
                aSize = sockConfig->iMaxTcpRecvBufferSize;
                status =  PVMFSuccess;
                break;
            }
        }
    }
    else
    {
        if (1 == iPortVector.size())
        {
            PVMFSocketPort* sockPort = iPortVector[0];
            SocketPortConfig* sockConfig = sockPort->iConfig;
            aSize = sockConfig->iMaxTcpRecvBufferSize;
            status =  PVMFSuccess;
        }
        else if (0 == iPortVector.size())
        {
            aSize = (iMaxTCPRecvBufferSizeToConfigure > 0) ? iMaxTCPRecvBufferSizeToConfigure : SNODE_DEFAULT_SOCKET_TCP_BUFFER_SIZE;
            status =  PVMFSuccess;
        }
        else
        {
            status =  PVMFFailure;
        }
    }

    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::GetMaxTCPRecvBufferSize --- [%d]", status));
    return status;
}

OSCL_EXPORT_REF PVMFStatus PVMFSocketNode::SetMaxTCPRecvBufferCount(uint32 aCount, PVMFPortInterface* aPort)
{
    PVMFStatus status =  PVMFErrArgument;

    if (aPort)
    {
        for (uint32 ii = 0; ii < iPortVector.size(); ii++)
        {
            PVMFSocketPort* sockPort = iPortVector[ii];
            SocketPortConfig* sockConfig = sockPort->iConfig;
            if (sockConfig->iPVMFPort && aPort == sockConfig->iPVMFPort)
            {
                sockConfig->iMaxTcpRecvBufferCount = aCount;
                status =  PVMFSuccess;
                break;
            }
        }
    }
    else
    {
        for (uint32 ii = 0; ii < iPortVector.size(); ii++)
        {
            PVMFSocketPort* sockPort = iPortVector[ii];
            SocketPortConfig* sockConfig = sockPort->iConfig;
            if (sockConfig)
            {
                sockConfig->iMaxTcpRecvBufferCount = aCount;
            }
            else
            {
                iMaxTCPRecvBufferCntToConfigure = aCount;
            }
        }
        if (0 == iPortVector.size())
        {
            iMaxTCPRecvBufferCntToConfigure = aCount;
        }
        status =  PVMFSuccess;
    }
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::SetMaxTCPRecvBufferCount status --- [%d]", status));
    return status;
}

OSCL_EXPORT_REF PVMFStatus PVMFSocketNode::GetMaxTCPRecvBufferCount(uint32& aCount, PVMFPortInterface* aPort) const
{
    PVMFStatus status =  PVMFErrArgument;
    if (aPort)
    {
        for (uint32 ii = 0; ii < iPortVector.size(); ii++)
        {
            PVMFSocketPort* sockPort = iPortVector[ii];
            SocketPortConfig* sockConfig = sockPort->iConfig;
            if (sockConfig->iPVMFPort && aPort == sockConfig->iPVMFPort)
            {
                aCount = sockConfig->iMaxTcpRecvBufferCount;
                status =  PVMFSuccess;
                break;
            }
        }
    }
    else
    {
        if (1 == iPortVector.size())
        {
            PVMFSocketPort* sockPort = iPortVector[0];
            SocketPortConfig* sockConfig = sockPort->iConfig;
            aCount = sockConfig->iMaxTcpRecvBufferCount;
            status =  PVMFSuccess;
        }
        else if (0 == iPortVector.size())
        {
            aCount = (iMaxTCPRecvBufferCntToConfigure > 0) ? iMaxTCPRecvBufferCntToConfigure : SNODE_DEFAULT_SOCKET_TCP_BUFFER_COUNT;
            status =  PVMFSuccess;
        }
        else
        {
            status =  PVMFFailure;
        }
    }
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::GetMaxTCPRecvBufferCount status --- [%d]", status));
    return status;
}

OsclMemPoolResizableAllocator* PVMFSocketNode::CreateSharedBuffer(const PVMFPortInterface* aPort , uint32 aBufferSize, uint32 aExpectedNumberOfBlocksPerBuffer, uint32 aResizeSize, uint32 aMaxNumResizes)
{
    //validate input params if required..
    OSCL_ASSERT(aPort);
    if (!aPort)
        return NULL;

    //If data buffer for the port is already created and is existing, then destroy the prev buffer and create new one (with requested attributes).
    //CreateResizableDataBufferAllocator func will take care of this.
    SocketPortConfig* portConfig = OSCL_STATIC_CAST(PVMFSocketPort*, aPort)->iConfig;
    PVMFSocketNodeMemPool * portMemPool = portConfig->iMemPool;
    portMemPool->iSharedDataBufferInfo.Init(aBufferSize, aExpectedNumberOfBlocksPerBuffer, aResizeSize, aMaxNumResizes);
    return portMemPool->CreateResizableDataBufferAllocator(portConfig->iMime.get_cstr());
}
///////////////////////////
// End Socket Extension Interface
///////////////////////////


//////////////////////////////////////
// Incoming Message Handlers
//////////////////////////////////////

//Tell whether it's possible to process an incoming message on a port.
bool PVMFSocketNode::CanProcessIncomingMsg(SocketPortConfig& aSockConfig)
{
    return
        //node is started
        iInterfaceState == EPVMFNodeStarted
        //port has input messages
        && aSockConfig.iPVMFPort && aSockConfig.iPVMFPort->IncomingMsgQueueSize() > 0
        //port is not busy with any sequence
        && aSockConfig.iState.iSequence == EPVSocketPortSequence_None;
}

//Process an incoming message on this port.
//Assume caller already verified "can process incoming msg".
void PVMFSocketNode::ProcessIncomingMsg(SocketPortConfig& aSockConfig)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::ProcessIncomingMsg: aPort=0x%x", aSockConfig.iPVMFPort));

    //Dequeue the incoming message
    PVMFSharedMediaMsgPtr msg;
    PVMFStatus status = aSockConfig.iPVMFPort->DequeueIncomingMsg(msg);
    if (status != PVMFSuccess)
    {
        PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::ProcessIncomingDataMsg: Error - DequeueIncomingMsg failed"));
        ReportErrorEvent(PVMFErrPortProcessing);
        return ;
    }

    //calling logic should prevent processing a message when some other sequence
    //is active on the port
    OSCL_ASSERT(aSockConfig.iState.iSequence == EPVSocketPortSequence_None);

    //Handle 3 types of messages
    if (msg->getFormatID() == PVMF_MEDIA_CMD_SOCKET_CONNECT_FORMAT_ID)
    {
#if(ENABLE_SOCKET_NODE_STATS)
        aSockConfig.iPortStats.iNumDequeueIncomingConnectMsg++;
#endif
        //Connect message
        PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::ProcessIncomingMsg - CONNECT SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_cstr()));

        //Parse the address
        OsclRefCounterMemFrag newSockAddr;
        msg->getFormatSpecificInfo(newSockAddr);
        if (newSockAddr.getMemFragPtr())
        {
            if (!ParseTransportConfig((char*)newSockAddr.getMemFragPtr(),
                                      newSockAddr.getMemFragSize(),
                                      aSockConfig.iAddr,
                                      aSockConfig.iMime))
            {
                PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::ProcessIncomingMsg: ERROR - Invalid port config"));
                ReportSocketNodeError(PVMFErrPortProcessing, PVMFSocketNodeErrorInvalidPortTag);
                return ;
            }
        }

        //Start the sequence
        StartSequence(aSockConfig, EPVSocketPortSequence_InputConnectMsg);
    }
    else if (msg->getFormatID() == PVMF_MEDIA_CMD_SOCKET_DISCONNECT_FORMAT_ID)
    {
#if(ENABLE_SOCKET_NODE_STATS)
        aSockConfig.iPortStats.iNumDequeueIncomingDisconnectMsg++;
#endif
        //Disconnect message
        PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::ProcessIncomingMsg - DISCONNECT msg - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_cstr()));

        //Start the sequence
        StartSequence(aSockConfig, EPVSocketPortSequence_InputDisconnectMsg);
    }
    else if (msg->getFormatID() == PVMF_MEDIA_MSG_DATA_FORMAT_ID)
    {
#if(ENABLE_SOCKET_NODE_STATS)
        aSockConfig.iPortStats.iNumDequeueIncomingDataMsg++;
#endif
        //Media Data message
        PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::ProcessIncomingMsg - MEDIA DATA msg - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_cstr()));

        //calling logic should prevent any simultaneous send/connect
        OSCL_ASSERT(aSockConfig.iState.iConnectOperation == EPVSocketPortConnectOperation_None);

        //Start the sequence
        StartSequence(aSockConfig, EPVSocketPortSequence_InputDataMsg, (OsclAny*)&msg);
    }
    else
    {
        //unexpected message type
        ReportErrorEvent(PVMFErrPortProcessing);
    }
}


//////////////////////////////////////
// End Incoming Message Handlers
//////////////////////////////////////

//////////////////////////////////////
// Connect Operation Handlers
//////////////////////////////////////


//Start the given "connect" operation on the port.
//If the connect fails, this will call "connect operation complete" and continue to
//the next operation.
PVMFStatus PVMFSocketNode::StartConnectOperation(SocketPortConfig& aSockConfig, TPVSocketPortConnectOperation aOperation)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::StartConnectOperation() In Operation %d", aOperation));

    //connect operation should be idle now.
    OSCL_ASSERT(aSockConfig.iState.iConnectOperation == EPVSocketPortConnectOperation_None);

    //Update the state
    aSockConfig.iState.iConnectOperation = aOperation;

    PVMFStatus status = PVMFFailure;

    switch (aOperation)
    {
        case EPVSocketPortConnectOperation_GetHostByName:
        {
            //This is the beginning of TCP socket create/connect.

            //this should be TCP.
            OSCL_ASSERT(aSockConfig.iAddr.iProtocol == INET_TCP);

            //Any old socket should be cleaned up or else queued for cleanup at this point.
            OSCL_ASSERT(!aSockConfig.iTCPSocket);

            //Create the socket
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartConnectOperation GetHostByName, Creating socket - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            aSockConfig.iTCPSocket = (OsclTCPSocket*)CreateOsclSocketAndBind(aSockConfig.iAddr, aSockConfig.iSockId);
            if (!aSockConfig.iTCPSocket)
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartConnectOperation GetHostByName, Creating socket FAILED - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::StartConnectOperation: ERROR - CreateSocket()"));
                if (aSockConfig.iState.iSequence == EPVSocketPortSequence_RequestPort)
                {
                    iCommandErrorCode = PVMFSocketNodeErrorSocketFailure;
                }
                else
                {
                    ReportSocketNodeError(PVMFErrResource, PVMFSocketNodeErrorSocketFailure);
                }
                status = PVMFErrResource;
                break;
            }

            //see if DNS is needed
            if (OsclValidInetAddr(aSockConfig.iAddr.iRemoteHost.get_cstr()))
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartConnectOperation GetHostByName, DNS is not needed - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                aSockConfig.iAddr.iRemoteAdd.ipAddr.Set(aSockConfig.iAddr.iRemoteHost.get_cstr());
                status = PVMFSuccess;//no lookup needed-- continue to next operation.
                break;
            }

            //DNS lookup needed.
            //see if we can use the DNS cache instead of an actual lookup
            aSockConfig.iAddr.iRemoteAdd.ipAddr.Set("");
            if (iDnsCache.QueryGetHostByName(aSockConfig.iAddr.iRemoteHost.get_str(), (char*)aSockConfig.iAddr.iRemoteAdd.ipAddr.Str(), aSockConfig.iAddr.iRemoteAdd.ipAddr.MaxLen()))
            {
                //DNS cache lookup success
                PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartConnectOperation GetHostByName, DNS cache lookup success - SockId=%d, Mime=%s, Host=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str(), aSockConfig.iAddr.iRemoteHost.get_str()));
                status = PVMFSuccess;//no lookup needed-- continue to next operation.
                break;
            }

            //Create DNS object
            if (!aSockConfig.iDNS)
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartConnectOperation GetHostByName, Creating DNS object - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                aSockConfig.iDNS = OsclDNS::NewL(iAlloc, *iSockServ, *this, aSockConfig.iSockId);
                if (!aSockConfig.iDNS)
                {
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartConnectOperation GetHostByName, Creating DNS FAILED - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                    PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::StartConnectOperation: ERROR - Create DNS()"));
                    if (aSockConfig.iState.iSequence == EPVSocketPortSequence_RequestPort)
                    {
                        iCommandErrorCode = PVMFSocketNodeError_DNSLookup;
                    }
                    else
                    {
                        ReportSocketNodeError(PVMFErrResource, PVMFSocketNodeError_DNSLookup);
                    }
                    status = PVMFErrResource;
                    break;
                }
            }

            //start the asynchronous DNS operation.

#if(ENABLE_SOCKET_NODE_STATS)
            aSockConfig.iPortStats.iNumGetHostByName++;
            aSockConfig.iPortStats.StartConnectTime(aSockConfig.iState.iConnectOperation);
#endif

            TPVDNSEvent aEvent = aSockConfig.iDNS->GetHostByName(aSockConfig.iAddr.iRemoteHost.get_str(),
                                 aSockConfig.iAddr.iRemoteAdd, -1);
            if (EPVDNSPending != aEvent)
            {
                aSockConfig.iState.iConnectOperation = EPVSocketPortConnectOperation_None;
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::StartConnectOperation: GetHostByName Failed - SockId=%d, Mime=%s, Host=%s",
                                                  aSockConfig.iSockId, aSockConfig.iMime.get_str(),
                                                  aSockConfig.iAddr.iRemoteHost.get_str()));
                if (aSockConfig.iState.iSequence == EPVSocketPortSequence_RequestPort)
                {
                    iCommandErrorCode = PVMFSocketNodeError_DNSLookup;
                }
                else
                {
                    ReportSocketNodeError(PVMFErrResource, PVMFSocketNodeError_DNSLookup);
                }
                status = PVMFErrResource;
                break;
            }

            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartConnectOperation: Waiting On DNS - SockId=%d, Mime=%s, Host=%s",
                                              aSockConfig.iSockId, aSockConfig.iMime.get_str(),
                                              aSockConfig.iAddr.iRemoteHost.get_str()));
#if (ENABLE_SOCKET_NODE_DEBUG_INFO_EVENT)
            ReportInfoEvent(PVMFSocketNodeInfoEventRequestedDNSResolution);
#endif
            status = PVMFPending;
            //wait on the DNS lookup to complete in HandleDNSEvent callback
        }
        break;

        case EPVSocketPortConnectOperation_Connect:
            //Initiate a socket connect, after DNS lookup was successful or address is already IP.
            //Will return "pending" or an error.
        {
            if (!aSockConfig.iTCPSocket)
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::StartConnectOperation: ERROR socket already exists - SockId=%d, Mime=%s",
                                                  aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                status = PVMFFailure;//unexpected
                break;
            }

            //start the asynchronous connect operation.

#if(ENABLE_SOCKET_NODE_STATS)
            aSockConfig.iPortStats.iNumConnect++;
            aSockConfig.iPortStats.StartConnectTime(aSockConfig.iState.iConnectOperation);
#endif

            TPVSocketEvent ret = aSockConfig.iTCPSocket->Connect(aSockConfig.iAddr.iRemoteAdd, TIMEOUT_CONNECT);
            if (ret != EPVSocketPending)
            {
                //failure
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::StartConnectOperation: Starting Connect FAILED - SockId=%d, Mime=%s, RemoteIP=%s",
                                                  aSockConfig.iSockId, aSockConfig.iMime.get_str(),
                                                  (char*)(aSockConfig.iAddr.iRemoteAdd.ipAddr.Str())));
                if (aSockConfig.iState.iSequence == EPVSocketPortSequence_RequestPort)
                {
                    iCommandErrorCode = PVMFSocketNodeError_TCPSocketConnect;
                }
                else
                {
                    ReportSocketNodeError(PVMFErrResource, PVMFSocketNodeError_TCPSocketConnect);
                }
                status = PVMFErrResource;
                break;
            }
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartConnectOperation - Socket Connect Pending...SockId=%d, Mime=%s, RemoteIP=%s"
                                              , aSockConfig.iSockId, aSockConfig.iMime.get_str(),
                                              (char*)(aSockConfig.iAddr.iRemoteAdd.ipAddr.Str())));
#if (ENABLE_SOCKET_NODE_DEBUG_INFO_EVENT)
            ReportInfoEvent(PVMFSocketNodeInfoEventConnectRequestPending);
#endif
            status = PVMFPending;
            //wait on the socket connect to complete in HandleSocketEvent callback
        }
        break;

        case EPVSocketPortConnectOperation_Shutdown:
        {
            if (!aSockConfig.iTCPSocket)
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::StartConnectOperation: ERROR socket already exists - SockId=%d, Mime=%s",
                                                  aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                status = PVMFFailure;//unexpected
                break;
            }

            //Initiate a socket shutdown.
#if(ENABLE_SOCKET_NODE_STATS)
            aSockConfig.iPortStats.iNumShutdown++;
            aSockConfig.iPortStats.StartConnectTime(aSockConfig.iState.iConnectOperation);
#endif
            TPVSocketEvent ret = aSockConfig.iTCPSocket->Shutdown(EPVSocketBothShutdown, TIMEOUT_SHUTDOWN);
            if (ret == EPVSocketPending)
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::StartConnectOperation - Shutdown Pending...SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                status = PVMFPending;
                //wait on the socket shutdown to complete in HandleSocketEvent callback
            }
            else
            {
                status = PVMFFailure;
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::StartConnectOperation - Shutdown FAILED - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            }
        }
        break;

        case EPVSocketPortConnectOperation_WaitOnConnectedPort:
            if (aSockConfig.iPVMFPort
                    && aSockConfig.iPVMFPort->IsOutgoingQueueBusy())
            {
#if(ENABLE_SOCKET_NODE_STATS)
                aSockConfig.iPortStats.iNumWaitOnConnectedPort++;
                aSockConfig.iPortStats.StartConnectTime(aSockConfig.iState.iConnectOperation);
#endif
                status = PVMFPending;
                //wait for CONNECTED_PORT_READY event in HandlePortActivity
            }
            else
            {
                status = PVMFSuccess;//nothing needed.
            }
            break;

        case EPVSocketPortConnectOperation_WaitOnSendRecvIdle:
            if (aSockConfig.iState.iRecvOperation == EPVSocketPortRecvOperation_None
                    && aSockConfig.iState.iSendOperation == EPVSocketPortSendOperation_None)
            {
                //send/recv are already idle.
                status = PVMFSuccess;
            }
            else
            {
#if(ENABLE_SOCKET_NODE_STATS)
                aSockConfig.iPortStats.iNumWaitOnSendRecvIdle++;
                aSockConfig.iPortStats.StartConnectTime(aSockConfig.iState.iConnectOperation);
#endif
                status = PVMFPending;
                //wait for send/recv completion (in RecvOperationComplete or SendOperationComplete)
            }
            break;

        default:
            //add code to handle this case
            status = PVMFFailure;
            OSCL_ASSERT(0);
            break;
    }

    //Handle synchronous completion or failure.
    if (status != PVMFPending)
        status = ConnectOperationComplete(aSockConfig, status, NULL);

    return status;
}

//The current connect operation is complete.
//Continue with the next operation, or finish the sequence.
//The status is in "aStatus".  If there was a socket callback, the result is in "aSocketActivity".
PVMFStatus PVMFSocketNode::ConnectOperationComplete(SocketPortConfig& aSockConfig, PVMFStatus aStatus, PVMFSocketActivity* aSocketActivity)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::ConnectOperationComplete() in"));

    //status should never be "pending" here
    OSCL_ASSERT(aStatus != PVMFPending);

    PVMFStatus status = aStatus;

    TPVSocketPortConnectOperation curOp = aSockConfig.iState.iConnectOperation;
    aSockConfig.iState.iConnectOperation = EPVSocketPortConnectOperation_None;
    aSockConfig.iState.iConnectOperationStatus = aStatus;
    aSockConfig.iState.iConnectOperationCanceled = false;


    switch (curOp)
    {
        case EPVSocketPortConnectOperation_None:
            //unexpected.
            break;

        case EPVSocketPortConnectOperation_GetHostByName:
            //TCP Get Host By Name is complete

            //catch completion of connect cancel during the cleanup sequence
            if (aSockConfig.iState.iSequence == EPVSocketPortSequence_SocketCleanup)
            {
                //Continue the shutdown sequence
                status = StartConnectOperation(aSockConfig, EPVSocketPortConnectOperation_Shutdown);
                break;
            }
            //else normal connect sequence.

            if (aStatus == PVMFSuccess)
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::ConnectOperationComplete GetHostByName Success - SockId=%d, Mime=%s Host= %s", aSockConfig.iSockId, aSockConfig.iMime.get_str()
                                                  , aSockConfig.iAddr.iRemoteHost.get_str()));
                //Save lookup results in the DNS cache
                if (aSocketActivity)
                {
                    iDnsCache.UpdateCacheRecord(aSockConfig.iAddr.iRemoteHost.get_str(), (char*)aSockConfig.iAddr.iRemoteAdd.ipAddr.Str());
                }

                //DNS Lookup is always followed by a Connect
                status = StartConnectOperation(aSockConfig, EPVSocketPortConnectOperation_Connect);
            }
            else
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::ConnectOperationComplete GetHostByName FAILED - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                //If DNS lookup failed, then fail the current sequence with
                //an error.
                switch (aSockConfig.iState.iSequence)
                {
                    case EPVSocketPortSequence_RequestPort:
                        //report the error in the command complete
                        iCommandErrorCode = PVMFSocketNodeError_DNSLookup;
                        break;
                    default:
                        //report the error in an error message
                        ReportSocketNodeError(PVMFErrResource, PVMFSocketNodeError_DNSLookup);
                        break;
                }
                //Fail the sequence.
                SequenceComplete(aSockConfig, aStatus);
            }
            break;

        case EPVSocketPortConnectOperation_Connect:
            //TCP Connect is complete

            //catch completion of connect cancel during the cleanup sequence
            if (aSockConfig.iState.iSequence == EPVSocketPortSequence_SocketCleanup)
            {
                //Continue the shutdown sequence
                status = StartConnectOperation(aSockConfig, EPVSocketPortConnectOperation_Shutdown);
                break;
            }
            //else normal connect sequence.

            if (aStatus == PVMFSuccess)
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::ConnectOperationComplete Connect Success - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            }
            else
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::ConnectOperationComplete Connect FAILED - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                //Report connect errors.
                switch (aSockConfig.iState.iSequence)
                {
                    case EPVSocketPortSequence_RequestPort:
                        //for a node command, we report the error in the node command completion message
                        iCommandErrorCode = PVMFSocketNodeError_TCPSocketConnect;
                        break;
                    case EPVSocketPortSequence_InputConnectMsg:
                    default:
                        //for other sequences, we report the error in an error message.
                        ReportSocketNodeError(PVMFErrResource, PVMFSocketNodeError_TCPSocketConnect);
                        break;
                }
            }
            //Connect complete is always the end of a sequence.
            SequenceComplete(aSockConfig, aStatus);
            break;

        case EPVSocketPortConnectOperation_Shutdown:
            //TCP Shutdown is complete

            if (aStatus == PVMFSuccess)
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::ConnectOperationComplete Shutdown Success - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            }
            else
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::ConnectOperationComplete Shutdown FAILED - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                if (aSocketActivity)
                {
                    PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::ConnectOperationComplete: ERROR aEvent=%d, Ln %d", aSocketActivity->iEvent, __LINE__));
                }
            }

            //Note: ignore shutdown failures and just continue onto the
            //next operation.

            //Shutdown is followed by waiting for send/recv to go idle.

            //On most OS the shutdown command is sufficient to cause send/recv to complete,
            //but on some it doesn't, so cancel any outstanding send/recv op here.
            CancelSendOperation(aSockConfig);
            CancelRecvOperation(aSockConfig);

            status = StartConnectOperation(aSockConfig, EPVSocketPortConnectOperation_WaitOnSendRecvIdle);
            break;

        case EPVSocketPortConnectOperation_WaitOnConnectedPort:
            //TCP Wait on connected port is complete.

            //Proceed to send the EOS and close the socket
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::ConnectOperationComplete WaitOnConnectedPort Calling CleanupTCP - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            CleanupTCP(aSockConfig);

            //Check the sequence...
            switch (aSockConfig.iState.iSequence)
            {
                case EPVSocketPortSequence_InputConnectMsg:
                    //a disconnect is followed by a host lookup + connect
                    //for an input connect message
                    status = StartConnectOperation(aSockConfig, EPVSocketPortConnectOperation_GetHostByName);
                    break;

                default:
                    //for all other sequences, this is the end
                    SequenceComplete(aSockConfig, PVMFSuccess);
                    status = PVMFSuccess;
                    break;
            }
            break;

        case EPVSocketPortConnectOperation_WaitOnSendRecvIdle:
            //UDP or TCP "Wait on Send/Recv Idle" is complete.

            //If TCP, wait on connected port to send EOS
            if (aSockConfig.iTCPSocket)
            {
                status = StartConnectOperation(aSockConfig, EPVSocketPortConnectOperation_WaitOnConnectedPort);
            }
            //If UDP, proceed to close & delete
            else if (aSockConfig.iUDPSocket)
            {
                CleanupUDP(aSockConfig);
                //This is the end of the sequence.
                SequenceComplete(aSockConfig, PVMFSuccess);
                status = PVMFSuccess;
            }
            else
            {
                //unexpected, but end the sequence anyway.
                SequenceComplete(aSockConfig, PVMFSuccess);
                status = PVMFSuccess;
            }
            break;


        default:
            OSCL_ASSERT(0);//unexpected, add code for this case.
            break;
    }
    return status;
}

PVMFStatus PVMFSocketNode::CancelConnectOperation(SocketPortConfig& aSockConfig)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::CancelConnectOperation() In"));

    PVMFStatus status = PVMFSuccess;

    switch (aSockConfig.iState.iConnectOperation)
    {
        case EPVSocketPortConnectOperation_None:
            break;

        case EPVSocketPortConnectOperation_GetHostByName:
            if (aSockConfig.iDNS)
            {
                if (!aSockConfig.iState.iConnectOperationCanceled)
                {
                    aSockConfig.iState.iConnectOperationCanceled = true;
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CancelConnectOperation Calling CancelGetHostByName - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                    aSockConfig.iDNS->CancelGetHostByName();
                }
                status = PVMFPending;
                //wait for host lookup to complete in HandleDNSEvent
            }
            break;

        case EPVSocketPortConnectOperation_Connect:
            if (aSockConfig.iTCPSocket)
            {
                if (!aSockConfig.iState.iConnectOperationCanceled)
                {
                    aSockConfig.iState.iConnectOperationCanceled = true;
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CancelConnectOperation Calling CancelConnect - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                    aSockConfig.iTCPSocket->CancelConnect();
                }
                status = PVMFPending;
                //wait for connect to complete in HandleSocketEvent
            }
            break;

        case EPVSocketPortConnectOperation_Shutdown:
            if (aSockConfig.iTCPSocket)
            {
                if (!aSockConfig.iState.iConnectOperationCanceled)
                {
                    aSockConfig.iState.iConnectOperationCanceled = true;
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CancelConnectOperation Calling CancelShutdown - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                    aSockConfig.iTCPSocket->CancelShutdown();
                }
                status = PVMFPending;
                //wait for shutdown to complete in HandleSocketEvent
            }
            break;

        case EPVSocketPortConnectOperation_WaitOnConnectedPort:
            //just clear the state
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CancelConnectOperation Cancelling WaitOnConnectedPort - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            aSockConfig.iState.iConnectOperation = EPVSocketPortConnectOperation_None;
            break;

        case EPVSocketPortConnectOperation_WaitOnSendRecvIdle:
            //just clear the state
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CancelConnectOperation Cancelling WaitOnSendRecvIdle - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            aSockConfig.iState.iConnectOperation = EPVSocketPortConnectOperation_None;
            break;

        default:
            OSCL_ASSERT(0);//add code for this case
            status = PVMFFailure;
            break;
    }
    return status;
}

//////////////////////////////////////
// End Connect Operation Handlers
//////////////////////////////////////

//////////////////////////////////
// Receive Operation Handlers
//////////////////////////////////

//Tell if it's possible to initiate a recv or recvfrom operation
//on this port.
bool PVMFSocketNode::CanReceive(SocketPortConfig& aSockConfig)
{
    return
        //node is started
        iInterfaceState == EPVMFNodeStarted
        //port is connected
        && aSockConfig.iPVMFPort && aSockConfig.iPVMFPort->IsConnected()
        //socket exists (gets created during request port or connect sequence)
        && (aSockConfig.iUDPSocket || aSockConfig.iTCPSocket)
        //port is not busy with any sequence other than sending data
        && (aSockConfig.iState.iSequence == EPVSocketPortSequence_None
            || aSockConfig.iState.iSequence == EPVSocketPortSequence_InputDataMsg)
        //port is not busy with any receive operation.
        && aSockConfig.iState.iRecvOperation == EPVSocketPortRecvOperation_None
        //there's no node stop going on.
        && iNumStopPortActivityPending < 0;
}

//Enter the "wait on memory" state
void PVMFSocketNode::StartRecvWaitOnMemory(SocketPortConfig& aSockConfig, int32 aSize)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::StartRecvWaitOnMemory() In"));

    aSockConfig.iState.iRecvOperation = EPVSocketPortRecvOperation_WaitOnMemory;

#if(ENABLE_SOCKET_NODE_STATS)
    aSockConfig.iPortStats.iNumWaitOnMemory++;
    aSockConfig.iPortStats.StartRecvTime(aSockConfig.iState.iRecvOperation);
#endif

    if (aSize)
    {//wait on data buffer
        PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartRecvWaitOnMemory, wait on data buffer - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
        if (aSockConfig.iMemPool->iSharedBufferAlloc)
        {
            aSockConfig.iMemPool->iSharedBufferAlloc->notifyfreeblockavailable(aSockConfig, aSize, NULL);
        }
        else
        {
            if (aSockConfig.iMemPool->iInternalAlloc)
                aSockConfig.iMemPool->iInternalAlloc->notifyfreeblockavailable(aSockConfig, aSize, NULL);
        }
    }
    else
    {//wait on media data wrapper
        PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartRecvWaitOnMemory, wait on data wrapper - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
        aSockConfig.iMemPool->iMediaDataMemPool->notifyfreechunkavailable(aSockConfig, NULL);
    }
}

//Enter the "wait on connected port" state
void PVMFSocketNode::StartRecvWaitOnConnectedPort(SocketPortConfig& aSockConfig, PVMFSocketActivity& aSocketActivity)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::StartRecvWaitOnConnectedPort() In"));

    //outgoing queue is busy-- must queue this event for later processing

    PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartRecvWaitOnConnectedPort, wait for connected port - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));

    switch (aSocketActivity.iFxn)
    {
        case EPVSocketRecv:
        case EPVSocketRecvFrom:
#if(ENABLE_SOCKET_NODE_STATS)
            aSockConfig.iPortStats.iNumQueueSocketRecv++;
#endif
            aSockConfig.iSocketRecvActivity.Set(aSocketActivity.iStatus
                                                , aSocketActivity.iId
                                                , aSocketActivity.iFxn
                                                , aSocketActivity.iEvent
                                                , aSocketActivity.iError);
            break;
        default:
            OSCL_ASSERT(false);//invalid input arg.
            break;
    }

    //current state shoudl be idle
    OSCL_ASSERT(aSockConfig.iState.iRecvOperation == EPVSocketPortRecvOperation_None);

    aSockConfig.iState.iRecvOperation = EPVSocketPortRecvOperation_WaitOnConnectedPort;

#if(ENABLE_SOCKET_NODE_STATS)
    aSockConfig.iPortStats.iNumWaitOnConnectedPort++;
    aSockConfig.iPortStats.StartRecvTime(aSockConfig.iState.iRecvOperation);
#endif

}

//Start a receive operation on the port's socket.
//Assume the caller already verified that the port can receive now.
//If there is a failure, this routine will call the "recv operation complete" routine to
//do error handling or continue to the next state.
PVMFStatus PVMFSocketNode::StartRecvOperation(SocketPortConfig& aSockConfig)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::StartRecvOperation() In"));

    //caller should have verified we can receive data right now.
    OSCL_ASSERT(aSockConfig.iState.iRecvOperation == EPVSocketPortRecvOperation_None);

    //there should be either a UDP or TCP socket on this port and a memory pool.
    if (!aSockConfig.iTCPSocket && !aSockConfig.iUDPSocket)
    {
        PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::StartRecvOperation ERROR no socket - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
        return PVMFFailure;
    }
    if (!aSockConfig.iMemPool)
    {
        PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::StartRecvOperation ERROR no mem pool - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
        return PVMFFailure;
    }

    PVMFStatus status = PVMFFailure;

    if (aSockConfig.iUDPSocket)
    {
        aSockConfig.iState.iRecvOperation = EPVSocketPortRecvOperation_RecvFrom;

        //Create the memory buffer

        int32 memSize;
        int32 multiRecvLimitBytes = 0;
        switch (aSockConfig.iMemPool->iPortTag)
        {
            case PVMF_SOCKET_NODE_PORT_TYPE_SOURCE:
                //source tag is used for RTP
#if SNODE_ENABLE_UDP_MULTI_PACKET
                //must allocate enough space for the max bytes per receive plus
                //one more max size packet, since we can't peek ahead to see
                //how much data is on the socket.
                memSize = SNODE_UDP_MULTI_MAX_BYTES_PER_RECV + MAX_UDP_PACKET_SIZE;
                //this is the amt of "free space" required to continue receiving
                //additional packets. Use the max packet size to avoid truncated
                //packets.
                multiRecvLimitBytes = MAX_UDP_PACKET_SIZE;
#else
                //for single packet recvs.
                memSize = MAX_UDP_PACKET_SIZE;
#endif
                break;
            case PVMF_SOCKET_NODE_PORT_TYPE_SINK:
                //sink tag is used for RTCP
            default:
                memSize = MAX_FEEDBACK_SOCKET_BUFFER_SIZE;
                break;
        }

        //Socket node provides the buffer to receive the data on the socket
        //Socket node gets this from the mem pool.
        //It may be possible that socket node may not be able to get the
        //buffer of required size from the mempool
        //If we are not able to get the packets from the OS, then the packets
        //received from server will eventually be lost.
        //In general, streaming server will be sending the UDP packets of small size
        //(say 2048 bytes.. = MIN_UDP_PACKET_SIZE)
        //So its better to attempt to allocate the memory of size
        //SNODE_UDP_MULTI_MIN_BYTES_PER_RECV + MIN_UDP_PACKET_SIZE/MIN_UDP_PACKET_SIZE
        //in such cases.

        const int32 largestMediaMsgSz = aSockConfig.iMemPool->GetMaxSizeMediaMsgLen();

        PVMF_SOCKETNODE_LOGINFO((0, "PVMFSocketNode::StartRecvOperation - MaxSizeMediMsg  %d memSize %d", largestMediaMsgSz, memSize));

        if (memSize > largestMediaMsgSz)
        {
#if SNODE_ENABLE_UDP_MULTI_PACKET
            multiRecvLimitBytes = MIN_UDP_PACKET_SIZE;

            const int32 minBufferToContinueRecv = (SNODE_UDP_MULTI_MIN_BYTES_PER_RECV + MIN_UDP_PACKET_SIZE);

            if (largestMediaMsgSz >= minBufferToContinueRecv)
            {
                memSize = largestMediaMsgSz;
            }
            else
            {
                memSize = minBufferToContinueRecv;
            }
#else
            if (largestMediaMsgSz >= MIN_UDP_PACKET_SIZE)
            {
                memSize = largestMediaMsgSz;
            }
            else
            {
                memSize = MIN_UDP_PACKET_SIZE;
            }
#endif
            PVMF_SOCKETNODE_LOGINFO((0, "PVMFSocketNode::StartRecvOperation - Resizing Mem Request Attributes## NewSz %d recvLimitBytes %d", memSize, multiRecvLimitBytes));
        }

        //Create the media data impl.
        int32 err;
        OsclSharedPtr<PVMFMediaDataImpl> mediaDataImpl;
        err = GetMediaDataImpl(aSockConfig, mediaDataImpl, memSize);
        if (err != OsclErrNone)
        {
            StartRecvWaitOnMemory(aSockConfig, memSize);
            status = PVMFPending;
            //wait on memory pool callback "notifyfreechunkavailable"
            goto Exit;
        }

        //Create the media data buffer.
        err = CreateMediaData(aSockConfig, mediaDataImpl);
        if (err != OsclErrNone)
        {
            StartRecvWaitOnMemory(aSockConfig);
            status = PVMFPending;
            //wait on memory pool callback "notifyfreechunkavailable"
            goto Exit;
        }

        // Retrieve memory fragment to write to
        OsclRefCounterMemFrag refCtrMemFragOut;
        aSockConfig.iPendingRecvMediaData->getMediaFragment(0, refCtrMemFragOut);

        //Issue the Oscl socket request

#if(ENABLE_SOCKET_NODE_STATS)
        aSockConfig.iPortStats.iNumRecvFrom++;
        aSockConfig.iPortStats.StartRecvTime(EPVSocketPortRecvOperation_RecvFrom);
#endif

        TPVSocketEvent retVal = aSockConfig.iUDPSocket->RecvFrom((uint8*)refCtrMemFragOut.getMemFragPtr()
                                , refCtrMemFragOut.getCapacity()
                                , aSockConfig.iSourceAddr
                                , TIMEOUT_RECVFROM
                                , multiRecvLimitBytes
                                , &aSockConfig.iRecvFromPacketLen);

        if (EPVSocketPending != retVal)
        {
            PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::RecvFrom() failed retVal=%d Ln %d", retVal, __LINE__));
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartRecvOperation RecvFrom FAILED - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            status = PVMFFailure;
            goto Exit;
        }
        PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartRecvOperation RecvFrom Pending - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
        status = PVMFPending;
        //wait on the socket callback HandleSocketEvent
    }

    else if (aSockConfig.iTCPSocket)
    {
        aSockConfig.iState.iRecvOperation = EPVSocketPortRecvOperation_Recv;

        //Allocate memory
        int32 err;
        OsclSharedPtr<PVMFMediaDataImpl> mediaDataImpl;
        mediaDataImpl = aSockConfig.iMemPool->getMediaDataImpl(aSockConfig.iMaxTcpRecvBufferSize);
        PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "Requesting to retrieve the chunk of size %d", aSockConfig.iMaxTcpRecvBufferSize));
        if (NULL == mediaDataImpl.GetRep())
        {
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "Cudnt retrieve the chunk of size %d", aSockConfig.iMaxTcpRecvBufferSize));
            StartRecvWaitOnMemory(aSockConfig, aSockConfig.iMaxTcpRecvBufferSize);
            status = PVMFPending;
            //wait on memory pool callback "notifyfreechunkavailable"
            goto Exit;
        }

        OSCL_TRY(err,
                 aSockConfig.iPendingRecvMediaData = PVMFMediaData::createMediaData(mediaDataImpl, aSockConfig.iMemPool->iMediaDataMemPool););
        if (err != OsclErrNone)
        {
            StartRecvWaitOnMemory(aSockConfig);
            status = PVMFPending;
            //wait on memory pool callback "notifyfreechunkavailable"
            goto Exit;
        }

        // Retrieve memory fragment to write to
        OsclRefCounterMemFrag refCtrMemFragOut;
        aSockConfig.iPendingRecvMediaData->getMediaFragment(0, refCtrMemFragOut);

        //Issue the Oscl socket request.

#if(ENABLE_SOCKET_NODE_STATS)
        aSockConfig.iPortStats.iNumRecv++;
        aSockConfig.iPortStats.StartRecvTime(EPVSocketPortRecvOperation_Recv);
#endif

        TPVSocketEvent retVal = aSockConfig.iTCPSocket->Recv((uint8*)refCtrMemFragOut.getMemFragPtr()
                                , refCtrMemFragOut.getCapacity()
                                , TIMEOUT_RECV);
        if (EPVSocketPending != retVal)
        {
            PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::Recv() failed retVal=%d Ln %d", retVal, __LINE__));
            PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::StartRecvOperation Recv FAILED - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            status = PVMFFailure;
            goto Exit;
        }
        PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartRecvOperation Recv Pending - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
        status = PVMFPending;
        //wait on HandleSocketEvent callback.
    }
    else
    {
        PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::StartRecvOperation() Unexpected error, no socket"));
    }

Exit:
    //Handle synchronous completion or failure.

    if (status != PVMFPending
            && status != PVMFFailure)
    {
        PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::StartRecvOperation: Error. status=%d", status));
    }

    if (status != PVMFPending)
        status = RecvOperationComplete(aSockConfig, status, NULL);

    return status;
}

//The current recv operation is complete.  Process the result and continue with the next operation.
//The status is in "aStatus".
//If there was a socket callback, the result is in "aSocketActivity".
PVMFStatus PVMFSocketNode::RecvOperationComplete(SocketPortConfig& aSockConfig, PVMFStatus aStatus, PVMFSocketActivity* aSocketActivity)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::RecvOperationComplete() In"));

    //status should never be pending here
    OSCL_ASSERT(aStatus != PVMFPending);

    PVMFStatus status = aStatus;
    bool recvOperationCanceled = aSockConfig.iState.iRecvOperationCanceled;

    //Update the state
    TPVSocketPortRecvOperation curOp = aSockConfig.iState.iRecvOperation;
    aSockConfig.iState.iRecvOperation = EPVSocketPortRecvOperation_None;
    aSockConfig.iState.iRecvOperationStatus = aStatus;
    aSockConfig.iState.iRecvOperationCanceled = false;

    switch (curOp)
    {
        case EPVSocketPortRecvOperation_WaitOnMemory:
            //a memory wait is complete.
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::RecvOperationComplete WaitOnMemory - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            break;

        case EPVSocketPortRecvOperation_WaitOnConnectedPort:
            //a port wait is complete
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::RecvOperationComplete WaitOnConnectedPort - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));

            //there may be a prior recv or recvfrom result that was waiting on this
            if (aSockConfig.iSocketRecvActivity.iValid)
            {
                aSockConfig.iSocketRecvActivity.iValid = false;

                switch (aSockConfig.iSocketRecvActivity.iFxn)
                {
                    case EPVSocketRecv:
                        HandleRecvComplete(aSockConfig
                                           , aSockConfig.iSocketRecvActivity.iStatus
                                           , &aSockConfig.iSocketRecvActivity, recvOperationCanceled);
                        break;
                    case EPVSocketRecvFrom:
                        HandleRecvFromComplete(aSockConfig
                                               , aSockConfig.iSocketRecvActivity.iStatus
                                               , &aSockConfig.iSocketRecvActivity, recvOperationCanceled);
                        break;
                    default:
                        OSCL_ASSERT(0);//invalid arg
                        break;
                }
            }
            break;

        case EPVSocketPortRecvOperation_Recv:
            //TCP receive is complete
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::RecvOperationComplete Recv - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));

            HandleRecvComplete(aSockConfig, aStatus, aSocketActivity, recvOperationCanceled);
            break;

        case EPVSocketPortRecvOperation_RecvFrom:
            //UDP receive from is complete
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::RecvOperationComplete RecvFrom - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));

            HandleRecvFromComplete(aSockConfig, aStatus, aSocketActivity, recvOperationCanceled);
            break;

        default:
            OSCL_ASSERT(0);//add code for this case
            break;
    }

    //Receive may have been blocked waiting on this operation to complete,
    //so start/resume receives now if possible
    if (CanReceive(aSockConfig))
        status = StartRecvOperation(aSockConfig);

    //Detect connect "Wait on send/recv idle" complete
    if (aSockConfig.iState.iConnectOperation == EPVSocketPortConnectOperation_WaitOnSendRecvIdle
            && aSockConfig.iState.iRecvOperation == EPVSocketPortRecvOperation_None
            && aSockConfig.iState.iSendOperation == EPVSocketPortSendOperation_None)
    {
        ConnectOperationComplete(aSockConfig, PVMFSuccess, NULL);
    }

    return status;
}

//Cancel any current receive operation.
//Return Success if the operation is canceled or Pending if we need to wait.
PVMFStatus PVMFSocketNode::CancelRecvOperation(SocketPortConfig& aSockConfig)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::CancelRecvOperation() In"));

    PVMFStatus status = PVMFSuccess;

    switch (aSockConfig.iState.iRecvOperation)
    {
        case EPVSocketPortRecvOperation_None:
            break;

        case EPVSocketPortRecvOperation_Recv:
            if (aSockConfig.iTCPSocket)
            {
                if (!aSockConfig.iState.iRecvOperationCanceled)
                {
                    aSockConfig.iState.iRecvOperationCanceled = true;
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CancelRecvOperation Calling CancelRecv - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                    aSockConfig.iTCPSocket->CancelRecv();
                }
                status = PVMFPending;
                //wait on recv to complete in HandleSocketEvent
            }
            break;

        case EPVSocketPortRecvOperation_RecvFrom:
            if (aSockConfig.iUDPSocket)
            {
                if (!aSockConfig.iState.iRecvOperationCanceled)
                {
                    aSockConfig.iState.iRecvOperationCanceled = true;
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CancelRecvOperation Calling CancelRecvFrom - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                    aSockConfig.iUDPSocket->CancelRecvFrom();
                }
                status = PVMFPending;
                //wait on recvfrom to complete in HandleSocketEvent
            }
            break;

        case EPVSocketPortRecvOperation_WaitOnConnectedPort:
            //just clear the state
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CancelRecvOperation Cancelling WaitOnConnectedPort - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            aSockConfig.iState.iRecvOperation = EPVSocketPortRecvOperation_None;
            //also discard the received data and the associated recv activity
            if (aSockConfig.iSocketRecvActivity.iValid)
                aSockConfig.iSocketRecvActivity.iValid = false;
            if (aSockConfig.iPendingRecvMediaData.GetRep())
                aSockConfig.iPendingRecvMediaData.Unbind();
            break;

        case EPVSocketPortRecvOperation_WaitOnMemory:
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CancelRecvOperation Cancelling WaitOnMemory - SockId=%d, Mime=%s ", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            if (aSockConfig.iMemPool != NULL)
            {
                if (aSockConfig.iMemPool->iInternalAlloc)
                    aSockConfig.iMemPool->iInternalAlloc->CancelFreeChunkAvailableCallback();
                if (aSockConfig.iMemPool->iSharedBufferAlloc)
                    aSockConfig.iMemPool->iSharedBufferAlloc->CancelFreeChunkAvailableCallback();
            }
            //clear the state
            aSockConfig.iState.iRecvOperation = EPVSocketPortRecvOperation_None;
            break;

        default:
            OSCL_ASSERT(0);//add code for this case
            status = PVMFFailure;
            break;
    }
    return status;
}

//a memory pool callback
void SocketPortConfig::freechunkavailable(OsclAny* aContextData)
{
#if(ENABLE_SOCKET_NODE_STATS)
    iPortStats.iNumFreeChunkCallback++;
#endif
    OSCL_UNUSED_ARG(aContextData);

    //complete the "wait on memory" state
    if (iState.iRecvOperation == EPVSocketPortRecvOperation_WaitOnMemory)
    {
#if(ENABLE_SOCKET_NODE_STATS)
        iPortStats.EndRecvTime(iState.iRecvOperation);
#endif
        iContainer->RecvOperationComplete(*this, PVMFSuccess, NULL);
    }
}

void SocketPortConfig::freeblockavailable(OsclAny* aContextData)
{
    freechunkavailable(aContextData);
}

//Handler for a "recv" complete.  This handles two input cases:
// - Operation failed to initiate.  Status will be in aStatus and aSocketActivity will be NULL.
// - Operation completed asynchronously via HandleSocketEvent callback. Status will be in aStatus
//   and socket callback result will be in aSocketActivity.
//
//The end result of processing will be one of the following:
// - Received data sent to connected port
// - Result queued on socket activity queue for later processing.
// - Error or cancellation processed.
void PVMFSocketNode::HandleRecvComplete(SocketPortConfig& aSockConfig, PVMFStatus aStatus, PVMFSocketActivity* aSocketActivity, bool aRecvOperationCanceled)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::HandleRecvComplete() In"));

    //operation should be complete when this is called.
    OSCL_ASSERT(aStatus != PVMFPending);


    int32 sockActivityEvent = aSocketActivity->iEvent;
    PVMFStatus status = aStatus;

    int32 tmplen;
    aSockConfig.iTCPSocket->GetRecvData(&tmplen);
    PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::HandleRecvComplete - Retrieved the chunk of lenngth %d", tmplen));
    // If data length is <= zero and aSocketActivity->iEvent is EPVSocketSuccess, it should be treated as failure.
    // On some platforms, its possible to get data length as zero and aSocketActivity->iEvent as EPVSocketSuccess.
    if (EPVSocketSuccess == sockActivityEvent && tmplen <= 0)
    {
        PVMF_SOCKETNODE_LOGINFO((0, "PVMFSocketNode::HandleRecvFromComplete() Sucessful Recv With Zero Length. Treating as failure."));

        sockActivityEvent = EPVSocketFailure;
        status = PVMFFailure;
    }

    //If there's no socket activity input, then this must be a failure in initiating
    //a Recv operation.
    if (!aSocketActivity)
    {
        OSCL_ASSERT(status != PVMFSuccess);
        PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::HandleRecvComplete: Request Failed - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
        ReportSocketNodeError(PVMFErrResource, PVMFSocketNodeErrorSocketFailure);
        //release media data
        if (aSockConfig.iPendingRecvMediaData.GetRep())
            aSockConfig.iPendingRecvMediaData.Unbind();
        return;
    }

    //Otherwise this is a result from Oscl Sockets of a Recv call.

    //See whether we can send this data to the connected port
    if (sockActivityEvent == EPVSocketSuccess)
    {
        if (!aSockConfig.iPVMFPort
                || !aSockConfig.iPVMFPort->IsConnected())
        {
            //port already disconnected-- just discard the data
            if (aSockConfig.iPendingRecvMediaData.GetRep())
                aSockConfig.iPendingRecvMediaData.Unbind();
            return;
        }
        if (aSockConfig.iPVMFPort->IsOutgoingQueueBusy())
        {
            //wait on port so we can send recv data.
            StartRecvWaitOnConnectedPort(aSockConfig, *aSocketActivity);
            return;
        }
    }

    //If we get here then it's time to process the recv result.

    //Release media data on failure
    if (status != PVMFSuccess)
    {
        if (aSockConfig.iPendingRecvMediaData.GetRep())
            aSockConfig.iPendingRecvMediaData.Unbind();
    }

    switch (sockActivityEvent)
    {
        case EPVSocketSuccess:
        {
            //Get data length and set media buffer size
            int32 len;
            aSockConfig.iTCPSocket->GetRecvData(&len);
            aSockConfig.iPendingRecvMediaData->setMediaFragFilledLen(0, len);

            // Resize the buffer
            if (aSockConfig.iMemPool)
            {
                OsclSharedPtr<PVMFMediaDataImpl> mediaMsgImpl;
                aSockConfig.iPendingRecvMediaData->getMediaDataImpl(mediaMsgImpl);
                aSockConfig.iMemPool->resizeSocketDataBuffer(mediaMsgImpl);
            }
            else
            {
                PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::HandleRecvComplete() ERROR:mempool not found"));
                OSCL_ASSERT(0);
                return ;
            }

            // set system time as timestamp
            TimeValue currentTime;
            currentTime.set_to_current_time();
            int32 currentMilliSec = currentTime.to_msec();
            aSockConfig.iPendingRecvMediaData->setTimestamp((PVMFTimestamp)currentMilliSec);

            //queue to next port
            PVMFSharedMediaMsgPtr aMediaMsgPtr;
            convertToPVMFMediaMsg(aMediaMsgPtr, aSockConfig.iPendingRecvMediaData);

#if(ENABLE_SOCKET_NODE_STATS)
            aSockConfig.iPortStats.iNumQueueOutgoingTCPMsg++;
#endif
            PVMFStatus status = aSockConfig.iPVMFPort->QueueOutgoingMsg(aMediaMsgPtr);
            if (status != PVMFSuccess)
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::HandleRecvComplete: QueueOutgoingMsg Failed - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::HandleRecvComplete() ERROR:%d, Outgoing queue size=%d. Data discarded!", status, aSockConfig.iPVMFPort->OutgoingMsgQueueSize()));
                ReportErrorEvent(PVMFErrPortProcessing);
                return ;
            }

            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::HandleRecvComplete: Request Succcess  - SockId=%d, Mime=%s, Len=%d", aSockConfig.iSockId, aSockConfig.iMime.get_str(), len));
        }
        break;

        case EPVSocketTimeout:
        {
            PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::HandleRecvComplete: Request TimedOut - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::HandleRecvComplete() ERROR EPVSocketTimeout Ln %d", __LINE__));
            ReportSocketNodeError(PVMFErrTimeout, PVMFSocketNodeErrorSocketTimeOut);
        }
        break;

        case EPVSocketCancel:
            //On some OS we may get EPVSocketCancel for recv failures, so check whether this
            //was response to a cancel command or not.
            if (aRecvOperationCanceled)
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::HandleRecvComplete: Request Cancelled - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                PVMF_SOCKETNODE_LOGINFO((0, "PVMFSocketNode::HandleRecvComplete() EPVSocketCancel"));
                break;
            }
            //else fallthrough to the failure processing...
        case EPVSocketFailure:
        {
            //After a receive failure, we may need to do a TCP shutdown.
            //Check what else is currently happening on the port.
            switch (aSockConfig.iState.iSequence)
            {
                case EPVSocketPortSequence_RequestPort:
                case EPVSocketPortSequence_InputConnectMsg:
                case EPVSocketPortSequence_InputDisconnectMsg:
                case EPVSocketPortSequence_SocketCleanup:
                    //some of these conditions may be impossible, but in any case,
                    //it doesn't make sense to start a shutdown sequence during
                    //any of these.  Ignore the error.
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::HandleRecvComplete: Request Failed, ignoring - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                    break;

                case EPVSocketPortSequence_None:
                case EPVSocketPortSequence_InputDataMsg:
                    //for these cases, start a shutdown sequence
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::HandleRecvComplete: Request Failed, starting shutdown sequence - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));

                    //start the sequence
                    StartSequence(aSockConfig, EPVSocketPortSequence_SocketCleanup);
                    break;

                default:
                    //need code to handle this case.
                    OSCL_ASSERT(0);
                    break;
            }
        }
        break;

        default:
            OSCL_ASSERT(0);
            break;
    }
}

//Handler for a "recv from" complete.  This handles two input cases:
// - Operation failed to initiate.  Status will be in aStatus and aSocketActivity will be NULL.
// - Operation completed asynchronously via HandleSocketEvent callback. Status will be in aStatus
//   and socket callback result will be in aSocketActivity.
//
//The end result of processing will be one of the following:
// - Received data sent to connected port
// - Result queued on socket activity queue for later processing.
// - Error or cancellation processed.
void PVMFSocketNode::HandleRecvFromComplete(SocketPortConfig& aSockConfig, PVMFStatus aStatus, PVMFSocketActivity* aSocketActivity, bool aRecvOperationCanceled)
{
    OSCL_UNUSED_ARG(aStatus);
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::HandleRecvFromComplete() In"));

    //operation should be complete when this is called.
    OSCL_ASSERT(aStatus != PVMFPending);

    //If there's no socket activity input, then this must be a failure in initiating
    //a RecvFrom operation.
    if (!aSocketActivity)
    {
        OSCL_ASSERT(aStatus != PVMFSuccess);
        PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::HandleRecvFromComplete: Request Failed - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
        ReportSocketNodeError(PVMFErrResource, PVMFSocketNodeErrorSocketFailure);
        //release media data
        if (aSockConfig.iPendingRecvMediaData.GetRep())
            aSockConfig.iPendingRecvMediaData.Unbind();
        return;
    }

    //Otherwise this is a result from Oscl Sockets of a RecvFrom call.

    //Handle "truncated packet" error, in which case we still have data even though
    //the result is EPVSocketFailure.
    int32 dataLen = 0;
    uint8* dataPtr = NULL;
    if (aSocketActivity->iEvent == EPVSocketFailure
            || aSocketActivity->iEvent == EPVSocketSuccess)
    {
        if (aSockConfig.iUDPSocket)
            dataPtr = aSockConfig.iUDPSocket->GetRecvData(&dataLen);
#if(ENABLE_SOCKET_NODE_STATS)
        aSockConfig.iPortStats.iNumRecvFromPackets += aSockConfig.iRecvFromPacketLen.size();
        if (aSockConfig.iRecvFromPacketLen.size() > aSockConfig.iPortStats.iMaxRecvFromPackets)
            aSockConfig.iPortStats.iMaxRecvFromPackets = aSockConfig.iRecvFromPacketLen.size();
#endif
    }

    //Handle cases where we got some data
    if (dataLen > 0)
    {
        //See if we can pass this data along to the connected port.  If not, then queue the
        //result for later processing.
        if (aSockConfig.iPVMFPort->IsOutgoingQueueBusy())
        {
            //outgoing queue is busy-- must queue this for later.
            StartRecvWaitOnConnectedPort(aSockConfig, *aSocketActivity);
        }
        else
        {
            //report truncated packet.
            if (aSocketActivity->iEvent == EPVSocketFailure)
            {
                PVUuid eventuuid = PVMFSocketNodeEventTypeUUID;
                int32 infocode = PVMFSocketNodeInfoEventPacketTruncated;
                ReportInfoEvent(PVMFErrCorrupt, NULL, &eventuuid, &infocode);
            }

            //set the media buffer size.
            aSockConfig.iPendingRecvMediaData->setMediaFragFilledLen(0, dataLen);

            //resize the buffer.
            if (aSockConfig.iMemPool)
            {
                OsclSharedPtr<PVMFMediaDataImpl> mediaMsgImpl;
                aSockConfig.iPendingRecvMediaData->getMediaDataImpl(mediaMsgImpl);
                aSockConfig.iMemPool->resizeSocketDataBuffer(mediaMsgImpl);
            }
            else
            {
                PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFSocketNode::HandleRecvFromComplete() ERROR:mempool not found"));
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::HandleRecvFromComplete: ERROR mempool not found - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                return;//unexpected, cleanup
            }

#if SNODE_ENABLE_UDP_MULTI_PACKET
            //The media buffer may contain multiple UDP packets.  We need to
            //re-package these into a media frag group.

            //Allocate a new media frag group.
            int32 err;
            OsclSharedPtr< PVMFMediaDataImpl > mediaFragGroup;
            err = Allocate(aSockConfig, mediaFragGroup);
            if (err != OsclErrNone)
            {
                //Unexpected error.  With current usage by JB node, this pool should
                //never run out.
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::HandleRecvFromComplete: Unexpected mempool error - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                ReportSocketNodeError(PVMFErrResource, PVMFSocketNodeErrorSocketFailure);
                //release media data
                if (aSockConfig.iPendingRecvMediaData.GetRep())
                    aSockConfig.iPendingRecvMediaData.Unbind();
                return;
            }

            //get the single frag data buffer pointer.
            OsclRefCounterMemFrag singleFrag;
            aSockConfig.iPendingRecvMediaData->getMediaFragment(0, singleFrag);

            for (uint32 i = 0; i < aSockConfig.iRecvFromPacketLen.size(); dataPtr += aSockConfig.iRecvFromPacketLen[i++])
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::HandleRecvFromComplete: Fragment %d Len %d - SockId=%d, Mime=%s"
                                                  , i, aSockConfig.iRecvFromPacketLen[i], aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                //Create a new fragment with the existing refcount
                //and the proper packet boundaries.
                OsclRefCounterMemFrag multiFrag(singleFrag);
                //now adjust the single frag to the actual packet boundary.
                multiFrag.getMemFrag().ptr = dataPtr;
                multiFrag.getMemFrag().len = aSockConfig.iRecvFromPacketLen[i];
                mediaFragGroup->appendMediaFragment(multiFrag);
#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
                if (aSockConfig.iRTP)
                {
                    LogRTPHeaderFields(aSockConfig, multiFrag);
                }
                else if (aSockConfig.iRTCP)
                {
                    LogRTCPHeaderFields(aSockConfig, multiFrag);
                }
#endif
            }

            //Replace the original media data message with the new one.
            //since we've linked the new frags to the original refcounter, we
            //can just unbind the current message then re-allocate it with the
            //new data.
            aSockConfig.iPendingRecvMediaData.Unbind();
            err = CreateMediaData(aSockConfig, mediaFragGroup);
            if (err != OsclErrNone)
            {
                //unexpected since we just freed one message
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::HandleRecvFromComplete: Unexpected mempool error - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                ReportSocketNodeError(PVMFErrResource, PVMFSocketNodeErrorSocketFailure);
                return;
            }

#else //SNODE_ENABLE_UDP_MULTI_PACKET

#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
            if (aSockConfig.iRTP)
            {
                OsclRefCounterMemFrag memfrag;
                aSockConfig.iPendingRecvMediaData->getMediaFragment(0, memfrag);
                LogRTPHeaderFields(aSockConfig, memfrag);
            }
            else if (aSockConfig.iRTCP)
            {
                OsclRefCounterMemFrag memfrag;
                aSockConfig.iPendingRecvMediaData->getMediaFragment(0, memfrag);
                LogRTCPHeaderFields(aSockConfig, memfrag);
            }
#endif

#endif //SNODE_ENABLE_UDP_MULTI_PACKET

            //push the received data to the connected port
            PVMFSharedMediaMsgPtr mediaMsgPtr;
            convertToPVMFMediaMsg(mediaMsgPtr, aSockConfig.iPendingRecvMediaData);

#if(ENABLE_SOCKET_NODE_STATS)
            aSockConfig.iPortStats.iNumQueueOutgoingUDPMsg++;
#endif
            PVMFStatus status = aSockConfig.iPVMFPort->QueueOutgoingMsg(mediaMsgPtr);
            if (status != PVMFSuccess)
            {
                //should never get here because we already checked outgoign queue earlier.
                PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::HandleRecvFromComplete() ERROR:%d, Outgoing queue size=%d. Data discarded!", status, aSockConfig.iPVMFPort->OutgoingMsgQueueSize()));
                ReportErrorEvent(PVMFInfoOverflow);
            }

            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::HandleRecvFromComplete: Request Succcess - SockId=%d, Mime=%s, Len=%d", aSockConfig.iSockId, aSockConfig.iMime.get_str(), dataLen));
        }
    }
    else
    {
        //handle error, cancel, and timeout cases.

        //release media data.
        if (aSockConfig.iPendingRecvMediaData.GetRep())
            aSockConfig.iPendingRecvMediaData.Unbind();

        //report error events.
        switch (aSocketActivity->iEvent)
        {
            case EPVSocketCancel:
                //On some OS we may get EPVSocketCancel for recv failures, so check whether this
                //was response to a cancel command or not.
                if (aRecvOperationCanceled)
                {
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::HandleRecvFromComplete: Request Cancelled - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                    break;
                }
                //else fallthrough to failure processing...
            case EPVSocketFailure:
                //report RTP failures.
                //Note: do not report RTCP errors, because some servers send zero-byte packets
                //and we want to be tolerant of that case.
                if (aSockConfig.iTag == PVMF_SOCKET_NODE_PORT_TYPE_SOURCE)
                {
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::HandleRecvFromComplete: Request Failed - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                    ReportSocketNodeError(PVMFErrResource, PVMFSocketNodeErrorSocketFailure);
                }
                break;

            case EPVSocketTimeout:
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::HandleRecvFromComplete: Request TimedOut - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::HandleRecvFromComplete() ERROR EPVSocketTimeout Ln %d", __LINE__));
                ReportSocketNodeError(PVMFErrTimeout, PVMFSocketNodeErrorSocketTimeOut);
            }
            break;

            default:
                break;
        }
    }
}

//////////////////////////////////
// End Receive Operation Handlers
//////////////////////////////////


//////////////////////////////////
// Send Operation Handlers
//////////////////////////////////


//Start a send operation on the port's socket.
//Assume the caller already verified that the port can send now.
//If there is a failure, this routine will call the "send operation complete" routine to
//do error handling or continue to the next state.
PVMFStatus PVMFSocketNode::StartSendOperation(SocketPortConfig& aSockConfig, PVMFSharedMediaMsgPtr& aMsg)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::StartSendOperation() In"));

    //caller should have verified we can send now.
    OSCL_ASSERT(aSockConfig.iState.iSendOperation == EPVSocketPortSendOperation_None);

    //caller should provide a media data message as input
    OSCL_ASSERT(aMsg->getFormatID() == PVMF_MEDIA_MSG_DATA_FORMAT_ID);

    //there should be either a UDP or TCP socket on this port
    if (!aSockConfig.iTCPSocket && !aSockConfig.iUDPSocket)
    {
        PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::StartSendOperation ERROR no socket - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
        return PVMFFailure;
    }

    aSockConfig.iPVMFPort->iNumFramesConsumed++;

    // Retrieve memory fragment to write to
    if (aSockConfig.iPendingSendMediaData.GetRep())
        aSockConfig.iPendingSendMediaData.Unbind();

    convertToPVMFMediaData(aSockConfig.iPendingSendMediaData, aMsg);
    OsclRefCounterMemFrag refCtrMemFragOut;
    aSockConfig.iPendingSendMediaData->getMediaFragment(0, refCtrMemFragOut);
    PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartSendOperation - SockId=%d, Mime=%s, Len=%d", aSockConfig.iSockId, aSockConfig.iMime.get_str(), refCtrMemFragOut.getMemFragSize()));

    PVMFStatus status = PVMFFailure;

    if (aSockConfig.iUDPSocket)
    {
        aSockConfig.iState.iSendOperation = EPVSocketPortSendOperation_SendTo;

#if(ENABLE_SOCKET_NODE_STATS)
        aSockConfig.iPortStats.iNumSendTo++;
        aSockConfig.iPortStats.StartSendTime(aSockConfig.iState.iSendOperation);
#endif
        TPVSocketEvent retVal = aSockConfig.iUDPSocket->SendTo((uint8*)refCtrMemFragOut.getMemFragPtr()
                                , refCtrMemFragOut.getMemFragSize()
                                , aSockConfig.iAddr.iRemoteAdd
                                , TIMEOUT_SENDTO);

        if (retVal == EPVSocketPending)
            status = PVMFPending;//wait on HandleSocketEvent callback
        else
            status = PVMFFailure;

        if (PVMFPending != status)
        {
            //error
            PVMF_SOCKETNODE_LOGERROR((0, "0x%x PVMFSocketNode::SendTo() failed retVal=%d Ln %d", this, retVal, __LINE__));
            PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::StartSendOperation: UDP - Error. status=%d", status));
            PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::StartSendOperation SendTo FAILED - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
        }
        else
        {
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartSendOperation SendTo Pending - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
        }
    }

    else if (aSockConfig.iTCPSocket)
    {
        aSockConfig.iState.iSendOperation = EPVSocketPortSendOperation_Send;

#if(ENABLE_SOCKET_NODE_STATS)
        aSockConfig.iPortStats.iNumSend++;
        aSockConfig.iPortStats.StartSendTime(aSockConfig.iState.iSendOperation);
#endif
        TPVSocketEvent retVal = aSockConfig.iTCPSocket->Send((uint8*)refCtrMemFragOut.getMemFragPtr(),
                                refCtrMemFragOut.getMemFragSize(),
                                TIMEOUT_SEND);

        if (retVal == EPVSocketPending)
            status = PVMFPending;//wait on HandleSocketEvent callback
        else
            status = PVMFFailure;

        if (PVMFPending != status)
        {
            PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::StartSendOperation: TCP - Error. status=%d", status));
            PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::StartSendOperation Calling Send FAILED - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
        }
        else
        {
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartSendOperation Send Pending - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
        }
    }

    //Handle synchronous completion or failures
    if (status != PVMFPending)
        status = SendOperationComplete(aSockConfig, status, NULL);

    return status;
}

//The current send operation is complete and status is in "aStatus".
//If there was a socket callback, the result is in "aSocketActivity".
//Process the result and continue with the next operation if needed.
PVMFStatus PVMFSocketNode::SendOperationComplete(SocketPortConfig& aSockConfig, PVMFStatus aStatus, PVMFSocketActivity* aSocketActivity)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::SendOperationComplete()"));

    OSCL_ASSERT(aStatus != PVMFPending);

    PVMFStatus status = aStatus;

    //Update the send state
    TPVSocketPortSendOperation curOp = aSockConfig.iState.iSendOperation;
    aSockConfig.iState.iSendOperation = EPVSocketPortSendOperation_None;
    aSockConfig.iState.iSendOperationStatus = aStatus;
    aSockConfig.iState.iSendOperationCanceled = false;

    //Release the media buffer after each send operation, regardless of success/fail.
    if (aSockConfig.iPendingSendMediaData.GetRep() != NULL)
        aSockConfig.iPendingSendMediaData.Unbind();

    if (aSocketActivity)
    {
        //Datapath logging
        switch (aSocketActivity->iEvent)
        {
            case EPVSocketSuccess:
                PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::SendOperationComplete - Success - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                break;
            case EPVSocketTimeout:
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::SendOperationComplete - TimeOut - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                break;
            case EPVSocketFailure:
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::SendOperationComplete - Failed - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                break;
            case EPVSocketCancel:
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::SendOperationComplete - Cancelled - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                break;
            default:
                OSCL_ASSERT(0);
                break;
        }
    }

    //report TCP errors.
    if (aStatus != PVMFSuccess
            && curOp == EPVSocketPortSendOperation_Send)
    {
        PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::SendOperationComplete - Send Failed - "
                                          "SockId=%d, Mime=%s, Operaton=%d",
                                          aSockConfig.iSockId, aSockConfig.iMime.get_str(), aSockConfig.iState.iSendOperation));
        PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::SendOperationComplete: Send/SendTo() ERROR status=%d, Ln %d", status, __LINE__));
        ReportSocketNodeError(PVMFErrResource, PVMFSocketNodeErrorTCPSocketSendError);
    }

    //This completes an input data message sequence
    if (aSockConfig.iState.iSequence == EPVSocketPortSequence_InputDataMsg)
        SequenceComplete(aSockConfig, aStatus);

    //Detect connect "Wait on send/recv idle" complete
    if (aSockConfig.iState.iConnectOperation == EPVSocketPortConnectOperation_WaitOnSendRecvIdle
            && aSockConfig.iState.iRecvOperation == EPVSocketPortRecvOperation_None
            && aSockConfig.iState.iSendOperation == EPVSocketPortSendOperation_None)
    {
        ConnectOperationComplete(aSockConfig, PVMFSuccess, NULL);
    }

    return status;
}

//Cancel the current send operation.
//Return Success if the operation is canceled, or Pending if we need to wait.
PVMFStatus PVMFSocketNode::CancelSendOperation(SocketPortConfig& aSockConfig)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::CancelSendOperation()"));

    PVMFStatus status = PVMFSuccess;

    switch (aSockConfig.iState.iSendOperation)
    {
        case EPVSocketPortSendOperation_None:
            break;

        case EPVSocketPortSendOperation_Send:
            if (aSockConfig.iTCPSocket)
            {
                if (!aSockConfig.iState.iSendOperationCanceled)
                {
                    aSockConfig.iState.iSendOperationCanceled = true;
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CancelSendOperation Calling CancelSend - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                    aSockConfig.iTCPSocket->CancelSend();
                }
                status = PVMFPending;
                //wait on send to complete in HandleSocketEvent
            }
            break;

        case EPVSocketPortSendOperation_SendTo:
            if (aSockConfig.iUDPSocket)
            {
                if (!aSockConfig.iState.iSendOperationCanceled)
                {
                    aSockConfig.iState.iSendOperationCanceled = true;
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CancelSendOperation Calling CancelSendTo - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
                    aSockConfig.iUDPSocket->CancelSendTo();
                }
                status = PVMFPending;
                //wait on sendto to complete in HandleSocketEvent
            }
            break;

        default:
            OSCL_ASSERT(0);
            status = PVMFFailure;
            break;
    }
    return status;
}

//////////////////////////////////
// End Send Operation Handlers
//////////////////////////////////

//////////////////////////////////////
// Sequence Handler
//////////////////////////////////////
static const char* const TPVSocketPortSequenceStr[] =
{
    "EPVSocketPortSequence_None"
    , "EPVSocketPortSequence_RequestPort"
    , "EPVSocketPortSequence_InputConnectMsg"
    , "EPVSocketPortSequence_InputDataMsg"
    , "EPVSocketPortSequence_InputDisconnectMsg"
    , "EPVSocketPortSequence_SocketCleanup"
    , "EPVSocketPortSequence_Last"
} ;

//Start a sequence on a port.
//This routine will complete all steps possible unless some operation has
//asynchronous completion.
//This call may actually complete the sequence.
//This routine documents the series of steps for each sequence.
PVMFStatus PVMFSocketNode::StartSequence(SocketPortConfig& aSockConfig, TPVSocketPortSequence aSequence, OsclAny* aParam)
{
    PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartSequence, '%s' - SockId=%d, Mime=%s"
                                      , TPVSocketPortSequenceStr[aSequence]
                                      , aSockConfig.iSockId, aSockConfig.iMime.get_cstr()));

    //Set the sequence.
    aSockConfig.iState.iSequence = aSequence;

    switch (aSequence)
    {
        case EPVSocketPortSequence_RequestPort:
            //Sequence:
            // 1. GetHostByName,
            // 2. Connect
            // 3. Command complete.

            return StartConnectOperation(aSockConfig, EPVSocketPortConnectOperation_GetHostByName);

        case EPVSocketPortSequence_InputConnectMsg:
            //Sequence:
            // If already connected,
            // 1. Shutdown
            // 2. Cancel send/recv operation if needed.
            // 3. Wait for send/recv idle if needed.
            // 4. Wait for connected port if needed.
            // 5. Close socket + send EOS to connected port + delete socket
            //      or add to cleanup queue & trigger AO.
            // 6. Create
            // 7. GetHostByName
            // 8. Connect
            // Else if not already connected,
            // 1. GetHostByName
            // 2. Connect

            if (aSockConfig.iTCPSocket)
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::StartSequence - Disconnecting before Connect SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_cstr()));
                return StartConnectOperation(aSockConfig, EPVSocketPortConnectOperation_Shutdown);
            }
            else
            {
                return StartConnectOperation(aSockConfig, EPVSocketPortConnectOperation_GetHostByName);
            }
            break;

        case EPVSocketPortSequence_InputDataMsg:
            //Sequence:
            // 1. Send

            OSCL_ASSERT(aParam);
            return StartSendOperation(aSockConfig, *((PVMFSharedMediaMsgPtr*)aParam));

        case EPVSocketPortSequence_InputDisconnectMsg:
            //Sequence:
            // 1. Shutdown
            // 2. Cancel send/recv operation if needed.
            // 3. Wait for send/recv idle if needed.
            // 4. Wait for connected port if needed.
            // 5. Close socket + send EOS to connected port + delete socket
            //      or add to cleanup queue & trigger AO.

            return StartConnectOperation(aSockConfig, EPVSocketPortConnectOperation_Shutdown);

        case EPVSocketPortSequence_SocketCleanup:
            if (aSockConfig.iTCPSocket)
            {
                //TCP Shutdown Sequence:
                // 1. Cancel current connect operation if needed.
                // 2. Cancel send/recv operation if needed.
                // 3. Shutdown
                // 4. Wait for send/recv idle if needed.
                // 5. Wait for connected port if needed.
                // 6. Close socket + send EOS to connected port + delete socket
                //      or add to cleanup queue & trigger AO.

                if (aSockConfig.iState.iConnectOperation == EPVSocketPortConnectOperation_Shutdown)
                {
                    return PVMFPending;//wait on completion in HandleSocketEvent
                }
                if (CancelConnectOperation(aSockConfig) == PVMFPending)
                {
                    return PVMFPending;//wait on connect operation to cancel
                    //(in HandleSocketEvent or HandleDNSEvent)
                }
                else
                {
                    //Go ahead and start any send/recv cancel since they can happen simultaneously
                    //with the Shutdown operation.
                    CancelRecvOperation(aSockConfig);
                    CancelSendOperation(aSockConfig);

                    return StartConnectOperation(aSockConfig, EPVSocketPortConnectOperation_Shutdown);
                }
            }
            else if (aSockConfig.iUDPSocket)
            {
                //UDP Shutdown Sequence:
                // 1. Cancel all current operations
                // 2. Wait for send/recv idle if needed.
                // 3. Close socket + delete socket or add to cleanup queue & trigger AO.

                switch (aSockConfig.iState.iConnectOperation)
                {
                    case EPVSocketPortConnectOperation_WaitOnSendRecvIdle:
                        //keep waiting for completion (in RecvOperationComplete or SendOperationComplete)
                        return PVMFPending;

                    case EPVSocketPortConnectOperation_None:

                        CancelRecvOperation(aSockConfig);
                        CancelSendOperation(aSockConfig);

                        return StartConnectOperation(aSockConfig, EPVSocketPortConnectOperation_WaitOnSendRecvIdle);

                    default:
                        //unexpected
                        OSCL_ASSERT(0);
                        return PVMFFailure;

                }
            }
            //else
            {
                //nothing needed.
                SequenceComplete(aSockConfig, PVMFSuccess);
                return PVMFSuccess;
            }
            break;

        default:
            //add code to handle this case
            OSCL_ASSERT(0);
            return PVMFFailure;
    }
}

//The current multi-operation sequence is complete.
//Process the result and continue with the next operation if needed.
void PVMFSocketNode::SequenceComplete(SocketPortConfig& aSockConfig, PVMFStatus aStatus)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::SequenceComplete() Sequence %d Status %d ", aSockConfig.iState.iSequence, aStatus));

    PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::SequenceComplete '%s' - SockId=%d, Mime=%s"
                                      , TPVSocketPortSequenceStr[aSockConfig.iState.iSequence]
                                      , aSockConfig.iSockId, aSockConfig.iMime.get_str()));

    //Update the state
    TPVSocketPortSequence curSequence = aSockConfig.iState.iSequence;
    aSockConfig.iState.iSequence = EPVSocketPortSequence_None;
    aSockConfig.iState.iSequenceStatus = aStatus;

    switch (curSequence)
    {
        case EPVSocketPortSequence_RequestPort:
            //may need to complete the node command
            if (iCurrentCommand.iCmd == PVMF_GENERIC_NODE_REQUESTPORT)
            {
                //@TODO would be nice to cleanup the allocated port in case of a failure.
                CommandComplete(iCurrentCommand, aStatus, NULL, iRequestedPort);
            }
            break;

        case EPVSocketPortSequence_InputConnectMsg:
        case EPVSocketPortSequence_InputDisconnectMsg:
        case EPVSocketPortSequence_InputDataMsg:
            //If we've just completed an input port message, this may complete a node Flush command
            if (iCurrentCommand.iCmd == PVMF_GENERIC_NODE_FLUSH)
            {
                //Flush is done when all input ports are empty.
                for (uint32 i = 0; i < iPortVector.size(); i++)
                {
                    if (iPortVector[i]->IncomingMsgQueueSize() > 0)
                        return;//keep waiting
                }
                //All ports empty-- complete the Flush.
                CommandComplete(iCurrentCommand, PVMFSuccess);
            }
            break;


        case EPVSocketPortSequence_SocketCleanup:
            //When socket cleanup is complete, decrement the "stop node activity"
            //counter and look for completion of all ports.

            //This port is done-- decrement the counter
            iNumStopPortActivityPending--;

            //When counter reaches zero, all ports are done and the sequence is complete.
            if (iNumStopPortActivityPending == 0)
            {
                //Reset the counter to the "idle" value.
                iNumStopPortActivityPending = (-1);

                //There may be a Reset or CancelAll command waiting on
                //this to complete.
                if (iCurrentCommand.iCmd == PVMF_GENERIC_NODE_RESET)
                {
                    CommandComplete(iCurrentCommand, PVMFSuccess);
                }
                else if (iCancelCommand.iCmd == PVMF_GENERIC_NODE_CANCELALLCOMMANDS)
                {
                    CommandComplete(iCancelCommand, PVMFSuccess);
                }
                //ports may be cleaned up now, so exit this routine now to
                //avoid a crash from further port processing.
                return;
            }
            break;

        default:
            break;
    }


    //All sequences other than input data message will
    //block receive operations, so may need to start or resume receives now.
    if (curSequence != EPVSocketPortSequence_InputDataMsg
            && (aStatus == PVMFSuccess)
            && CanReceive(aSockConfig))
    {
        StartRecvOperation(aSockConfig);
    }

    //Input message processing may have been blocked waiting on
    //this sequence to complete, so resume now.
    if (CanProcessIncomingMsg(aSockConfig)
            && (aStatus == PVMFSuccess))
    {
        ProcessIncomingMsg(aSockConfig);
    }
}

//////////////////////////////////////
// End Sequence Handler
//////////////////////////////////////


//////////////////////////////////////
// Command Handlers
//////////////////////////////////////

//Called to complete a node command.
void PVMFSocketNode::CommandComplete(PVMFNodeCommand& aCmd,
                                     PVMFStatus aStatus,
                                     PVInterface* aExtMsg,
                                     OsclAny* aEventData,
                                     PVUuid* aEventUUID,
                                     int32* aEventCode,
                                     int32 aEventDataLen)

{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode:CommandComplete Id %d Cmd %d Status %d Context %d Data %d"
                    , aCmd.iId, aCmd.iCmd, aStatus, aCmd.iContext, aEventData));

    // check if "command error code" was set.
    PVInterface* extif = NULL;
    PVMFBasicErrorInfoMessage* errormsg = NULL;

    if (aExtMsg)
    {
        extif = aExtMsg;
    }
    else if (iCommandErrorCode != PVMFSocketNodeErrorEventStart)
    {
        PVUuid eventuuid = PVMFSocketNodeEventTypeUUID;
        errormsg = OSCL_NEW(PVMFBasicErrorInfoMessage, (iCommandErrorCode, eventuuid, NULL));
        extif = OSCL_STATIC_CAST(PVInterface*, errormsg);
    }

    PVMFNodeInterfaceImpl::CommandComplete(aCmd, aStatus, extif, aEventData, aEventUUID, aEventCode);

    iCommandErrorCode = PVMFSocketNodeErrorEventStart;//reset.

    //See if there was a pending cancel waiting on the current command to
    //complete.
    if (iCancelCommand.iCmd == PVMF_GENERIC_NODE_CANCELCOMMAND)
    {
        CommandComplete(iCancelCommand, PVMFSuccess);
    }

    if (errormsg)
    {
        errormsg->removeRef();
    }

    //May need to resume command handling if the AO was blocked
    //waiting on asynchronous command completion, but it's unblocked now.
    if (!iInputCommands.empty())
        Reschedule();

}

void PVMFSocketNode::ReportErrorEvent(PVMFEventType aEventType,
                                      OsclAny* aEventData,
                                      PVUuid* aEventUUID,
                                      int32* aEventCode)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_ERR,
                    (0, "PVMFSocketNode:NodeErrorEvent Type %d Data %d"
                     , aEventType, aEventData));

    if (aEventUUID && aEventCode)
    {
        PVMFBasicErrorInfoMessage* eventmsg =
            OSCL_NEW(PVMFBasicErrorInfoMessage, (*aEventCode, *aEventUUID, NULL));
        PVMFAsyncEvent asyncevent(PVMFErrorEvent,
                                  aEventType,
                                  NULL,
                                  OSCL_STATIC_CAST(PVInterface*, eventmsg),
                                  aEventData,
                                  NULL,
                                  0);
        PVMFNodeInterfaceImpl::ReportErrorEvent(asyncevent);
        eventmsg->removeRef();
    }
    else
    {
        PVMFNodeInterfaceImpl::ReportErrorEvent(aEventType, aEventData);
    }
}

void PVMFSocketNode::ReportInfoEvent(PVMFEventType aEventType,
                                     OsclAny* aEventData,
                                     PVUuid* aEventUUID,
                                     int32* aEventCode)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_MLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVMFSocketNode:NodeInfoEvent Type %d Data %d"
                     , aEventType, aEventData));

    if (aEventUUID && aEventCode)
    {
        PVMFBasicErrorInfoMessage* eventmsg =
            OSCL_NEW(PVMFBasicErrorInfoMessage, (*aEventCode, *aEventUUID, NULL));
        PVMFAsyncEvent asyncevent(PVMFInfoEvent,
                                  aEventType,
                                  NULL,
                                  OSCL_STATIC_CAST(PVInterface*, eventmsg),
                                  aEventData,
                                  NULL,
                                  0);
        PVMFNodeInterfaceImpl::ReportInfoEvent(asyncevent);
        eventmsg->removeRef();
    }
    else
    {
        PVMFNodeInterfaceImpl::ReportInfoEvent(aEventType, aEventData);
    }
}

PVMFCommandId PVMFSocketNode::QueueCommandL(PVMFNodeCommand& aCmd)
{
#if(ENABLE_SOCKET_NODE_STATS)
    iSocketNodeStats.iNumQueueNodeCmd++;
#endif

    return PVMFNodeInterfaceImpl::QueueCommandL(aCmd);
}

PVMFStatus PVMFSocketNode::DoReset()
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::DoReset()"));

    /* This node allows a reset from any state */

    PVMFStatus status = DoStopNodeActivity();
    if (status == PVMFSuccess)
    {
#if(ENABLE_SOCKET_NODE_STATS)
        iSocketNodeStats.Log(iPortVector);
#endif
        //cleanup all ports.
        CleanupPorts();
        //go back to Idle state
        iPortVector.Reconstruct();
    }

    return status;
}

bool PVMFSocketNode::queryInterface(const PVUuid& uuid, PVInterface*& iface)
{
    iface = NULL;
    if (uuid == PVUuid(PVMF_SOCKET_NODE_EXTENSION_INTERFACE_UUID))
    {
        if (!iExtensionInterface)
        {
            PVMFSocketNodeAllocator alloc;
            int32 err;
            OsclAny*ptr = NULL;
            OSCL_TRY(err,
                     ptr = alloc.ALLOCATE(sizeof(PVMFSocketNodeExtensionInterfaceImpl));
                    );
            if (err != OsclErrNone || !ptr)
            {
                PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::queryInterface: Error - Out of memory"));
                OSCL_LEAVE(OsclErrNoMemory);
            }
            iExtensionInterface =
                OSCL_PLACEMENT_NEW(ptr, PVMFSocketNodeExtensionInterfaceImpl(this));
        }
        if (iExtensionInterface)
        {
            return (iExtensionInterface->queryInterface(uuid, iface));
        }
        else
        {
            PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::queryInterface: Error - Out of memory"));
            OSCL_LEAVE(OsclErrNoMemory);
            return false;
        }
    }
    else
    {
        return false;
    }
}

PVMFStatus PVMFSocketNode::DoQueryInterface()
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
                    (0, "PVMFSocketNode::DoQueryInterface"));

    PVUuid* uuid;
    PVInterface** ptr;
    iCurrentCommand.PVMFNodeCommandBase::Parse(uuid, ptr);
    if (*uuid == PVUuid(PVMF_SOCKET_NODE_EXTENSION_INTERFACE_UUID))
    {
        if (!iExtensionInterface)
        {
            PVMFSocketNodeAllocator alloc;
            int32 err;
            OsclAny*ptr = NULL;
            OSCL_TRY(err,
                     ptr = alloc.ALLOCATE(sizeof(PVMFSocketNodeExtensionInterfaceImpl));
                    );
            if (err != OsclErrNone || !ptr)
            {
                PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::queryInterface: Error - Out of memory"));
                OSCL_LEAVE(OsclErrNoMemory);
            }
            iExtensionInterface = OSCL_PLACEMENT_NEW(ptr, PVMFSocketNodeExtensionInterfaceImpl(this));
        }
        if (iExtensionInterface)
        {
            if (iExtensionInterface->queryInterface(*uuid, *ptr))
            {
                return PVMFSuccess;
            }
            else
            {
                return PVMFErrNotSupported;
            }
        }
        else
        {
            return PVMFErrNoMemory;
        }
    }
    else
    {//not supported
        *ptr = NULL;
        return PVMFErrNotSupported;
    }
}

PVMFStatus PVMFSocketNode::DoRequestPort(PVMFPortInterface* &aPort)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::DoRequestPort() In"));

    iRequestedPort = NULL;

    //retrieve port tag.
    int32 tag;
    OSCL_String* portconfig;
    iCurrentCommand.PVMFNodeCommandBase::Parse(tag, portconfig);
    //validate the tag...
    switch (tag)
    {
        case PVMF_SOCKET_NODE_PORT_TYPE_SOURCE:
        case PVMF_SOCKET_NODE_PORT_TYPE_SINK:
        case PVMF_SOCKET_NODE_PORT_TYPE_PASSTHRU:
            break;
        default:
            //bad port tag
            PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::DoRequestPort: Error - Invalid port tag"));
            iCommandErrorCode = PVMFSocketNodeErrorInvalidPortTag;
            return PVMFErrArgument;
    }

    SOCKET_ADDR sock_add;
    sock_add.iTag = tag;
    OSCL_HeapString<OsclMemAllocator> mime;
    if (!ParseTransportConfig(portconfig, sock_add, mime))
    {
        PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::DoRequestPort: ERROR - Invalid port config"));
        iCommandErrorCode = PVMFSocketNodeErrorInvalidPortTag;
        return PVMFErrArgument;
    }

    PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::DoRequestPort tag %d config %s",
                                      tag, portconfig->get_cstr()));

    switch (sock_add.iProtocol)
    {
        case INET_TCP:
        {
            //Create a new port with no socket.

            PVMFStatus status = AddPort(tag, iRequestedPort);
            if (status != PVMFSuccess)
                return status;

            //create the socket config

            SocketPortConfig* sock_config = OSCL_NEW(SocketPortConfig, ());
            iRequestedPort->iConfig = sock_config;
            sock_config->iPVMFPort = iRequestedPort;

            sock_config->iMime = mime;
            sock_config->iContainer = this;
            sock_config->iSockId = iSocketID++;
            sock_config->iTag = tag;
            sock_config->iAddr = sock_add;
            if (iMaxTCPRecvBufferSizeToConfigure > 0)
            {
                sock_config->iMaxTcpRecvBufferSize = iMaxTCPRecvBufferSizeToConfigure;
            }
            if (iMaxTCPRecvBufferCntToConfigure > 0)
            {
                sock_config->iMaxTcpRecvBufferCount = iMaxTCPRecvBufferCntToConfigure;
            }

            //create the mem pool
            PVMFSocketNodeMemPool* memPool;
            status = AllocatePortMemPool(tag, memPool);
            if (status == PVMFSuccess)
                sock_config->iMemPool = memPool;
            if (status != PVMFSuccess)
                return status;

            //optionally create the socket and launch the connect sequence.
            if (oscl_strstr(portconfig->get_cstr(), ";no-connect-on-create") != NULL)
            {
                //if "no create on connect" was selected then port creation is complete now.
                status = PVMFSuccess;
            }
            else
            {
                //else create the socket and launch the connect sequence.
                OSCL_ASSERT(sock_config->iState.iSequence == EPVSocketPortSequence_None);
                status = StartSequence(*sock_config, EPVSocketPortSequence_RequestPort);
                //may need to wait on connect completion here, or else there could
                //be an error.
            }
            // assign created port
            aPort = iRequestedPort;
            return status;
        }

        case INET_UDP:
        {
            //We should have already created this UDP socket in a call to AllocateConsecutivePorts.
            SocketPortConfig* sockConfig = FindSocketPortConfig(sock_add);
            if (!sockConfig)
            {
                PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::DoRequestPort: ERROR - Invalid protocol for port request"));
                return PVMFFailure;
            }

            //The udp socket was already created using AllocateConsecutivePorts(),
            //the but PVMFPort and memory pool were not yet created.

            //Allocate a new PVMF port

            PVMFStatus status = AddPort(tag, iRequestedPort);
            if (status == PVMFSuccess)
            {
                PVMFSocketNodeMemPool* memPool = NULL;
                status = AllocatePortMemPool(tag, memPool);
                if (status == PVMFSuccess)
                    sockConfig->iMemPool = memPool;
            }

            if (status != PVMFSuccess)
            {
                //put the port config back in the allocated port vector
                iAllocatedPortVector.push_back(sockConfig);
                return status;
            }

            //move the sock config to the PVMF port vector and link the config
            //back to the port.
            iRequestedPort->iConfig = sockConfig;
            sockConfig->iPVMFPort = iRequestedPort;

            // assign created port
            aPort = iRequestedPort;

            return status;
        }
        break;
        default:
            PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::DoRequestPort: ERROR - Invalid protocol for port request"));
            return PVMFFailure;
    }
    PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::DoRequestPort: ERROR - Invalid protocol for port request"));

    return PVMFFailure;
}

//Release ports is a do-nothing for this node.
PVMFStatus PVMFSocketNode::DoReleasePort()
{
    return PVMFSuccess;
}

PVMFStatus PVMFSocketNode::DoInit()
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::DoInit() In"));

    if (EPVMFNodeInitialized == iInterfaceState)
    {
        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::DoInit() Already in Initialized state"));
        return PVMFSuccess;
    }

#if(ENABLE_SOCKET_NODE_STATS)
    iSocketNodeStats.Init();
#endif

    PVMFStatus status = PVMFSuccess;

    //Create socket server session
    if (NULL == iSockServ)
    {
        int32 err;
        OSCL_TRY(err, iSockServ = OsclSocketServ::NewL(iAlloc););
        if (err || (iSockServ ==  NULL))
        {
            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
                            (0, "PVMFSocketNode::DoInit: ERROR. OsclSocketServ::NewL() fail Ln %d", __LINE__));

            iCommandErrorCode = PVMFSocketNodeErrorSocketServerCreateError;
            status =  PVMFErrNoResources;
        }
        else
        {
            if (iSockServ->Connect() == OsclErrNone)
            {
                status = PVMFSuccess;
            }
            else
            {
                PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR,
                                (0, "PVMFSocketNode::DoInit: ERROR. OsclSocketServ::Connect() fail Ln %d", __LINE__));

                iCommandErrorCode = PVMFSocketNodeErrorSocketServConnectError;
                status = PVMFErrResource;
            }
        }
    }
    return status;
}

PVMFStatus PVMFSocketNode::DoStart()
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::DoStart() In"));
    /*
     * If the node is already started just return success - multiple starts can happen with
     * flow control (auto-pause / auto-resume) scenarios
     */
    if (EPVMFNodeStarted == iInterfaceState)
    {
        PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::DoStart() Already in Started state"));
        return PVMFSuccess;
    }

    //We need to update the node state before
    //we can get things going.
    TPVMFNodeInterfaceState curState = iInterfaceState;
    SetState(EPVMFNodeStarted);

    PVMFStatus status = PVMFSuccess;
    for (uint32 i = 0; i < iPortVector.size(); i++)
    {
        SocketPortConfig* sockConfig = iPortVector[i]->iConfig;
        if (sockConfig)
        {
            //Start handling incoming messages
            if (CanProcessIncomingMsg(*sockConfig))
                ProcessIncomingMsg(*sockConfig);

            //Start the receives.
            if (CanReceive(*sockConfig))
            {
                status = StartRecvOperation(*sockConfig);
                //receive may be pending, but we don't block
                //the start command for it.
                if (status == PVMFPending)
                {
                    status = PVMFSuccess;
                }
                else if (status != PVMFSuccess)
                {
                    //fail the command if any individual startups fail.
                    //restore the old node state.
                    SetState(curState);
                    break;//out of for loop
                }
            }
        }
    }
    return status;
}

PVMFStatus PVMFSocketNode::DoStop()
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::DoStop() In"));

    //Stop will essentially just stop the receive operations and input port processing,
    //since those handlers check the node state.  Current operations will not be
    //interrupted.

#if(ENABLE_SOCKET_NODE_STATS)
    //dump the stats.
    iSocketNodeStats.Log(iPortVector);
#endif
    return PVMFSuccess;
}

//Stop all current socket/DNS activity and clear port messages.
//Return PVMFSuccess if everything is stopped, or else PVMFPending if some
//ports still have operations pending.
//
//Also update the global "iNumStopNodeActivityPending"
//with the number of ports that still have operations pending

PVMFStatus PVMFSocketNode::DoStopNodeActivity()
{
    //note that "iNumStopNodeActivityPending" uses the value (-1) to indicate idle state,
    //or N...0 to countdown how many ports we're waiting on.

    //Note: in case there's already a "stop node activity" going on, just
    //return the status.
    if (iNumStopPortActivityPending > 0)
        return PVMFPending; //keep waiting on completion (in SequenceComplete)

    //Notify all PVMF ports to suspend their input, and discard any current messages.
    for (uint32 i = 0; i < iPortVector.size(); i++)
    {
        iPortVector[i]->SuspendInput();
        iPortVector[i]->ClearMsgQueues();
    }

    //Stop socket activity on all ports.
    {
        uint32 nPortsPending = 0;
        for (uint32 i = 0; i < iPortVector.size(); i++)
        {
            SocketPortConfig* portConfig = iPortVector[i]->iConfig;
            if (portConfig)
            {
                // discard any saved socket activity events
                portConfig->iSocketRecvActivity.iValid = false;

                // start a shutdown sequence on the port
                // look at what else might be happening currently.

                //if a request port is going on, be sure to complete the command,
                //although we will interrupt the current processing.
                if (portConfig->iState.iSequence == EPVSocketPortSequence_RequestPort
                        && iCurrentCommand.iCmd == PVMF_GENERIC_NODE_REQUESTPORT)
                {
                    //@TODO would be nice to cleanup the allocated port in case of a failure.
                    CommandComplete(iCurrentCommand, PVMFErrCancelled);
                }
                //for any other sequence, we will just interrupt it with the shutdown.

                //if a cleanup is already underway, just keep waiting for it to complete,
                //else start a new sequence
                if (portConfig->iState.iSequence == EPVSocketPortSequence_SocketCleanup)
                {
                    nPortsPending++;
                }
                else if (StartSequence(*portConfig, EPVSocketPortSequence_SocketCleanup) == PVMFPending)
                {
                    nPortsPending++;
                }
            }
        }

        if (nPortsPending > 0)
            iNumStopPortActivityPending = nPortsPending;
    }

    if (iNumStopPortActivityPending > 0)
        return PVMFPending; //wait on completion in SequenceComplete.

    return PVMFSuccess;
}

//Flush is implemented for this node, but hasn't been tested.
PVMFStatus PVMFSocketNode::DoFlush()
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::DoFlush() In"));

    //Notify all ports to suspend their input, then
    //wait on completion of processing of current input.
    PVMFStatus status = PVMFSuccess;
    {
        for (uint32 i = 0; i < iPortVector.size(); i++)
        {
            iPortVector[i]->SuspendInput();
            if (status != PVMFPending
                    && iPortVector[i]->IncomingMsgQueueSize() > 0)
            {
                status = PVMFPending;//Wait on this queue to empty.
                //Completion is detected in SequenceComplete.
            }
        }
    }

    return status;
}

PVMFStatus PVMFSocketNode::CancelCurrentCommand()
{
    PVMFStatus status = PVMFSuccess;

    //wait on current command to complete.  The cancel command
    //will ultimately be completed in the "CommandComplete" for the current command.
    status = DoCancelCurrentCommand();

    if (status != PVMFPending || status != PVMFFailure)
    {
        CommandComplete(iCurrentCommand, PVMFErrCancelled);
        return PVMFSuccess;
    }
    else
    {
        return status;
    }
}

//This routine must cancel the currently executing node command.
//It only needs to handle those commands that may have asynchronous completion.
PVMFStatus PVMFSocketNode::DoCancelCurrentCommand()
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::DoCancelCurrentCommand()"));
    switch (iCurrentCommand.iCmd)
    {

        case PVMF_GENERIC_NODE_REQUESTPORT:
            //there may be a connect operation pending-- cancel it.
        {
            if (iRequestedPort)
            {
                SocketPortConfig* sockConfig = iRequestedPort->iConfig;
                if (sockConfig
                        && sockConfig->iState.iConnectOperation != EPVSocketPortConnectOperation_None)
                {
                    CancelConnectOperation(*sockConfig);
                    return PVMFPending;//wait on the operation to complete
                    //in HandleSocketEvent or HandleDNSEvent
                }
            }
            //shouldn't get here...
            return PVMFFailure;
        }
        break;

        case PVMF_GENERIC_NODE_RESET:
            //it's too complicated to cancel a reset, so just wait on completion
            return PVMFPending;

        case PVMF_GENERIC_NODE_FLUSH:
            //to cancel a flush, just discard all remaining port messages
            //and keep waiting on completion of current message.
        {
            for (uint32 i = 0; i < iPortVector.size(); i++)
                iPortVector[i]->ClearMsgQueues();
        }
        return PVMFPending;//keep waiting on flush completion in SequenceComplete.

        case PVMF_GENERIC_NODE_CANCELCOMMAND:
        case PVMF_GENERIC_NODE_CANCELALLCOMMANDS:
            //these have asynchronous completion, but the command handling prevents
            //processing a cancel during a cancel, so we shouldn't get here.
            OSCL_ASSERT(0);
            return PVMFFailure;

        default:
            //no other node commands have asynchronous completion, so this is unexpected.
            OSCL_ASSERT(0);
            return PVMFFailure;
    }
}

PVMFStatus PVMFSocketNode::HandleExtensionAPICommands()
{
    return PVMFErrNotSupported;
}

//////////////////////////////////////
// End Command Handlers
//////////////////////////////////////


//////////////////////////////////////
// DNS & Socket Callbacks
//////////////////////////////////////

OSCL_EXPORT_REF void PVMFSocketNode::HandleDNSEvent(int32 aId, TPVDNSFxn aFxn, TPVDNSEvent aEvent, int32 aError)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::HandleDNSEvent() In aId=%d, aFxn=%d, aEvent=%d, aError=%d", aId, aFxn, aEvent, aError));

    iInSocketCallback = true;

    if (aEvent != EPVDNSSuccess)
    {
        PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::HandleDNSEvent: Error - Failure"));
    }

    //Note: since the DNS object ID is identical to the socket ID, we can lookup the
    //socket port config using the DNS ID.
    SocketPortConfig* sockConfigPtr = FindSocketPortConfig((uint32)aId);
    if (!sockConfigPtr)
    {
        //it's possible the DNS object was already delete-- so just fail gracefully.
        PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::HandleDNSEvent: Error - Invalid Socket ID"));
    }
    else
    {

#if(ENABLE_SOCKET_NODE_STATS)
        sockConfigPtr->iPortStats.iNumDNSCallback++;
#endif

        //create socket activity
        PVMFSocketActivity activity((aEvent == EPVDNSSuccess) ? PVMFSuccess : PVMFFailure, aId, aFxn, aEvent, aError);

        //Call the appropriate handler
        switch (aFxn)
        {
            case EPVDNSGetHostByName:
                OSCL_ASSERT(sockConfigPtr->iState.iConnectOperation == EPVSocketPortConnectOperation_GetHostByName);
#if(ENABLE_SOCKET_NODE_STATS)
                if (aEvent == EPVDNSSuccess)
                    sockConfigPtr->iPortStats.EndConnectTime(sockConfigPtr->iState.iConnectOperation);
#endif
                ConnectOperationComplete(*sockConfigPtr, activity.iStatus, &activity);
                break;

            default:
                OSCL_ASSERT(0);//unexpected
                break;
        }
    }

    iInSocketCallback = false;
}


//This is the callback from Oscl Sockets for socket operation completion.
OSCL_EXPORT_REF  void PVMFSocketNode::HandleSocketEvent(int32 aId, TPVSocketFxn aFxn, TPVSocketEvent aEvent, int32 aError)
{
    PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0, "PVMFSocketNode::HandleSocketEvent() In aId=%d, aFxn=%d, aEvent=%d, aError=%d", aId, aFxn, aEvent, aError));

    iInSocketCallback = true;

    SocketPortConfig* sockConfigPtr = FindSocketPortConfig((uint32)aId);
    if (!sockConfigPtr)
    {
        //it's possible the socket was already deleted-- so just fail gracefully.
        PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::HandleSocketEvent: Error - Invalid Socket ID"));
    }
    else
    {
        if (aEvent != EPVSocketSuccess)
        {
            PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::HandleSocketEvent: Error - Event=%d, SockId=%d, Mime=%s",
                                      aEvent, aId, sockConfigPtr->iMime.get_cstr()));
        }
#if(ENABLE_SOCKET_NODE_STATS)
        sockConfigPtr->iPortStats.iNumSocketCallback++;
#endif
        //create socket activity
        PVMFSocketActivity activity((aEvent == EPVSocketSuccess) ? PVMFSuccess : PVMFFailure, aId, aFxn, aEvent, aError);

        //Call the appropriate handler
        switch (aFxn)
        {
            case EPVSocketRecvFrom:
            case EPVSocketRecv:
                OSCL_ASSERT(sockConfigPtr->iState.iRecvOperation == EPVSocketPortRecvOperation_Recv
                            || sockConfigPtr->iState.iRecvOperation == EPVSocketPortRecvOperation_RecvFrom);
#if(ENABLE_SOCKET_NODE_STATS)
                if (aEvent == EPVSocketSuccess)
                    sockConfigPtr->iPortStats.EndRecvTime(sockConfigPtr->iState.iRecvOperation);
#endif
                RecvOperationComplete(*sockConfigPtr, activity.iStatus, &activity);
                break;

            case EPVSocketSendTo:
            case EPVSocketSend:
                OSCL_ASSERT(sockConfigPtr->iState.iSendOperation == EPVSocketPortSendOperation_Send
                            || sockConfigPtr->iState.iSendOperation == EPVSocketPortSendOperation_SendTo);
#if(ENABLE_SOCKET_NODE_STATS)
                if (aEvent == EPVSocketSuccess)
                    sockConfigPtr->iPortStats.EndSendTime(sockConfigPtr->iState.iSendOperation);
#endif
                SendOperationComplete(*sockConfigPtr, activity.iStatus, &activity);
                break;

            case EPVSocketConnect:
                OSCL_ASSERT(sockConfigPtr->iState.iConnectOperation == EPVSocketPortConnectOperation_Connect);
#if(ENABLE_SOCKET_NODE_STATS)
                if (aEvent == EPVSocketSuccess)
                    sockConfigPtr->iPortStats.EndConnectTime(sockConfigPtr->iState.iConnectOperation);
#endif
                ConnectOperationComplete(*sockConfigPtr, activity.iStatus, &activity);
                break;

            case EPVSocketShutdown:
                OSCL_ASSERT(sockConfigPtr->iState.iConnectOperation == EPVSocketPortConnectOperation_Shutdown);
#if(ENABLE_SOCKET_NODE_STATS)
                if (aEvent == EPVSocketSuccess)
                    sockConfigPtr->iPortStats.EndConnectTime(sockConfigPtr->iState.iConnectOperation);
#endif
                ConnectOperationComplete(*sockConfigPtr, activity.iStatus, &activity);
                break;

            default:
                OSCL_ASSERT(0);//unexpected
                break;
        }
    }

    iInSocketCallback = false;
}

//////////////////////////////////////
// End DNS & Socket Callbacks
//////////////////////////////////////

///////////////////////
// Low-level port processing
///////////////////////

//Allocate a node port and add it to the port vector.
PVMFStatus PVMFSocketNode::AddPort(int32 tag, PVMFSocketPort* &port)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::AddPort() In"));
    int32 err;
    OsclAny *ptr = NULL;
    OSCL_TRY(err, ptr = iPortVector.Allocate(););
    if (err != OsclErrNone || !ptr)
    {
        PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::AddPort: ERROR - err=%d Ln %d", err, __LINE__));
        return PVMFErrNoMemory;
    }

    port = new(ptr) PVMFSocketPort((int32)tag,
                                   this,
                                   DEFAULT_DATA_QUEUE_CAPACITY,
                                   DEFAULT_DATA_QUEUE_CAPACITY,
                                   DEFAULT_READY_TO_RECEIVE_THRESHOLD_PERCENT,
                                   //the output queue is empty because
                                   //this node pushes data directly to the
                                   //connecte port's input.
                                   0, 0, 0);

    //Add the port to the port vector.
    OSCL_TRY(err, iPortVector.AddL(port););
    if (err != OsclErrNone)
    {
        iPortVector.DestructAndDealloc(port);
        return PVMFErrNoMemory;
    }
    return PVMFSuccess;
}

//Allocate a memory pool for the input port config.
//When finished, the port config is updated with the
//mempool and the port tag.
PVMFStatus PVMFSocketNode::AllocatePortMemPool(int32 tag, PVMFSocketNodeMemPool* & aMemPool)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::AllocatePortMemPool() In"));
    aMemPool = NULL;
    OsclAny *MemPtr = NULL;
    int32 err;
    OSCL_TRY(err, MemPtr = iAlloc.ALLOCATE(sizeof(PVMFSocketNodeMemPool)););
    if ((err != OsclErrNone) || (MemPtr == NULL))
    {
        PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::DoRequestPort: PVMFSocketNodeMemPool Allocate Failed Ln %d", err, __LINE__));
        return PVMFErrNoMemory;
    }

    switch (tag)
    {
        case PVMF_SOCKET_NODE_PORT_TYPE_SOURCE:
            //source tag is used for RTP
        {
            int32 errcode = 0;
            errcode = SocketPlacementNew(aMemPool, MemPtr, DEFAULT_NUM_MEDIA_MSGS_IN_JITTER_BUFFER);
            if (errcode != OsclErrNone)
            {
                PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::DoRequestPort: PVMFSocketNodeMemPool Construct Failed Ln %d", err, __LINE__));
                iAlloc.deallocate(MemPtr);
                return PVMFErrNoMemory;
            }
        }
        break;
        case PVMF_SOCKET_NODE_PORT_TYPE_SINK:
        case PVMF_SOCKET_NODE_PORT_TYPE_PASSTHRU:
            //sink tag is used for RTCP
        {
            int32 errcode = 0;
            errcode = SocketPlacementNew(aMemPool, MemPtr, SNODE_DEFAULT_NUMBER_MEDIADATA_IN_MEMPOOL);
            if (errcode != OsclErrNone)
            {
                PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::DoRequestPort: PVMFSocketNodeMemPool Construct Failed Ln %d", err, __LINE__));
                iAlloc.deallocate(MemPtr);
                return PVMFErrNoMemory;
            }
        }
        break;

        default://unexpected-- caller already validated the tag.
            iAlloc.deallocate(MemPtr);
            return PVMFFailure;
            break;
    }
    aMemPool->iPortTag = tag;
    return PVMFSuccess;
}


//Lookup the socket port config entry, given a socket address.
//If the entry is in the "allocated port" vector, it will be erased, so
//it's up to the caller to make sure it gets deleted or moved.
SocketPortConfig* PVMFSocketNode::FindSocketPortConfig(SOCKET_ADDR& aSockAddr)
{
    uint32 i;
    //search the allocated port vector
    for (i = 0; i < iAllocatedPortVector.size(); i++)
    {
        if (iAllocatedPortVector[i]
                && MatchSocketAddr(aSockAddr, *iAllocatedPortVector[i]))
        {
            //erase it from the vector before returning to the caller.
            SocketPortConfig* elem = iAllocatedPortVector[i];
            iAllocatedPortVector.erase(&iAllocatedPortVector[i]);
            return elem;
        }
    }
    //search the port vector
    for (i = 0; i < iPortVector.size(); i++)
    {
        if (iPortVector[i]->iConfig
                && MatchSocketAddr(aSockAddr, *iPortVector[i]->iConfig))
        {
            return iPortVector[i]->iConfig;
        }
    }
    return NULL;
}

//return "true" if input socket address matches port config
bool PVMFSocketNode::MatchSocketAddr(SOCKET_ADDR& aSockAddr, SocketPortConfig& aSockConfig)
{
    return (aSockConfig.iAddr.iProtocol == aSockAddr.iProtocol
            && aSockConfig.iAddr.iRemoteAdd.port == aSockAddr.iRemoteAdd.port
            && aSockConfig.iAddr.iRemoteHost == aSockAddr.iRemoteHost
            && aSockConfig.iTag == aSockAddr.iTag
            //local address may or may not be specified-- ignore if not.
            && (!aSockAddr.iLocalAdd.port
                || (aSockConfig.iAddr.iLocalAdd.port == aSockAddr.iLocalAdd.port)));
}

//Lookup the socket port config entry, given a socket ID.
SocketPortConfig* PVMFSocketNode::FindSocketPortConfig(uint32 aId)
{
    for (uint32 i = 0; i < iPortVector.size(); i++)
    {
        if (iPortVector[i]->iConfig
                && iPortVector[i]->iConfig->iSockId == aId)
        {
            return iPortVector[i]->iConfig;
        }
    }
    return NULL;
}

//Create a socket using the given socket ID and protocol.
//For UDP, this will also attempt to bind, incrementing port numbers until
//either success or maximum attempts is reached.  This has the side effect
//of updating the port number in the local address.
//It returns a pointer to the socket cast as OsclAny*.
OsclAny* PVMFSocketNode::CreateOsclSocketAndBind(SOCKET_ADDR &aSockAdd, uint32 aSockId)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::CreateOsclSocketAndBind() In"));
    //create the socket server session if it doesn't exist yet.
    if (iSockServ == NULL)
    {
        int32 err;
        OSCL_TRY(err, iSockServ = OsclSocketServ::NewL(iAlloc););
        if (err || (iSockServ ==  NULL))
        {
            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFSocketNode::CreateSocket() ERROR- iSockServ=0x%x, err=%d, Ln %d", iSockServ, err, __LINE__));
            return NULL;
        }
        if (iSockServ->Connect() != OsclErrNone)
        {
            PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFSocketNode::CreateSocket() ERROR Connect(), Ln %d", __LINE__));
            return NULL;
        }
    }

    switch (aSockAdd.iProtocol)
    {
        case INET_UDP:
        {
            int32 err;
            OsclUDPSocket *UDPSocket = NULL;
            OSCL_TRY(err, UDPSocket = OsclUDPSocket::NewL(iAlloc, *iSockServ, this, aSockId););
            if (err || (UDPSocket ==  NULL))
            {
                PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_ERR, (0, "PVMFSocketNode::CreateSocket() ERROR- UDPSocket=0x%x, err=%d, Ln %d", UDPSocket, err, __LINE__));
                return NULL;
            }

            //Bind this socket to the address
            bool bBindOK = false;
            while (iUdpPortRange-- > 0)
            {
#if(ENABLE_SOCKET_NODE_STATS)
                iSocketNodeStats.iNumBind++;
#endif
                if (UDPSocket->Bind(aSockAdd.iLocalAdd) == EPVSocketSuccess)
                {
                    bBindOK = true;
                    break;
                }
                aSockAdd.iLocalAdd.port++;
            };

            //If bind failed, delete the socket.
            if (!bBindOK)
            {
                UDPSocket->~OsclUDPSocket();
                iAlloc.deallocate(UDPSocket);

                UDPSocket = NULL;
            }
            return UDPSocket;
        }

        case INET_TCP:
        {

            int32 err;
            OsclTCPSocket *TCPSocket = NULL;

            OSCL_TRY(err, TCPSocket = OsclTCPSocket::NewL(iAlloc, *iSockServ, this, aSockId););
            if (err || (TCPSocket ==  NULL))
            {
                return NULL;
            }
            return TCPSocket;
        }

        default:
            return NULL;
    }
}

//This finishes up a TCP socket cleanup, after the socket shutdown
//is complete.
void PVMFSocketNode::CleanupTCP(SocketPortConfig& aSockConfig)
{
    if (aSockConfig.iTCPSocket)
    {
        //Close the socket.  This will free the OS-level resources.  This
        //socket object cannot be re-used.
        aSockConfig.iTCPSocket->Close();
        PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CleanupTCP - Socket Closed - SockId=%d, Mime=%s, Port=0x%x", aSockConfig.iSockId, aSockConfig.iMime.get_str(), aSockConfig.iPVMFPort));

        //Send EOS.  To avoid multiple EOS we only do this when the
        //socket is still open.
        if (aSockConfig.iPVMFPort
                && aSockConfig.iPVMFPort->IsConnected())
        {
            PVMFSharedMediaCmdPtr sharedMediaCmdPtr = PVMFMediaCmd::createMediaCmd();
            sharedMediaCmdPtr->setFormatID(PVMF_MEDIA_CMD_EOS_FORMAT_ID);
            PVMFSharedMediaMsgPtr mediaMsgOut;
            convertToPVMFMediaCmdMsg(mediaMsgOut, sharedMediaCmdPtr);
#if(ENABLE_SOCKET_NODE_STATS)
            aSockConfig.iPortStats.iNumQueueOutgoingEOSMsg++;
#endif
            PVMFStatus status = aSockConfig.iPVMFPort->QueueOutgoingMsg(mediaMsgOut);
            //There's no recovery from a queue busy condition here.
            //We assume the caller already waited on the connected port before
            //calling this routine.
            if (status != PVMFSuccess)
            {
                PVMF_SOCKETNODE_LOGERROR((0, "PVMFSocketNode::SendPVMFEOS() ERROR:%d, Outgoing queue size=%d. Data discarded!", status, aSockConfig.iPVMFPort->OutgoingMsgQueueSize()));
                ReportErrorEvent(PVMFErrPortProcessing);
                PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode::CleanupTCP - EOS Send FAILED - SockId=%d, Mime=%s, Port=0x%x", aSockConfig.iSockId, aSockConfig.iMime.get_str(), aSockConfig.iPVMFPort));
            }
            else
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CleanupTCP - EOS Sent - SockId=%d, Mime=%s, Port=0x%x", aSockConfig.iSockId, aSockConfig.iMime.get_str(), aSockConfig.iPVMFPort));
            }
        }

        if (iInSocketCallback)
        {
            //prevent deleting an object from within its own Run.
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CleanupTCP - queueing old socket for deletion - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            iClosedTCPSocketVector.push_back(aSockConfig.iTCPSocket);
            aSockConfig.iTCPSocket = NULL;
            RunIfNotReady();//schedule the AO to delete the socket.
        }
        else
        {
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CleanupTCP - Deleting socket - SockId=%d, Mime=%s, Port=0x%x", aSockConfig.iSockId, aSockConfig.iMime.get_str(), aSockConfig.iPVMFPort));
            aSockConfig.iTCPSocket->~OsclTCPSocket();
            iAlloc.deallocate(aSockConfig.iTCPSocket);
            aSockConfig.iTCPSocket = NULL;
        }
    }

    //cleanup media messages
    //(this must happen *after* the optional EOS)
    if (aSockConfig.iPendingRecvMediaData.GetRep() != NULL)
        aSockConfig.iPendingRecvMediaData.Unbind();
    if (aSockConfig.iPendingSendMediaData.GetRep() != NULL)
        aSockConfig.iPendingSendMediaData.Unbind();
}

//Cancel and/or delete UDP socket
void PVMFSocketNode::CleanupUDP(SocketPortConfig& aSockConfig)
{
    //delete
    if (aSockConfig.iUDPSocket)
    {
        if (iInSocketCallback)
        {
            //prevent deleting an object from within its own Run.
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CleanupTCP - queueing old socket for deletion - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            iClosedUDPSocketVector.push_back(aSockConfig.iUDPSocket);
            aSockConfig.iUDPSocket = NULL;
            Reschedule();//schedule the AO to delete the socket.
        }
        else
        {
            aSockConfig.iUDPSocket->~OsclUDPSocket();
            iAlloc.deallocate(aSockConfig.iUDPSocket);
            aSockConfig.iUDPSocket = NULL;
        }
    }

    //cleanup media messages when socket is deleted
    if (aSockConfig.iPendingRecvMediaData.GetRep() != NULL)
        aSockConfig.iPendingRecvMediaData.Unbind();
    if (aSockConfig.iPendingSendMediaData.GetRep() != NULL)
        aSockConfig.iPendingSendMediaData.Unbind();
}

void PVMFSocketNode::CleanupDNS(SocketPortConfig& aSockConfig)
{
    if (aSockConfig.iDNS)
    {
        if (iInSocketCallback)
        {
            //prevent deleting an object from within its own Run.
            PVMF_SOCKETNODE_LOGDATATRAFFIC_I((0, "PVMFSocketNode::CleanupDNS - queueing old DNS for deletion - SockId=%d, Mime=%s", aSockConfig.iSockId, aSockConfig.iMime.get_str()));
            iClosedDNSVector.push_back(aSockConfig.iDNS);
            aSockConfig.iDNS = NULL;
            Reschedule();//schedule the AO to delete the object.
        }
        else
        {
            aSockConfig.iDNS->~OsclDNS();
            iAlloc.deallocate(aSockConfig.iDNS);
            aSockConfig.iDNS = NULL;
        }
    }
}

//A synchronous cleanup routine for all ports.
//It is assumed that all sockets are idle when this is called.
//This is used in node destructor, and in completion of
//Reset and Cancel All commands.
void PVMFSocketNode::CleanupPorts()
{
    // Cleanup port vector
    while (!iPortVector.empty())
    {
        SocketPortConfig* it = iPortVector.front()->iConfig;
        if (it)
        {
            //unlink the PVMFPort so we won't try to send any EOS msg
            //during the TCP cleanup.
            it->iPVMFPort = NULL;
            CleanupTCP(*it);
            CleanupUDP(*it);
            CleanupDNS(*it);
            it->CleanupMemPools(iAlloc);
            OSCL_DELETE(it);
            iPortVector.front()->iConfig = NULL;
        }
        iPortVector.Erase(&iPortVector.front());
    }
    // Cleanup allocated ports (these may have bound UDP sockets
    // but don't have any PVMF ports).
    while (!iAllocatedPortVector.empty())
    {
        SocketPortConfig* it = iAllocatedPortVector.front();
        CleanupTCP(*it);
        CleanupUDP(*it);
        CleanupDNS(*it);
        it->CleanupMemPools(iAlloc);
        OSCL_DELETE(it);
        iAllocatedPortVector.erase(&iAllocatedPortVector.front());
    }
}

void PVMFSocketNode::CleanupClosedTCPSockets()
{
    while (!iClosedTCPSocketVector.empty())
    {
        OsclTCPSocket* obj = iClosedTCPSocketVector.front();
        obj->~OsclTCPSocket();
        iAlloc.deallocate(obj);
        iClosedTCPSocketVector.erase(&iClosedTCPSocketVector.front());
    }
}

void PVMFSocketNode::CleanupClosedUDPSockets()
{
    while (!iClosedUDPSocketVector.empty())
    {
        OsclUDPSocket* obj = iClosedUDPSocketVector.front();
        obj->~OsclUDPSocket();
        iAlloc.deallocate(obj);
        iClosedUDPSocketVector.erase(&iClosedUDPSocketVector.front());
    }
}

void PVMFSocketNode::CleanupClosedDNS()
{
    while (!iClosedDNSVector.empty())
    {
        OsclDNS* obj = iClosedDNSVector.front();
        obj->~OsclDNS();
        iAlloc.deallocate(obj);
        iClosedDNSVector.erase(&iClosedDNSVector.front());
    }
}

bool PVMFSocketNode::ParseTransportConfig(OSCL_String *aPortConfig,
        SOCKET_ADDR &aSockConfig,
        OSCL_String& aMime)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::ParseTransportConfig() In"));
    char* head = aPortConfig->get_str();
    int32 len = aPortConfig->get_size();
    return ParseTransportConfig(head, len, aSockConfig, aMime);
}

bool PVMFSocketNode::ParseTransportConfig(char *aPortConfig,
        int32 aLen,
        SOCKET_ADDR &aSockConfig,
        OSCL_String& aMime)
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::ParseTransportConfig() In"));
    char* head = aPortConfig;
    int32 len = aLen;

    char *tail = head + len;

    if (oscl_strstr(head, "TCP"))
        aSockConfig.iProtocol = INET_TCP;
    else if (oscl_strstr(head, "UDP"))
        aSockConfig.iProtocol = INET_UDP;
    else
        return false;//invalid protocol.

    //for future extension
    aSockConfig.iLocalAdd.ipAddr.Set("0.0.0.0");    //INADDR_ANY

    aSockConfig.iRemoteAdd.ipAddr.Set("");

    OSCL_StackString<128> address("remote_address=");

    char *tmpHead = OSCL_CONST_CAST(char*, oscl_strstr(head, address.get_cstr()));
    if (tmpHead)
    {
        tmpHead += address.get_size();
        char *tmpTail = OSCL_CONST_CAST(char*, oscl_strstr(tmpHead, ";"));
        if (tmpTail == NULL)
        {
            tmpTail = tail;
        }
        char tmpChar = *tmpTail;
        *tmpTail = '\0';
        aSockConfig.iRemoteAdd.ipAddr.Set(tmpHead);

        OSCL_HeapString<PVMFSocketNodeAllocator> tmpServerName(tmpHead, (tmpTail - tmpHead));
        aSockConfig.iRemoteHost = tmpServerName;

        *tmpTail = tmpChar;
    }

    {
        TimeValue current_time;
        current_time.set_to_current_time();
        uint32 my_seed = current_time.get_sec();

        OsclRand random_num;
        random_num.Seed(my_seed);
        int32 first = random_num.Rand();
        uint32 myport = (first & 0x1FFF) + 0x2000;  //start from 8192
        aSockConfig.iLocalAdd.port = (myport >> 1) << 1;    //start from even;
    }
    OSCL_StackString<128> client_port("client_port=");
    tmpHead = OSCL_CONST_CAST(char*, oscl_strstr(head, client_port.get_cstr()));
    if (tmpHead)
    {
        tmpHead += client_port.get_size();
        char *tmpTail = OSCL_CONST_CAST(char*, oscl_strstr(tmpHead, ";"));
        if (tmpTail == NULL)
        {
            tmpTail = tail;
        }
        char tmpChar = *tmpTail;
        *tmpTail = '\0';

        uint32 atoi_tmp;
        if (PV_atoi(tmpHead, 'd', atoi_tmp))
        {
            aSockConfig.iLocalAdd.port = atoi_tmp;
        }
        *tmpTail = tmpChar;
    }

    aSockConfig.iRemoteAdd.port = 0;
    OSCL_StackString<128> server_port("remote_port=");
    tmpHead = OSCL_CONST_CAST(char*, oscl_strstr(head, server_port.get_cstr()));
    if (tmpHead)
    {
        tmpHead += server_port.get_size();
        char *tmpTail = OSCL_CONST_CAST(char*, oscl_strstr(tmpHead, ";"));
        if (tmpTail == NULL)
        {
            tmpTail = tail;
        }

        char tmpChar = *tmpTail;
        *tmpTail = '\0';

        uint32 atoi_tmp;
        if (PV_atoi(tmpHead, 'd', atoi_tmp))
        {
            aSockConfig.iRemoteAdd.port = atoi_tmp;
        }
        *tmpTail = tmpChar;
    }

    OSCL_StackString<128> mime("mime=");
    tmpHead = OSCL_CONST_CAST(char*, oscl_strstr(head, mime.get_cstr()));
    if (tmpHead)
    {
        tmpHead += mime.get_size();
        char *tmpTail = OSCL_CONST_CAST(char*, oscl_strstr(tmpHead, ";"));
        if (tmpTail == NULL)
        {
            tmpTail = tail;
        }
        aMime += tmpHead;
    }
    return true;
}

///////////////////////
// End Low-level port processing
///////////////////////


//////////////////////////////
// Logging & Diagnostics
//////////////////////////////

void PVMFSocketNode::LogRTPHeaderFields(SocketPortConfig& aSockConfig,
                                        OsclRefCounterMemFrag& memFragIn)
{
    OSCL_UNUSED_ARG(aSockConfig);
    uint8* rtpHeader = NULL;
    uint32 rtpPacketLen = 0;

    /* Get start of RTP packet */
    rtpHeader    = (uint8*)(memFragIn.getMemFrag().ptr);
    rtpPacketLen = memFragIn.getMemFrag().len;

    if ((rtpHeader != NULL) && (rtpPacketLen > 0))
    {
        /* is this a legal data packet? */
        if (rtpPacketLen <= 12)
        {
            PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode - illegal RTP pkt size"));
        }

        /* Parse RTP version */
        uint8  rtpVersion = (((*rtpHeader) & 0xC0) >> 6);
        if (rtpVersion != 2)
        {
            PVMF_SOCKETNODE_LOGDATATRAFFIC_E((0, "PVMFSocketNode illegal rtp version"));
        }

        /* Check for padding */
        uint8 pbit = (((*rtpHeader) & 0x20) >> 5);
        uint8 numPaddingOctets = 0;
        if (pbit)
        {
            numPaddingOctets = *(rtpHeader + (rtpPacketLen - 1));
        }

        // skip over xbit, csrc and mbit
        rtpHeader++;

        rtpHeader++;

        /* Parse sequence number */
        uint16 seqNum16 = 0;
        oscl_memcpy((char *)&seqNum16, rtpHeader, sizeof(seqNum16));
        big_endian_to_host((char *)&seqNum16, sizeof(seqNum16));
        rtpHeader += 2;

        /* Parse rtp time stamp */
        uint32 ts32 = 0;
        oscl_memcpy((char *)&ts32, rtpHeader, sizeof(ts32));
        big_endian_to_host((char *)&ts32, sizeof(ts32));
        rtpHeader += 4;

        /* Parse SSRC */
        uint32 ssrc32 = 0;
        oscl_memcpy((char *)&ssrc32, rtpHeader, sizeof(ssrc32));
        big_endian_to_host((char *)&ssrc32, sizeof(ssrc32));
        rtpHeader += 4;

        PVMF_SOCKETNODE_LOGDATATRAFFIC_RTP((0, "SN-RTP - Mime=%s, ssrc=%d, seq=%d, ts=%d, len=%d",
                                            aSockConfig.iMime.get_cstr(), ssrc32, (uint32)seqNum16, (PVMFTimestamp)ts32, rtpPacketLen));
    }
}

void PVMFSocketNode::LogRTCPHeaderFields(SocketPortConfig& aSockConfig,
        OsclRefCounterMemFrag& memFragIn)
{
    OSCL_UNUSED_ARG(aSockConfig);
    const uint8 SR_PACKET_TYPE = 200;
    const uint8 RR_PACKET_TYPE = 201;
    const uint8 SDES_PACKET_TYPE = 202;
    const uint8 BYE_PACKET_TYPE = 203;
    const uint8 APP_PACKET_TYPE = 204;
    uint8* rtcpHeader = NULL;
    int32 rtcpPacketLen = 0;

    /* Get start of RTP packet */
    rtcpHeader    = (uint8*)(memFragIn.getMemFrag().ptr);
    rtcpPacketLen = (int32)(memFragIn.getMemFrag().len);

    if ((rtcpHeader != NULL) && (rtcpPacketLen > 0))
    {
        while (rtcpPacketLen > 0)
        {
            OsclBinIStreamBigEndian inStream;
            inStream.Attach(rtcpHeader, rtcpPacketLen);
            uint8 tempChar;
            inStream >> tempChar;
            if (inStream.fail())
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_RTCP((0, "SN-RTCP - Mime=%s, Invalid RTCP Packet",
                                                     aSockConfig.iMime.get_cstr()));
                return;
            }
            // read the type
            uint8 payloadType;
            uint16 rtcpLength;
            inStream >> payloadType;
            inStream >> rtcpLength;
            if (inStream.fail())
            {
                PVMF_SOCKETNODE_LOGDATATRAFFIC_RTCP((0, "SN-RTCP - Mime=%s, Invalid RTCP Packet Headers",
                                                     aSockConfig.iMime.get_cstr()));
                return;
            }
            switch (payloadType)
            {
                case SR_PACKET_TYPE:
                {
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_RTCP((0, "SN-RTCP - Mime=%s, RTCP_SR RECVD",
                                                         aSockConfig.iMime.get_cstr()));
                }
                break;

                case RR_PACKET_TYPE:
                {
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_RTCP((0, "SN-RTCP - Mime=%s, RTCP_RR RECVD",
                                                         aSockConfig.iMime.get_cstr()));
                }
                break;

                case SDES_PACKET_TYPE:
                {
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_RTCP((0, "SN-RTCP - Mime=%s, RTCP_SDES_PKT RECVD",
                                                         aSockConfig.iMime.get_cstr()));
                }
                break;

                case BYE_PACKET_TYPE:
                {
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_RTCP((0, "SN-RTCP - Mime=%s, RTCP_BYE RECVD",
                                                         aSockConfig.iMime.get_cstr()));
                }
                break;

                case APP_PACKET_TYPE:
                {
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_RTCP((0, "SN-RTCP - Mime=%s, RTCP_APP_PKT RECVD",
                                                         aSockConfig.iMime.get_cstr()));
                }
                break;

                default:
                    break;
            }
            rtcpPacketLen -= (rtcpLength + 1) * 4;
            rtcpHeader += (rtcpLength + 1) * 4;
            if (rtcpLength)
            {
                inStream.seekFromCurrentPosition((rtcpLength*4));
                if (inStream.fail())
                {
                    PVMF_SOCKETNODE_LOGDATATRAFFIC_RTCP((0, "SN-RTCP - Mime=%s, RTCP Packet Read Failed",
                                                         aSockConfig.iMime.get_cstr()));
                    return;
                }
            }
        } //end of while loop
    }
}

//////////////////////////////
// End Logging & Diagnostics
//////////////////////////////


///////////////////////////////////
// AO
///////////////////////////////////

void PVMFSocketNode::Run()
{
    PVMF_SOCKETNODE_LOGSTACKTRACE((0, "PVMFSocketNode::Run() In"));

#if(ENABLE_SOCKET_NODE_STATS)
    iSocketNodeStats.iNumRun++;
#endif

    if (!iClosedTCPSocketVector.empty())
        CleanupClosedTCPSockets();
    if (!iClosedUDPSocketVector.empty())
        CleanupClosedUDPSockets();
    if (!iClosedDNSVector.empty())
        CleanupClosedDNS();

    //Process node commands
    if (!iInputCommands.empty())
    {
        iCommandErrorCode = PVMFSocketNodeErrorEventStart; //no error
        ProcessCommand();
    }
}

int32 PVMFSocketNode::SocketPlacementNew(PVMFSocketNodeMemPool *& aMemPool, OsclAny *aMemPtr, int32 aMemPoolNumBufs)
{
    int32 errcode = 0;
    OSCL_TRY(errcode, aMemPool = OSCL_PLACEMENT_NEW(aMemPtr, PVMFSocketNodeMemPool(aMemPoolNumBufs);));
    return errcode;
}

int32 PVMFSocketNode::CreateMediaData(SocketPortConfig& aSockConfig, OsclSharedPtr< PVMFMediaDataImpl > &aMediaptr)
{
    int32 err = 0;
    OSCL_TRY_NO_TLS(iOsclErrorTrapImp, err,
                    aSockConfig.iPendingRecvMediaData = PVMFMediaData::createMediaData(aMediaptr, aSockConfig.iMemPool->iMediaDataMemPool););
    return err;
}

int32 PVMFSocketNode::Allocate(SocketPortConfig &aSockConfig, OsclSharedPtr< PVMFMediaDataImpl > &aMediaFragGroup)
{
#if SNODE_ENABLE_UDP_MULTI_PACKET
    int32 err = 0;
    OSCL_TRY_NO_TLS(iOsclErrorTrapImp, err,
                    aMediaFragGroup = aSockConfig.iMemPool->iMediaFragGroupAlloc->allocate(););
    return err;
#else
    return OsclErrNotSupported;
#endif
}

int32 PVMFSocketNode::GetMediaDataImpl(SocketPortConfig& aSockConfig, OsclSharedPtr<PVMFMediaDataImpl> &aMediaDataImpl, int32 aMemSize)
{
    int32 err = 0;
    aMediaDataImpl = aSockConfig.iMemPool->getMediaDataImpl(aMemSize);
    if (NULL == aMediaDataImpl.GetRep())
    {
        err = OsclErrNoMemory;
    }
    return err;
}

