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); }