Exemplo n.º 1
0
void SipTransactionList::toStringWithRelations(UtlString& string,
                                               SipMessage& message,
                                               UtlBoolean isOutGoing)
{
    lock();

    string.remove(0);

    UtlHashBagIterator iterator(mTransactions);
    SipTransaction* transactionFound = NULL;
    UtlString oneTransactionString;
    SipTransaction::messageRelationship relation;
    UtlString relationString;

    while((transactionFound = (SipTransaction*) iterator()))
    {
        relation = transactionFound->whatRelation(message, isOutGoing);
        SipTransaction::getRelationshipString(relation, relationString);
        string.append(relationString);
        string.append(" ");


        transactionFound->toString(oneTransactionString, FALSE);
        string.append(oneTransactionString);
        oneTransactionString.remove(0);

        string.append("\n");
    }

    unlock();
}
Exemplo n.º 2
0
void SipTransactionList::deleteTransactionTimers()
{
#ifdef TIME_LOG
    Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                               "SipTransactionList::deleteTransactionTimers entered");
#endif

    // It is possible that there are a very large number of transactions,
    // so we don't want to hold the lock while processing all of them.
    // So we make a list of the addresses of all the SipTransactions
    // and then process them afterward.

    lock();

    int numTransactions = mTransactions.entries();
    SipTransaction** transactionsToBeProcessed =
        new SipTransaction*[numTransactions];

    if (numTransactions > 0)
    {
        UtlHashBagIterator iterator(mTransactions);
        SipTransaction* transactionFound;
        int count = 0;

        while ((transactionFound = dynamic_cast <SipTransaction*> (iterator())))
        {
            transactionsToBeProcessed[count++] = transactionFound;
        }
    }

    unlock();

    // Now process each transaction in turn.
    for (int i = 0; i < numTransactions; i++)
    {
        lock();

        SipTransaction* transaction = transactionsToBeProcessed[i];
        // Verify (within a critical section) that this transaction is
        // still in mTransactions.
        if (mTransactions.findReference(transaction))
        {
            transaction->deleteTimers();
        }

        unlock();

        // Let any threads that are waiting for mListMutex run.
        OsTask::yield();
    }

    // Delete list of transactions.
    delete[] transactionsToBeProcessed;

#ifdef TIME_LOG
    Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                               "SipTransactionList::deleteTransactionTimers exited %d entries",
                               numTransactions);
#endif
}
Exemplo n.º 3
0
void SipTransactionList::markAvailable(SipTransaction& transaction)
{
    lock();

    if(!transaction.isBusy())
    {
        UtlString transactionString;
        transaction.toString(transactionString, FALSE);
        OsSysLog::add(FAC_SIP, PRI_ERR, "SipTransactionList::markAvailable transaction not locked: %s\n",
            transactionString.data());
    }
    else
    {
        transaction.markAvailable();
    }

    unlock();
}
Exemplo n.º 4
0
void SipTransactionList::deleteTransactionTimers()
{
    lock();

    int numTransactions = mTransactions.entries();
    if(numTransactions > 0)
    {
        UtlHashBagIterator iterator(mTransactions);
        SipTransaction* transactionFound = NULL;

        while((transactionFound = (SipTransaction*) iterator()))
        {
            transactionFound->deleteTimers();
        }
    }

    unlock();
}
Exemplo n.º 5
0
void SipTransactionList::toString(UtlString& string)
{
    lock();

    string.remove(0);

    UtlHashBagIterator iterator(mTransactions);
    SipTransaction* transactionFound = NULL;
    UtlString oneTransactionString;

    while((transactionFound = (SipTransaction*) iterator()))
    {
        transactionFound->toString(oneTransactionString, FALSE);
        string.append(oneTransactionString);
        oneTransactionString.remove(0);
    }

    unlock();
}
Exemplo n.º 6
0
void SipTransactionList::markAvailable(SipTransaction& transaction)
{
    lock();

    if(!transaction.isBusy())
    {
        UtlString transactionString;
        transaction.toString(transactionString, FALSE);
        Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipTransactionList::markAvailable"
                                   " transaction not locked: %s",
                                   transactionString.data());
    }
    else
    {
        transaction.markAvailable();
    }

    unlock();
}
Exemplo n.º 7
0
//: Find a transaction for the given message
SipTransaction*
SipTransactionList::findTransactionFor(const SipMessage& message,
                                       UtlBoolean isOutgoing,
                   enum SipTransaction::messageRelationship& relationship)
{
    SipTransaction* transactionFound = NULL;
    UtlString callId;
    SipTransaction::buildHash(message, isOutgoing, callId);

