<commit_before>//
// Copyright (C) 2004-2006 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004-2006 Pingtel Corp.  All rights reserved.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
///////////////////////////////////////////////////////////////////////////////


// SYSTEM INCLUDES
#include <assert.h>

// APPLICATION INCLUDES
#include <net/SipProtocolServerBase.h>
#include <net/SipUserAgent.h>
#include <utl/UtlHashMapIterator.h>
#include <os/OsDateTime.h>
#include <os/OsEvent.h>
#include <os/OsLock.h>

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
//#define TEST_PRINT
// STATIC VARIABLE INITIALIZATIONS

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */

// Constructor
SipProtocolServerBase::SipProtocolServerBase(SipUserAgent* userAgent,
                                             const char* protocolString,
                                             const char* taskName) :
     OsTask(taskName),
     mClientLock(OsMutex::Q_FIFO)
{
   mSipUserAgent = userAgent;
   mProtocolString = protocolString;
   mDefaultPort = SIP_PORT;
}

// Copy constructor
SipProtocolServerBase::SipProtocolServerBase(const SipProtocolServerBase& rSipProtocolServerBase) :
    mClientLock(OsMutex::Q_FIFO)
{
}

// Destructor
SipProtocolServerBase::~SipProtocolServerBase()
{
    mDataGuard.acquire();
    mClientLock.acquireWrite();

    waitUntilShutDown();
    
    int iteratorHandle = mClientList.getIteratorHandle();
    SipClient* client = NULL;
    while ((client = (SipClient*)mClientList.next(iteratorHandle)))
    {
        mClientList.remove(iteratorHandle);
        delete client;
    }
    mClientList.releaseIteratorHandle(iteratorHandle);
    mClientLock.releaseWrite();
    mDataGuard.release();
}

/* ============================ MANIPULATORS ============================== */



UtlBoolean SipProtocolServerBase::send(SipMessage* message,
                            const char* hostAddress,
                            int hostPort)
{
    UtlBoolean sendOk = FALSE;


    UtlString localIp(message->getLocalIp());
    
    if (localIp.length() < 1)
    {
        localIp = mDefaultIp;
    }

    SipClient* client = createClient(hostAddress, hostPort, localIp);
    if(client)
    {
        int isBusy = client->isInUseForWrite();
        UtlString clientNames;

        client->getClientNames(clientNames);
        OsSysLog::add(FAC_SIP, PRI_DEBUG, "Sip%sServerBase::send %p isInUseForWrite %d, client info\n %s",
                mProtocolString.data(), client, isBusy, clientNames.data());

        sendOk = client->sendTo(*message, hostAddress, hostPort);
        if(!sendOk)
        {
            OsTask* pCallingTask = OsTask::getCurrentTask();
            int callingTaskId = -1;
            int clientTaskId = -1;

            if ( pCallingTask )
            {
               pCallingTask->id(callingTaskId);
            }
            client->id(clientTaskId);

            if (clientTaskId != callingTaskId)
            {
               // Do not need to clientLock.acquireWrite();
               // as deleteClient uses the locking list lock
               // which is all that is needed as the client is
               // already marked as busy when we called
               // createClient above.
               deleteClient(client);
               client = NULL;
            }
        }
    }

        if(client)
        {
            releaseClient(client);
        }

    return(sendOk);
}

void SipProtocolServerBase::releaseClient(SipClient* client)
{
    mClientLock.acquireWrite();

    if(client &&
                clientExists(client))
    {
        if(client->isInUseForWrite())
        {
            client->markAvailbleForWrite();
        }
        else
        {
            OsSysLog::add(FAC_SIP, PRI_DEBUG,
                          "SipProtocolServerBase::releaseClient releasing %s client not locked: %p",
                          mProtocolString.data(), client);
        }
    }
    else
    {
        OsSysLog::add(FAC_SIP, PRI_DEBUG,
                      "SipProtocolServerBase::releaseClient releasing %s client not in list: %p",
                      mProtocolString.data(), client);
    }

    mClientLock.releaseWrite();
}

