Пример #1
0
UtlBoolean SipDialogMgr::isNewRemoteTransaction(const SipMessage& message)
{
    UtlBoolean matchesTransaction = FALSE;
    UtlString handle;
    SipDialog::getDialogHandle(message, handle);

    UtlString callId;
    UtlString fromTag;
    UtlString toTag;
    Url fromField;
    Url toField;
    message.getFromUrl(fromField);
    message.getToUrl(toField);
    message.getCallIdField(callId);
    fromField.getFieldParameter("tag", fromTag);
    toField.getFieldParameter("tag", toTag);

    lock();
    // Looking for any dialog that matches this handle
    SipDialog* dialog = findDialog(handle,
                                   TRUE, // if established, match early dialog
                                   TRUE); // if early, match established dialog

    if(dialog && 
       dialog->isTransactionRemotelyInitiated(callId, fromTag, toTag) &&
       dialog->isNextRemoteCseq(message))
    {
        matchesTransaction = TRUE;
    }

    unlock();
    
    return(matchesTransaction);
}
Пример #2
0
UtlString SessionContext::getDiscriminatingTagValue( const SipMessage& message ) const
{
   UtlString discriminatingTag;
   Url tempUrl;

   // We do not know the directionality of the message.  In this case
   // we cannot tell if the discriminating tag will come from the From:
   // or To: header.  Return the one that does not match the dialog's
   // original From-tag.

   // Look at the To-Tag first
   message.getToUrl( tempUrl );
   tempUrl.getFieldParameter( "tag", discriminatingTag );
   if( discriminatingTag == mDialogOriginalFromTag )
   {
      message.getFromUrl( tempUrl );
      tempUrl.getFieldParameter( "tag", discriminatingTag );
   }
   return discriminatingTag;
}
Пример #3
0
UtlBoolean SipDialogMgr::isLastLocalTransaction(const SipMessage& message, 
                                                const char* dialogHandle)
{
    UtlBoolean matchesTransaction = FALSE;
    UtlString handle(dialogHandle ? dialogHandle : "");
    // If the dialog handle was not set, get it from the message
    if(handle.isNull())
    {
       SipDialog::getDialogHandle(message, handle);
    }

    UtlString callId;
    UtlString fromTag;
    UtlString toTag;
    Url fromField;
    Url toField;
    message.getFromUrl(fromField);
    message.getToUrl(toField);
    message.getCallIdField(callId);
    fromField.getFieldParameter("tag", fromTag);
    toField.getFieldParameter("tag", toTag);

    lock();
    // Looking for any dialog that matches this handle
    SipDialog* dialog = findDialog(handle,
                                   TRUE, // if established, match early dialog
                                   TRUE); // if early, match established dialog

    if(dialog && 
       dialog->isTransactionLocallyInitiated(callId, fromTag, toTag) &&
       dialog->isSameLocalCseq(message))
    {
        matchesTransaction = TRUE;
    }

    unlock();
    
    return(matchesTransaction);
}
Пример #4
0
UtlBoolean SipDialog::isSameDialog(const SipMessage& message) const
{
    UtlString messageCallId;
    message.getCallIdField(&messageCallId);
    UtlBoolean isSameDialog = FALSE;
    if(messageCallId.compareTo(*this, UtlString::ignoreCase) == 0)
    {
        Url messageFromUrl;
        message.getFromUrl(messageFromUrl);
        UtlString messageFromTag;
        messageFromUrl.getFieldParameter("tag", messageFromTag);
        if(messageFromTag.compareTo(mLocalTag, UtlString::ignoreCase) == 0)
        {
            Url messageToUrl;
            message.getToUrl(messageToUrl);
            UtlString messageToTag;
            messageToUrl.getFieldParameter("tag", messageToTag);
            if(messageToTag.compareTo(mRemoteTag, UtlString::ignoreCase) == 0)
            {
                isSameDialog = TRUE;
            }
        }
        else if(messageFromTag.compareTo(mRemoteTag, UtlString::ignoreCase) == 0)
        {
            Url messageToUrl;
            message.getToUrl(messageToUrl);
            UtlString messageToTag;
            messageToUrl.getFieldParameter("tag", messageToTag);
            if(messageToTag.compareTo(mLocalTag, UtlString::ignoreCase) == 0)
            {
                isSameDialog = TRUE;
            }
        }

    }
    return(isSameDialog);

}
Пример #5
0
/// Decode the identity from a message.
SipXauthIdentity::SipXauthIdentity(const SipMessage& message,
                                   const HeaderName headerName,
                                   DialogRule bindRule
                                   )
  : mIsValidIdentity(FALSE)
{
   UtlString callId;
   UtlString fromTag;
   Url fromUrl;
   message.getCallIdField(&callId);
   message.getFromUrl(fromUrl);
   fromUrl.getFieldParameter("tag", fromTag);

   decode(headerName, message, callId, fromTag, bindRule);
}
Пример #6
0
/// Add identity info to a message.
bool SipXauthIdentity::insert(SipMessage & message,
                              HeaderName headerName,
                              const OsDateTime * timestamp)
{
   // Don't proceed if the encapsulated identity is invalid
   if (!mIsValidIdentity)
   {
      Os::Logger::instance().log(FAC_SIP, PRI_CRIT,
                    "SipXauthIdentity::insert: "
                    "encapsulated SipXauthIdentity is invalid");
   }
   else
   {
      // make sure no existing identity in the message
      remove(message, headerName);

      // set Call-Id and from-tag for the signature calculation
      UtlString callId;
      UtlString fromTag;
      Url fromUrl;
      message.getCallIdField(&callId);
      message.getFromUrl(fromUrl);
      fromUrl.getFieldParameter("tag", fromTag);

      OsDateTime now;
      OsDateTime::getCurTime(now);
      if (NULL==timestamp)
      {
         timestamp = &now;
      }

      UtlString value;
      encode(value, callId, fromTag, *timestamp);

      // Insert displayName if it is an P-Asserted-Identity header.
      if (headerName == SipXauthIdentity::PAssertedIdentityHeaderName)
      {
          UtlString displayName;
          fromUrl.getDisplayName(displayName);
          value.prepend(displayName.data());
      }

      message.addHeaderField(headerName, value.data());
   }

   return mIsValidIdentity;
}
Пример #7
0
UtlString SessionContext::getDiscriminatingTagValue( const SipMessage& message, bool bFromCallerToCallee ) const
{
   UtlString discriminatingTag;
   Url tempUrl;

   if( bFromCallerToCallee )
   {
      // caller-to-callee uses To-tag to distinguish between dialogs
      message.getToUrl( tempUrl );
   }
   else
   {
      // callee-to-caller uses From-tag to distinguish between dialogs
      message.getFromUrl( tempUrl );
   }
   tempUrl.getFieldParameter( "tag", discriminatingTag );
   return discriminatingTag;
}
Пример #8
0
/// Encode identity info into a URL
bool SipXauthIdentity::encodeUri(Url              & uri,
                                 const char*    pCallId,
                                 const Url      fromUrl,
                                 const OsDateTime * timestamp)
{
   // Don't proceed if the encapsulated identity is invalid
   if (!mIsValidIdentity)
   {
      Os::Logger::instance().log(FAC_SIP, PRI_CRIT,
                    "SipXauthIdentity::encodeUri[no msg]: "
                    "encapsulated SipXauthIdentity is invalid");
   }
   else
   {
      // make sure no existing identity in the URI
      uri.removeHeaderParameter(SipXauthIdentity::PAssertedIdentityHeaderName);
      // set Call-Id and from-tag for the signature calculation
      UtlString callId(pCallId);
      UtlString fromTag;
      fromUrl.getFieldParameter("tag", fromTag);

      OsDateTime now;
      OsDateTime::getCurTime(now);
      if (NULL==timestamp)
      {
         timestamp = &now;
      }

      UtlString value;
      encode(value, callId, fromTag, *timestamp);
      uri.setHeaderParameter(SipXauthIdentity::PAssertedIdentityHeaderName, value.data());

      Os::Logger::instance().log(FAC_SIP, PRI_DEBUG,
                    "SipXauthIdentity::encodeUri[o msg] "
                    "encoded URI '%s'",
                    uri.toString().data()
                    );
   }

   return mIsValidIdentity;
}
Пример #9
0
/// Decode the identity from a message by searching for SipXauthIdentity then P-Asserted-Identity
SipXauthIdentity::SipXauthIdentity( const SipMessage& message,
                                    UtlString& matchedHeaderName,
                                    bool bSipXauthIdentityTakesPrecedence,
                                    DialogRule bindRule )
  : mIsValidIdentity(FALSE)
{
   UtlString callId;
   UtlString fromTag;
   Url fromUrl;
   message.getCallIdField(&callId);
   message.getFromUrl(fromUrl);
   fromUrl.getFieldParameter("tag", fromTag);
   matchedHeaderName.remove(0);
   HeaderName firstHeaderToTest;
   HeaderName secondHeaderToTest;

   if( bSipXauthIdentityTakesPrecedence == true )
   {
      firstHeaderToTest  = AuthIdentityHeaderName;
      secondHeaderToTest = PAssertedIdentityHeaderName;
   }
   else
   {
      firstHeaderToTest  = PAssertedIdentityHeaderName;
      secondHeaderToTest = AuthIdentityHeaderName;
   }

   if( decode(firstHeaderToTest, message, callId, fromTag, bindRule) )
   {
      matchedHeaderName = firstHeaderToTest;
   }
   else if( decode(secondHeaderToTest, message, callId, fromTag, bindRule) )
   {
      matchedHeaderName = secondHeaderToTest;
   }
}
Пример #10
0
void SipDialog::updateDialogData(const SipMessage& message)
{
    UtlString messageCallId;
    message.getCallIdField(&messageCallId);
    Url messageFromUrl;
    message.getFromUrl(messageFromUrl);
    UtlString messageFromTag;
    messageFromUrl.getFieldParameter("tag", messageFromTag);
    Url messageToUrl;
    message.getToUrl(messageToUrl);
    UtlString messageToTag;
    messageToUrl.getFieldParameter("tag", messageToTag);

    int cSeq;
    UtlString method;
    message.getCSeqField(&cSeq, &method);
    int responseCode = message.getResponseStatusCode();

    // Figure out if the request is from the local or
    // the remote side
    if(isTransactionLocallyInitiated(messageCallId,
                                     messageFromTag,
                                     messageToTag))
    {
        // This message is part of a transaction initiated by
        // the local side of the dialog

        if(cSeq > mLastLocalCseq)
        {
            mLastLocalCseq = cSeq;
        }

        if(cSeq >= mLastLocalCseq)
        {
            // Always update the contact if it is set
            UtlString messageContact;
            // Get the Contact value, but as an addr-spec.
            if(message.getContactUri(0, &messageContact) &&
                !messageContact.isNull())
            {
                if(message.isResponse())
                {
                   mRemoteContact.fromString(messageContact, TRUE);
                }
                else
                {
                   mLocalContact.fromString(messageContact, TRUE);
                }
            }
        }

        // Cannot assume that we only establish a dialog with the
        // initial cseq.  For example if there is an authentication
        // challenge, the dialog will not be established until the
        // second transaction.
        if(cSeq == mLastLocalCseq)
        {
            // A successful response to an INVITE or SUBSCRIBE
            // make this early dialog a set up dialog
            if(mLocalInitiatedDialog &&
               message.isResponse() &&
               responseCode >= SIP_2XX_CLASS_CODE && // successful dialog setup
               responseCode < SIP_3XX_CLASS_CODE &&
               mRemoteTag.isNull() && // tag not set
               mRouteSet.isNull()) // have not yet set the route set
            {
                // Change this early dialog to a set up dialog.
                // The tag gets set in the 2xx response
                // so we need to update the URL
                message.getToUrl(mRemoteField);
                mRemoteField.getFieldParameter("tag", mRemoteTag);

                // Need to get the route set as well
                // Make sure the Request Method is allowed to set Record-Routes
                if(message.isRecordRouteAccepted())
                {
                    message.buildRouteField(&mRouteSet);
                }
            }
        }
    }
    else if(isTransactionRemotelyInitiated(messageCallId,
                                           messageFromTag,
                                           messageToTag))
    {
        int prevRemoteCseq = mLastRemoteCseq;

        // This message is part of a transaction initiated by
        // the callee/destination of the session
        if(cSeq > mLastRemoteCseq)
        {
            mLastRemoteCseq = cSeq;
        }

        if(cSeq >= mLastRemoteCseq)
        {
            // Always update the contact if it is set
            UtlString messageContact;
            // Get the Contact value, but as an addr-spec.
            if(message.getContactUri(0, &messageContact) &&
                !messageContact.isNull())
            {
                if(message.isResponse())
                {
                   mLocalContact.fromString(messageContact, TRUE);
                }
                else
                {
                   mRemoteContact.fromString(messageContact, TRUE);
                }
            }
        }

        // First transaction from the otherside
        if(cSeq == mLastRemoteCseq && prevRemoteCseq == -1)
        {
            // A response (e.g. NOTIFY) can come before we get the
            // successful response to the initial transaction
            if(!mLocalInitiatedDialog &&
               !message.isResponse() &&
               mRemoteTag.isNull()) // tag not set
            {
                // Change this early dialog to a set up dialog.
                // The tag gets set in the 2xx response
                // so we need to update the URL
                message.getFromUrl(mRemoteField);
                mRemoteField.getFieldParameter("tag", mRemoteTag);
            }
        }

        // First successful response from the local side
        if(cSeq == mLastRemoteCseq)
        {
            if(!mLocalInitiatedDialog &&
               message.isResponse() &&
               responseCode >= SIP_2XX_CLASS_CODE && // successful dialog setup
               responseCode < SIP_3XX_CLASS_CODE &&
               mLocalTag.isNull())
            {
                // Update the local tag
                message.getToUrl(mLocalField);
                mLocalField.getFieldParameter("tag", mLocalTag);
            }
        }
    }
}
Пример #11
0
void getMessageData(UtlString& content,
                   UtlBoolean isOutgoing,
                   UtlString& date,
                   UtlString& hostname,
                   UtlString& eventCount,
                   int outputFileDescriptor)
{
    UtlString remoteHost;
    UtlString remoteAddress;
    UtlString remotePort;
    UtlString remoteSourceAddress;
    UtlString message;
    UtlString branchId;
    UtlString transactionId;
    UtlString method;
    UtlString responseCode;
    UtlString responseText;
    UtlBoolean failed = FALSE;

    int hostIndex = content.index("----Remote Host:");
    if(hostIndex > 0)
    {
        hostIndex += 16;
        int hostEnd = content.index("----", hostIndex);
        remoteHost.append(&(content.data()[hostIndex]),
                          hostEnd - hostIndex);

        remoteAddress = remoteHost;

        remoteHost.append(":");

        int portIndex = hostEnd + 11;
        int portEnd = content.index("----", portIndex);
        remotePort.append(&(content.data()[portIndex]),
                          portEnd - portIndex);
        remoteHost.append(remotePort);

        int messageIndex = portEnd + 5;
        size_t messageEnd;
        if(isOutgoing)
        {
            messageEnd = content.index("--------------------END", messageIndex);
            // Record whether the send failed or not.
            failed = (content.index("User Agent failed to send message") !=
                      UTL_NOT_FOUND);
         }
        else
        {
            messageEnd = content.index("====================END", messageIndex);
        }
        if ( UTL_NOT_FOUND == messageEnd )
        {
           messageEnd = content.length();
        }

        message.append(&(content.data()[messageIndex]),
                          messageEnd - messageIndex);

        SipMessage sipMsg(message);

        remoteSourceAddress = remoteHost;

        if(sipMsg.isResponse())
        {
            sipMsg.getFirstHeaderLinePart(1, &responseCode);
            if (failed)
            {
               responseCode = responseCode + " FAILED";
            }
            sipMsg.getFirstHeaderLinePart(2, &responseText);
        }
        else
        {
            // Get the method.
            sipMsg.getRequestMethod(&method);

            // If it is a re-INVITE, make that clear.
            if (method.compareTo("INVITE", UtlString::ignoreCase) == 0)
            {
               Url to;
               sipMsg.getToUrl(to);
               UtlString toTag;
               to.getFieldParameter("tag", toTag);
               if (!toTag.isNull())
               {
                  method = "re-INVITE";
               }
            }
               
            // Prepend FAILED if it is a failed transmission.
            if (failed)
            {
               method = "FAILED " + method;
            }

            //We can derive the source entity from the via in
            // incoming requests
            if(!isOutgoing)
            {
                UtlString viaAddress;
                UtlString protocol;
                int viaPortNum;

                sipMsg.getLastVia(&viaAddress,
                                  &viaPortNum,
                                  &protocol);
                char numBuff[30];
                sprintf(numBuff, "%d", viaPortNum);
                UtlString viaPort(numBuff);

                remoteHost = remoteAddress + ":" + viaPort;

            }
        }

        // transaction token: cseq,call-id,from-tag,to=tag
        int cseq;
        UtlString cseqMethod;
        sipMsg.getCSeqField(&cseq, &cseqMethod);
        char numBuf[20];
        sprintf(numBuf, "%d", cseq);
        UtlString callId;
        sipMsg.getCallIdField(&callId);
        Url to;
        sipMsg.getToUrl(to);
        UtlString toTag;
        to.getFieldParameter("tag", toTag);
        Url from;
        sipMsg.getFromUrl(from);
        UtlString fromTag;
        from.getFieldParameter("tag", fromTag);

        transactionId = numBuf;
        transactionId.append(",");
        transactionId.append(callId);
        transactionId.append(",");
        transactionId.append(fromTag);
        transactionId.append(",");
        transactionId.append(toTag);

        // Write all the stuff out

        // Write out the node container start
        writeBranchNodeBegin(outputFileDescriptor);

        // Write out the branchId container start
        writeBranchSetBegin(outputFileDescriptor);

        // Write out the branchIds
        int viaIndex = 0;
        UtlString topVia;
        while(sipMsg.getViaFieldSubField(&topVia, viaIndex))
        {
            SipMessage::getViaTag(topVia.data(),
                                  "branch",
                                  branchId);
            writeBranchId(outputFileDescriptor, branchId);
            viaIndex++;
        }

        // Write out the branchId container finish
        writeBranchSetEnd(outputFileDescriptor);

        // Write out the rest of the node data
        writeBranchNodeData(outputFileDescriptor,
                 date,
                 isOutgoing ? hostname : remoteHost,
                 isOutgoing ? remoteHost : hostname,
                 isOutgoing ? hostname : remoteSourceAddress,
                 isOutgoing ? remoteSourceAddress : hostname,
                 transactionId,
                 eventCount,
                 method,
                 responseCode,
                 responseText,
                 message);

        // Write out the node container finish
        writeBranchNodeEnd(outputFileDescriptor);
    }
}
Пример #12
0
   // XECS-1810: Verify that subscription is *not* terminated when NOTIFY
   // returns a Timeout error.
   void terminateSubscriptionOnErrorTimeout()
      {
         // Test MWI messages
         const char* mwiSubscribe =
            "SUBSCRIBE sip:111@localhost SIP/2.0\r\n"
            "From: <sip:[email protected]>;tag=1612c1612\r\n"
            "To: <sip:[email protected]>\r\n"
            "Cseq: 1 SUBSCRIBE\r\n"
            "Event: message-summary\r\n"
            "Accept: application/simple-message-summary\r\n"
            "Expires: 3600\r\n"
            "Date: Tue, 4 Nov 2008 15:59:30 GMT\r\n"
            "Max-Forwards: 20\r\n"
            "User-Agent: Pingtel/2.2.0 (VxWorks)\r\n"
            "Accept-Language: en\r\n"
            "Supported: sip-cc, sip-cc-01, timer, replaces\r\n"
            "Content-Length: 0\r\n"
            "\r\n";

         // Send a SUBSCRIBE to ourselves
         SipMessage mwiSubscribeRequest(mwiSubscribe);
         {
            UtlString c;
            CallId::getNewCallId(c);
            mwiSubscribeRequest.setCallIdField(c);
         }
         mwiSubscribeRequest.setSipRequestFirstHeaderLine(SIP_SUBSCRIBE_METHOD,
                                                          aor,
                                                          SIP_PROTOCOL_VERSION);
         mwiSubscribeRequest.setContactField(aor_name_addr);
         mwiSubscribeRequest.incrementCSeqNumber();

         CPPUNIT_ASSERT(userAgentp->send(mwiSubscribeRequest));

         // We should get a 202 response and a NOTIFY request in the queue
         // Send a Timeout error response to the NOTIFY.
         OsTime messageTimeout(1, 0);  // 1 second
         {
            const SipMessage* subscribeResponse;
            const SipMessage* notifyRequest;
            runListener(incomingClientMsgQueue,
                        *userAgentp,
                        messageTimeout,
                        messageTimeout,
                        notifyRequest,
                        subscribeResponse,
                        SIP_REQUEST_TIMEOUT_CODE,
                        FALSE,
                        0,
                        NULL);

            // We should have received a SUBSCRIBE response and a NOTIFY request.
            CPPUNIT_ASSERT(subscribeResponse);
            CPPUNIT_ASSERT(subscribeResponse->getResponseStatusCode() == SIP_ACCEPTED_CODE);
            CPPUNIT_ASSERT(notifyRequest);

            // Extract the to-tag in the response, apply it to mwiSubscribeRequest.
            // This allows the re-SUBSCRIBE below to be applied to the existing dialog.
            Url toUrl;
            subscribeResponse->getToUrl(toUrl);
            UtlString toTag;
            toUrl.getFieldParameter("tag", toTag);
            mwiSubscribeRequest.setToFieldTag(toTag);
         }

         // Send a re-SUBSCRIBE in the existing dialog, to find out if the
         // subscription was terminated or not.
         mwiSubscribeRequest.incrementCSeqNumber();
         // Leave the Expires header with the default value.

         CPPUNIT_ASSERT(userAgentp->send(mwiSubscribeRequest));

         // We should get a 202 response and a NOTIFY, because the Timeout
         // error suppresses the termination of the subscription.
         {
            const SipMessage* subscribeResponse;
            const SipMessage* notifyRequest;
            runListener(incomingClientMsgQueue,
                        *userAgentp,
                        messageTimeout,
                        messageTimeout,
                        notifyRequest,
                        subscribeResponse,
                        SIP_OK_CODE,
                        FALSE,
                        0,
                        NULL);

            // We should have received a SUBSCRIBE response and no NOTIFY request.
            CPPUNIT_ASSERT(subscribeResponse);
            CPPUNIT_ASSERT(notifyRequest);
            CPPUNIT_ASSERT(subscribeResponse->getResponseStatusCode() == SIP_ACCEPTED_CODE);
         }
      }