    lock();

    // See if the message knows its transaction
    // DO NOT TOUCH THE CONTENTS of this transaction as it may no
    // longer exist.  It can only be used as an ID for the transaction.
    SipTransaction* messageTransaction = message.getSipTransaction();

    UtlString matchTransaction(callId);

    UtlHashBagIterator iterator(mTransactions, &matchTransaction);

    relationship = SipTransaction::MESSAGE_UNKNOWN;
    while ((transactionFound = (SipTransaction*) iterator()))
    {
        // If the message knows its SIP transaction
        // and the found transaction pointer does not match, skip the
        // expensive relationship calculation
        // The messageTransaction MUST BE TREATED AS OPAQUE
        // as it may have been deleted.
        if(   messageTransaction && transactionFound != messageTransaction )
        {
           continue;
        }

        // If the transaction has never sent the original rquest
        // it should never get a match for any messages.
        if(   messageTransaction == NULL // this message does not point to this TX
           && ((transactionFound->getState()) == SipTransaction::TRANSACTION_LOCALLY_INIITATED)
           )
        {
            continue;
        }

        relationship = transactionFound->whatRelation(message, isOutgoing);
        if(relationship == SipTransaction::MESSAGE_REQUEST ||
            relationship ==  SipTransaction::MESSAGE_PROVISIONAL ||
            relationship ==  SipTransaction::MESSAGE_FINAL ||
            relationship ==  SipTransaction::MESSAGE_NEW_FINAL ||
            relationship ==  SipTransaction::MESSAGE_CANCEL ||
            relationship ==  SipTransaction::MESSAGE_CANCEL_RESPONSE ||
            relationship ==  SipTransaction::MESSAGE_ACK ||
            relationship ==  SipTransaction::MESSAGE_2XX_ACK ||
            relationship ==  SipTransaction::MESSAGE_DUPLICATE)
        {
            break;
        }
    }

    UtlBoolean isBusy = FALSE;
    if(transactionFound == NULL)
    {
        relationship =
            SipTransaction::MESSAGE_UNKNOWN;
    }
    else
    {
        isBusy = transactionFound->isBusy();
        if(!isBusy)
        {
            transactionFound->markBusy();
        }
    }

    unlock();

    if(transactionFound && isBusy)
    {
        // If we cannot lock it, it does not exist
        if(!waitUntilAvailable(transactionFound, callId))
        {
            if (OsSysLog::willLog(FAC_SIP, PRI_WARNING))
            {
                UtlString relationString;
                SipTransaction::getRelationshipString(relationship, relationString);
                OsSysLog::add(FAC_SIP, PRI_WARNING,
                              "SipTransactionList::findTransactionFor %p not available relation: %s",
                              transactionFound, relationString.data());
            }
            transactionFound = NULL;
        }
    }

#if 0 // enable only for transaction match debugging - log is confusing otherwise
    UtlString relationString;
    SipTransaction::getRelationshipString(relationship, relationString);
    UtlString bytes;
    int len;
    message.getBytes(&bytes, &len);
    OsSysLog::add(FAC_SIP, PRI_DEBUG
                  ,"SipTransactionList::findTransactionFor %p %s %s %s"
#                 ifdef TIME_LOG
                  "\n\tTime Log %s"
#                 endif
                  ,&message
                  ,isOutgoing ? "OUTGOING" : "INCOMING"
                  ,transactionFound ? "FOUND" : "NOT FOUND"
                  ,relationString.data()
#                 ifdef TIME_LOG
                  ,findTimeLog.data()
#                 endif
                  );
    
#endif