UtlBoolean SipProtocolServerBase::startListener()
{
#       ifdef TEST_PRINT
        osPrintf("SIP Server binding to port %d\n", serverPort);
#       endif

    UtlHashMapIterator iter(mServerSocketMap);
    UtlVoidPtr* pSocketContainer = NULL;
    UtlString* pKey;
    while ((pKey =(UtlString*)iter()))
    {
        OsSocket* pSocket = NULL;
        SipClient* pServer = NULL;
        UtlVoidPtr* pServerContainer = NULL;

        UtlString localIp = *pKey;
        pSocketContainer = (UtlVoidPtr*)iter.value();
         
        if (pSocketContainer)
        {    
            pSocket = (OsSocket*)pSocketContainer->getValue();
        }
        
        pServerContainer = (UtlVoidPtr*)mServers.findValue(&localIp);
        if (!pServerContainer)
        {
            pServer = new SipClient(pSocket);
            this->mServers.insertKeyAndValue(new UtlString(localIp), new UtlVoidPtr((void*)pServer));
            pServer->start();
        }
        else
        {
            pServer = (SipClient*) pServerContainer->getValue();
        }
        if(mSipUserAgent)
        {
            if (pServer)
            {
                pServer->setUserAgent(mSipUserAgent);
            }
        }
    }
    return(TRUE);
}

