Example #1
0
UtlBoolean SipDialogMgr::createDialog(const SipMessage& message, 
                                      UtlBoolean messageIsFromLocalSide,
                                      const char* dialogHandle)
{
    UtlBoolean createdDialog = FALSE;
    UtlString handle(dialogHandle ? dialogHandle : "");
    // If the dialog handle was not set, get it from the message
    if(handle.isNull())
    {
        message.getDialogHandle(handle);
    }

    // Check to see if the dialog exists
    if(dialogExists(handle) ||
        earlyDialogExistsFor(handle))
    {
        // Should not try to create a dialog for one that
        // already exists
        OsSysLog::add(FAC_SIP, PRI_ERR,
            "SipDialogMgr::createDialog called with handle: %s for existing dialog",
            handle.data());
    }

    // Dialog needs to be created
    else
    {
        createdDialog = TRUE;
        SipDialog* dialog = new SipDialog(&message, messageIsFromLocalSide);
        lock();
        mDialogs.insert(dialog);
        unlock();
    }

    return(createdDialog);
}
Example #2
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())
    {
        message.getDialogHandle(handle);
    }

    UtlString callId;
    UtlString fromTag;
    UtlString toTag;
    SipDialog::parseHandle(handle, callId, fromTag, 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);
}
Example #3
0
UtlBoolean SipDialogMgr::setNextLocalTransactionInfo(SipMessage& request,
                                                     const char* method,
                                                     const char* dialogHandle)
{
    UtlBoolean requestSet = FALSE;
    UtlString dialogHandleString(dialogHandle ? dialogHandle : "");
    if(dialogHandleString.isNull())
    {
        request.getDialogHandle(dialogHandleString);
    }

    lock();
    SipDialog* dialog = findDialog(dialogHandleString,
                                   FALSE, // If established only want exact match dialogs
                                   TRUE); // If message is from a prior transaction
                                          // when the dialog was in an early state
                                          // allow it to match an established
                                          // dialog
    if(dialog)
    {
        dialog->setRequestData(request, method);
        requestSet = TRUE;

#ifdef TEST_PRINT
        UtlString dialogDump;
        dialog->toString(dialogDump);
        OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipDialogMgr::setNextLocalTransactionInfo dialog: '%s'",
                      dialogDump.data());
#endif
    }
    else
    {
       OsSysLog::add(FAC_SIP, PRI_ERR, "SipDialogMgr::setNextLocalTransactionInfo dialog not found for handle '%s'",
                     dialogHandle);

       if (OsSysLog::willLog(FAC_SIP, PRI_DEBUG))
       {
          SipDialog* dialog;
          UtlHashBagIterator iterator(mDialogs);
          
          while ((dialog = (SipDialog*) iterator()))
          {
             UtlString callId, localTag, remoteTag;
             dialog->getCallId(callId);
             dialog->getLocalTag(localTag);
             dialog->getRemoteTag(remoteTag);
             OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipDialogMgr::setNextLocalTransactionInfo dialog call-id = '%s', local tag = '%s', remote tag = '%s'",
                           callId.data(), localTag.data(), remoteTag.data());
          }
       }
    }

    unlock();

    return(requestSet);
}
UtlBoolean SipSubscribeServer::handleNotifyResponse(const SipMessage& notifyResponse)
{
    UtlBoolean handledNotifyResponse = FALSE;
    int responseCode = notifyResponse.getResponseStatusCode();

    // Ignore provisional responses or success cases
    if(responseCode >= SIP_3XX_CLASS_CODE)
    {
        UtlString dialogHandle;
        notifyResponse.getDialogHandle(dialogHandle);

        // Not modifying the SubscribeServerEventData, just reading it
        lockForRead();

        // Get the event specific handler and information
        SubscribeServerEventData* eventPackageInfo = NULL;
        UtlHashMapIterator iterator(mEventDefinitions);
        
        while((eventPackageInfo = (SubscribeServerEventData*) iterator()))
        {
            // End this subscription as we got an error response from
            // the NOTIFY request.
            // Returns TRUE if the SipSubscriptionMgr has this dialog
            handledNotifyResponse = 
                eventPackageInfo->mpEventSpecificSubscriptionMgr->endSubscription(
                                                                    dialogHandle);
            if(handledNotifyResponse)
            {
                break;
            }
        }

        unlockForRead();

        // Should not happen, first of all we should never get a
        // response which does not correspond to a request sent from 
        // the SipUserAgent.  Secondly, we should not get a response to
        // and event type that we do not support
        if(!handledNotifyResponse)
        {
            OsSysLog::add(FAC_SIP, PRI_ERR,
                "SipSubscribeServer::handleNotifyResponse NOTIFY response with no dialog. Handle: %s",
                 dialogHandle.data());
        }
    }

    // Provisional or 2XX class responses
    else
    {
        handledNotifyResponse = TRUE;
    }

    return(handledNotifyResponse);
}
Example #5
0
UtlBoolean SipDialog::isEarlyDialogFor(const SipMessage& message) const
{
    UtlString handle;

    message.getDialogHandle(handle);

    UtlString callId;
    UtlString localTag;
    UtlString remoteTag;
    parseHandle(handle, callId, localTag, remoteTag);

    return(isEarlyDialogFor(callId, localTag, remoteTag));
}
Example #6
0
enum SipDialogMgr::transactionSequence
    SipDialogMgr::isNewRemoteTransaction(const SipMessage& message)
{
    enum transactionSequence ordering;
    UtlString handle;
    message.getDialogHandle(handle);

    UtlString callId;
    UtlString fromTag;
    UtlString toTag;
    SipDialog::parseHandle(handle, callId, fromTag, 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))
    {
       int messageCSeq;
       message.getCSeqField(&messageCSeq, NULL);
       int lastRemoteCSeq = dialog->getLastRemoteCseq();
       ordering =
          messageCSeq < lastRemoteCSeq ? OUT_OF_ORDER :
          /** If this message was an exact duplicate of a previous message
           *  (with the same CSeq and branch parameter), it would have been
           *  absorbed earlier in processing.  So we know the branch parameter
           *  is different without having to remember the previous value.
           */
          messageCSeq == lastRemoteCSeq ? LOOPED :
          IN_ORDER;
    }
    else
    {
       ordering = NO_DIALOG;
    }

    unlock();
    
    return ordering;
}
Example #7
0
UtlBoolean SipDialogMgr::updateDialog(const SipMessage& message, 
                                      const char* dialogHandle)
{
    UtlString handle(dialogHandle ? dialogHandle : "");
    // If the dialog handle was not set, get it from the message
    if(handle.isNull())
    {
        message.getDialogHandle(handle);
    }

    lock();
    
    SipDialog* dialog = findDialog(handle,
                                   TRUE, // if established handle, find early dialog
                                   FALSE); // do not want established dialogs for early handle
    if(dialog)
    {
#ifdef TEST_PRINT
        UtlString dialogDump;
        dialog->toString(dialogDump);
        printf("SipDialogMgr::updateDialog dialog before:\n%s\n",
               dialogDump.data());
#endif

        dialog->updateDialogData(message);

#ifdef TEST_PRINT
        dialog->toString(dialogDump);
        printf("SipDialogMgr::updateDialog dialog after:\n%s\n",
               dialogDump.data());
#endif
    }


    unlock();

    return(dialog != NULL);
}
Example #8
0
// Send a NOTIFY to all subscribers to the given resourceId and eventTypeKey.
UtlBoolean SipSubscribeServer::notifySubscribers(const char* resourceId,
                                                 const char* eventTypeKey,
                                                 const char* eventType,
                                                 const char* reason)
{
   OsSysLog::add(FAC_SIP, PRI_DEBUG,
                 "SipSubscribeServer::notifySubscribers resourceId '%s', eventTypeKey '%s', eventType '%s', reason '%s'",
                 resourceId, eventTypeKey, eventType,
                 reason ? reason : "[null]");
    UtlBoolean notifiedSubscribers = FALSE;
    UtlString eventName(eventType);

    lockForRead();
    SubscribeServerEventData* eventData =
       dynamic_cast <SubscribeServerEventData*>
           (mEventDefinitions.find(&eventName));

    // Get the event-specific info to find subscriptions interested in
    // this content.
    if (eventData)
    {
        int numSubscriptions = 0;
        SipMessage** notifyArray = NULL;
        UtlString** acceptHeaderValuesArray = NULL;

        // Select the subscriptionChange value to describe what we're doing
        // with the subscriptions.
        enum SipSubscriptionMgr::subscriptionChange change;

        {
           // Select the correct format for generating the Subscription-State value.
           UtlString* formatp = NULL; // We may need a temp UtlString.
           const char* format;

           if (reason == NULL)
           {
              format = "active;expires=%ld";
              change = SipSubscriptionMgr::subscriptionContinues;
           }
           else if (strcmp(reason, terminationReasonSilent) == 0)
           {
              // Do not admit that the subscription is ending.
              format = "active;expires=%ld";
              change = SipSubscriptionMgr::subscriptionTerminatedSilently;
           }
           else if (strcmp(reason, terminationReasonNone) == 0)
           {
              format = "terminated";
              change = SipSubscriptionMgr::subscriptionTerminated;
           }
           else
           {
              // Allocate a UtlString and assemble the Subscription-State format in it.
              formatp = new UtlString();
              formatp->append("terminated;reason=");
              formatp->append(reason);
              format = formatp->data();
              change = SipSubscriptionMgr::subscriptionTerminated;
           }

           // Construct a NOTIFY (without body) for each subscription, containing
           // the dialog-related information about each subscription.
           eventData->mpEventSpecificSubscriptionMgr->
              createNotifiesDialogInfo(resourceId,
                                       eventTypeKey,
                                       format,
                                       numSubscriptions,
                                       acceptHeaderValuesArray,
                                       notifyArray);

           OsSysLog::add(FAC_SIP, PRI_DEBUG,
                         "SipSubscribeServer::notifySubscribers numSubscriptions for '%s' = %d",
                         resourceId, numSubscriptions);

           // Free the temporary UtlString, if necessary.
           if (formatp)
           {
              delete formatp;
           }
        }

        // For each NOTIFY, add the subscription-related information and then
        // send it.
        for (int notifyIndex = 0;
             notifyIndex < numSubscriptions;
             notifyIndex++)
        {
            SipMessage* notify = notifyArray[notifyIndex];

            // Check to see if the dialog information could be added.
            // (The subscription might have been destroyed between when
            // it was decided to respond to it, and when the dialog information
            // was retrieved.)
            UtlString callId;
            notify->getCallIdField(&callId);
            if (!callId.isNull())
            {
               if (change != SipSubscriptionMgr::subscriptionTerminatedSilently)
               {
                  // Fill in the NOTIFY request body/content
                  eventData->mpEventSpecificHandler->
                     getNotifyContent(resourceId,
                                      eventTypeKey,
                                      eventType,
                                      *(eventData->mpEventSpecificContentMgr),
                                      *(acceptHeaderValuesArray[notifyIndex]),
                                      *notify,
                                      eventData->mEventSpecificFullState,
                                      NULL);

                  // Call the application callback to edit the NOTIFY
                  // content if that is required for this event type.
                  // Also gets 'version' (if relevant) and 'savedEventTypeKey'.
                  int version;
                  UtlString savedEventTypeKey;
                  eventData->mpEventSpecificSubscriptionMgr->
                     updateNotifyVersion(eventData->mpEventSpecificContentVersionCallback,
                                         *notify,
                                         version,
                                         savedEventTypeKey);

                  // Update the saved record of the NOTIFY CSeq and the
                  // XML version number for the specified savedEventTypeKey,
                  // as needed by the subscription manager.
                  // In practice, this is only used by SipPersistentSubscriptionMgr
                  // to write the NOTIFY Cseq and XML version into the IMDB.
                  eventData->mpEventSpecificSubscriptionMgr->
                     updateVersion(*notify, version, savedEventTypeKey);

                  // Set the Contact header.
                  setContact(notify);

                  // Send the NOTIFY request.
                  eventData->mpEventSpecificUserAgent->send(*notify);
               }

               if (change != SipSubscriptionMgr::subscriptionContinues)
               {
                  // Remove the record of the subscription.
                  UtlString dialogHandle;
                  notify->getDialogHandle(dialogHandle);
                  eventData->mpEventSpecificSubscriptionMgr->
                     endSubscription(dialogHandle, change);
               }
            }
        }

        // Free the NOTIFY requests and accept header field values.
        eventData->mpEventSpecificSubscriptionMgr->
           freeNotifies(numSubscriptions,
                        acceptHeaderValuesArray,
                        notifyArray);
    }
    // event type not enabled
    else
    {
        OsSysLog::add(FAC_SIP, PRI_ERR,
                      "SipSubscribeServer::notifySubscribers "
                      "event type: %s not enabled - "
                      "Why are we seeing a callback for this?",
            eventName.data());
    }

    unlockForRead();

    return notifiedSubscribers;
}
Example #9
0
/// Terminate all subscriptions and accept no new ones.
void SipSubscribeServer::shutdown(const char* reason)
{
   // If reason is NULL, use the default reason established by the constructor.
   if (!reason)
   {
      reason = mDefaultTermination;
   }

   OsSysLog::add(FAC_SIP, PRI_DEBUG,
                 "SipSubscribeServer::shutdown reason '%s'",
                 reason ? reason : "[null]");                 

   lockForRead();

   // Select the subscriptionChange value to describe what we're doing
   // with the subscriptions.
   enum SipSubscriptionMgr::subscriptionChange change;

   // Select the correct format for generating the Subscription-State value.
   UtlString* formatp = NULL; // We may need a temp UtlString.
   const char* format;

   if (reason == NULL)
   {
      format = "active;expires=%ld";
      change = SipSubscriptionMgr::subscriptionContinues;
   }
   else if (strcmp(reason, terminationReasonSilent) == 0)
   {
      // Do not admit that the subscription is ending.
      format = "active;expires=%ld";
      change = SipSubscriptionMgr::subscriptionTerminatedSilently;
   }
   else if (strcmp(reason, terminationReasonNone) == 0)
   {
      format = "terminated";
      change = SipSubscriptionMgr::subscriptionTerminated;
   }
   else
   {
      // Allocate a UtlString and assemble the Subscription-State format in it.
      formatp = new UtlString();
      formatp->append("terminated;reason=");
      formatp->append(reason);
      format = formatp->data();
      change = SipSubscriptionMgr::subscriptionTerminated;
   }

   // For each event type that is registered, delete all the subscriptions.

   UtlHashBagIterator event_itor(mEventDefinitions);
   SubscribeServerEventData* eventData;
   while ((eventData =
              dynamic_cast <SubscribeServerEventData*> (event_itor())))
   {
      // Unregister interest in SUBSCRIBE requests and NOTIFY
      // responses for this event type, so we do not service new subscriptions.

      eventData->mpEventSpecificUserAgent->removeMessageObserver(*(getMessageQueue()));
      
      int numSubscriptions = 0;
      SipMessage** notifyArray = NULL;
      UtlString** acceptHeaderValuesArray = NULL;
      UtlString** resourceIdArray = NULL;
      UtlString** eventTypeKeyArray = NULL;

      // :TODO: The four situations where NOTIFYs are generated should
      // be factored into a series of methods in
      // mpEventSpecificSubscriptionMgr that generate NOTIFYs
      // sequentially, and for each NOTIFY, call a common service
      // method that does the remaining operations and sends the
      // NOTIFY.

      // Construct a NOTIFY (without body) for every subscription, containing
      // the dialog-related information about each subscription.
      eventData->mpEventSpecificSubscriptionMgr->
         createNotifiesDialogInfoEvent(static_cast <const UtlString&> (*eventData),
                                       format,
                                       numSubscriptions,
                                       acceptHeaderValuesArray,
                                       notifyArray,
                                       resourceIdArray,
                                       eventTypeKeyArray);

      OsSysLog::add(FAC_SIP, PRI_DEBUG,
                    "SipSubscribeServer::shutdown eventType = '%s', numSubscriptions = %d",
                    eventData->data(), numSubscriptions);

      // For each NOTIFY, add the subscription-related information and then
      // send it.
      for (int notifyIndex = 0;
           notifyIndex < numSubscriptions;
           notifyIndex++)
      {
         SipMessage* notify = notifyArray[notifyIndex];

         // Check to see if the dialog information could be added.
         // (The subscription might have been destroyed between when
         // it was decided to respond to it, and when the dialog information
         // was retrieved.)
         UtlString callId;
         notify->getCallIdField(&callId);
         if (!callId.isNull())
         {
            if (change != SipSubscriptionMgr::subscriptionTerminatedSilently)
            {
               // Fill in the NOTIFY request body/content
               eventData->mpEventSpecificHandler->
                  getNotifyContent(*(resourceIdArray[notifyIndex]),
                                   *(eventTypeKeyArray[notifyIndex]),
                                   *eventData,
                                   *(eventData->mpEventSpecificContentMgr),
                                   *(acceptHeaderValuesArray[notifyIndex]),
                                   *notify,
                                   eventData->mEventSpecificFullState,
                                   NULL);

               // Call the application callback to edit the NOTIFY
               // content if that is required for this event type.
               // Also gets 'version' (if relevant) and 'savedEventTypeKey'.
               int version;
               UtlString savedEventTypeKey;
               eventData->mpEventSpecificSubscriptionMgr->
                  updateNotifyVersion(eventData->mpEventSpecificContentVersionCallback,
                                      *notify,
                                      version,
                                      savedEventTypeKey);

               // Set the Contact header.
               setContact(notify);

               // Send the NOTIFY request.
               eventData->mpEventSpecificUserAgent->send(*notify);
            }

            // Remove the record of the subscription.
            UtlString dialogHandle;
            notify->getDialogHandle(dialogHandle);
            eventData->mpEventSpecificSubscriptionMgr->
               endSubscription(dialogHandle, change);
         }
      }

      // Free the NOTIFY requests and accept header field values.
      SipSubscriptionMgr::freeNotifies(numSubscriptions,
                                       acceptHeaderValuesArray,
                                       notifyArray);

      // Free the resource and event type arrays.
      for (int index = 0;
           index < numSubscriptions;
           index++)
      {
         delete resourceIdArray[index];
         delete eventTypeKeyArray[index];
      }
      delete[] resourceIdArray;
      delete[] eventTypeKeyArray;

      // Remove eventData from mEventDefinitions.
      mEventDefinitions.removeReference(eventData);
      delete eventData;
   }

   unlockForRead();

   // Free the temporary UtlString, if necessary.
   if (formatp)
   {
      delete formatp;
   }

   lockForWrite();
   mEventDefinitions.destroyAll();
   unlockForWrite();
}
Example #10
0
UtlBoolean SipRefreshManager::initiateRefresh(SipMessage& subscribeOrRegisterRequest,
                                               void* applicationData,
                                               const RefreshStateCallback refreshStateCallback,
                                               UtlString& earlyDialogHandle)
{

    UtlBoolean intitialRequestSent = FALSE;

    // Make sure we do not have an existing dialog or refresh session state
    // going for the given message
    UtlString messageDialogHandle;
    subscribeOrRegisterRequest.getDialogHandle(messageDialogHandle);
    UtlBoolean existingRefreshState = FALSE;
    UtlBoolean existingDialogState = FALSE;
    if(!SipDialog::isEarlyDialog(messageDialogHandle))
    {
        existingDialogState = TRUE;
        OsSysLog::add(FAC_SIP, PRI_ERR,
                "SipRefreshManager::initiateRefresh called with established dialog handle: %s",
                messageDialogHandle.data());
    }

    else
    {
        OsLock localLock(mRefreshMgrMutex);
        // See if there is an early or established dialog for this message
        if(getAnyDialog(messageDialogHandle))
        {
            existingRefreshState = TRUE;
            intitialRequestSent = FALSE;
            OsSysLog::add(FAC_SIP, PRI_ERR,
                "SipRefreshManager::initiateRefresh called with pre-existing refresh state: %s",
                messageDialogHandle.data());
        }

        // The dialog should not exist either
        else if(mpDialogMgr->dialogExists(messageDialogHandle) ||
            mpDialogMgr->earlyDialogExistsFor(messageDialogHandle))
        {
            existingDialogState = TRUE;
            OsSysLog::add(FAC_SIP, PRI_ERR,
                "SipRefreshManager::initiateRefresh called with pre-existing dialog: %s",
                messageDialogHandle.data());
        }
    }

    // Should not be any existing refresh or dialog states
    // for this message
    if(!existingRefreshState && !existingDialogState)
    {
        // Make sure we are registered to receive responses
        // for the message we are about to send
        UtlString method;
        subscribeOrRegisterRequest.getRequestMethod(&method);
        if(method.compareTo(SIP_REGISTER_METHOD) == 0)
        {
            lock();
            if(!mReceivingRegisterResponses)
            {
                mReceivingRegisterResponses = TRUE;
                // receive REGISTER responses 
                mpUserAgent->addMessageObserver(*(getMessageQueue()), 
                                                SIP_REGISTER_METHOD,
                                                FALSE, // yes requests
                                                TRUE, // no responses
                                                TRUE, // incoming,
                                                FALSE, // outgoing
                                                NULL);
            }
            unlock();
        }
        else if(method.compareTo(SIP_SUBSCRIBE_METHOD) == 0)
        {
            UtlString eventType;
            subscribeOrRegisterRequest.getEventField(&eventType, NULL);
            // Check to see if we have already registered to
            // receive the event type
            lock();
            if(mEventTypes.find(&eventType) == NULL)
            {
                mEventTypes.insert(new UtlString(eventType));
                // receive SUBSCRIBE responses for this event type
                mpUserAgent->addMessageObserver(*(getMessageQueue()), 
                                                SIP_SUBSCRIBE_METHOD,
                                                FALSE, // no requests
                                                TRUE, // yes responses
                                                TRUE, // incoming,
                                                FALSE, // outgoing
                                                eventType);
            }
            unlock();

        }

        // Create a new refresh state
        int requestedExpiration = 0;  // returned from following call
        RefreshDialogState* state = createNewRefreshState(subscribeOrRegisterRequest,
                                                        messageDialogHandle,
                                                        applicationData,
                                                        refreshStateCallback,
                                                        requestedExpiration);

        // create a new dialog
        mpDialogMgr->createDialog(subscribeOrRegisterRequest, 
                                  TRUE, // message from this side
                                  messageDialogHandle);

        // Keep track of when we send this request to be refreshed
        long now = OsDateTime::getSecsSinceEpoch();
        state->mPendingStartTime = now;
        state->mRequestState = REFRESH_REQUEST_PENDING;

        // Set a timer  at which to resend the next refresh based upon the 
        // assumption that the request will succeed.  When we receive a 
        // failed response, we will cancel the timer and reschedule
        // a new timer based upon a smaller fraction of the requested 
        // expiration period 
        setRefreshTimer(*state, 
                        TRUE); // Resend with successful timeout
        OsTimer* resendTimer = state->mpRefreshTimer;

        // Mark the refresh state as having an outstanding request
        // and make a copy of the request.  The copy needs to be
        // attached to the state before the send incase the response
        // comes back before we return from the send.
        state->mRequestState = REFRESH_REQUEST_PENDING;
        state->mpLastRequest = new SipMessage(subscribeOrRegisterRequest);

        // Add the state to the container of refresh states
        // No need to lock this refreshMgr earlier as this is a new
        // state and no one can touch it until it is in the list.
        lock();
        mRefreshes.insert(state);
        unlock();
        // NOTE: at this point is is no longer safe to touch the state
        // without locking it again.  Avoid locking this refresh mgr
        // when something can block (e.g. like calling SipUserAgent ::send)

        // Send the request
        // Is the correct?  Should we send the request first and only set
        // a timer if the request succeeds??
        intitialRequestSent = mpUserAgent->send(subscribeOrRegisterRequest);

        // We do not clean up the state even if the send fails.
        // The application must end the refresh as the refresh
        // manager should retry the send if it failed
        if(!intitialRequestSent)
        {
            // Need to lock this refresh mgr and make sure the state
            // still exists.  It could have been deleted while this
            // was unlocked above.
            lock();
            if(stateExists(state))
            {
                // It is now safe to touch the state again

                // Mark the state of the last request as having 
                // failed, so we know to resend when the timer
                // fires
                state->mRequestState = REFRESH_REQUEST_FAILED;

                // The expiration should still be set to zero

                // the initial send failed, cancel the timer and
                // fire the notification.  The handleMessage method
                // will see that the subscription or registration
                // has never succeeded and reshedule the timer for
                // a failure timeout.  We cannot reschedule the
                // timer here as there is a race condition between
                // deleting the timer here (in the applications context)
                // and in handleMessage in this refresh manager's 
                // context.
                // If the timer has not changed assume it is still safe
                // to touch it
                if(state->mpRefreshTimer == resendTimer)
                {
                    stopTimerForFailureReschedule(state->mpRefreshTimer);
                }

                // Do not notify the application that the request failed
                // when it occurs on the first invokation.  The application
                // will know by the return.
            }
            unlock();
        }
    }

    return(intitialRequestSent);
}
Example #11
0
UtlBoolean SipSubscriptionMgr::insertDialogInfo(const SipMessage& subscribeRequest,
                                                const UtlString& resourceId,
                                                const UtlString& eventTypeKey,
                                                UtlString& subscribeDialogHandle,
                                                UtlBoolean& isNew,
                                                UtlBoolean& isSubscriptionExpired,
                                                SipMessage& subscribeResponse)
{
    isNew = FALSE;
    UtlBoolean subscriptionSucceeded = FALSE;
    UtlString dialogHandle;
    subscribeRequest.getDialogHandle(dialogHandle);
    SubscriptionServerState* state = NULL;
    int expiration = -1;
    isSubscriptionExpired = TRUE;

    // If this is an early dialog we need to make it an established dialog.
    if(SipDialog::isEarlyDialog(dialogHandle))
    {
        UtlString establishedDialogHandle;
        if(mDialogMgr.getEstablishedDialogHandleFor(dialogHandle, establishedDialogHandle))
        {
            OsSysLog::add(FAC_SIP, PRI_WARNING,
                "Incoming early SUBSCRIBE dialog: %s matches established dialog: %s",
                dialogHandle.data(), establishedDialogHandle.data());
        }

        // make up a To tag and set it
        UtlString toTag;
        CallId::getNewTag(dialogHandle.data(), toTag);

        // Get and validate the expires period
        // This potentially should be delegated to the event handler specifics
        if(!subscribeRequest.getExpiresField(&expiration))
        {
            expiration = mDefaultExpiration;
        }

        else if(expiration > mMaxExpiration)
        {
            expiration = mMaxExpiration;
        }

        // Acceptable expiration, create a subscription and dialog
        if(expiration >= mMinExpiration ||
           expiration == 0 ||
           // :WORKAROUND:  Also allow expiration == 1, to support the
           // 1-second subscriptions the pick-up agent makes because
           // current Snom phones do not respond to 0-second subscriptions.
           // See XPB-399 and ENG-319.
           expiration == 1)
        {
            // Create a dialog and subscription state even if
            // the expiration is zero as we need the dialog info
            // to route the one-time NOTIFY.  The immediately
            // expired dialog will be garbage collected.

            SipMessage* subscribeCopy = new SipMessage(subscribeRequest);
            subscribeCopy->setToFieldTag(toTag);

            // Re-get the dialog handle now that the To tag is set
            subscribeCopy->getDialogHandle(dialogHandle);

            // Create the dialog
            mDialogMgr.createDialog(*subscribeCopy, FALSE, dialogHandle);
            isNew = TRUE;

            // Create a subscription state
            state = new SubscriptionServerState();
            *((UtlString*) state) = dialogHandle;
            state->mEventTypeKey = eventTypeKey;
            state->mpLastSubscribeRequest = subscribeCopy;
            state->mResourceId = resourceId;
            subscribeCopy->getAcceptField(state->mAcceptHeaderValue);

            long now = OsDateTime::getSecsSinceEpoch();
            state->mExpirationDate = now + expiration;

            // TODO: currently the SipSubsribeServer does not handle timeout
            // events to send notifications that the subscription has ended.
            // So we do not set a timer at the end of the subscription
            state->mpExpirationTimer = NULL;

            // Create the index by resourceId and eventTypeKey key
            SubscriptionServerStateIndex* stateKey = new SubscriptionServerStateIndex;
            *((UtlString*) stateKey) = resourceId;
            stateKey->append(eventTypeKey);
            stateKey->mpState = state;

            subscribeResponse.setResponseData(subscribeCopy, 
                                              SIP_ACCEPTED_CODE,
                                              SIP_ACCEPTED_TEXT, 
                                              NULL);
            subscribeResponse.setExpiresField(expiration);
            subscribeCopy->getDialogHandle(subscribeDialogHandle);

            lock();
            mSubscriptionStatesByDialogHandle.insert(state);
            mSubscriptionStateResourceIndex.insert(stateKey);
            if (OsSysLog::willLog(FAC_SIP, PRI_DEBUG))
            {
               UtlString requestContact;
               subscribeRequest.getContactField(0, requestContact);
               OsSysLog::add(FAC_SIP, PRI_DEBUG,
                             "SipSubscriptionMgr::insertDialogInfo insert early-dialog subscription for dialog handle '%s', key '%s', contact '%s', mExpirationDate %ld",
                             state->data(), stateKey->data(),
                             requestContact.data(), state->mExpirationDate);
            }

            // Not safe to touch these after we unlock
            stateKey = NULL;
            state = NULL;
            subscribeCopy = NULL;
            unlock();

            subscriptionSucceeded = TRUE;

            // One time subscribe?
            isSubscriptionExpired = expiration == 0;
        }
        // Expiration too small
        else
        {
            // Set expiration too small error
            subscribeResponse.setResponseData(&subscribeRequest, 
                                                SIP_TOO_BRIEF_CODE,
                                                SIP_SUB_TOO_BRIEF_TEXT);
            subscribeResponse.setMinExpiresField(mMinExpiration);
            isSubscriptionExpired = TRUE;
        }
    }

    // Not an early dialog handle -- The dialog for this message may already exist
    else
    {
        // Get and validate the expires period
        // This potentially should be delegated to the event handler specifics
        if(!subscribeRequest.getExpiresField(&expiration))
        {
            expiration = mDefaultExpiration;
        }

        else if(expiration > mMaxExpiration)
        {
            expiration = mMaxExpiration;
        }

        // Acceptable expiration, create a subscription and dialog
        if(expiration > mMinExpiration ||
           expiration == 0)
        {
            // Update the dialog state
            mDialogMgr.updateDialog(subscribeRequest, dialogHandle);

            // Get the subscription state and update that
            // TODO:  This assumes that no one reuses the same dialog
            // to subscribe to more than one event type.  mSubscriptionStatesByDialogHandle
            // will need to be changed to a HashBag and we will need to
            // search through to find a matching event type
            lock();
            state = (SubscriptionServerState*)
                mSubscriptionStatesByDialogHandle.find(&dialogHandle);
            if(state)
            {
                long now = OsDateTime::getSecsSinceEpoch();
                state->mExpirationDate = now + expiration;
                if(state->mpLastSubscribeRequest)
                {
                    delete state->mpLastSubscribeRequest;
                }
                state->mpLastSubscribeRequest = new SipMessage(subscribeRequest);
                subscribeRequest.getAcceptField(state->mAcceptHeaderValue);

                // Set the contact to the same request URI that came in
                UtlString contact;
                subscribeRequest.getRequestUri(&contact);

                // Add the angle brackets for contact
                Url url(contact);
                url.includeAngleBrackets();
                contact = url.toString();

                subscribeResponse.setResponseData(&subscribeRequest, 
                                                SIP_ACCEPTED_CODE,
                                                SIP_ACCEPTED_TEXT, 
                                                contact);
                subscribeResponse.setExpiresField(expiration);
                subscriptionSucceeded = TRUE;
                isSubscriptionExpired = FALSE;
                subscribeDialogHandle = dialogHandle;
            }

            // No state, but SUBSCRIBE had a to-tag.
            else
            {
                SipMessage* subscribeCopy = new SipMessage(subscribeRequest);
                // Create the dialog
                mDialogMgr.createDialog(*subscribeCopy, FALSE, dialogHandle);
                isNew = TRUE;

                // Create a subscription state
                state = new SubscriptionServerState();
                *((UtlString*)state) = dialogHandle;
                state->mEventTypeKey = eventTypeKey;
                state->mpLastSubscribeRequest = subscribeCopy;
                state->mResourceId = resourceId;
                subscribeCopy->getAcceptField(state->mAcceptHeaderValue);

                long now = OsDateTime::getSecsSinceEpoch();
                state->mExpirationDate = now + expiration;
                // TODO: currently the SipSubsribeServer does not handle timeout
                // events to send notifications that the subscription has ended.
                // So we do not set a timer at the end of the subscription
                state->mpExpirationTimer = NULL;

                // Create the index by resourceId and eventTypeKey key
                SubscriptionServerStateIndex* stateKey = new SubscriptionServerStateIndex;
                *((UtlString*)stateKey) = resourceId;
                stateKey->append(eventTypeKey);
                stateKey->mpState = state;
                mSubscriptionStatesByDialogHandle.insert(state);
                mSubscriptionStateResourceIndex.insert(stateKey);
                if (OsSysLog::willLog(FAC_SIP, PRI_DEBUG))
                {
                   UtlString requestContact;
                   subscribeRequest.getContactField(0, requestContact);
                   OsSysLog::add(FAC_SIP, PRI_DEBUG,
                         "SipSubscriptionMgr::insertDialogInfo insert subscription for key '%s', contact '%s', mExpirationDate %ld",
                         stateKey->data(), requestContact.data(), state->mExpirationDate);
                }

                // Not safe to touch these after we unlock
                stateKey = NULL;
                state = NULL;
                subscribeCopy = NULL;

                // Set the contact to the same request URI that came in
                UtlString contact;
                subscribeRequest.getRequestUri(&contact);

                // Add the angle brackets for contact
                Url url(contact);
                url.includeAngleBrackets();
                contact = url.toString();

                subscribeResponse.setResponseData(&subscribeRequest, 
                                                  SIP_ACCEPTED_CODE,
                                                  SIP_ACCEPTED_TEXT, 
                                                  contact);
                subscribeResponse.setExpiresField(expiration);
                subscriptionSucceeded = TRUE;
                // Unsubscribe
                if(expiration == 0)
                {
                    isSubscriptionExpired = TRUE;
                }
                else
                {
                    isSubscriptionExpired = FALSE;
                }
                subscribeDialogHandle = dialogHandle;
            }
            unlock();
        }

        // Expiration too small
        else
        {
            // Set expiration too small error
            subscribeResponse.setResponseData(&subscribeRequest, 
                                                SIP_TOO_BRIEF_CODE,
                                                SIP_SUB_TOO_BRIEF_TEXT);
            subscribeResponse.setMinExpiresField(mMinExpiration);
            isSubscriptionExpired = isExpired(dialogHandle);
        }
    }

    return(subscriptionSucceeded);
}
Example #12
0
UtlBoolean SipSubscriptionMgr::updateDialogInfo(const SipMessage& subscribeRequest,
                                                UtlString& resourceId,
                                                UtlString& eventTypeKey,
                                                UtlString& eventType,
                                                UtlString& subscribeDialogHandle,
                                                UtlBoolean& isNew,
                                                UtlBoolean& isSubscriptionExpired,
                                                SipMessage& subscribeResponse,
                                                SipSubscribeServerEventHandler& handler)
{
    isNew = FALSE;
    UtlBoolean subscriptionSucceeded = FALSE;
    UtlString dialogHandle;
    subscribeRequest.getDialogHandle(dialogHandle);
    SubscriptionServerState* state = NULL;
    int expiration = -1;
    isSubscriptionExpired = TRUE;
    
    // Double check the sanity of the class attributes
    
    if(mMaxExpiration < mMinExpiration)
    {
        // This is an error case. Switch the values so that we do not
        // run into any negative expiration times.
        int tmp = mMaxExpiration;
        mMaxExpiration = mMinExpiration;
        mMinExpiration = tmp;
        
        OsSysLog::add(FAC_SIP, PRI_WARNING,
            "Swapping values as mMinExpiration => %d is greater than mMaxExpiration => %d",
            mMinExpiration, mMaxExpiration);
    }
    
    if(mMaxExpiration < mDefaultExpiration)
    {
        // This is an error case. Switch the values so that we do not
        // run into any negative expiration times.
        int tmp = mMaxExpiration;
        mMaxExpiration = mDefaultExpiration;
        mDefaultExpiration = tmp;
        
        OsSysLog::add(FAC_SIP, PRI_WARNING,
            "Swapping values as mDefaultExpiration => %d is greater than mMaxExpiration => %d",
            mDefaultExpiration, mMaxExpiration);
    }
    
    // Set the expires period randomly
    int spreadFloor = mMinExpiration*2;
    if(!subscribeRequest.getExpiresField(&expiration))
    {
        // no expires field
        // spread it between the default expiration and max allowed expiration
        expiration = (  (rand() % (mMaxExpiration - mDefaultExpiration))
                       + mDefaultExpiration);
    }
    else if ( expiration >= mMaxExpiration )
    {
        if (mMaxExpiration > spreadFloor)
        {
            // - spread it between the spreadFloor and the max allowed expiration
            expiration = (  (rand() % (mMaxExpiration - spreadFloor))
                           + spreadFloor);
        }
        else
        {                
            // Max Expiration is smaller than the spreadFloor, hence
            // spread it between the min and the max allowed expiration
            expiration = (  (rand() % (mMaxExpiration - mMinExpiration))
                           + mMinExpiration);
        }
    }
    else if ( expiration > spreadFloor )
    {
        // a normal (long) expiration
        // - spread it between the spreadFloor and the longest they asked for
        expiration = (  (rand() % (expiration - spreadFloor))
                       + spreadFloor);
    }
    else if ( expiration > mMinExpiration )
    {
        // a short but greater than minimum expiration
        // - spread it between the min and the longest they asked for
        expiration = (  (rand() % (expiration - mMinExpiration))
                       + mMinExpiration);
    }
    // Cases where the expiration is less than the min value is handled below.

    // If this is an early dialog we need to make it an established dialog.
    if(SipDialog::isEarlyDialog(dialogHandle))
    {
        UtlString establishedDialogHandle;
        if(mDialogMgr.getEstablishedDialogHandleFor(dialogHandle, establishedDialogHandle))
        {
            OsSysLog::add(FAC_SIP, PRI_WARNING,
                "Incoming early SUBSCRIBE dialog: %s matches established dialog: %s",
                dialogHandle.data(), establishedDialogHandle.data());
        }

        // make up a To tag and set it
        UtlString toTag;
        CallId::getNewTag(dialogHandle.data(), toTag);

        // Acceptable expiration, create a subscription and dialog
        if(expiration >= mMinExpiration ||
           expiration == 0 ||
           // :WORKAROUND:  Also allow expiration == 1, to support the
           // 1-second subscriptions the pick-up agent makes because
           // current Snom phones do not respond to 0-second subscriptions.
           // See XPB-399 and ENG-319.
           expiration == 1)
        {
            // Call the event-specific function to determine the resource ID
            // and event type for this SUBSCRIBE.
            handler.getKeys(subscribeRequest,
                            resourceId,
                            eventTypeKey,
                            eventType);

            // Create a dialog and subscription state even if
            // the expiration is zero as we need the dialog info
            // to route the one-time NOTIFY.  The immediately
            // expired dialog will be garbage collected.

            SipMessage* subscribeCopy = new SipMessage(subscribeRequest);
            subscribeCopy->setToFieldTag(toTag);

            // Re-get the dialog handle now that the To tag is set
            subscribeCopy->getDialogHandle(dialogHandle);

            // Create the dialog
            mDialogMgr.createDialog(*subscribeCopy, FALSE, dialogHandle);
            isNew = TRUE;

            // Create a subscription state
            state = new SubscriptionServerState();
            *((UtlString*) state) = dialogHandle;
            state->mEventTypeKey = eventTypeKey;
            state->mpLastSubscribeRequest = subscribeCopy;
            state->mResourceId = resourceId;
            subscribeCopy->getAcceptField(state->mAcceptHeaderValue);

            long now = OsDateTime::getSecsSinceEpoch();
            state->mExpirationDate = now + expiration;

            // TODO: currently the SipSubsribeServer does not handle timeout
            // events to send notifications that the subscription has ended.
            // So we do not set a timer at the end of the subscription
            state->mpExpirationTimer = NULL;

            // Create the index by resourceId and eventTypeKey key
            SubscriptionServerStateIndex* stateKey = new SubscriptionServerStateIndex;
            *((UtlString*) stateKey) = resourceId;
            stateKey->append(eventTypeKey);
            stateKey->mpState = state;

            subscribeResponse.setResponseData(subscribeCopy, 
                                              SIP_ACCEPTED_CODE,
                                              SIP_ACCEPTED_TEXT, 
                                              NULL);
            subscribeResponse.setExpiresField(expiration);
            subscribeCopy->getDialogHandle(subscribeDialogHandle);

            lock();
            mSubscriptionStatesByDialogHandle.insert(state);
            mSubscriptionStateResourceIndex.insert(stateKey);
	    if (OsSysLog::willLog(FAC_SIP, PRI_DEBUG))
	    {
	       UtlString requestContact;
	       subscribeRequest.getContactField(0, requestContact);
	       OsSysLog::add(FAC_SIP, PRI_DEBUG,
			     "SipSubscriptionMgr::updateDialogInfo insert early-dialog subscription for dialog handle '%s', key '%s', contact '%s', mExpirationDate %ld",
			     state->data(), stateKey->data(),
                             requestContact.data(), state->mExpirationDate);
            }

            // Not safe to touch these after we unlock
            stateKey = NULL;
            state = NULL;
            subscribeCopy = NULL;
            unlock();

            subscriptionSucceeded = TRUE;

            // One time subscribe?
            isSubscriptionExpired = expiration == 0;
        }
        // Expiration too small
        else
        {
            // Set expiration too small error
            subscribeResponse.setResponseData(&subscribeRequest, 
                                                SIP_TOO_BRIEF_CODE,
                                                SIP_SUB_TOO_BRIEF_TEXT);
            subscribeResponse.setMinExpiresField(mMinExpiration);
            isSubscriptionExpired = TRUE;
        }
    }

    // Not an early dialog handle -- The dialog for this message should already exist
    else
    {
        // Acceptable expiration, create a subscription and dialog
        if(expiration > mMinExpiration ||
           expiration == 0)
        {
            // Update the dialog state
            mDialogMgr.updateDialog(subscribeRequest, dialogHandle);

            // Get the subscription state and update that
            // TODO:  This assumes that no one reuses the same dialog
            // to subscribe to more than one event type.  mSubscriptionStatesByDialogHandle
            // will need to be changed to a HashBag and we will need to
            // search through to find a matching event type
            lock();
            state = (SubscriptionServerState*)
                mSubscriptionStatesByDialogHandle.find(&dialogHandle);
            if(state)
            {
                // Update the expiration time.
                long now = OsDateTime::getSecsSinceEpoch();
                state->mExpirationDate = now + expiration;
                // Record this SUBSCRIBE as the latest SUBSCRIBE request.
                if(state->mpLastSubscribeRequest)
                {
                    delete state->mpLastSubscribeRequest;
                }
                state->mpLastSubscribeRequest = new SipMessage(subscribeRequest);
                subscribeRequest.getAcceptField(state->mAcceptHeaderValue);

                // Set our Contact to the same request URI that came in
                UtlString contact;
                subscribeRequest.getRequestUri(&contact);

                // Add the angle brackets to Contact, since it is a name-addr.
                Url url(contact);
                url.includeAngleBrackets();
                contact = url.toString();

                subscribeResponse.setResponseData(&subscribeRequest, 
                                                SIP_ACCEPTED_CODE,
                                                SIP_ACCEPTED_TEXT, 
                                                contact);
                subscribeResponse.setExpiresField(expiration);
                subscriptionSucceeded = TRUE;
                isSubscriptionExpired = FALSE;
                subscribeDialogHandle = dialogHandle;

                // Set the resource information so our caller can generate a NOTIFY.
                resourceId = state->mResourceId;
                eventTypeKey = state->mEventTypeKey;
                // Unfortuantely, we don't record the eventType separately.
                eventType = state->mEventTypeKey;
            }

            // No state, but SUBSCRIBE had a to-tag.
            else
            {
               // Unknown subscription.
               subscribeResponse.setResponseData(&subscribeRequest, 
                                                 SIP_BAD_SUBSCRIPTION_CODE,
                                                 SIP_BAD_SUBSCRIPTION_TEXT);
            }
            unlock();
        }

        // Expiration too small
        else
        {
            // Set expiration too small error
            subscribeResponse.setResponseData(&subscribeRequest, 
                                                SIP_TOO_BRIEF_CODE,
                                                SIP_SUB_TOO_BRIEF_TEXT);
            subscribeResponse.setMinExpiresField(mMinExpiration);
            isSubscriptionExpired = isExpired(dialogHandle);
        }
    }

    return(subscriptionSucceeded);
}