    return(transactionFound);
}
Exemplo n.º 8
0
void SipTransactionList::removeOldTransactions(long oldTransaction,
                                               long oldInviteTransaction)
{
    SipTransaction** transactionsToBeDeleted = NULL;
    int deleteCount = 0;
    int busyCount = 0;

#   ifdef TIME_LOG
    OsTimeLog gcTimes;
    gcTimes.addEvent("start");
#   endif

    lock();

    int numTransactions = mTransactions.entries();
    if(numTransactions > 0)
    {
        UtlHashBagIterator iterator(mTransactions);
        SipTransaction* transactionFound = NULL;
        long transTime;


        // Pull all of the transactions to be deleted out of the list
        while((transactionFound = (SipTransaction*) iterator()))
        {
            if(transactionFound->isBusy()) busyCount++;

            transTime = transactionFound->getTimeStamp();
            // Invites need to be kept longer than other transactions
            if(((!transactionFound->isMethod(SIP_INVITE_METHOD) &&
                transTime < oldTransaction) ||
                transTime < oldInviteTransaction) &&
                ! transactionFound->isBusy())
            {
                // Remove it from the list
                mTransactions.removeReference(transactionFound);

                OsSysLog::add(FAC_SIP, PRI_DEBUG, "removing transaction %p\n",transactionFound);

                // Make sure we have a pointer array to hold it
                if(transactionsToBeDeleted == NULL)
                {
                     transactionsToBeDeleted =
                        new SipTransaction*[numTransactions];
                }

                // Put it in the pointer array
                transactionsToBeDeleted[deleteCount] = transactionFound;
                deleteCount++;

                // Make sure the events waiting for the transaction
                // to be available are signaled before we delete
                // any of the transactions or we end up with
                // incomplete transaction trees (i.e. deleted branches)
                transactionFound->signalAllAvailable();
                transactionFound = NULL;
            }
        }
    }

    unlock();

    // We do not need the lock if the transactions have been
    // removed from the list
    if ( deleteCount || busyCount ) // do not log 'doing nothing when nothing to do', even at debug level
    {
        OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipTransactionList::removeOldTransactions deleting %d of %d transactions (%d busy)\n",
                      deleteCount , numTransactions, busyCount);
    }

    // Delete the transactions in the array
    if (transactionsToBeDeleted)
    {
#       ifdef TIME_LOG
        gcTimes.addEvent("start delete");
#       endif

        for(int txIndex = 0; txIndex < deleteCount; txIndex++)
        {
            delete transactionsToBeDeleted[txIndex];
#           ifdef TIME_LOG
            gcTimes.addEvent("transaction deleted");
#           endif
       }

#      ifdef TIME_LOG
       gcTimes.addEvent("finish delete");
#      endif
/*
        while((transactionFound = (SipTransaction*) iterator()))
        {
            transactionFound->stopTimers();
        }
*/
       delete[] transactionsToBeDeleted;
       transactionsToBeDeleted = NULL;
    }

#   ifdef TIME_LOG
    UtlString timeString;
    gcTimes.getLogString(timeString);
    OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipTransactionList::removeOldTransactions "
                  "%s", timeString.data()
                  );
#   endif
}
Exemplo n.º 9
0
//: Find a transaction for the given message
SipTransaction*
SipTransactionList::findTransactionFor(const SipMessage& message,
                                       UtlBoolean isOutgoing,
                                       enum SipTransaction::messageRelationship& relationship)
{
    SipTransaction* transactionFound = NULL;
    SipTransaction* transaction2xxFound = NULL;
    enum SipTransaction::messageRelationship relationship2xx = SipTransaction::MESSAGE_UNKNOWN;
    UtlString callId;
    SipTransaction::buildHash(message, isOutgoing, callId);

    //
    // Call garbage collection before we further process existence of a transaction.
    //
    mpSipUserAgent->garbageCollection();

    lock();

    // See if the message knows its transaction
    // DO NOT TOUCH THE CONTENTS of this transaction as it may no
    // longer exist.  It can only be used as an ID for the transaction.
    SipTransaction* messageTransaction = message.getSipTransaction();

    UtlString matchTransaction(callId);

    UtlHashBagIterator iterator(mTransactions, &matchTransaction);

