Exemple #1
0
bool disruptorPublish( disruptor* d, char* ptr )
{
    int64_t claim;
    sendBuffer* buf;
    volatile sharedSlot* slot;

    (void)d;
    (void)ptr;
    buf = &d->buffers[ d->id ];

    /* increment the claim cursor. */
    claim = xadd64( &d->ringbuffer->claimCursor.v, 1 );

    /* block until the slot is ready. */
    if ( !waitUntilAvailable( d, claim ) )
        return false;

    /* fill out the slot. */
    {
        slot = getSlot( d, claim );
        assert( slot );
        if ( !slot )
            return false;

        slot->sender = d->id;
        slot->size = (buf->tail - ptr);
        slot->offset = (ptr - buf->start);
        slot->timestamp = rdtsc();

        /*
        handleInfo( d, "slot %lld sender=%lld size=%lld offset=%lld timestamp=%lld",
                claim,
                slot->sender,
                slot->size,
                slot->offset,
                slot->timestamp );
                */
    }


    /* wait until any other producers have published. */
    {
        int64_t expectedCursor = ( claim - 1 );
        while ( d->ringbuffer->publishCursor.v < expectedCursor )
        {
            atomicYield();
        }
    }

    /* increment the publish cursor. */
    d->ringbuffer->publishCursor.v = claim;

    handleInfo( d, "publish %d", (int)claim );

    return true;
}
//: 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);
}
//: 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);
}