SipClient* SipProtocolServerBase::createClient(const char* hostAddress,
                                               int hostPort,
                                               const char* localIp)
{
    UtlString remoteHostAddr;
    UtlBoolean clientStarted = FALSE;

    mClientLock.acquireWrite();

    SipClient* client = getClient(hostAddress, hostPort, localIp);

    if(! client)<commit_msg>Fixed race condition that can occur when starting SipUserAgent.<commit_after>//
// Copyright (C) 2004-2006 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004-2006 <NAME>.  All rights reserved.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
///////////////////////////////////////////////////////////////////////////////


// SYSTEM INCLUDES
#include <assert.h>

// APPLICATION INCLUDES
#include <net/SipProtocolServerBase.h>
#include <net/SipUserAgent.h>
#include <utl/UtlHashMapIterator.h>
#include <os/OsDateTime.h>
#include <os/OsEvent.h>
#include <os/OsLock.h>

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
//#define TEST_PRINT
// STATIC VARIABLE INITIALIZATIONS

/* //////////////////////////// PUBLIC //////////////////////////////////// */

/* ============================ CREATORS ================================== */

// Constructor
SipProtocolServerBase::SipProtocolServerBase(SipUserAgent* userAgent,
                                             const char* protocolString,
                                             const char* taskName) :
     OsTask(taskName),
     mClientLock(OsMutex::Q_FIFO)
{
   mSipUserAgent = userAgent;
   mProtocolString = protocolString;
   mDefaultPort = SIP_PORT;
}

// Copy constructor
SipProtocolServerBase::SipProtocolServerBase(const SipProtocolServerBase& rSipProtocolServerBase) :
    mClientLock(OsMutex::Q_FIFO)
{
}

// Destructor
SipProtocolServerBase::~SipProtocolServerBase()
{
    mDataGuard.acquire();
    mClientLock.acquireWrite();

    waitUntilShutDown();
    
    int iteratorHandle = mClientList.getIteratorHandle();
    SipClient* client = NULL;
    while ((client = (SipClient*)mClientList.next(iteratorHandle)))
    {
        mClientList.remove(iteratorHandle);
        delete client;
    }
    mClientList.releaseIteratorHandle(iteratorHandle);
    mClientLock.releaseWrite();
    mDataGuard.release();
}

/* ============================ MANIPULATORS ============================== */



UtlBoolean SipProtocolServerBase::send(SipMessage* message,
                            const char* hostAddress,
                            int hostPort)
{
    UtlBoolean sendOk = FALSE;


    UtlString localIp(message->getLocalIp());
    
    if (localIp.length() < 1)
    {
        localIp = mDefaultIp;
    }

    SipClient* client = createClient(hostAddress, hostPort, localIp);
    if(client)
    {
        int isBusy = client->isInUseForWrite();
        UtlString clientNames;

        client->getClientNames(clientNames);
        OsSysLog::add(FAC_SIP, PRI_DEBUG, "Sip%sServerBase::send %p isInUseForWrite %d, client info\n %s",
                mProtocolString.data(), client, isBusy, clientNames.data());

        sendOk = client->sendTo(*message, hostAddress, hostPort);
        if(!sendOk)
        {
            OsTask* pCallingTask = OsTask::getCurrentTask();
            int callingTaskId = -1;
            int clientTaskId = -1;

            if ( pCallingTask )
            {
               pCallingTask->id(callingTaskId);
            }
            client->id(clientTaskId);

            if (clientTaskId != callingTaskId)
            {
               // Do not need to clientLock.acquireWrite();
               // as deleteClient uses the locking list lock
               // which is all that is needed as the client is
               // already marked as busy when we called
               // createClient above.
               deleteClient(client);
               client = NULL;
            }
        }
    }

        if(client)
        {
            releaseClient(client);
        }

    return(sendOk);
}

void SipProtocolServerBase::releaseClient(SipClient* client)
{
    mClientLock.acquireWrite();

    if(client &&
                clientExists(client))
    {
        if(client->isInUseForWrite())
        {
            client->markAvailbleForWrite();
        }
        else
        {
            OsSysLog::add(FAC_SIP, PRI_DEBUG,
                          "SipProtocolServerBase::releaseClient releasing %s client not locked: %p",
                          mProtocolString.data(), client);
        }
    }
    else
    {
        OsSysLog::add(FAC_SIP, PRI_DEBUG,
                      "SipProtocolServerBase::releaseClient releasing %s client not in list: %p",
                      mProtocolString.data(), client);
    }

    mClientLock.releaseWrite();
}

UtlBoolean SipProtocolServerBase::startListener()
{
#       ifdef TEST_PRINT
        osPrintf("SIP Server binding to port %d\n", serverPort);
#       endif

    UtlHashMapIterator iter(mServerSocketMap);
    UtlVoidPtr* pSocketContainer = NULL;
    UtlString* pKey;
    while ((pKey =(UtlString*)iter()))
    {
        OsSocket* pSocket = NULL;
        SipClient* pServer = NULL;
        UtlVoidPtr* pServerContainer = NULL;

        UtlString localIp = *pKey;
        pSocketContainer = (UtlVoidPtr*)iter.value();
         
        if (pSocketContainer)
        {    
            pSocket = (OsSocket*)pSocketContainer->getValue();
        }
        
        pServerContainer = (UtlVoidPtr*)mServers.findValue(&localIp);
        if (!pServerContainer)
        {
            pServer = new SipClient(pSocket);

            // This used to be done at the end of this else statement
            // however there is a race and the userAgent must be set before
            // starting this client.  I think the race occurs if there is
            // immediately an incoming message on the socket.
            if(mSipUserAgent)
            {
                if (pServer)
                {
                    pServer->setUserAgent(mSipUserAgent);
                }
            }
            this->mServers.insertKeyAndValue(new UtlString(localIp), new UtlVoidPtr((void*)pServer));
            pServer->start();
        }
        else
        {
            pServer = (SipClient*) pServerContainer->getValue();
            if(mSipUserAgent)
            {
                if (pServer)
                {
                    pServer->setUserAgent(mSipUserAgent);
                }
            }
        }
    }
    return(TRUE);
}

SipClient* SipProtocolServerBase::createClient(const char* hostAddress,
                                               int hostPort,
                                               const char* localIp)
{
    UtlString remoteHostAddr;
    UtlBoolean clientStarted = FALSE;

    mClientLock.acquireWrite();

    SipClient* client = getClient(hostAddress, hostPort, localIp);

    if(! client)
{'fraction_non_alphanumeric': 0.13792, 'fraction_numerical': 0.00304, 'mean_word_length': 1.89375, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6806604', 'n_tokens_mistral': 3544, 'n_tokens_neox': 3436, 'n_words': 692}