reSIProcate/DialogUsageManager  9694
ServerSubscription.cxx
Go to the documentation of this file.
00001 #include "resip/dum/AppDialog.hxx"
00002 #include "resip/dum/Dialog.hxx"
00003 #include "resip/dum/DialogUsageManager.hxx"
00004 #include "resip/dum/ServerSubscription.hxx"
00005 #include "resip/dum/SubscriptionHandler.hxx"
00006 #include "resip/dum/UsageUseException.hxx"
00007 #include "resip/stack/Helper.hxx"
00008 #include "rutil/Logger.hxx"
00009 
00010 #include <time.h>
00011 
00012 using namespace resip;
00013 
00014 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
00015 
00016 ServerSubscriptionHandle 
00017 ServerSubscription::getHandle()
00018 {
00019    return ServerSubscriptionHandle(mDum, getBaseHandle().getId());
00020 }
00021 
00022 ServerSubscription::ServerSubscription(DialogUsageManager& dum,
00023                                        Dialog& dialog,
00024                                        const SipMessage& req)
00025    : BaseSubscription(dum, dialog, req),
00026      mSubscriber(req.header(h_From).uri().getAor()),
00027      mExpires(60),
00028      mAbsoluteExpiry(0)
00029 {
00030    if (req.header(h_RequestLine).method() == REFER && req.header(h_To).exists(p_tag))
00031    {
00032       // If this is an in-dialog REFER, then use a subscription id
00033       mSubscriptionId = Data(req.header(h_CSeq).sequence());
00034    }   
00035    Data key = getEventType() + getDocumentKey();
00036    mDum.mServerSubscriptions.insert(DialogUsageManager::ServerSubscriptions::value_type(key, this));
00037 }
00038 
00039 ServerSubscription::~ServerSubscription()
00040 {
00041    DebugLog(<< "ServerSubscription::~ServerSubscription");
00042    
00043    Data key = getEventType() + getDocumentKey();
00044 
00045    std::pair<DialogUsageManager::ServerSubscriptions::iterator,DialogUsageManager::ServerSubscriptions::iterator> subs;
00046    subs = mDum.mServerSubscriptions.equal_range(key);
00047    for (DialogUsageManager::ServerSubscriptions::iterator i=subs.first; i!=subs.second; ++i)
00048    {
00049       if (i->second == this)
00050       {
00051          mDum.mServerSubscriptions.erase(i);
00052          break;
00053       }
00054    }
00055    
00056    mDialog.mServerSubscriptions.remove(this);
00057 }
00058 
00059 UInt32
00060 ServerSubscription::getTimeLeft()
00061 {
00062    UInt32 timeleft =  UInt32(mAbsoluteExpiry - Timer::getTimeSecs());
00063    if (timeleft < 0) // .kw. this can NEVER happen since unsigned!
00064    {
00065       return 0;
00066    }
00067    else
00068    {
00069       return timeleft;
00070    }
00071 }
00072 
00073 SharedPtr<SipMessage>
00074 ServerSubscription::accept(int statusCode)
00075 {
00076    mDialog.makeResponse(*mLastResponse, mLastSubscribe, statusCode);
00077    mLastResponse->header(h_Expires).value() = mExpires;
00078    return mLastResponse;
00079 }
00080 
00081 SharedPtr<SipMessage>
00082 ServerSubscription::reject(int statusCode)
00083 {
00084    if (statusCode < 300)
00085    {
00086       throw UsageUseException("Must reject with a code greater than or equal to 300", __FILE__, __LINE__);
00087    }
00088    mDialog.makeResponse(*mLastResponse, mLastSubscribe, statusCode);
00089    return mLastResponse;
00090 }
00091 
00092 
00093 void 
00094 ServerSubscription::send(SharedPtr<SipMessage> msg)
00095 {
00096    ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
00097    assert(handler);   
00098    if (msg->isResponse())
00099    {
00100       int code = msg->header(h_StatusLine).statusCode();
00101       if (code < 200)
00102       {
00103          DialogUsage::send(msg);
00104       }
00105       else if (code < 300)
00106       {
00107          if(msg->exists(h_Expires))
00108          {
00109             mDum.addTimer(DumTimeout::Subscription, msg->header(h_Expires).value(), getBaseHandle(), ++mTimerSeq);
00110             DialogUsage::send(msg);
00111             mAbsoluteExpiry = Timer::getTimeSecs() + msg->header(h_Expires).value();            
00112             mSubDlgState = SubDlgEstablished;            
00113          }
00114          else
00115          {
00116             throw UsageUseException("2xx to a Subscribe MUST contain an Expires header", __FILE__, __LINE__);
00117          }
00118       }
00119       else if (code < 400)
00120       {
00121          DialogUsage::send(msg);
00122          handler->onTerminated(getHandle());
00123          delete this;
00124          return;
00125       }
00126       else
00127       {
00128          if (shouldDestroyAfterSendingFailure(*msg))
00129          {
00130             DialogUsage::send(msg);
00131             handler->onTerminated(getHandle());
00132             delete this;
00133             return;
00134          }
00135          else
00136          {
00137             DialogUsage::send(msg);
00138          }
00139       }
00140    }
00141    else
00142    {
00143       DialogUsage::send(msg);
00144       if (mSubscriptionState == Terminated)
00145       {
00146          handler->onTerminated(getHandle());
00147          delete this;
00148       }
00149    }
00150 }
00151 
00152 bool 
00153 ServerSubscription::shouldDestroyAfterSendingFailure(const SipMessage& msg)
00154 {
00155    int code = msg.header(h_StatusLine).statusCode();
00156    switch(mSubDlgState)
00157    {
00158       case SubDlgInitial:
00159          return true;
00160       case SubDlgTerminating: //terminated state not using in ServerSubscription
00161          assert(0);
00162          return true;
00163       case SubDlgEstablished:
00164       {
00165          if (code == 405)
00166          {
00167             return true;
00168          }
00169          switch (Helper::determineFailureMessageEffect(*mLastResponse))
00170          {
00171             case Helper::TransactionTermination:
00172             case Helper::RetryAfter:
00173                break;
00174             case Helper::OptionalRetryAfter:
00175             case Helper::ApplicationDependant: 
00176                // .bwc. Uh, no. ApplicationDependent should imply that the 
00177                // app-writer has decided what to do. We don't decide here. And 
00178                // OptionalRetryAfter certainly doesn't mean we should tear the 
00179                // Usage down.
00180 //               throw UsageUseException("Not a reasonable code to reject a SUBSCIRBE(refresh) inside a dialog.", 
00181 //                                       __FILE__, __LINE__);
00182                break;            
00183             case Helper::DialogTermination: //?dcm? -- throw or destroy this?
00184             case Helper::UsageTermination:
00185                return true;
00186          }
00187          break;
00188       }
00189       default: // !jf!
00190          assert(0);
00191          break;
00192          
00193    }
00194    return false;   
00195 }
00196 
00197 void 
00198 ServerSubscription::setSubscriptionState(SubscriptionState state)
00199 {
00200    mSubscriptionState = state;
00201 }
00202 
00203 void 
00204 ServerSubscription::dispatch(const SipMessage& msg)
00205 {
00206    DebugLog( << "ServerSubscriptionHandler::dispatch: " << msg.brief());
00207 
00208    ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
00209    assert(handler);
00210 
00211    if (msg.isRequest())
00212    {      
00214       //expiration times for an event package--part of handler API?
00215       //added to handler for now.
00216       mLastSubscribe = msg;      
00217    
00218       int errorResponseCode = 0;
00219       handler->getExpires(msg,mExpires,errorResponseCode);
00220       if (errorResponseCode >= 400)
00221       {
00222          handler->onError(getHandle(), msg);
00223          SharedPtr<SipMessage> response = reject(errorResponseCode);
00224 
00225          if (errorResponseCode == 423 && handler->hasMinExpires())
00226          {
00227             response->header(h_MinExpires).value() = handler->getMinExpires();             
00228          }
00229          send(response);
00230          return;
00231       }     
00232 
00233       InviteSessionHandle invSession;
00234       if (getAppDialog().isValid())
00235       {
00236          invSession = getAppDialog()->getInviteSession();
00237       }
00238 
00239       if (mExpires == 0)
00240       {
00241          /* This is to handle the case where mExpires is zero because the client
00242             is attempting to poll.  In order for polling to work, the subscription
00243             handler needs to get the onNewSubscription call. .mjf.
00244           */
00245          if (mSubscriptionState == Invalid)
00246          {
00247             mSubscriptionState = Terminated;
00248             if (mEventType != "refer" )
00249             {
00250                handler->onNewSubscription(getHandle(), msg);
00251             }
00252             else if (!invSession.isValid())
00253             {
00254                handler->onNewSubscriptionFromRefer(getHandle(), msg);
00255             }
00256          }
00257 
00258          makeNotifyExpires();
00259          handler->onExpiredByClient(getHandle(), msg, *mLastRequest);
00260          
00261          mDialog.makeResponse(*mLastResponse, mLastSubscribe, 200);
00262          mLastResponse->header(h_Expires).value() = mExpires;
00263          send(mLastResponse);
00264 
00265          send(mLastRequest);  // Send Notify Expires
00266          return;
00267       }
00268       if (mSubscriptionState == Invalid)
00269       {
00271          mSubscriptionState = Init;
00272          if (mEventType != "refer")
00273          {
00274             DebugLog(<< "onNewSubscription called");
00275             handler->onNewSubscription(getHandle(), msg);
00276          }
00277          else if (!invSession.isValid())
00278          {
00279             DebugLog(<< "onNewSubscriptionFromRefer called");
00280             handler->onNewSubscriptionFromRefer(getHandle(), msg);
00281          }
00282       }
00283       else
00284       {
00285          DebugLog(<< "onRefresh called");
00286          handler->onRefresh(getHandle(), msg);            
00287       }
00288    }
00289    else
00290    {     
00291       //.dcm. - will need to change if retry-afters are reaching here
00292       mLastRequest->releaseContents();
00293       int code = msg.header(h_StatusLine).statusCode();
00294       if (code < 300)
00295       { 
00296          return;
00297       }
00298       else if (code < 400)
00299       {
00300          //in dialog NOTIFY got redirected? Bizarre...
00301          handler->onError(getHandle(), msg);
00302          handler->onTerminated(getHandle());
00303          delete this;         
00304       }
00305       else
00306       {
00307          switch(Helper::determineFailureMessageEffect(msg))
00308          {
00309             case Helper::TransactionTermination:
00310                DebugLog( << "ServerSubscriptionHandler::TransactionTermination: " << msg.brief());
00311                handler->onNotifyRejected(getHandle(), msg);
00312                break;
00313             case Helper::UsageTermination:
00314             case Helper::RetryAfter:
00315             case Helper::OptionalRetryAfter:
00316             case Helper::ApplicationDependant: 
00317             case Helper::DialogTermination:
00318                DebugLog( << "ServerSubscriptionHandler::UsageTermination: " << msg.brief());
00319                handler->onError(getHandle(), msg);
00320                handler->onTerminated(getHandle());
00321                delete this;
00322                break;
00323          }
00324       }
00325    }
00326 }
00327 
00328 void
00329 ServerSubscription::makeNotifyExpires()
00330 {
00331    mSubscriptionState = Terminated;
00332    makeNotify();
00333    mLastRequest->header(h_SubscriptionState).param(p_reason) = getTerminateReasonString(Timeout);   
00334 }
00335 
00336 void
00337 ServerSubscription::makeNotify()
00338 {
00339    mDialog.makeRequest(*mLastRequest, NOTIFY);
00340    mLastRequest->header(h_SubscriptionState).value() = getSubscriptionStateString(mSubscriptionState);
00341    if (mSubscriptionState == Terminated)
00342    {
00343       mLastRequest->header(h_SubscriptionState).remove(p_expires);      
00344    }
00345    else
00346    {
00347       mLastRequest->header(h_SubscriptionState).param(p_expires) = getTimeLeft();
00348    }
00349    
00350    mLastRequest->header(h_Event).value() = mEventType;   
00351    if (!mSubscriptionId.empty())
00352    {
00353       mLastRequest->header(h_Event).param(p_id) = mSubscriptionId;
00354    }
00355 }
00356 
00357 
00358 void
00359 ServerSubscription::end(TerminateReason reason, const Contents* document)
00360 {
00361    mSubscriptionState = Terminated;
00362    makeNotify();
00363    mLastRequest->header(h_SubscriptionState).param(p_reason) = getTerminateReasonString(reason);   
00364    if (document)
00365    {
00366       mLastRequest->setContents(document);
00367    }
00368    send(mLastRequest);
00369 }
00370 
00371 void
00372 ServerSubscription::end()
00373 {
00374    end(Timeout);
00375 }
00376 
00377 void
00378 ServerSubscription::dispatch(const DumTimeout& timeout)
00379 {
00380    assert(timeout.type() == DumTimeout::Subscription);
00381    if (timeout.seq() == mTimerSeq)
00382    {
00383       ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
00384       assert(handler);
00385       makeNotifyExpires();
00386       handler->onExpired(getHandle(), *mLastRequest);
00387       send(mLastRequest);
00388    }
00389 }
00390 
00391 SharedPtr<SipMessage>
00392 ServerSubscription::update(const Contents* document)
00393 {
00394    makeNotify();
00395    mLastRequest->setContents(document);
00396    return mLastRequest;
00397 }
00398 
00399 SharedPtr<SipMessage>
00400 ServerSubscription::neutralNotify()
00401 {
00402    makeNotify();
00403    mLastRequest->releaseContents();   
00404    return mLastRequest;
00405 }
00406 
00407 void 
00408 ServerSubscription::dialogDestroyed(const SipMessage& msg)
00409 {
00410    ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
00411    assert(handler);   
00412    handler->onError(getHandle(), msg);
00413    handler->onTerminated(getHandle());
00414    delete this;
00415 }
00416 
00417 void 
00418 ServerSubscription::onReadyToSend(SipMessage& msg)
00419 {
00420    ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
00421    assert(handler);
00422    handler->onReadyToSend(getHandle(), msg);
00423 }
00424 
00425 void
00426 ServerSubscription::flowTerminated()
00427 {
00428    // notify handler
00429    ServerSubscriptionHandler* handler = mDum.getServerSubscriptionHandler(mEventType);
00430    assert(handler);
00431    handler->onFlowTerminated(getHandle());
00432 }
00433 
00434 EncodeStream& 
00435 ServerSubscription::dump(EncodeStream& strm) const
00436 {
00437    strm << "ServerSubscription " << mSubscriber;
00438    return strm;
00439 }
00440 
00441 
00442 /* ====================================================================
00443  * The Vovida Software License, Version 1.0 
00444  * 
00445  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00446  * 
00447  * Redistribution and use in source and binary forms, with or without
00448  * modification, are permitted provided that the following conditions
00449  * are met:
00450  * 
00451  * 1. Redistributions of source code must retain the above copyright
00452  *    notice, this list of conditions and the following disclaimer.
00453  * 
00454  * 2. Redistributions in binary form must reproduce the above copyright
00455  *    notice, this list of conditions and the following disclaimer in
00456  *    the documentation and/or other materials provided with the
00457  *    distribution.
00458  * 
00459  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00460  *    and "Vovida Open Communication Application Library (VOCAL)" must
00461  *    not be used to endorse or promote products derived from this
00462  *    software without prior written permission. For written
00463  *    permission, please contact vocal@vovida.org.
00464  *
00465  * 4. Products derived from this software may not be called "VOCAL", nor
00466  *    may "VOCAL" appear in their name, without prior written
00467  *    permission of Vovida Networks, Inc.
00468  * 
00469  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00470  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00471  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00472  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00473  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00474  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00475  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00476  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00477  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00478  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00479  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00480  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00481  * DAMAGE.
00482  * 
00483  * ====================================================================
00484  * 
00485  * This software consists of voluntary contributions made by Vovida
00486  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00487  * Inc.  For more information on Vovida Networks, Inc., please see
00488  * <http://www.vovida.org/>.
00489  *
00490  */