Example #1
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 #2
0
UtlBoolean SipRefreshManager::handleMessage(OsMsg &eventMessage)
{
    int msgType = eventMessage.getMsgType();
    int msgSubType = eventMessage.getMsgSubType();

    // Timer fired
    if(msgType == OsMsg::OS_EVENT &&
       msgSubType == OsEventMsg::NOTIFY)
    {
        int eventData = 0;
        RefreshDialogState* state = NULL;

        ((OsEventMsg&)eventMessage).getUserData((int&)state);
        ((OsEventMsg&)eventMessage).getEventData(eventData);

        lock();
        // If the state is not still in the list we cannot
        // touch it. It may have been deleted.
        if(state && stateExists(state))
        {
            // Refresh request failed, need to clean up and
            // schedule a refresh in a short/failed time period
            if(eventData == OS_INTERRUPTED)
            {
                // Clean up the timer and notifier
                deleteTimerAndEvent(state->mpRefreshTimer);
                state->mpRefreshTimer = NULL;

                // Create and set a new timer for the failed time out period
                setRefreshTimer(*state, 
                                FALSE);  // Resend with failure timeout
            }

            // Normal timer fire, time to refresh
            else if(eventData != 0 ||
               ((OsTimer*)eventData) == state->mpRefreshTimer)
            {
                // Clean up the timer and notifier
                deleteTimerAndEvent(state->mpRefreshTimer);
                state->mpRefreshTimer = NULL;

                // Legitimate states to reSUBSCRIBE or reREGISTER
                if(state->mRequestState == REFRESH_REQUEST_FAILED || 
                    state->mRequestState == REFRESH_REQUEST_SUCCEEDED)
                {
                    // Create and set a new timer for resending assuming
                    // the resend is successful.  If it fails we will
                    // cancel the timer and set a shorter timeout
                    setRefreshTimer(*state, 
                                    TRUE); // Resend with successful timeout

                    // reset the message for resend
                    setForResend(*state,
                                 FALSE); // do not expire now

                    // Keep track of when this refresh is sent so we know 
                    // when the new expiration is relative to.
                    state->mPendingStartTime = OsDateTime::getSecsSinceEpoch();

                    // Do not want to keep the lock while we send the
                    // message as it could block.  Presumably it is better
                    // to incure the cost of copying the message????
                    SipMessage tempRequest(*(state->mpLastRequest));
                    unlock();
                    mpUserAgent->send(tempRequest);
                    // do not need the lock any more, but this gives us
                    // clean locking symmetry.  DO NOT TOUCH state or
                    // any of its members BEYOND this point as it may 
                    // have been deleted
                    lock(); 
                }

                // This should not happen
                else
                {
                    OsSysLog::add(FAC_SIP, PRI_ERR,
                        "SipRefreshManager::handleMessage timer fired for state: %d",
                        state->mRequestState);

                    if(state->mRequestState == REFRESH_REQUEST_PENDING)
                    {
                        // Try again later if it was pending
                        setRefreshTimer(*state, 
                                        FALSE); // Resend with failed timeout
                    }
                }
            }

            // Bad do not know what happened
            else
            {
                OsSysLog::add(FAC_SIP, PRI_ERR,
                    "SipRefreshManager::handleMessage timer: %x does not match states timer: %p",
                    eventData, state->mpRefreshTimer);
            }
        }
        unlock();
    }

    // SIP message
    else if(msgType == OsMsg::PHONE_APP &&
       msgSubType == SipMessage::NET_SIP_MESSAGE)
    {
        const SipMessage* sipMessage = ((SipMessageEvent&)eventMessage).getMessage();
        int messageType = ((SipMessageEvent&)eventMessage).getMessageStatus();

        // messageType can be:
        //    SipMessageEvent::TRANSPORT_ERROR for requests that do not get sent
        //            but we would have to register with the SipUserAgent to
        //            receive requests.
        //    SipMessageEvent::AUTHENTICATION_RETRY for 401 or 407 responses
        //            that are resent with credentials.  We ge this message so
        //            that we can keep the dialog info. up to date.
        //    SipMessageEvent::APPLICATION normal messages
        // For now we will treat the APPLICATION and AUTHENTICATION_RETRY
        // identically.


        // If this is a SUBSCRIBE or REGISTER response
        UtlString method;
        int cseq;
        if(sipMessage) sipMessage->getCSeqField(&cseq, &method);
        if(sipMessage &&
           sipMessage->isResponse() &&
             (method.compareTo(SIP_SUBSCRIBE_METHOD) == 0 ||
              method.compareTo(SIP_REGISTER_METHOD) == 0))
        {
            UtlString eventField;
            sipMessage->getEventField(&eventField, NULL);
            // We could validate that the event field is
            // set and is the right event type, but mostly
            // we should not care as we know the event type
            // from the subscription.  We can be tolerant of
            // missing or malformed event headers in the
            // NOTIFY request.  The event header is not
            // required in the subscribe response.

            UtlString dialogHandle;
            UtlString earlyDialogHandle;
            sipMessage->getDialogHandle(dialogHandle);
            UtlBoolean foundDialog = 
                mpDialogMgr->dialogExists(dialogHandle);
            UtlBoolean foundEarlyDialog = FALSE;
            UtlBoolean matchesLastLocalTransaction = FALSE;
            if(foundDialog)
            {
                matchesLastLocalTransaction = 
                    mpDialogMgr->isLastLocalTransaction(*sipMessage, 
                                                        dialogHandle);
            }
            else
            {
                foundEarlyDialog = 
                    mpDialogMgr->getEarlyDialogHandleFor(dialogHandle, 
                                                         earlyDialogHandle);

                if(foundEarlyDialog)
                {
                    matchesLastLocalTransaction =
                        mpDialogMgr->isLastLocalTransaction(*sipMessage, 
                                                          earlyDialogHandle);
                }
            }

#ifdef TEST_PRINT
            osPrintf("Looking for refresh state with dialog handle: %s\n",
                   dialogHandle.data());
            UtlString refreshStateDump;
            dumpRefreshStates(refreshStateDump);
            osPrintf("SipRefreshManager::handleMessage state dump:\n%s\n", refreshStateDump.data());
#endif

            lock();
            // Find the refresh state for this response
            RefreshDialogState* state = NULL;
            if(foundDialog && matchesLastLocalTransaction)
            {
                state = (RefreshDialogState*) mRefreshes.find(&dialogHandle);
                // Check if the key has the tags reversed
                if(state == NULL)
                {
                    UtlString reversedDialogHandle;
                    SipDialog::reverseTags(dialogHandle, reversedDialogHandle);
                    state = (RefreshDialogState*) 
                        mRefreshes.find(&reversedDialogHandle);
                }
            }
            else if(foundEarlyDialog && matchesLastLocalTransaction)
            {
                state = (RefreshDialogState*) mRefreshes.remove(&earlyDialogHandle);

                // See if the key has the tags reversed
                if(state == NULL)
                {
                    UtlString reversedEarlyDialogHandle;
                    SipDialog::reverseTags(earlyDialogHandle, reversedEarlyDialogHandle);
                    state = (RefreshDialogState*) 
                        mRefreshes.remove(&reversedEarlyDialogHandle);
                }

                if(state)
                {
#ifdef TEST_PRINT
                    osPrintf("Removed refresh state with dialog handle: %s\n",
                             state->data());
                    osPrintf("Inserting refresh state with dialog handle: %s\n",
                             dialogHandle.data());
#endif
                    // Fix the state handle and put it back in the list
                    *((UtlString*) state) = dialogHandle;
                    mRefreshes.insert(state);
                }
            }

            if(state)
            {

                // Need to check for error responses or 2xx class responses
                int responseCode = sipMessage->getResponseStatusCode();
                UtlString responseText;
                sipMessage->getResponseStatusText(&responseText);

                // Update the expiration members
                int expirationPeriod = 0;
                if(responseCode >= SIP_2XX_CLASS_CODE &&
                   responseCode < SIP_3XX_CLASS_CODE)
                {
                    // Should we tolerate no Expires header in response?
                    // Currently assume that if Expires header is not
                    // set that we got what we asked for
                    if(!getAcceptedExpiration(state, *sipMessage, 
                        expirationPeriod))
                    {
                        expirationPeriod = state->mExpirationPeriodSeconds;
                    }

                    // SUBSCRIBE or REGISTER gave us expiration seconds
                    // from when the request was sent.
                    if(expirationPeriod > 0)
                    {
                        state->mExpiration = state->mPendingStartTime +
                            expirationPeriod;
                    }
                    // UnSUBSCRIBE or unREGISTER
                    else
                    {
                        state->mExpiration = 0;
                    }

                    // The request succeeded
                    state->mRequestState = REFRESH_REQUEST_SUCCEEDED;
                }

                // Provisional response, do nothing
                else if(responseCode < SIP_2XX_CLASS_CODE)
                {
                }

                // There was a resend with credentials for this
                // failed response (should be a 401 or 407 auth.
                // challenge.
                else if(messageType == SipMessageEvent::AUTHENTICATION_RETRY)
                {
                    // Do not stop the timer and do not change the
                    // state from PENDING to FAILED
                }

                // a non-success response code, don't care what
                // type of error.  It is the applications job
                // to care.  If the credentials are wrong, the
                // application needs to fix it.  We will just keep
                // on trying, hoping that the credentials get fixed on 
                //this side or on the server side
                else
                {
                    state->mFailedResponseCode = responseCode;
                    state->mFailedResponseText = responseText;
                    state->mRequestState = REFRESH_REQUEST_FAILED;
                    // Do not change the expiration date, it
                    // is what ever it was before the response was
                    // sent.

                    // Kill the timer and have it fire now and 
                    // reschedule with the error timeout.  We
                    // cannot delete the timer or notifier here 
                    // as there is a race condition where the 
                    // timer might fire before we delete it.  Then
                    // it would be deleted twice (i.e. bad).
                    stopTimerForFailureReschedule(state->mpRefreshTimer);
                }

                //updateState(state, sipMessage);
                mpDialogMgr->updateDialog(*sipMessage);

                // Invoke the callback to let the application
                // know that the state changed
                if(state->mpStateCallback)
                {
                    (state->mpStateCallback)(state->mRequestState,
                                     earlyDialogHandle,
                                     dialogHandle,
                                     state->mpApplicationData,
                                     responseCode, // responseCode
                                     responseText, // responseText,
                                     state->mExpiration, // zero means expires now
                                     sipMessage); // response
                }
            }
            unlock();
        }  // endif SUBSCRIBE or REGISTER response
    } // endif SipMessage event

            return(TRUE);
}
Example #3
0
bool KstViewPicture::setImage(const QString& source) {
  KURL url;

  if (QFile::exists(source) && QFileInfo(source).isRelative()) {
    url.setPath(source);
  } else {
    url = KURL::fromPathOrURL(source);
  }

#if KDE_VERSION >= KDE_MAKE_VERSION(3,3,0)
  // FIXME: come up with a way to indicate the "widget" and fill it in here so
  //        that KIO dialogs are associated with the proper window
  if (!KIO::NetAccess::exists(url, true, 0L)) {
#else
  if (!KIO::NetAccess::exists(url, true)) {
#endif
    return false;
  }

  QString tmpFile;
#if KDE_VERSION >= KDE_MAKE_VERSION(3,3,0)
  // FIXME: come up with a way to indicate the "widget" and fill it in here so
  //        that KIO dialogs are associated with the proper window
  if (!KIO::NetAccess::download(url, tmpFile, 0L)) {
#else
  if (!KIO::NetAccess::download(url, tmpFile)) {
#endif
    return false;
  }

  bool success = true;

  QImage ti;
  ti.setAlphaBuffer(true);
  if (ti.load(tmpFile)) {
    setImage(ti);
    _url = source;

    if (_maintainAspect == true) { restoreAspect(); }
  } else {
    success = false;
  }

  KIO::NetAccess::removeTempFile(tmpFile);
  return success;
}


void KstViewPicture::setImage(const QImage& image) {
  _url = QString::null;
  _image = image;
  _iCache = QImage();
  setDirty();
}


const QString& KstViewPicture::url() const {
  return _url;
}


const QImage& KstViewPicture::image() const {
  return _image;
}


void KstViewPicture::doRefresh() {
  if (_url.isEmpty()) {
    setRefreshTimer(0);
  } else {
    QString u = _url;
    bool rc = setImage(_url);
    _url = u;
    // FIXME: after n failures, give up?
    if (rc) {
      KstApp::inst()->paintAll(KstPainter::P_PAINT);
    }
  }
}


void KstViewPicture::setRefreshTimer(int seconds) {
  _refresh = kMax(0, seconds);
  if (_refresh) {
    if (!_timer) {
      _timer = new QTimer(this);
      connect(_timer, SIGNAL(timeout()), this, SLOT(doRefresh()));
    }
    _timer->start(_refresh * 1000, false);
  } else {
    delete _timer;
    _timer = 0L;
  }
}