    relationship = SipTransaction::MESSAGE_UNKNOWN;
#   ifdef TIME_LOG
    OsTimeLog findTimes;
    findTimes.addEvent("start");
#   endif
    while ((transactionFound = (SipTransaction*) iterator()))
    {
        // If the message knows its SIP transaction
        // and the found transaction pointer does not match, skip the
        // expensive relationship calculation
        // The messageTransaction MUST BE TREATED AS OPAQUE
        // as it may have been deleted.
        if(   messageTransaction && transactionFound != messageTransaction )
        {
#          ifdef TIME_LOG
            findTimes.addEvent("mismatch");
#          endif
            continue;
        }

        // If the transaction has never sent the original rquest
        // it should never get a match for any messages.
        if(   messageTransaction == NULL // this message does not point to this TX
                && ((transactionFound->getState()) == SipTransaction::TRANSACTION_LOCALLY_INIITATED)
          )
        {
#           ifdef TIME_LOG
            findTimes.addEvent("unsent");
#           endif
            continue;
        }

        relationship = transactionFound->whatRelation(message, isOutgoing);

        // Since 2xx ACK transactions always get a new Via branch, we have to
        // make sure there isn't another error transaction with a better match (branch included)
        //
        // NOTE: Adding this code makes obvious that ACK's for 2xx responses always(??? at least on initial invite)
        // match more than one transaction tree, the original tx tree in the forking proxy function and the
        // consequent tx tree in the auth proxy function.  This is a result of the fix for XECS-414, which
        // allows matching a transaction for a 2xx ACK without matching branch id's.
        // This 2xx-ACK-match-except-branch result combined with the failuer to find a complete 2xx-ACK_match-with-branch,
        // means we can be assured that this ACK should be sent upstream. The ACK is then treated as a new transaction
        // and the EXISTENCE of the matching transaction is used to navigate through the code.
        // The CONTENTS of the matched transaction are not important except for the matching itself.
        // ACKs for error responses will always match ONLY one transaction, since the branch id must also match.
        if(relationship ==  SipTransaction::MESSAGE_2XX_ACK ||
                relationship ==  SipTransaction::MESSAGE_2XX_ACK_PROXY )
        {
            if (transaction2xxFound)
            {
                UtlString bytes;
                ssize_t len;
                message.getBytes(&bytes, &len);
                Os::Logger::instance().log(FAC_SIP, PRI_DEBUG
                                           ,"SipTransactionList::findTransactionFor"
                                           " more than one 2xx match for message %p(%p) %s "
                                           " previous match (%p) %s"
                                           " current match (%p) %s"
                                           ,&message
                                           ,messageTransaction
                                           ,isOutgoing ? "OUTGOING" : "INCOMING"
                                           ,transaction2xxFound
                                           ,SipTransaction::relationshipString(relationship2xx)
                                           ,transactionFound
                                           ,SipTransaction::relationshipString(relationship)
                                          );
                relationship2xx = relationship;
                transaction2xxFound = transactionFound;
            }
            else
            {
                relationship2xx = relationship;
                transaction2xxFound = transactionFound;

                UtlString bytes;
                ssize_t len;
                message.getBytes(&bytes, &len);
                Os::Logger::instance().log(FAC_SIP, PRI_DEBUG
                                           ,"SipTransactionList::findTransactionFor"
                                           " 2xx match for message %p(%p) %s "
                                           " current match (%p) %s"
                                           ,&message
                                           ,messageTransaction
                                           ,isOutgoing ? "OUTGOING" : "INCOMING"
                                           ,transactionFound
                                           ,SipTransaction::relationshipString(relationship)
                                          );
            }
            continue;
        }
        if(relationship ==  SipTransaction::MESSAGE_ACK )
        {
            UtlString bytes;
            ssize_t len;
            message.getBytes(&bytes, &len);
            Os::Logger::instance().log(FAC_SIP, PRI_DEBUG
                                       ,"SipTransactionList::findTransactionFor"
                                       " ACK match for message %p(%p) %s "
                                       " current match (%p) %s"
                                       " previous match (%p) %s"
                                       ,&message
                                       ,messageTransaction
                                       ,isOutgoing ? "OUTGOING" : "INCOMING"
                                       ,transactionFound
                                       ,SipTransaction::relationshipString(relationship)
                                       ,transaction2xxFound
                                       ,SipTransaction::relationshipString(relationship2xx)
                                      );
        }
        if(relationship == SipTransaction::MESSAGE_REQUEST ||
                relationship ==  SipTransaction::MESSAGE_PROVISIONAL ||
                relationship ==  SipTransaction::MESSAGE_FINAL ||
                relationship ==  SipTransaction::MESSAGE_NEW_FINAL ||
                relationship ==  SipTransaction::MESSAGE_CANCEL ||
                relationship ==  SipTransaction::MESSAGE_CANCEL_RESPONSE ||
                relationship ==  SipTransaction::MESSAGE_ACK ||
                relationship ==  SipTransaction::MESSAGE_DUPLICATE)
        {
            break;
        }
    }

    //
    if((transactionFound == NULL) && transaction2xxFound)
    {
        relationship = relationship2xx;
        transactionFound = transaction2xxFound;
    }

#   ifdef TIME_LOG
    if ( transactionFound )
    {
        findTimes.addEvent("found");
    }
    else
    {
        findTimes.addEvent("unfound");
    }
#   endif

    UtlBoolean isBusy = FALSE;
    if(transactionFound == NULL)
    {
        relationship = SipTransaction::MESSAGE_UNKNOWN;
    }
    else
    {
        isBusy = transactionFound->isBusy();
        if(!isBusy)
        {
            transactionFound->markBusy();
        }
    }