Пример #13
0
UtlBoolean SipXProxyCseObserver::handleMessage(OsMsg& eventMessage)
{
   int msgType = eventMessage.getMsgType();
   switch (msgType)
   {
   case OsMsg::OS_EVENT:
      switch (eventMessage.getMsgSubType())
      {
      case OsEventMsg::NOTIFY:
         if (mpWriter)
         {
            mpWriter->flush();
         }
         break;
      }
      break ;
      
   case OsMsg::PHONE_APP:
   {
      SipMessage* sipMsg;

      if(SipMessageEvent::TRANSPORT_ERROR == ((SipMessageEvent&)eventMessage).getMessageStatus())
      {
         Os::Logger::instance().log(FAC_SIP, PRI_ERR,
                       "SipXProxyCseObserver::handleMessage transport error");
      }
      else if((sipMsg = (SipMessage*)((SipMessageEvent&)eventMessage).getMessage()))
      {
         UtlString method;
         int       rspStatus = 0;
         UtlString rspText;
         UtlString contact;
         UtlString toTag;
         
         enum 
            {
               UnInteresting,
               aCallRequest,
               aCallSetup,
               aCallFailure,
               aCallEnd,
               aCallTransfer
            } thisMsgIs = UnInteresting;
         
         Url toUrl;

         sipMsg->getToUrl(toUrl);

         // explicitly, an INVITE Request
         toUrl.getFieldParameter("tag", toTag);

         if (!sipMsg->isResponse())
         {

            // sipMsg is a Request
            sipMsg->getRequestMethod(&method);

            if (0==method.compareTo(SIP_INVITE_METHOD, UtlString::ignoreCase))
            {
               if (toTag.isNull())
               {
                  sipMsg->getContactEntry(0, &contact);               
                  thisMsgIs = aCallRequest;
               }
            }
            else if (0==method.compareTo(SIP_REFER_METHOD, UtlString::ignoreCase))
            {
               thisMsgIs = aCallTransfer;
               sipMsg->getContactEntry(0, &contact);               
            }
            else if (0==method.compareTo(SIP_BYE_METHOD, UtlString::ignoreCase))
            {
               thisMsgIs = aCallEnd; // no additional information needed
            }
            else
            {
               // other request methods are not interesting
            }
         }
         else // this is a response
         {
            int seq;
            if (sipMsg->getCSeqField(&seq, &method)) // get the method out of cseq field
            {
               if (0==method.compareTo(SIP_INVITE_METHOD, UtlString::ignoreCase))
               {
                  // Responses to INVITES are handled differently based on whether
                  // or not the INVITE is dialog-forming.  If dialog-forming,
                  // any final response above 400 is considered a failure for CDR
                  // purposes.  If not dialog-forming, then any final response above 400
                  // except 401 Unauthorized, 407 Proxy Authentication Required and 
                  // 408 Request Timeout will terminate.  If we're in a dialog then
            	  // only 408 (Request Timeout) and 481 (Call/Transaction does not exist)
            	  // will terminate the dialog.

                  rspStatus = sipMsg->getResponseStatusCode();
                  if (rspStatus >= SIP_4XX_CLASS_CODE) // any failure
                  {
                     // a failure code - this is a potential CallFailure - Call Resolver will determine.
                     thisMsgIs = aCallFailure;
                     sipMsg->getResponseStatusText(&rspText);
                  }
                  else if (   ( rspStatus >= SIP_2XX_CLASS_CODE )
                           && ( rspStatus <  SIP_3XX_CLASS_CODE )
                           )
                  {
                     thisMsgIs = aCallSetup;
                     sipMsg->getContactEntry(0, &contact);
                  }
               }
               else
               {
                  // responses to non-INVITES are not interesting
               }
            }
            else
            {
               Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver - no Cseq in response");
            }
         }

#        ifdef LOG_DEBUG
         Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipXProxyCseObserver message is %s",
                       (  thisMsgIs == UnInteresting ? "UnInteresting"
                        : thisMsgIs == aCallEnd      ? "a Call End"
                        : thisMsgIs == aCallFailure  ? "a Call Failure"
                        : thisMsgIs == aCallRequest  ? "a call Request"      
                        : thisMsgIs == aCallSetup    ? "a Call Setup"
                        : thisMsgIs == aCallTransfer ? "a Call Transfer"
                        : "BROKEN"
                        )); 
#        endif

         if (thisMsgIs != UnInteresting)
         {
            // collect the sequence data
            mSequenceNumber++;
            
            OsTime timeNow;
            OsDateTime::getCurTime(timeNow); 

            // collect the dialog information
            UtlString callId;
            sipMsg->getCallIdField(&callId);
         
            Url toUrl;
            sipMsg->getToUrl(toUrl);
            UtlString toTag;
            toUrl.getFieldParameter("tag", toTag);

            Url fromUrl;
            sipMsg->getFromUrl(fromUrl);
            UtlString fromTag;
            fromUrl.getFieldParameter("tag", fromTag);

            // collect the To and From
            UtlString toField;
            sipMsg->getToField(&toField);
            
            UtlString fromField;
            sipMsg->getFromField(&fromField);


            // collect the branch Id (i.e. transaction id) and via count.
            UtlString viaValue;
            int viaCount;
            UtlString branchId;
            viaCount = sipMsg->getCountHeaderFields(SIP_VIA_FIELD);
            viaCount = viaCount + sipMsg->getCountHeaderFields(SIP_SHORT_VIA_FIELD);
            if ( sipMsg->getViaFieldSubField( &viaValue, 0 ) ) {
               sipMsg->getViaTag( viaValue, "branch", branchId );
            }
            UtlString referTo;
            UtlString referredBy;
            UtlString requestUri;
            UtlString references;
            UtlString replaces_callId;
            UtlString replaces_toTag;
            UtlString replaces_fromTag;
            UtlString matchingIdentityHeader;
            SipXauthIdentity sipxIdentity(*sipMsg, matchingIdentityHeader, true,SipXauthIdentity::allowUnbound);

            sipMsg->getReferToField(referTo);
            sipMsg->getReferredByField(referredBy);   
            sipMsg->getRequestUri(&requestUri);
            sipMsg->getReferencesField(&references);
            if (sipMsg->getReplacesData(replaces_callId, replaces_toTag, replaces_fromTag)) {
               if (references.length() != 0) {
                  references.append(",");
               }
               references.append(replaces_callId);
               references.append(";rel=xfer");
            }
            
            UtlString responseMethod;
            UtlString calleeRoute;

            int cseqNumber;
            sipMsg->getCSeqField(&cseqNumber, &responseMethod);            

            BranchTimePair* callIdBranchIdTime;
            // generate the call state event record
            if (mpBuilder)
            {
               UtlString identity;
               UtlString recordRoute;
               bool routeFound = false;
               bool paiPresent = false;

               switch (thisMsgIs)
               {
               case aCallRequest:
                 
                  if (sipxIdentity.getIdentity(identity)) {
                     paiPresent = true;
                  }

                  if ( branchId && branchId.data() ) {
                     mCallTransMutex.acquire();
                     unsigned long currentTime = OsDateTime::getSecsSinceEpoch();

                     UtlString* keyCallId = new UtlString(callId);
                     BranchTimePair* valBranchTimePair = new BranchTimePair(branchId.data(), &currentTime, &paiPresent);
                     if (NULL == mCallTransMap.insertKeyAndValue(keyCallId, valBranchTimePair) ) {
                        // Unable to add callId to map so it must already be present.  
                        delete keyCallId;
                        delete valBranchTimePair;

                        // Check if the paiPresent value is set to true or not.
                        // If not set and we now have a PAI for this call, set it and generate another call request state event 
                        // with this info. Otherwise skip over.
                        if ( paiPresent ) {
                           callIdBranchIdTime = (BranchTimePair*) mCallTransMap.findValue(&callId);
                           if ( callIdBranchIdTime && (*callIdBranchIdTime->getPaiPresent() == false) ) {
                              // need to generate another call request event in order to state originator is internal.
                              callIdBranchIdTime->setPaiPresent(&paiPresent);
                           }
                           else {
                              mCallTransMutex.release();
                              return(TRUE);
                           }
                        }
                        else {
                           mCallTransMutex.release();
                           return(TRUE);
                        }
                     }
                     mCallTransMutex.release();
                  }
                  mpBuilder->callRequestEvent(mSequenceNumber, timeNow, contact, references, branchId, viaCount, paiPresent);
                  break;
                  
               case aCallSetup:
                  // Clear out from the map only if rspStatus is higher than 200 as its possible to receive multiple 200 messages.
                  // If the response is 200, the call in the map will be cleared out when the call ends.
                  mCallTransMutex.acquire();
                  callIdBranchIdTime = (BranchTimePair*) mCallTransMap.findValue(&callId);
                  if ( callIdBranchIdTime && (0 == branchId.compareTo(callIdBranchIdTime)) ) {
                     if ( rspStatus > SIP_2XX_CLASS_CODE ) {
                           mCallTransMap.destroy(&callId);
                        }
                     mCallTransMutex.release();
                  }
                  else
                  {
                     // CallId/BranchId are either not found or doesn't match.  Not a final response.
                     mCallTransMutex.release();
                     return(TRUE);
                  }
                  for (int rrNum = 0;
                       (!routeFound && sipMsg->getRecordRouteUri(rrNum, &recordRoute));
                       rrNum++
                  )
                  {
                     Url recordRouteUrl(recordRoute);
                     if (mpSipUserAgent->isMyHostAlias(recordRouteUrl)) {
                        // This is a record route for our proxy, extract Call tags if they exist.
                        recordRouteUrl.getUrlParameter(SIP_SIPX_CALL_DEST_FIELD, calleeRoute, 0);
                        routeFound = true;
                     }
                  }
                  mpBuilder->callSetupEvent(mSequenceNumber, timeNow, contact, calleeRoute, branchId, viaCount);
                  break;
   
               case aCallFailure:
                  // Failure case means that the response code is > 400.  If the call is found
                  // in the map, then this is a final response.  Delete from the map and build an event.
                  mCallTransMutex.acquire();
                  callIdBranchIdTime = (BranchTimePair*) mCallTransMap.findValue(&callId);
                  if ( callIdBranchIdTime && (0 == branchId.compareTo(callIdBranchIdTime)) ) {
                     mCallTransMap.destroy(&callId);
                     mCallTransMutex.release();
                     if ( rspStatus != SIP_PROXY_AUTH_REQ_CODE ) {
                        mpBuilder->callFailureEvent(mSequenceNumber, timeNow, branchId, viaCount, rspStatus, rspText);
                     }
                     else {
                        // response was an authentication required.  Don't build a CSE for these as a new Invite will
                        // occur.
                        return(TRUE);
                     }
                  }
                  else
                  {
                     // Call was not found in the map so this is not a final response.  Ignore it.
                     mCallTransMutex.release();
                     return(TRUE);
                  }
                  break;
                  
               case aCallEnd:
                  mCallTransMutex.acquire();
                  mCallTransMap.destroy(&callId);
                  mCallTransMutex.release();
                  mpBuilder->callEndEvent(mSequenceNumber, timeNow);
                  break;
                  
               case aCallTransfer:
                  mpBuilder->callTransferEvent(mSequenceNumber, timeNow, 
                                               contact, referTo, referredBy, requestUri);
                  break;   
   
               default:
                  // shouldn't be possible to get here
                  Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver invalid thisMsgIs");
                  break;
               }
   
               mpBuilder->addCallData(cseqNumber, callId, fromTag, toTag, fromField, toField);
               UtlString via;
               for (int i=0; sipMsg->getViaField(&via, i); i++)
               {
                  mpBuilder->addEventVia(via);
               }
   
               mpBuilder->completeCallEvent();
                 
               // get the completed record
               UtlString event;
               mpBuilder->finishElement(event);
               
               if (mpWriter)
               {
                 mpWriter->writeLog(event.data());
               }
            }
            else
            {
               Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver - no CallStateEventBuilder!");               
            }
         }
      }
      else
      {
         Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver getMessage returned NULL");
      }
   }
   break;
   
   default:
   {
      Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver invalid message type %d", msgType );
   }
   } // end switch (msgType)
   
   return(TRUE);
}
Пример #14
0
UtlBoolean
SubscribeServerThread::isAuthenticated (
    const SipMessage* message,
    SipMessage *responseMessage,
    UtlString& authenticatedUser,
    UtlString& authenticatedRealm )
{
    UtlBoolean isAuthorized = FALSE;

    // if we are not using a database we must assume authenticated
    if ( !mIsCredentialDB )
    {
        OsSysLog::add(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthenticated() "
            ":: No Credential DB - request is always AUTHENTICATED");
        isAuthorized = TRUE;
    } else
    {
        // realm and auth type should be default for server
        // if URI not defined in DB, the user is not authorized to modify bindings -
        OsSysLog::add( FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthenticated():TRUE realm=\"%s\" ",
                mRealm.data());

        UtlString requestNonce;
        UtlString requestRealm;
        UtlString requestUser;
        UtlString requestUserBase;
        UtlString requestUriParam;
        int requestAuthIndex = 0;
        // can have multiphe authorization / authorization-proxy headers
        // headers search for a realm match
        while ( message->getDigestAuthorizationData (
                &requestUser,
                &requestRealm,
                &requestNonce,
                NULL,
                NULL,
                &requestUriParam,
                HttpMessage::SERVER,
                requestAuthIndex,
                &requestUserBase) )
        {
            OsSysLog::add(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthenticated() "
                   "- Authorization header set in message, validate it.\n"
                   "- reqRealm=\"%s\", reqUser=\"%s\", reqUserBase=\"%s\"",
                          requestRealm.data(), requestUser.data(),
                          requestUserBase.data());

            // case sensitive comparison of realm
            if ( mRealm.compareTo( requestRealm ) == 0 )
            {
                OsSysLog::add(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthenticated()"
                    "- Realm matches, now validate userid/password");

                // See if the nonce is valid - see net/SipNonceDb.cpp
                UtlString reqUri;
                message->getRequestUri(&reqUri);
                Url mailboxUrl(reqUri);

                UtlString authTypeDB;
                UtlString passTokenDB;
                UtlString callId;
                UtlString fromTag;
                long     nonceExpires = (5*60); // five minutes

                Url fromUrl;
                message->getFromUrl(fromUrl);
                fromUrl.getFieldParameter("tag", fromTag);

                message->getCallIdField(&callId);

                if (mNonceDb.isNonceValid(requestNonce, callId, fromTag,
                                          mRealm, nonceExpires))
                {
                    // then get the credentials for this realm
                    if (CredentialDB::getInstance()->
                        getCredentialByUserid(
                           mailboxUrl,
                           mRealm,
                           requestUserBase,
                           passTokenDB,
                           authTypeDB))
                    {
                        // the Digest Password is calculated from the request
                        // user, passtoken, nonce and request URI

                        isAuthorized =
                           message->verifyMd5Authorization(requestUser.data(),
                                                           passTokenDB.data(),
                                                           requestNonce,
                                                           requestRealm.data(),
                                                           requestUriParam.data());
                        if (isAuthorized)
                        {
                            // can have multiple credentials for same realm so only break out
                            // when we have a positive match
                            OsSysLog::add(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthenticated() "
                                "- request is AUTHENTICATED");
                            // copy the authenticated user/realm for subsequent authorization
                            authenticatedUser = requestUserBase;
                            authenticatedRealm = requestRealm;
                            break;
                        }
                        else
                        {
                            OsSysLog::add(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthenticated() "
                                "- digest authorization failed");
                        }
                    }
                    else
                    {
                        OsSysLog::add(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthenticated() "
                            "- No Credentials for mailboxUrl=\"%s\", reqRealm=\"%s\", reqUser=\"%s\"",
                            mailboxUrl.toString().data(),
                            requestRealm.data(),
                            requestUser.data());
                    }
                }
                else
                {
                    OsSysLog::add(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthenticated() "
                           "- Invalid nonce \"%s\" for mailboxUrl=\"%s\", reqRealm=\"%s\", reqUser=\"%s\"",
                           requestNonce.data(),
                           mailboxUrl.toString().data(),
                           requestRealm.data(),
                           requestUser.data());

                }
                // end check credentials
            }
            requestAuthIndex++;
        } //end while

        if ( !isAuthorized )
        {
            // Generate the 401 Unauthorized response to challenge for credentials
            // Use the SipNonceDB to generate a nonce
            UtlString newNonce;
            UtlString callId;
            UtlString fromTag;

            Url fromUrl;
            message->getFromUrl(fromUrl);
            fromUrl.getFieldParameter("tag", fromTag);

            message->getCallIdField(&callId);

            mNonceDb.createNewNonce(callId,
                                    fromTag,
                                    mRealm,
                                    newNonce);

            responseMessage->setRequestUnauthorized(message, HTTP_DIGEST_AUTHENTICATION,
                                                    mRealm, newNonce);
        }
    }
    return isAuthorized;
}
Пример #15
0
bool SessionContext::handleRequest( SipMessage& message, const char* address, int port, bool bFromCallerToCallee )
{
   // This routine steers incoming requests to the DialogTracker instance that is
   // responsible for handling them based on the request's to- or from-tags depending
   // on the directionality of the request.
   ssize_t numberOfDialogTrackersEnteringRoutine = getNumberOfTrackedDialogs();
   bool bTrackRequestResponse = false;

   UtlString discriminatingTag = getDiscriminatingTagValue( message, bFromCallerToCallee );

   // if a discriminating tag was found, try to find a DialogTracker for it.
   if( !discriminatingTag.isNull() )
   {
      DialogTracker* pDialogTracker = 0;
      if( ( pDialogTracker = getDialogTrackerForTag( discriminatingTag ) ) != 0 )
      {
         bTrackRequestResponse = pDialogTracker->handleRequest( message, address, port, bFromCallerToCallee );
      }
      else
      {
         OsSysLog::add(FAC_NAT, PRI_CRIT, "SessionContext[%s]::handleRequest: received in-dialog request with unknown discriminating tag: %s",
                                           mHandle.data(), discriminatingTag.data() );
      }
   }
   else
   {
      // The request does not yet have a discriminating tag.  This is likely indicating a
      // dialog-forming INVITE but to be sure, check that the request is indeed an
      // INVITE in the caller->callee direction.
      UtlString method;
      message.getRequestMethod(&method);
      if( bFromCallerToCallee && method.compareTo( SIP_INVITE_METHOD ) == 0 )
      {
         // The INVITE is dialog-forming.  Check whether or not already have
         // the reference dialog tracker for it.
         if( !mpReferenceDialogTracker )
         {
            // This is the first time we see that dialog-forming request - create
            // a reference dialog tracker that will serve as a template to create
            // new DialogTracker objects for the dialogs that responses to the
            // request will establish.
            Url tempUrl;
            char tempBuffer[50];
            sprintf( tempBuffer, "%s-%s", mHandle.data(), "ref" );

            if( ( mpReferenceDialogTracker = new DialogTracker( tempBuffer, mSystemIdentificationString, this ) ) )
            {
               mpReferenceDialogTracker->handleRequest( message, address, port, bFromCallerToCallee );
               // save the From tag of the dialog-forming request. This will be used to identify
               // the discriminating tag when the directionality of a message is unknown.
               message.getFromUrl( tempUrl );
               tempUrl.getFieldParameter( "tag", mDialogOriginalFromTag );
               mDialogFormingInviteCseq.setValue( message );
               bTrackRequestResponse = true;
            }
         }
         else
         {
            // This dialog-forming request has already been seen - this is likely a
            // retransmission.  Present it to the reference dialog tracker so that
            // it can handle the retransmission properly.
            bTrackRequestResponse = mpReferenceDialogTracker->handleRequest( message, address, port, bFromCallerToCallee );
         }
      }
   }

   // Check if the processing of the request caused the last DialogTracker to be deleted.
   // If so, the SessionContext is not required anymore therefore tell the CallTracker that
   // we are ready for deletion
   if( numberOfDialogTrackersEnteringRoutine &&
       deleteDialogTrackersReadyForDeletion() == numberOfDialogTrackersEnteringRoutine )
   {
      mpOwningCallTracker->reportSessionContextReadyForDeletion( mHandle );
   }
   return bTrackRequestResponse;
}
Пример #16
0
UtlBoolean SipXProxyCseObserver::handleMessage(OsMsg& eventMessage)
{
   int msgType = eventMessage.getMsgType();
   switch (msgType)
   {
   case OsMsg::OS_EVENT:
      switch (eventMessage.getMsgSubType())
      {
      case OsEventMsg::NOTIFY:
         if (mpWriter)
         {
            mpWriter->flush();
         }
         break;
      }
      break ;
      
   case OsMsg::PHONE_APP:
   {
      SipMessage* sipMsg;

      if(SipMessageEvent::TRANSPORT_ERROR == ((SipMessageEvent&)eventMessage).getMessageStatus())
      {
         OsSysLog::add(FAC_SIP, PRI_ERR,
                       "SipXProxyCseObserver::handleMessage transport error");
      }
      else if((sipMsg = (SipMessage*)((SipMessageEvent&)eventMessage).getMessage()))
      {
         UtlString method;
         int       rspStatus = 0;
         UtlString rspText;
         UtlString contact;
         UtlString toTag;
         
         enum 
            {
               UnInteresting,
               aCallRequest,
               aCallSetup,
               aCallFailure,
               aCallEnd,
               aCallTransfer
            } thisMsgIs = UnInteresting;
         
         Url toUrl;
         sipMsg->getToUrl(toUrl);
         // explicitly, an INVITE Request
         toUrl.getFieldParameter("tag", toTag);

         if (!sipMsg->isResponse())
         {

            // sipMsg is a Request
            sipMsg->getRequestMethod(&method);

            if (0==method.compareTo(SIP_INVITE_METHOD, UtlString::ignoreCase))
            {
               if (toTag.isNull())
               {
                  thisMsgIs = aCallRequest;
               }
            }
            else if (0==method.compareTo(SIP_REFER_METHOD, UtlString::ignoreCase))
            {
               thisMsgIs = aCallTransfer;
               sipMsg->getContactEntry(0, &contact);               
            }
            else if (0==method.compareTo(SIP_BYE_METHOD, UtlString::ignoreCase))
            {
               thisMsgIs = aCallEnd; // no additional information needed
            }
            else
            {
               // other request methods are not interesting
            }
         }
         else // this is a response
         {
            int seq;
            if (sipMsg->getCSeqField(&seq, &method)) // get the method out of cseq field
            {
               if (0==method.compareTo(SIP_INVITE_METHOD, UtlString::ignoreCase))
               {
                  // Responses to INVITES are handled differently based on whether
                  // or not the INVITE is dialog-forming.  If dialog-forming,
                  // any final response above 400 is considered a failure for CDR
                  // purposes.  If not dialog-forming, then any final response above 400
                  // except 401 Unauthorized, 407 Proxy Authentication Required and 
                  // 408 Request Timeout will terminate.  If we're in a dialog then
            	  // only 408 (Request Timeout) and 481 (Call/Transaction does not exist)
            	  // will terminate the dialog.

                  rspStatus = sipMsg->getResponseStatusCode();
                  if (rspStatus >= SIP_4XX_CLASS_CODE) // any failure
                  {
                     // a failure code - this is a potential CallFailure - Call Resolver will determine.
                     thisMsgIs = aCallFailure;
                     sipMsg->getResponseStatusText(&rspText);
                  }
                  else if (   ( rspStatus >= SIP_2XX_CLASS_CODE )
                           && ( rspStatus <  SIP_3XX_CLASS_CODE )
                           )
                  {
                     thisMsgIs = aCallSetup;
                     sipMsg->getContactEntry(0, &contact);
                  }
               }
               else
               {
                  // responses to non-INVITES are not interesting
               }
            }
            else
            {
               OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver - no Cseq in response");
            }
         }

#        ifdef LOG_DEBUG
         OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipXProxyCseObserver message is %s",
                       (  thisMsgIs == UnInteresting ? "UnInteresting"
                        : thisMsgIs == aCallEnd      ? "a Call End"
                        : thisMsgIs == aCallFailure  ? "a Call Failure"
                        : thisMsgIs == aCallRequest  ? "a call Request"      
                        : thisMsgIs == aCallSetup    ? "a Call Setup"
                        : thisMsgIs == aCallTransfer ? "a Call Transfer"
                        : "BROKEN"
                        )); 
#        endif

         if (thisMsgIs != UnInteresting)
         {
            // collect the sequence data
            mSequenceNumber++;
            
            OsTime timeNow;
            OsDateTime::getCurTime(timeNow); 

            // collect the dialog information
            UtlString callId;
            sipMsg->getCallIdField(&callId);
         
            Url toUrl;
            sipMsg->getToUrl(toUrl);
            UtlString toTag;
            toUrl.getFieldParameter("tag", toTag);

            Url fromUrl;
            sipMsg->getFromUrl(fromUrl);
            UtlString fromTag;
            fromUrl.getFieldParameter("tag", fromTag);

            // collect the To and From
            UtlString toField;
            sipMsg->getToField(&toField);
            
            UtlString fromField;
            sipMsg->getFromField(&fromField);

            UtlString referTo;
            UtlString referredBy;
            UtlString requestUri;
            sipMsg->getReferToField(referTo);
            sipMsg->getReferredByField(referredBy);   
            sipMsg->getRequestUri(&requestUri);
            
            UtlString responseMethod;
            int cseqNumber;
            sipMsg->getCSeqField(&cseqNumber, &responseMethod);            

            // generate the call state event record
            if (mpBuilder)
            {
               switch (thisMsgIs)
               {
               case aCallRequest:
                  mpBuilder->callRequestEvent(mSequenceNumber, timeNow, contact);
                  break;
                  
               case aCallSetup:
                  mpBuilder->callSetupEvent(mSequenceNumber, timeNow, contact);
                  break;
   
               case aCallFailure:
                  mpBuilder->callFailureEvent(mSequenceNumber, timeNow, rspStatus, rspText);
                  break;
                  
               case aCallEnd:
                  mpBuilder->callEndEvent(mSequenceNumber, timeNow);
                  break;
                  
               case aCallTransfer:
                  mpBuilder->callTransferEvent(mSequenceNumber, timeNow, 
                                               contact, referTo, referredBy, requestUri);
                  break;   
   
               default:
                  // shouldn't be possible to get here
                  OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver invalid thisMsgIs");
                  break;
               }
   
               mpBuilder->addCallData(cseqNumber, callId, fromTag, toTag, fromField, toField);
               UtlString via;
               for (int i=0; sipMsg->getViaField(&via, i); i++)
               {
                  mpBuilder->addEventVia(via);
               }
   
               mpBuilder->completeCallEvent();
                 
               // get the completed record
               UtlString event;
               mpBuilder->finishElement(event);
               
               if (mpWriter)
               {
                 mpWriter->writeLog(event.data());
               }
            }
            else
            {
               OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver - no CallStateEventBuilder!");               
            }
         }
      }
      else
      {
         OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver getMessage returned NULL");
      }
   }
   break;
   
   default:
   {
      OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver invalid message type %d", msgType );
   }
   } // end switch (msgType)
   
   return(TRUE);
}
UtlBoolean AppAgentSubscribePolicy::isAuthenticated(const SipMessage & subscribeRequest,
                                                    SipMessage & subscribeResponse)
{
   UtlBoolean isAuthorized = FALSE;

   UtlString callId;
   subscribeRequest.getCallIdField(&callId);

   Url fromNameAddr;
   UtlString fromTag;
   subscribeRequest.getFromUrl(fromNameAddr);
   fromNameAddr.getFieldParameter("tag", fromTag);

   UtlString authNonce;
   UtlString authRealm;
   UtlString authUser;
   UtlString authUserBase;
   UtlString uriParam;
   UtlString authCnonce;
   UtlString authNonceCount;
   UtlString authQop;

   // Iterate through Authorization and Proxy-Authorization credentials,
   // looking for one that shows this request is authenticated.
   for (int authIndex = 0;
        ! isAuthorized
        && subscribeRequest.getDigestAuthorizationData(&authUser,
                                                       &authRealm,
                                                       &authNonce,
                                                       NULL, NULL, 
                                                       &uriParam,
                                                       &authCnonce,
                                                       &authNonceCount,
                                                       &authQop,
                                                       HttpMessage::SERVER, 
                                                       authIndex,
                                                       &authUserBase);
        authIndex++
      )
   {
      Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, 
                    "AppAgentSubscribePolicy::isAuthenticated "
                    "Message Authorization received: "
                    "reqRealm='%s', reqUser='******', reqUserBase='%s'",
                    authRealm.data(), authUser.data(), authUserBase.data());

      UtlString qopType;

      if (mRealm.compareTo(authRealm) ) // case sensitive check that realm is correct
      {
         Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG,
                       "AppAgentSubscribePolicy::isAuthenticated "
                       "Realm does not match");
      }

      // validate the nonce
      else if (!mNonceDb.isNonceValid(authNonce, callId, fromTag, mRealm, mNonceExpiration))
      {
          Os::Logger::instance().log(FAC_AUTH, PRI_INFO,
                        "AppAgentSubscribePolicy::isAuthenticated -"
                        "Invalid nonce: nonce='%s', callId='%s'",
                        authNonce.data(), callId.data());
      }

      // verify that qop,cnonce, nonceCount are compatible
      else if (subscribeRequest.verifyQopConsistency(authCnonce.data(),
                                                     authNonceCount.data(),
                                                     &authQop,
                                                     qopType)
               >= HttpMessage::AUTH_QOP_NOT_SUPPORTED)
      {
          Os::Logger::instance().log(FAC_AUTH, PRI_INFO,
                        "AppAgentSubscribePolicy::isAuthenticated -"
                        "Invalid combination of QOP('%s'), cnonce('%s') and nonceCount('%s')",
                        authQop.data(), authCnonce.data(), authNonceCount.data());
      }

      else // realm, nonce and qop are all ok
      {    
         // build the "authorization identity" from the auth credentials
         Url authIdentity;
         UtlString authTypeDB;
         UtlString passTokenDB;

         // then get the credentials for this user & realm
         if (mEntityDb.getCredential(authUserBase, authRealm, authIdentity, passTokenDB, authTypeDB))
         {
            // only DIGEST is used, so the authTypeDB above is ignored
            if ((isAuthorized =
                 subscribeRequest.verifyMd5Authorization(authUser.data(),
                                                         passTokenDB.data(),
                                                         authNonce.data(),
                                                         authRealm.data(),
                                                         authCnonce.data(),
                                                         authNonceCount.data(),
                                                         authQop.data(),
                                                         uriParam.data())
                   ))
            {
               Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG,
                             "AppAgentSubscribePolicy::isAuthenticated "
                             "response auth hash matches");
            }
            else
            {
               UtlString identity;
               authIdentity.getIdentity(identity);
               Os::Logger::instance().log(FAC_AUTH, PRI_ERR,
                             "AppAgentSubscribePolicy::isAuthenticated "
                             "Response auth hash does not match (bad password?)"
                             " authIdentity='%s' authUser='******' authUserBase='%s'",
                             identity.data(), authUser.data(), authUserBase.data());
            }
         }
         else // failed to get credentials
         {
            UtlString identity;
            authIdentity.getIdentity(identity);
            Os::Logger::instance().log(FAC_AUTH, PRI_ERR,
                          "AppAgentSubscribePolicy::isAuthenticated "
                          "Unable to get credentials for realm='%s', user='******', userBase = '%s'",
                          mRealm.data(), authUser.data(), authUserBase.data());
         }
      }     // end DB check
   } //end for

   if ( !isAuthorized )
   {
      // Generate a new challenge
      UtlString newNonce;
      UtlString opaque;

      mNonceDb.createNewNonce(callId,
                              fromTag,
                              mRealm,
                              newNonce);

      subscribeResponse.setRequestUnauthorized(&subscribeRequest,
                                               HTTP_DIGEST_AUTHENTICATION,
                                               mRealm,
                                               newNonce,
                                               NULL // opaque
         );
   }

   return isAuthorized;
}
Пример #18
0
   // Test for XECS-247, When subscribe server receives 481 for a
   // NOTIFY, it does not terminate the subscription.
   // Test for XECS-282, When subscribe server receives 500 for a
   // NOTIFY, it does not terminate the subscription.
   // Verify that subscription is terminated when NOTIFY returns a variety
   // of error responses.  (Retry-After suppresses termination.  That case
   // is tested in terminateSubscriptionOnErrorRetryAfter.)
   void terminateSubscriptionOnError()
      {
         // Test MWI messages
         const char* mwiSubscribe =
            "SUBSCRIBE sip:111@localhost SIP/2.0\r\n"
            "From: <sip:[email protected]>;tag=1612c1612\r\n"
            "To: <sip:[email protected]>\r\n"
            "Cseq: 1 SUBSCRIBE\r\n"
            "Event: message-summary\r\n"
            "Accept: application/simple-message-summary\r\n"
            "Expires: 3600\r\n"
            "Date: Tue, 26 Apr 2005 14:59:30 GMT\r\n"
            "Max-Forwards: 20\r\n"
            "User-Agent: Pingtel/2.2.0 (VxWorks)\r\n"
            "Accept-Language: en\r\n"
            "Supported: sip-cc, sip-cc-01, timer, replaces\r\n"
            "Content-Length: 0\r\n"
            "\r\n";

         // Loop through this scenario for a series of response codes.
         int test_codes[] = { SIP_BAD_REQUEST_CODE,
                              SIP_NOT_FOUND_CODE,
                              SIP_BAD_TRANSACTION_CODE,
                              499,
                              SIP_SERVER_INTERNAL_ERROR_CODE,
                              SIP_SERVICE_UNAVAILABLE_CODE,
                              599,
                              SIP_GLOBAL_BUSY_CODE,
                              699 };
         for (unsigned int i = 0;
              i < sizeof (test_codes) / sizeof (test_codes[0]);
              i++)
         {
            // Send a SUBSCRIBE to ourselves
            SipMessage mwiSubscribeRequest(mwiSubscribe);
            {
               UtlString c;
               CallId::getNewCallId(c);
               mwiSubscribeRequest.setCallIdField(c);
            }
            mwiSubscribeRequest.setSipRequestFirstHeaderLine(SIP_SUBSCRIBE_METHOD,
                                                             aor,
                                                             SIP_PROTOCOL_VERSION);
            mwiSubscribeRequest.setContactField(aor_name_addr);
            mwiSubscribeRequest.incrementCSeqNumber();

            CPPUNIT_ASSERT(userAgentp->send(mwiSubscribeRequest));

            // We should get a 202 response and a NOTIFY request in the queue
            // Send the specified response to the NOTIFY.
            OsTime messageTimeout(1, 0);  // 1 second
            {
               const SipMessage* subscribeResponse;
               const SipMessage* notifyRequest;
               runListener(incomingClientMsgQueue,
                           *userAgentp,
                           messageTimeout,
                           messageTimeout,
                           notifyRequest,
                           subscribeResponse,
                           test_codes[i],
                           FALSE,
                           0,
                           NULL);

               // We should have received a SUBSCRIBE response and a NOTIFY request.
               CPPUNIT_ASSERT(subscribeResponse);

               // Extract the to-tag in the response, apply it to
               // mwiSubscribeRequest.
               Url toUrl;
               subscribeResponse->getToUrl(toUrl);
               UtlString toTag;
               toUrl.getFieldParameter("tag", toTag);
               mwiSubscribeRequest.setToFieldTag(toTag);

               CPPUNIT_ASSERT(notifyRequest);

               CPPUNIT_ASSERT(subscribeResponse->getResponseStatusCode() ==
                              SIP_ACCEPTED_CODE);
            }

            // Wait for the subscription to be ended.
            OsTask::delay(100);

            // Send a re-SUBSCRIBE in the existing dialog, to find out if the
            // subscription was terminated or not.
            mwiSubscribeRequest.incrementCSeqNumber();
            // Leave the Expires header with the default value.

            CPPUNIT_ASSERT(userAgentp->send(mwiSubscribeRequest));

            // We should get a 481 response and no NOTIFY, because the
            // subscription has been terminated.
            {
               const SipMessage* subscribeResponse;
               const SipMessage* notifyRequest;
               runListener(incomingClientMsgQueue,
                           *userAgentp,
                           messageTimeout,
                           messageTimeout,
                           notifyRequest,
                           subscribeResponse,
                           SIP_OK_CODE,
                           FALSE,
                           0,
                           NULL);

               // We should have received a SUBSCRIBE response and no NOTIFY request.
               CPPUNIT_ASSERT(subscribeResponse);
               CPPUNIT_ASSERT(subscribeResponse->getResponseStatusCode() ==
                              SIP_BAD_TRANSACTION_CODE);
               CPPUNIT_ASSERT(!notifyRequest);
            }
         }
      }