    unlock();
    if(transactionFound && isBusy)
    {
#       ifdef TIME_LOG
        findTimes.addEvent("checking");
#       endif

        // If we cannot lock it, it does not exist
        if(!waitUntilAvailable(transactionFound, callId))
        {
            if (Os::Logger::instance().willLog(FAC_SIP, PRI_WARNING))
            {
                Os::Logger::instance().log(FAC_SIP, PRI_WARNING,
                                           "SipTransactionList::findTransactionFor"
                                           " %p not available relation: %s",
                                           transactionFound, SipTransaction::relationshipString(relationship));
            }
#           ifdef TIME_LOG
            findTimes.addEvent("notavail");
#           endif

            transactionFound = NULL;
        }
    }
#   ifdef TIME_LOG
    findTimes.addEvent("done");
    UtlString findTimeLog;
    findTimes.getLogString(findTimeLog);
#   endif

#ifdef TRANSACTION_MATCH_DEBUG
    UtlString bytes;
    ssize_t len;
    message.getBytes(&bytes, &len);
    Os::Logger::instance().log(FAC_SIP, PRI_DEBUG
                               ,"SipTransactionList::findTransactionFor %p(%p) %s %s(%p) %s"
#                 ifdef TIME_LOG
                               "\n\tTime Log %s"
#                 endif
                               ,&message
                               ,messageTransaction
                               ,isOutgoing ? "OUTGOING" : "INCOMING"
                               ,transactionFound ? "FOUND" : "NOT FOUND"
                               ,transactionFound
                               ,SipTransaction::relationshipString(relationship)
#                 ifdef TIME_LOG
                               ,findTimeLog.data()
#                 endif
                              );

#endif

    return(transactionFound);
}
Exemplo n.º 10
0
void SipTransactionList::removeOldTransactions(long oldTransaction,
        long oldInviteTransaction)
{
    SipTransaction** transactionsToBeDeleted = NULL;
    int deleteCount = 0;
    int busyCount = 0;

#   ifdef TIME_LOG
    OsTimeLog gcTimes;
    gcTimes.addEvent("start");
#   endif

    lock();
#   ifdef TIME_LOG
    gcTimes.addEvent("locked");
#   endif

    int numTransactions = mTransactions.entries();
    if(numTransactions > 0)
    {
        UtlHashBagIterator iterator(mTransactions);
        SipTransaction* transactionFound = NULL;
        long transTime;

        // Pull all of the transactions to be deleted out of the list
        while ((transactionFound = (SipTransaction*) iterator()))
        {
            if(transactionFound->isBusy())
            {
                busyCount++;
            }
            else
            {
                transTime = transactionFound->getTimeStamp();

                // Invites need to be kept longer than other transactions
                if ( transTime < (  transactionFound->isMethod(SIP_INVITE_METHOD)
                                    ? oldInviteTransaction
                                    : oldTransaction
                                 )
                   )
                {
#ifdef TRANSACTION_MATCH_DEBUG
                    Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                                               "SipTransactionList::removeOldTransactions "
                                               " removing %p",  transactionFound );
#endif

                    // Remove it from the list
                    mTransactions.removeReference(transactionFound);

                    // Make sure we have a pointer array to hold it
                    if(transactionsToBeDeleted == NULL)
                    {
                        transactionsToBeDeleted = new SipTransaction*[numTransactions];
                    }

                    // Put it in the pointer array
                    transactionsToBeDeleted[deleteCount] = transactionFound;
                    deleteCount++;

                    // Make sure the events waiting for the transaction
                    // to be available are signaled before we delete
                    // any of the transactions or we end up with
                    // incomplete transaction trees (i.e. deleted branches)
                    // :TODO: move to the actual deletion loop so we're not holding the lock? -SDL
                    transactionFound->signalAllAvailable();
                }
            }
        }
    }

#   ifdef TIME_LOG
    gcTimes.addEvent("scan done");
#   endif

    // We do not need the lock now that the transactions have been
    // removed from the list
    unlock();

    if ( deleteCount || busyCount ) // do not log 'doing nothing when nothing to do', even at debug
    {
        Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                                   "SipTransactionList::removeOldTransactions"
                                   " deleting %d of %d transactions (%d busy)",
                                   deleteCount , numTransactions, busyCount
                                  );
    }

    // Delete the transactions in the array
    if (transactionsToBeDeleted)
    {
#      ifdef TIME_LOG
        gcTimes.addEvent("start delete");
#      endif

        for(int txIndex = 0; txIndex < deleteCount; txIndex++)
        {
            delete transactionsToBeDeleted[txIndex];
        }

#      ifdef TIME_LOG
        gcTimes.addEvent("finish delete");
#      endif

        delete[] transactionsToBeDeleted;
    }

#   ifdef TIME_LOG
    UtlString timeString;
    gcTimes.getLogString(timeString);
    Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipTransactionList::removeOldTransactions "
                               "%s", timeString.data()
                              );
#   endif
}