Пример #19
0
SubscribeServerThread::SubscribeStatus SubscribeServerThread::addSubscription(
    const int timeNow,
    const SipMessage* subscribeMessage,
    const char* domain,
    const UtlString& eventType,
    const UtlString& eventId,
    const UtlHashMap& eventParams,
    UtlString& newToTag,
    int& grantedExpiration)
{
    SubscribeStatus returnStatus = STATUS_INTERNAL_ERROR;
    int subscribeCseqInt = 0;
    UtlString callId;
    UtlString contactEntry;
    UtlString to;
    UtlString from;
    UtlString route;
    UtlString key;
    UtlString method;
    Url identity;

    //  Construct the identity
    UtlString uriUser, requestUri;
    subscribeMessage->getUri( NULL, NULL, NULL, &uriUser );
    subscribeMessage->getRequestUri( &requestUri );
    identity.setUserId( uriUser );
    identity.setUrlType( "sip" );
    identity.setHostAddress( domain );

    subscribeMessage->getToField(&to);
    subscribeMessage->getFromField(&from);
    subscribeMessage->getCallIdField(&callId);
    subscribeMessage->getCSeqField(&subscribeCseqInt, &method);
    subscribeMessage->getContactEntry(0, &contactEntry);

    subscribeMessage->buildRouteField(&route);
    Url toUrl;
    subscribeMessage->getToUrl(toUrl);
    int commonExpires = -1;
    if ( subscribeMessage->getExpiresField( &commonExpires ) )
    {
       if( commonExpires > 0 ) // came from request
       {
          if (commonExpires < mMinExpiresTimeint)
          {
             returnStatus = STATUS_LESS_THAN_MINEXPIRES;
             OsSysLog::add( FAC_SIP, PRI_ERR, "addSubscription: "
                            "Expires (%d) less than Minimum (%d)",
                           commonExpires, mMinExpiresTimeint);
             return returnStatus;
          }
          else if (commonExpires > mDefaultSubscribePeriod)
          {
             commonExpires = mDefaultSubscribePeriod;
          }
          else
          {
             // commonExpires is in the allowed range - use the requested value
          }
        }
        else if( commonExpires == 0 )
        {
            // remove subscription binding
            // remove all bindings  because one contact value is *
            OsSysLog::add(FAC_SIP, PRI_DEBUG,"SubscribeServerThread::addSubscription -"
                " subscription for url %s and event %s to be removed after sending NOTIFY",
                toUrl.toString().data(), eventType.data());

            returnStatus = STATUS_TO_BE_REMOVED;
            return returnStatus;
        }
        else if( commonExpires == -1) // no expires value in request
        {
            // Assume the default value
            commonExpires = mDefaultSubscribePeriod;
            OsSysLog::add(FAC_SIP, PRI_DEBUG,"SubscribeServerThread::addSubscription -"
                " No Expires Value, assigning default value (%d)", commonExpires);
        }
    }

    UtlString sipxImpliedParameter(SIPX_IMPLIED_SUB);
    UtlString* sipxImpliedDuration = NULL;

    int grantedExpirationTime;
    if ((  sipxImpliedDuration
         = dynamic_cast<UtlString*>(eventParams.findValue(&sipxImpliedParameter))))
    {
       /*
        * This request was generated by the registrar as an implied subscription;
        * its duration must therefore match that of the registration, which has
        * already been randomized.
        */
       grantedExpirationTime = atoi(sipxImpliedDuration->data());
    }
    else
    {
       /*
        * The request is for a new or refreshed subscription (other cases were handled above);
        * commonExpires is now the requested duration in the range:
        *    mMinExpiresTimeint <= commonExpires <= mDefaultSubscribePeriod
        * In order to distribute expirations smoothly, we actually grant a randomized duration
        */
       int spreadFloor = mMinExpiresTimeint*2;

       if ( commonExpires > spreadFloor )
       {
          // a normal (long) registration
          // - spread it between twice the min and the longest they asked for
          grantedExpirationTime = (  (rand() % (commonExpires - spreadFloor))
                                   + spreadFloor);
       }
       else if ( commonExpires > mMinExpiresTimeint )
       {
          // a short but not minimum registration
          // - spread it between the min and the longest they asked for
          grantedExpirationTime = (  (rand()
                                      % (commonExpires - mMinExpiresTimeint)
                                      )
                                   + mMinExpiresTimeint
                                   );
       }
       else // longestExpiration == mMinExpiresTimeint
       {
          // minimum - can't randomize because we can't shorten or lengthen it
          grantedExpirationTime = mMinExpiresTimeint;
       }
    }

    // Handle the to-tag:
    // If no to-tag, this is a new subscription, for which we must create
    // a to-tag.
    // If there is a to-tag, this is a renewal of a subscription, and we
    // must first check that the subscription exists.  (This is because if
    // the UA thinks there is a subscription, but we do not know of it, we
    // cannot reconstitute the subscription, as we do not know the NOTIFY CSeq
    // that the UA expects.  See XECS-406 for the ill consequences of
    // this problem.)

    // Clear the returned new to-tag.
    newToTag.remove(0);
    {
       UtlString x;
       bool r = toUrl.getFieldParameter("tag", x);
       OsSysLog::add(FAC_SIP, PRI_DEBUG,"SubscribeServerThread::addSubscription getting to-tag, return %d, value '%s'",
                     (int) r, x.data());
    }
    UtlString toTag;
    if (toUrl.getFieldParameter("tag", toTag))
    {
       // Check to see if this subscription exists.
       // Critical Section here
       OsLock mutex(mLock);

       bool exists = SubscriptionDB::getInstance()->subscriptionExists(
          SUBSCRIPTION_COMPONENT_STATUS,
          to, from, callId, OsDateTime::getSecsSinceEpoch());

       OsSysLog::add(FAC_SIP, PRI_DEBUG,"SubscribeServerThread::addSubscription subscriptionExists(..., '%s', '%s', '%s', %d) = %d",
                     to.data(), from.data(),
                     callId.data(), (int) OsDateTime::getSecsSinceEpoch(),
                     exists);

       if (!exists)
       {
          returnStatus = STATUS_BAD_SUBSCRIPTION;
          return returnStatus;
       }
    }
    else
    {
       // Generate a random to-tag.
       CallId::getNewTag(newToTag);
       // Add it to the remembered To header value.
       to.append(";tag=");
       to.append(newToTag);
       OsSysLog::add(FAC_SIP, PRI_DEBUG,"SubscribeServerThread::addSubscription generated to-tag '%s'",
                     newToTag.data());
    }

    OsSysLog::add(FAC_SIP, PRI_DEBUG,
                  "SubscribeServerThread::addSubscription -"
                  " Adding/updating subscription for URI '%s' event %s duration %d to '%s'",
                  toUrl.toString().data(), eventType.data(), grantedExpirationTime, contactEntry.data());

    // trim the contact to just the uri
    Url contactUrl(contactEntry);
    contactUrl.getUri(contactEntry);

    // add bindings
    identity.getIdentity( key );

    // Insert or update the information for this subscription.
    // (Note that the "notify CSeq" parameter is ignored if there is
    // an existing SubscriptionDB row for this subscription.)
    if (insertRow(requestUri, // identity,
                  callId,
                  contactEntry,
                  grantedExpirationTime + timeNow,
                  subscribeCseqInt,
                  eventType,
                  eventId,
                  to,
                  from,
                  key,                 // this will be searched for later
                  route,
                  1))                  // initial notify cseq (sent to phone)
    {
       grantedExpiration = grantedExpirationTime;
       returnStatus = STATUS_SUCCESS;
    }
    else
    {
       // log the error and send error indication to subscriber
       OsSysLog::add(FAC_SIP, PRI_ERR,
                     "SubscribeServerThread::addSubscription -"
                     " Could not insert record in Database");

       returnStatus = STATUS_INTERNAL_ERROR;
    }

    return returnStatus;
}
Пример #20
0
UtlBoolean
SubscribeServerThread::isAuthenticated (const SipMessage* message,
                                        SipMessage *responseMessage,
                                        UtlString& authenticatedUser,
                                        UtlString& authenticatedRealm )
{
    UtlBoolean retIsAuthenticated = FALSE;

    // if we are not using a database we must assume authenticated
    if ( !mIsCredentialDB )
    {
        Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthenticated() "
            ":: No Credential DB - request is always AUTHENTICATED");
        retIsAuthenticated = TRUE;
    } else
    {
        // realm and auth type should be default for server
        // if URI not defined in DB, the user is not authorized to modify bindings -
        Os::Logger::instance().log( FAC_AUTH, PRI_DEBUG, "SubscribeServerThread::isAuthenticated():TRUE realm=\"%s\" ",
                mRealm.data());

        UtlString requestNonce;
        UtlString requestCnonce;
        UtlString requestNonceCount;
        UtlString requestQop;
        UtlString requestRealm;
        UtlString requestUser;
        UtlString requestUserBase;
        UtlString requestUriParam;
        int requestAuthIndex = 0;
        EntityDB* entityDb = StatusServer::getInstance()->getEntityDb();
        // can have multiple authorization / authorization-proxy headers
        // headers search for a realm match
        while ( message->getDigestAuthorizationData ( &requestUser,
                                                      &requestRealm,
                                                      &requestNonce,
                                                      NULL, // opaque
                                                      NULL, // response
                                                      &requestUriParam,
                                                      &requestCnonce,
                                                      &requestNonceCount,
                                                      &requestQop,
                                                      HttpMessage::SERVER,
                                                      requestAuthIndex,
                                                      &requestUserBase) )
        {
            Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, 
                          "SubscribeServerThread::isAuthenticated() "
                          "- Authorization header set in message, validate it.\n"
                          "- reqRealm=\"%s\", reqUser=\"%s\", reqUserBase=\"%s\"",
                          requestRealm.data(), requestUser.data(),
                          requestUserBase.data());

            UtlString qopType;
            UtlString callId;
            UtlString fromTag;
            long     nonceExpires = (5*60); // five minutes

            Url fromUrl;
            message->getFromUrl(fromUrl);
            fromUrl.getFieldParameter("tag", fromTag);
            UtlString reqUri;
            message->getRequestUri(&reqUri);
            Url mailboxUrl(reqUri);

            message->getCallIdField(&callId);

            if (mRealm.compareTo(requestRealm) ) // case sensitive check that realm is correct
            {
               Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG,
                             "SubscribeServerThread::isAuthenticated() "
                             "Realm does not match");
            }

            // See if the nonce is valid - see net/SipNonceDb.cpp
            else if (!mNonceDb.isNonceValid(requestNonce, callId, fromTag, mRealm, nonceExpires))
            {
                Os::Logger::instance().log(FAC_AUTH, PRI_INFO,
                              "SubscribeServerThread::isAuthenticated() "
                              "Invalid NONCE: '%s' found for mailboxUrl '%s' "
                              "realm: '%s' user: '******' "
                              "cnonce: '%s' nc: '%s' qop: '%s' "
                              "expiration: %ld",
                              requestNonce.data(), mailboxUrl.toString().data(),
                              mRealm.data(), requestUser.data(), 
                              requestCnonce.data(), requestNonceCount.data(), 
                              requestQop.data(), nonceExpires);
            }

            // verify that qop,cnonce, nonceCount are compatible
            else if (message->verifyQopConsistency(requestCnonce.data(),
                                                     requestNonceCount.data(),
                                                     &requestQop,
                                                     qopType)
                     >= HttpMessage::AUTH_QOP_NOT_SUPPORTED)
            {
                Os::Logger::instance().log(FAC_AUTH, PRI_INFO,
                              "SubscribeServerThread::isAuthenticated() "
                              "Invalid combination of QOP('%s'), cnonce('%s') and nonceCount('%s')",
                              requestQop.data(), requestCnonce.data(), requestNonceCount.data());
            }

            else // realm, nonce and qop are all ok
            {    
                UtlString authTypeDB;
                UtlString passTokenDB;

                // then get the credentials for this realm
                if (entityDb->getCredential(mailboxUrl, mRealm, requestUserBase, passTokenDB, authTypeDB))
                {
                    // the Digest Password is calculated from the request
                    // user, passtoken, nonce and request URI

                    retIsAuthenticated =
                       message->verifyMd5Authorization(requestUser.data(),
                                                       passTokenDB.data(),
                                                       requestNonce.data(),
                                                       requestRealm.data(),
                                                       requestCnonce.data(),
                                                       requestNonceCount.data(),
                                                       requestQop.data(),
                                                       requestUriParam.data());
                    if (retIsAuthenticated)
                    {
                        // can have multiple credentials for same realm so only break out
                        // when we have a positive match
                        Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, 
                                      "SubscribeServerThread::isAuthenticated() "
                                      "- request is AUTHENTICATED");
                        // copy the authenticated user/realm for subsequent authorization
                        authenticatedUser = requestUserBase;
                        authenticatedRealm = requestRealm;
                        break;
                    }
                    else
                    {
                        Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG,
                                      "SubscribeServerThread::isAuthenticated() "
                                      "- digest authorization failed "
                                      "nonce \"%s\", cnonce \"%s\" for "
                                      "mailboxUrl=\"%s\", reqRealm=\"%s\", reqUser=\"%s\"",
                                      requestNonce.data(),
                                      requestCnonce.data(),
                                      mailboxUrl.toString().data(),
                                      requestRealm.data(),
                                      requestUser.data());
                    }
                }
                else
                {
                    Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, 
                                  "SubscribeServerThread::isAuthenticated() "
                                  "- No Credentials for mailboxUrl=\"%s\", reqRealm=\"%s\", reqUser=\"%s\"",
                        mailboxUrl.toString().data(),
                        requestRealm.data(),
                        requestUser.data());
                }  // end check credentials
            }
            requestAuthIndex++;
        } //end while

        if ( !retIsAuthenticated )
        {
            // Generate the 401 Unauthorized response to challenge for credentials
            // Use the SipNonceDB to generate a nonce
            UtlString newNonce;
            UtlString callId;
            UtlString fromTag;

            Url fromUrl;
            message->getFromUrl(fromUrl);
            fromUrl.getFieldParameter("tag", fromTag);

            message->getCallIdField(&callId);

            mNonceDb.createNewNonce(callId,
                                    fromTag,
                                    mRealm,
                                    newNonce);

            responseMessage->setRequestUnauthorized(message, HTTP_DIGEST_AUTHENTICATION,
                                                    mRealm, newNonce);
        }
    }  // end DB exists
    return retIsAuthenticated;
}