reSIProcate/DialogUsageManager  9680
Dialog.cxx
Go to the documentation of this file.
00001 #include "resip/stack/Contents.hxx"
00002 #include "resip/stack/Helper.hxx"
00003 #include "resip/stack/SipMessage.hxx"
00004 #include "resip/dum/AppDialog.hxx"
00005 #include "resip/dum/BaseCreator.hxx"
00006 #include "resip/dum/ClientAuthManager.hxx"
00007 #include "resip/dum/ClientInviteSession.hxx"
00008 #include "resip/dum/ClientSubscription.hxx"
00009 #include "resip/dum/Dialog.hxx"
00010 #include "resip/dum/DialogUsageManager.hxx"
00011 #include "resip/dum/MasterProfile.hxx"
00012 #include "resip/dum/InviteSessionCreator.hxx"
00013 #include "resip/dum/InviteSessionHandler.hxx"
00014 #include "resip/dum/ServerInviteSession.hxx"
00015 #include "resip/dum/ServerSubscription.hxx"
00016 #include "resip/dum/SubscriptionHandler.hxx"
00017 #include "resip/dum/UsageUseException.hxx"
00018 #include "rutil/Logger.hxx"
00019 #include "rutil/Inserter.hxx"
00020 #include "rutil/WinLeakCheck.hxx"
00021 
00022 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
00023 
00024 using namespace resip;
00025 using namespace std;
00026 
00027 Dialog::Dialog(DialogUsageManager& dum, const SipMessage& msg, DialogSet& ds)
00028    : mDum(dum),
00029      mDialogSet(ds),
00030      mId("INVALID", "INVALID", "INVALID"),
00031      mClientSubscriptions(),
00032      mServerSubscriptions(),
00033      mInviteSession(0),
00034      mType(Fake),
00035      mRouteSet(),
00036      mLocalContact(),
00037      mLocalCSeq(0),
00038      mRemoteCSeq(0),
00039      mRemoteTarget(),
00040      mLocalNameAddr(),
00041      mRemoteNameAddr(),
00042      mCallId(msg.header(h_CallID)),
00043      mDefaultSubExpiration(0),
00044      mAppDialog(0),
00045      mDestroying(false),
00046      mReUseDialogSet(false)
00047 {
00048    assert(msg.isExternal());
00049 
00050    assert(msg.header(h_CSeq).method() != MESSAGE);
00051    assert(msg.header(h_CSeq).method() != REGISTER);
00052    assert(msg.header(h_CSeq).method() != PUBLISH);
00053 
00054    mNetworkAssociation.setDum(&dum);
00055 
00056    if (msg.isRequest()) // UAS
00057    {
00058       const SipMessage& request = msg;
00059 
00060       switch (request.header(h_CSeq).method())
00061       {
00062          case INVITE:
00063             mType = Invitation;
00064             break;
00065 
00066          case SUBSCRIBE:
00067          case REFER:
00068          case NOTIFY:
00070             mType = Subscription;
00071             break;
00072 
00073          default:
00074             mType = Fake;
00075       }
00076       if (request.exists(h_RecordRoutes))
00077       {
00078          mRouteSet = request.header(h_RecordRoutes); 
00079       }
00080 
00081       switch (request.header(h_CSeq).method())
00082       {
00083          case INVITE:
00084          case SUBSCRIBE:
00085          case REFER:
00086          case NOTIFY:
00087             DebugLog ( << "UAS dialog ID creation, DS: " << ds.getId());
00088             mId = DialogId(ds.getId(), 
00089                            request.header(h_From).exists(p_tag) ? request.header(h_From).param(p_tag) : Data::Empty);            
00090 
00091             mRemoteNameAddr = request.header(h_From);
00092             mLocalNameAddr = request.header(h_To);
00093             mLocalNameAddr.param(p_tag) = mId.getLocalTag();
00094             if (request.exists(h_Contacts) && request.header(h_Contacts).size() == 1)
00095             {
00096                const NameAddr& contact = request.header(h_Contacts).front();
00097                if (isEqualNoCase(contact.uri().scheme(), Symbols::Sips) ||
00098                    isEqualNoCase(contact.uri().scheme(), Symbols::Sip))
00099                {
00100                   // Store Remote Target
00101                   mRemoteTarget = contact;
00102                   
00103                   // Create Local Contact
00104                   if(mDialogSet.mUserProfile->hasUserAgentCapabilities())
00105                   {
00106                      mLocalContact = mDialogSet.mUserProfile->getUserAgentCapabilities();
00107                   }
00108                   if(!mDialogSet.mUserProfile->isAnonymous() && mDialogSet.mUserProfile->hasPublicGruu())
00109                   {
00110                      mLocalContact.uri() = mDialogSet.mUserProfile->getPublicGruu();
00111                   }
00112                   else if(mDialogSet.mUserProfile->isAnonymous() && mDialogSet.mUserProfile->hasTempGruu())
00113                   {
00114                      mLocalContact.uri() = mDialogSet.mUserProfile->getTempGruu();
00115                   }
00116                   else
00117                   {
00118                      if (mDialogSet.mUserProfile->hasOverrideHostAndPort())
00119                      {
00120                         mLocalContact.uri() = mDialogSet.mUserProfile->getOverrideHostAndPort();
00121                      }
00122                      if(request.header(h_RequestLine).uri().user().empty())
00123                      {
00124                         mLocalContact.uri().user() = request.header(h_To).uri().user(); 
00125                      }
00126                      else
00127                      {
00128                         mLocalContact.uri().user() = request.header(h_RequestLine).uri().user(); 
00129                      }
00130                      const Data& instanceId = mDialogSet.mUserProfile->getInstanceId();
00131                      if (!contact.uri().exists(p_gr) && !instanceId.empty())
00132                      {
00133                         mLocalContact.param(p_Instance) = instanceId;
00134                      }
00135                   }
00136                   if(mDialogSet.mUserProfile->clientOutboundEnabled())
00137                   {
00138                      // Add ;ob parm to non-register requests - RFC5626 pg17
00139                      mLocalContact.uri().param(p_ob);
00140                   }
00141                }
00142                else
00143                {
00144                   InfoLog(<< "Got an INVITE or SUBSCRIBE with invalid scheme");
00145                   InfoLog(<< request);
00146                   throw Exception("Invalid scheme in request", __FILE__, __LINE__);
00147                }
00148             }
00149             else
00150             {
00151                InfoLog (<< "Got an INVITE or SUBSCRIBE that doesn't have exactly one contact");
00152                InfoLog (<< request);
00153                throw Exception("Too many (or no contact) contacts in request", __FILE__, __LINE__);
00154             }
00155             break;
00156          default:
00157             break;
00158       }
00159 
00160       mRemoteCSeq = request.header(h_CSeq).sequence();
00161       mLocalCSeq = 1;
00162 
00163       DebugLog ( << "************** Created Dialog as UAS **************" );
00164       DebugLog ( << "mRemoteNameAddr: " << mRemoteNameAddr );
00165       DebugLog ( << "mLocalNameAddr: " << mLocalNameAddr );
00166       DebugLog ( << "mLocalContact: " << mLocalContact );
00167       DebugLog ( << "mRemoteTarget: " << mRemoteTarget );
00168    }
00169    else if (msg.isResponse())
00170    {
00171       mId = DialogId(msg);
00172       const SipMessage& response = msg;
00173       mRemoteNameAddr = response.header(h_To);
00174       mLocalNameAddr = response.header(h_From);
00175 
00176       switch (msg.header(h_CSeq).method())
00177       {
00178          case INVITE:
00179             mType = Invitation;
00180             break;
00181 
00182          case SUBSCRIBE:
00183          case REFER:
00184             mType = Subscription;
00185             break;
00186 
00187          default:
00188             mType = Fake;
00189       }
00190 
00191       if (response.exists(h_RecordRoutes))
00192       {
00193          mRouteSet = response.header(h_RecordRoutes).reverse();
00194       }
00195 
00196       switch (response.header(h_CSeq).method())
00197       {
00198          case INVITE:
00199          case SUBSCRIBE:
00200          case REFER:
00201             if (response.header(h_StatusLine).statusCode() > 100 &&
00202                 response.header(h_StatusLine).statusCode() < 300)
00203             {
00204 
00205                if  (response.exists(h_Contacts) && response.header(h_Contacts).size() == 1)
00206                {
00207                   const NameAddr& contact = response.header(h_Contacts).front();
00208                   if (isEqualNoCase(contact.uri().scheme(), Symbols::Sips) ||
00209                      isEqualNoCase(contact.uri().scheme(), Symbols::Sip))
00210                   {
00211                      BaseCreator* creator = mDialogSet.getCreator();                                     
00212 
00213                      if( 0 == creator )
00214                      {
00215                         ErrLog(<< "BaseCreator is null for DialogSet");
00216                         ErrLog(<< response);
00217                         throw Exception("BaseCreator is null for DialogSet", __FILE__, __LINE__);
00218                      }
00219 
00220                      SharedPtr<SipMessage> lastRequest(creator->getLastRequest());
00221 
00222                      if( 0 == lastRequest.get() ||
00223                         !lastRequest->exists(h_Contacts) ||
00224                         lastRequest->header(h_Contacts).empty())
00225                      {
00226                         InfoLog(<< "lastRequest does not contain a valid contact");                                             
00227                         InfoLog(<< response);
00228                         throw Exception("lastRequest does not contain a valid contact.", __FILE__, __LINE__);
00229                      }
00230                      mLocalContact = creator->getLastRequest()->header(h_Contacts).front();
00231                      mRemoteTarget = contact;
00232                   }
00233                   else
00234                   {
00235                      InfoLog (<< "Got an INVITE or SUBSCRIBE with invalid scheme");
00236                      DebugLog (<< response);
00237                      throw Exception("Bad scheme in contact in response", __FILE__, __LINE__);
00238                   }
00239                }
00240                else
00241                {
00242                   InfoLog (<< "Got an INVITE or SUBSCRIBE that doesn't have exactly one contact");
00243                   DebugLog (<< response);
00244                   throw Exception("Too many contacts (or no contact) in response", __FILE__, __LINE__);
00245                }
00246                break;
00247                default:
00248                   break;
00249             }
00250       }
00251 
00252       mLocalCSeq = response.header(h_CSeq).sequence();
00253       mRemoteCSeq = 0;
00254       DebugLog ( << "************** Created Dialog as UAC **************" );
00255       DebugLog ( << "mRemoteNameAddr: " << mRemoteNameAddr );
00256       DebugLog ( << "mLocalNameAddr: " << mLocalNameAddr );
00257       DebugLog ( << "mLocalContact: " << mLocalContact );
00258       DebugLog ( << "mRemoteTarget: " << mRemoteTarget );
00259    }
00260    mDialogSet.addDialog(this);
00261    DebugLog ( <<"Dialog::Dialog " << mId);
00262 }
00263 
00264 Dialog::~Dialog()
00265 {
00266    DebugLog ( <<"Dialog::~Dialog() ");
00267 
00268    mDestroying = true;
00269 
00270    while (!mClientSubscriptions.empty())
00271    {
00272       delete *mClientSubscriptions.begin();
00273    }
00274 
00275    while (!mServerSubscriptions.empty())
00276    {
00277       delete *mServerSubscriptions.begin();
00278    }
00279 
00280    delete mInviteSession;
00281    mDialogSet.mDialogs.erase(this->getId());
00282    delete mAppDialog;
00283    if(!mReUseDialogSet)
00284    {
00285       mDialogSet.possiblyDie();
00286    }
00287 }
00288 
00289 const DialogId&
00290 Dialog::getId() const
00291 {
00292    return mId;
00293 }
00294 
00295 const NameAddr&
00296 Dialog::getLocalNameAddr() const
00297 {
00298    return mLocalNameAddr;
00299 }
00300 
00301 const NameAddr&
00302 Dialog::getLocalContact() const
00303 {
00304    return mLocalContact;
00305 }
00306 
00307 const NameAddr&
00308 Dialog::getRemoteNameAddr() const
00309 {
00310    return mRemoteNameAddr;
00311 }
00312 
00313 const NameAddr&
00314 Dialog::getRemoteTarget() const
00315 {
00316    return mRemoteTarget;
00317 }
00318 
00319 const NameAddrs&
00320 Dialog::getRouteSet() const
00321 {
00322    return mRouteSet;
00323 }
00324 
00325 void
00326 Dialog::cancel()
00327 {
00328    assert(mType == Invitation);
00329    ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession);
00330    assert (uac);
00331    uac->cancel();
00332 }
00333 
00334 void
00335 Dialog::end()
00336 {
00337    if (mInviteSession)
00338    {
00339       mInviteSession->end();
00340    }
00341 
00342    // End Subscriptions
00343    // !jrm! WARN ClientSubscription and ServerSubscription have access to this dialog and will remove themselves
00344    // from the m<client|server>Subscriptions collections in the call to end().
00345    for (list<ClientSubscription*>::iterator it(mClientSubscriptions.begin());
00346         it != mClientSubscriptions.end();)
00347    {
00348            ClientSubscription* c = *it;
00349        it++;       
00350            c->end();
00351    }
00352 
00353    for (list<ServerSubscription*>::iterator it2(mServerSubscriptions.begin());
00354         it2 != mServerSubscriptions.end();)
00355    {
00356            ServerSubscription* s = *it2;
00357        it2++;       
00358            s->end();
00359    }
00360 }
00361 
00362 void
00363 Dialog::handleTargetRefresh(const SipMessage& msg)
00364 {
00365    switch(msg.header(h_CSeq).method())
00366    {
00367       case INVITE:
00368       case UPDATE:
00369          if (msg.isRequest() || (msg.isResponse() && msg.header(h_StatusLine).statusCode()/100 == 2))
00370          {
00371             //?dcm? modify local target; 12.2.2 of 3261 implies that the remote
00372             //target is immediately modified.  Should we wait until a 2xx class
00373             //reponse is sent to a re-invite(easy when all send requests go
00374             //through Dialog)
00375             if (msg.exists(h_Contacts))
00376             {
00377                //.dcm. replace or check then replace
00378                mRemoteTarget = msg.header(h_Contacts).front();
00379             }
00380          }
00381          break;
00382       default:
00383          return;
00384    }
00385 }
00386 
00387 void
00388 Dialog::dispatch(const SipMessage& msg)
00389 {
00390    // !jf! Should be checking for messages with out of order CSeq and rejecting
00391 
00392    DebugLog ( << "Dialog::dispatch: " << msg.brief());
00393 
00394    if(msg.isExternal())
00395    {
00396       const Data& receivedTransport = msg.header(h_Vias).front().transport();
00397       int keepAliveTime = 0;
00398       if(receivedTransport == Symbols::TCP ||
00399          receivedTransport == Symbols::TLS ||
00400          receivedTransport == Symbols::SCTP)
00401       {
00402          keepAliveTime = mDialogSet.mUserProfile->getKeepAliveTimeForStream();
00403       }
00404       else
00405       {
00406          keepAliveTime = mDialogSet.mUserProfile->getKeepAliveTimeForDatagram();
00407       }
00408 
00409       if(keepAliveTime > 0)
00410       {
00411          mNetworkAssociation.update(msg, keepAliveTime, false /* targetSupportsOutbound */); // target supports outbound is detected in registration responses only
00412       }
00413    }
00414    
00415    handleTargetRefresh(msg);
00416    if (msg.isRequest())
00417    {
00418       const SipMessage& request = msg;
00419       switch (request.header(h_CSeq).method())
00420       {
00421          case INVITE:  // new INVITE
00422             if (mInviteSession == 0)
00423             {
00424                DebugLog ( << "Dialog::dispatch  --  Created new server invite session" << msg.brief());
00425                mInviteSession = makeServerInviteSession(request);
00426             }
00427             mInviteSession->dispatch(request);
00428             break;
00429             //refactor, send bad request for BYE, INFO, CANCEL?
00430          case BYE:
00431             if (mInviteSession == 0)
00432             {
00433                InfoLog ( << "Spurious BYE" );
00434                return;
00435             }
00436             else
00437             {
00438                mInviteSession->dispatch(request);
00439             }
00440             break;
00441          case UPDATE:
00442             if (mInviteSession == 0)
00443             {
00444                InfoLog ( << "Spurious UPDATE" );
00445                return;
00446             }
00447             else
00448             {
00449                mInviteSession->dispatch(request);
00450             }
00451             break;
00452          case INFO:
00453             if (mInviteSession == 0)
00454             {
00455                InfoLog ( << "Spurious INFO" );
00456                return;
00457             }
00458             else
00459             {
00460                mInviteSession->dispatch(request);
00461             }
00462             break;
00463          case MESSAGE:
00464             if (mInviteSession == 0)
00465             {
00466                InfoLog ( << "Spurious MESSAGE" );
00467                return;
00468             }
00469             else
00470             {
00471                mInviteSession->dispatch(request);
00472             }
00473             break;
00474          case ACK:
00475          case CANCEL:
00476             if (mInviteSession == 0)
00477             {
00478                InfoLog (<< "Drop stray ACK or CANCEL in dialog on the floor");
00479                DebugLog (<< request);
00480             }
00481             else
00482             {
00483                mInviteSession->dispatch(request);
00484             }
00485             break;
00486          case SUBSCRIBE:
00487          {
00488             ServerSubscription* server = findMatchingServerSub(request);
00489             if (server)
00490             {
00491                server->dispatch(request);
00492             }
00493             else
00494             {
00495                if (request.exists(h_Event) && request.header(h_Event).value() == "refer")
00496                {
00497                   InfoLog (<< "Received a subscribe to a non-existent refer subscription: " << request.brief());
00498                   SipMessage failure;
00499                   makeResponse(failure, request, 403);
00500                   mDum.sendResponse(failure);
00501                   return;
00502                }
00503                else
00504                {
00505                   if (mDum.checkEventPackage(request))
00506                   {
00507                      server = makeServerSubscription(request);
00508                      mServerSubscriptions.push_back(server);
00509                      server->dispatch(request);
00510                   }
00511                }
00512             }
00513          }
00514          break;
00515          case REFER:
00516          {
00517 //             if (mInviteSession == 0)
00518 //             {
00519 //                InfoLog (<< "Received an in dialog refer in a non-invite dialog: " << request.brief());
00520 //                SipMessage failure;
00521 //                makeResponse(failure, request, 603);
00522 //                mDum.sendResponse(failure);
00523 //                return;
00524 //             }
00525 //             else 
00526 
00527             if  (!request.exists(h_ReferTo))
00528             {
00529                InfoLog (<< "Received refer w/out a Refer-To: " << request.brief());
00530                SipMessage failure;
00531                makeResponse(failure, request, 400);
00532                mDum.sendResponse(failure);
00533                return;
00534             }
00535             else
00536             {
00537                if ((request.exists(h_ReferSub) && 
00538                      request.header(h_ReferSub).isWellFormed() &&
00539                      request.header(h_ReferSub).value()=="false") ||
00540                      (request.exists(h_Requires) &&
00541                      request.header(h_Requires).find(Token("norefersub"))))
00542                {
00543                   assert(mInviteSession);
00544                   mInviteSession->referNoSub(msg);
00545                }
00546                else
00547                {
00548                   ServerSubscription* server = findMatchingServerSub(request);
00549                   ServerSubscriptionHandle serverHandle;
00550                   if (server)
00551                   {
00552                      serverHandle = server->getHandle();
00553                      server->dispatch(request);
00554                   }
00555                   else
00556                   {
00557                      server = makeServerSubscription(request);
00558                      mServerSubscriptions.push_back(server);
00559                      serverHandle = server->getHandle();
00560                      server->dispatch(request);
00561                   }
00562 
00563                   if (mInviteSession)
00564                   {
00565                      mDum.mInviteSessionHandler->onRefer(mInviteSession->getSessionHandle(), serverHandle, msg);
00566                   }
00567                   
00568                }
00569             }
00570          }
00571          break;
00572          case NOTIFY:
00573             {
00574                ClientSubscription* client = findMatchingClientSub(request);
00575                if (client)
00576                {
00577                   client->dispatch(request);
00578                }
00579                else
00580                {
00581                   BaseCreator* creator = mDialogSet.getCreator();
00582                   if (creator && (creator->getLastRequest()->header(h_RequestLine).method() == SUBSCRIBE ||
00583                      creator->getLastRequest()->header(h_RequestLine).method() == REFER))  
00584                   {
00585                      DebugLog (<< "Making subscription (from creator) request: " << *creator->getLastRequest());
00586                      ClientSubscription* sub = makeClientSubscription(*creator->getLastRequest());
00587                      mClientSubscriptions.push_back(sub);
00588                      sub->dispatch(request);
00589                   }
00590                   else
00591                   {
00592                      if (mInviteSession != 0 && (!msg.exists(h_Event) || msg.header(h_Event).value() == "refer") && 
00593                          mDum.getClientSubscriptionHandler("refer")!=0) 
00594                      {
00595                         DebugLog (<< "Making subscription from NOTIFY: " << msg);
00596                         ClientSubscription* sub = makeClientSubscription(msg);
00597                         mClientSubscriptions.push_back(sub);
00598                         ClientSubscriptionHandle client = sub->getHandle();
00599                         mDum.mInviteSessionHandler->onReferAccepted(mInviteSession->getSessionHandle(), client, msg);                                 
00600                         sub->dispatch(request);
00601                      }
00602                      else
00603                      {
00604                         SharedPtr<SipMessage> response(new SipMessage);
00605                         makeResponse(*response, msg, 406);
00606                         send(response);
00607                      }
00608                   }
00609                }
00610             }
00611             break;
00612         default:
00613            assert(0);
00614            return;
00615       }
00616    }
00617    else if (msg.isResponse())
00618    {
00619       // !jf! There is a substantial change in how this works in teltel-branch
00620       // from how it worked in main branch pre merge.
00621       // If the response doesn't match a cseq for a request I've sent, ignore
00622       // the response
00623       {//scope 'r' as it is invalidated below
00624          RequestMap::iterator r = mRequests.find(msg.header(h_CSeq).sequence());
00625          if (r != mRequests.end())
00626          {         
00627             bool handledByAuth = false;
00628             if (mDum.mClientAuthManager.get() && 
00629                 mDum.mClientAuthManager->handle(*mDialogSet.mUserProfile, *r->second, msg))
00630             {
00631                InfoLog( << "about to re-send request with digest credentials" << r->second->brief());
00632 
00633                assert (r->second->isRequest());
00634 
00635                mLocalCSeq++;
00636                send(r->second);
00637                handledByAuth = true;
00638             }
00639             mRequests.erase(r);
00640             if (handledByAuth) return;
00641          }
00642       }
00643       
00644       const SipMessage& response = msg;
00645       int code = response.header(h_StatusLine).statusCode();
00646       // If this is a 200 response to the initial request, then store the routeset (if present)
00647       BaseCreator* creator = mDialogSet.getCreator();
00648       if (creator && (creator->getLastRequest()->header(h_CSeq) == response.header(h_CSeq)) && code >=200 && code < 300)
00649       {
00650          if (response.exists(h_RecordRoutes))
00651          {
00652             mRouteSet = response.header(h_RecordRoutes).reverse();
00653          }
00654          else
00655          {
00656             // Ensure that if the route-set in the 200 is empty, then we overwrite any existing route-sets
00657             mRouteSet.clear();
00658          }
00659       }
00660 
00661       // !jf! should this only be for 2xx responses? !jf! Propose no as an
00662       // answer !dcm! what is he on?
00663       switch (response.header(h_CSeq).method())
00664       {
00665          case INVITE:
00666             if (mInviteSession == 0)
00667             {
00668                DebugLog ( << "Dialog::dispatch  --  Created new client invite session" << msg.brief());
00669 
00670                mInviteSession = makeClientInviteSession(response);
00671                if (mInviteSession)
00672                {
00673                   mInviteSession->dispatch(response);
00674                }
00675                else
00676                {
00677                   ErrLog( << "Dialog::dispatch  --  Unable to create invite session from response" << msg.brief());
00678                }
00679             }
00680             else
00681             {
00682                mInviteSession->dispatch(response);
00683             }
00684             break;
00685          case BYE:
00686          case ACK:
00687          case CANCEL:
00688          case INFO:
00689          case MESSAGE:
00690          case UPDATE:
00691             if (mInviteSession)
00692             {
00693                mInviteSession->dispatch(response);
00694             }
00695             // else drop on the floor
00696             break;       
00697 
00698                  case REFER:
00699             if(mInviteSession)
00700             {
00701                if (code >= 300)
00702                {
00703                   mDum.mInviteSessionHandler->onReferRejected(mInviteSession->getSessionHandle(), msg);
00704                }
00705                else
00706                {
00708                   if (!mInviteSession->mReferSub && 
00709                       ((msg.exists(h_ReferSub) && msg.header(h_ReferSub).value()=="false") || 
00710                        !msg.exists(h_ReferSub)))
00711                   {
00712                      DebugLog(<< "refer accepted with norefersub");
00713                      mDum.mInviteSessionHandler->onReferAccepted(mInviteSession->getSessionHandle(), ClientSubscriptionHandle::NotValid(), msg);
00714                   }
00715                   // else no need for action - first Notify will cause onReferAccepted to be called
00716                }
00717                mInviteSession->nitComplete();
00718                break;
00719             }
00720             // fall through, out of dialog refer was sent.
00721 
00722          case SUBSCRIBE:
00723          {
00724             int code = response.header(h_StatusLine).statusCode();
00725             ClientSubscription* client = findMatchingClientSub(response);
00726             if (client)
00727             {
00728                client->dispatch(response);
00729             }
00730             else if (code < 300)
00731             {
00732                /*
00733                   we're capturing the  value from the expires header off
00734                   the 2xx because the ClientSubscription is only created
00735                   after receiving the NOTIFY that comes (usually) after
00736                   this 2xx.  We really should be creating the
00737                   ClientSubscription at either the 2xx or the NOTIFY
00738                   whichever arrives first. .mjf.
00739                   Note: we're capturing a duration here (not the
00740                   absolute time because all the inputs to
00741                   ClientSubscription desling with the expiration are expecting
00742                   duration type values from the headers. .mjf.
00743                 */
00744                if(response.exists(h_Expires))
00745                {
00746                   mDefaultSubExpiration = response.header(h_Expires).value();
00747                }
00748                else
00749                {
00750                   //?dcm? defaults to 3600 in ClientSubscription if no expires value
00751                   //is provided anywhere...should we assume the value from the
00752                   //sub in the basecreator if it exists?
00753                   mDefaultSubExpiration = 0;
00754                }               
00755                return;
00756             }
00757             else
00758             {
00760                //a bit of a hack; currently, spurious failure messages may cause callbacks
00761                BaseCreator* creator = mDialogSet.getCreator();
00762                if (!creator || !creator->getLastRequest()->exists(h_Event))
00763                {
00764                   return;
00765                }
00766                else
00767                {
00768                   ClientSubscriptionHandler* handler =
00769                      mDum.getClientSubscriptionHandler(creator->getLastRequest()->header(h_Event).value());
00770                   if (handler)
00771                   {
00772                      ClientSubscription* sub = makeClientSubscription(*creator->getLastRequest());
00773                      mClientSubscriptions.push_back(sub);
00774                      sub->dispatch(response);
00775                   }
00776                }
00777             }
00778 
00779          }
00780          break;
00781          case NOTIFY:
00782          {
00783             //2xx responses are treated as retransmission quenchers(handled by
00784             //the stack). Failures are dispatched to all ServerSubsscriptions,
00785             //which may not be correct.
00786 
00787             int code = msg.header(h_StatusLine).statusCode();
00788             if (code >= 300)
00789             {
00791                mDestroying = true;
00792                for (list<ServerSubscription*>::iterator it = mServerSubscriptions.begin();
00793                     it != mServerSubscriptions.end(); )
00794                {
00795                   ServerSubscription* s = *it;
00796                   it++;
00797                   s->dispatch(msg);
00798                }
00799                mDestroying = false;
00800                possiblyDie();
00801             }
00802 //             ServerSubscription* server = findMatchingServerSub(response);
00803 //             if (server)
00804 //             {
00805 //                server->dispatch(response);
00806 //             }
00807          }
00808          break;
00809          default:
00810             assert(0);
00811             return;
00812       }
00813 
00814 #if 0     // merged from head back to teltel-branch
00815       if (msg.header(h_StatusLine).statusCode() >= 400
00816           && Helper::determineFailureMessageEffect(msg) == Helper::DialogTermination)
00817       {
00818          //kill all usages
00819          mDestroying = true;
00820 
00821          for (list<ServerSubscription*>::iterator it = mServerSubscriptions.begin();
00822               it != mServerSubscriptions.end(); )
00823          {
00824             ServerSubscription* s = *it;
00825             it++;
00826             s->dialogDestroyed(msg);
00827          }
00828 
00829          for (list<ClientSubscription*>::iterator it = mClientSubscriptions.begin();
00830               it != mClientSubscriptions.end(); )
00831          {
00832             ClientSubscription* s = *it;
00833             it++;
00834             s->dialogDestroyed(msg);
00835          }
00836          if (mInviteSession)
00837          {
00838             mInviteSession->dialogDestroyed(msg);
00839          }
00840          mDestroying = false;
00841          possiblyDie(); //should aways result in destruction of this
00842          return;
00843       }
00844 #endif
00845    }
00846 }
00847 
00848 ServerSubscription*
00849 Dialog::findMatchingServerSub(const SipMessage& msg)
00850 {
00851    for (std::list<ServerSubscription*>::iterator i=mServerSubscriptions.begin();
00852         i != mServerSubscriptions.end(); ++i)
00853    {
00854       if ((*i)->matches(msg))
00855       {
00856          return *i;
00857       }
00858    }
00859    return 0;
00860 }
00861 
00862 ClientSubscription*
00863 Dialog::findMatchingClientSub(const SipMessage& msg)
00864 {
00865    for (std::list<ClientSubscription*>::iterator i=mClientSubscriptions.begin();
00866         i != mClientSubscriptions.end(); ++i)
00867    {
00868       if ((*i)->matches(msg))
00869       {
00870          return *i;
00871       }
00872    }
00873    return 0;
00874 }
00875 
00876 InviteSessionHandle
00877 Dialog::getInviteSession()
00878 {
00879    if (mInviteSession)
00880    {
00881       return mInviteSession->getSessionHandle();
00882    }
00883    else
00884    {
00885       return InviteSessionHandle::NotValid();
00886    }
00887 }
00888 
00889 std::vector<ClientSubscriptionHandle>
00890 Dialog::findClientSubscriptions(const Data& event)
00891 {
00892    std::vector<ClientSubscriptionHandle> handles;
00893 
00894    for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
00895         i != mClientSubscriptions.end(); ++i)
00896    {
00897       if ( (*i)->getEventType() == event)
00898       {
00899          handles.push_back((*i)->getHandle());
00900       }
00901    }
00902    return handles;
00903 }
00904 
00905 std::vector<ServerSubscriptionHandle>
00906 Dialog::findServerSubscriptions(const Data& event)
00907 {
00908    std::vector<ServerSubscriptionHandle> handles;
00909 
00910    for (std::list<ServerSubscription*>::const_iterator i = mServerSubscriptions.begin();
00911         i != mServerSubscriptions.end(); ++i)
00912    {
00913       if ( (*i)->getEventType() == event)
00914       {
00915          handles.push_back((*i)->getHandle());
00916       }
00917    }
00918    return handles;
00919 }
00920 
00921 std::vector<ClientSubscriptionHandle>
00922 Dialog::getClientSubscriptions()
00923 {
00924    std::vector<ClientSubscriptionHandle> handles;
00925 
00926    for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
00927         i != mClientSubscriptions.end(); ++i)
00928    {
00929       handles.push_back((*i)->getHandle());
00930    }
00931 
00932    return handles;
00933 }
00934 
00935 std::vector<ServerSubscriptionHandle>
00936 Dialog::getServerSubscriptions()
00937 {
00938    std::vector<ServerSubscriptionHandle> handles;
00939 
00940    for (std::list<ServerSubscription*>::const_iterator i = mServerSubscriptions.begin();
00941         i != mServerSubscriptions.end(); ++i)
00942    {
00943       handles.push_back((*i)->getHandle());
00944    }
00945 
00946    return handles;
00947 }
00948 
00949 void
00950 Dialog::redirected(const SipMessage& msg)
00951 {
00952    //Established dialogs are not destroyed by a redirect
00953    if (!mClientSubscriptions.empty() || !mServerSubscriptions.empty())
00954    {
00955       return;
00956    }
00957    if (mInviteSession)
00958    {
00959       ClientInviteSession* cInv = dynamic_cast<ClientInviteSession*>(mInviteSession);
00960       if (cInv)
00961       {
00962          cInv->handleRedirect(msg);
00963          mReUseDialogSet = true;  // Set flag so that DialogSet will not be destroyed and new Request can use it
00964       }
00965    }
00966 }
00967 
00968 void
00969 Dialog::makeRequest(SipMessage& request, MethodTypes method)
00970 {
00971    RequestLine rLine(method);
00972 
00973    rLine.uri() = mRemoteTarget.uri();
00974 
00975    request.header(h_RequestLine) = rLine;
00976    request.header(h_To) = mRemoteNameAddr;
00977 //   request.header(h_To).param(p_tag) = mId.getRemoteTag();
00978    request.header(h_From) = mLocalNameAddr;
00979 //   request.header(h_From).param(p_tag) = mId.getLocalTag();
00980 
00981    request.header(h_CallId) = mCallId;
00982 
00983    request.remove(h_RecordRoutes);  
00984    request.remove(h_Replaces);
00985 
00986    request.remove(h_Contacts);
00987    request.header(h_Contacts).push_front(mLocalContact);
00988 
00989    request.header(h_CSeq).method() = method;
00990    request.header(h_MaxForwards).value() = 70;
00991 
00992    //must keep old via for cancel
00993    if (method != CANCEL)
00994    {
00995       request.header(h_Routes) = mRouteSet;
00996       request.remove(h_Vias);
00997       Via via;
00998       via.param(p_branch); // will create the branch
00999       request.header(h_Vias).push_front(via);
01000    }
01001    else
01002    {
01003       assert(request.exists(h_Vias));
01004    }
01005 
01006    //don't increment CSeq for ACK or CANCEL
01007    if (method != ACK && method != CANCEL)
01008    {
01009       request.header(h_CSeq).sequence() = ++mLocalCSeq;
01010    }
01011    else
01012    {
01013       // ACK and cancel have a minimal header set
01014       request.remove(h_Accepts);
01015       request.remove(h_AcceptEncodings);
01016       request.remove(h_AcceptLanguages);
01017       request.remove(h_Allows);
01018       request.remove(h_Requires);
01019       request.remove(h_ProxyRequires);
01020       request.remove(h_Supporteds);
01021       // request.header(h_CSeq).sequence() = ?;  // Caller should provide original request, or modify CSeq to proper value after calling this method
01022    }
01023 
01024    // If method is INVITE then advertise required headers
01025    if(method == INVITE || method == UPDATE)
01026    {
01027       if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::Allow)) request.header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods();
01028       if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::AcceptEncoding)) request.header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings();
01029       if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::AcceptLanguage)) request.header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages();
01030       if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::AllowEvents)) request.header(h_AllowEvents) = mDum.getMasterProfile()->getAllowedEvents();
01031       if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::Supported)) request.header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags();
01032    }
01033 
01034    if (mDialogSet.mUserProfile->isAnonymous())
01035    {
01036       request.header(h_Privacys).push_back(PrivacyCategory(Symbols::id));
01037    }
01038 
01039    DebugLog ( << "Dialog::makeRequest: " << std::endl << std::endl << request );
01040 }
01041 
01042 
01043 void
01044 Dialog::makeResponse(SipMessage& response, const SipMessage& request, int code)
01045 {
01046    assert( code >= 100 );
01047    response.remove(h_Contacts);
01048    if (code < 300 && code > 100)
01049    {
01050       assert(request.isRequest());
01051       assert(request.header(h_RequestLine).getMethod() == INVITE ||
01052              request.header(h_RequestLine).getMethod() == SUBSCRIBE ||
01053              request.header(h_RequestLine).getMethod() == BYE ||
01054              request.header(h_RequestLine).getMethod() == CANCEL ||
01055              request.header(h_RequestLine).getMethod() == REFER ||
01056              request.header(h_RequestLine).getMethod() == MESSAGE ||
01057              request.header(h_RequestLine).getMethod() == NOTIFY ||
01058              request.header(h_RequestLine).getMethod() == INFO ||
01059              request.header(h_RequestLine).getMethod() == OPTIONS ||
01060              request.header(h_RequestLine).getMethod() == UPDATE
01061              );
01062 
01063 //      assert (request.header(h_RequestLine).getMethod() == CANCEL ||  // Contact header is not required for Requests that do not form a dialog
01064 //                    request.header(h_RequestLine).getMethod() == BYE ||
01065 //                    request.header(h_Contacts).size() == 1);
01066       Helper::makeResponse(response, request, code, mLocalContact);
01067       response.header(h_To).param(p_tag) = mId.getLocalTag();
01068 
01069       if((request.header(h_RequestLine).getMethod() == INVITE ||
01070           request.header(h_RequestLine).getMethod() == UPDATE)
01071          && code >= 200 && code < 300)
01072       {
01073          // Check if we should add our capabilites to the invite success response
01074          if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::Allow)) 
01075          {
01076             response.header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods();
01077          }
01078          if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::AcceptEncoding)) 
01079          {
01080             response.header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings();
01081          }
01082          if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::AcceptLanguage)) 
01083          {
01084             response.header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages();
01085          }
01086          if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::AllowEvents)) 
01087          {
01088             response.header(h_AllowEvents) = mDum.getMasterProfile()->getAllowedEvents();
01089          }
01090          if(mDialogSet.mUserProfile->isAdvertisedCapability(Headers::Supported)) 
01091          {
01092             response.header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags();
01093          }
01094       }
01095    }
01096    else
01097    {
01098       Helper::makeResponse(response, request, code);
01099       response.header(h_To).param(p_tag) = mId.getLocalTag();
01100    }
01101 
01102    DebugLog ( << "Dialog::makeResponse: " << std::endl << std::endl << response);
01103 }
01104 
01105 
01106 ClientInviteSession*
01107 Dialog::makeClientInviteSession(const SipMessage& response)
01108 {
01109    InviteSessionCreator* creator = dynamic_cast<InviteSessionCreator*>(mDialogSet.getCreator());
01110    if (!creator)
01111    {
01112       assert(0); // !jf! this maybe can assert by evil UAS
01113       return 0;
01114    }
01115    //return mDum.createAppClientInviteSession(*this, *creator);
01116    return new ClientInviteSession(mDum, *this, creator->getLastRequest(),
01117                                   creator->getInitialOffer(), creator->getEncryptionLevel(), creator->getServerSubscription());
01118 }
01119 
01120 
01121 
01122 ClientSubscription*
01123 Dialog::makeClientSubscription(const SipMessage& request)
01124 {
01125    return new ClientSubscription(mDum, *this, request, mDefaultSubExpiration);
01126 }
01127 
01128 
01129 ServerInviteSession*
01130 Dialog::makeServerInviteSession(const SipMessage& request)
01131 {
01132    return new ServerInviteSession(mDum, *this, request);
01133 }
01134 
01135 ServerSubscription*
01136 Dialog::makeServerSubscription(const SipMessage& request)
01137 {
01138    return new ServerSubscription(mDum, *this, request);
01139 }
01140 
01141 Dialog::Exception::Exception(const Data& msg, const Data& file, int line)
01142    : BaseException(msg, file, line)
01143 {
01144 }
01145 
01146 
01147 void
01148 Dialog::send(SharedPtr<SipMessage> msg)
01149 {
01150    if (msg->isRequest() && msg->header(h_CSeq).method() != ACK)
01151    {
01152       mRequests[msg->header(h_CSeq).sequence()] = msg;
01153    }
01154    mDum.send(msg);
01155 }
01156 
01157 void
01158 Dialog::onForkAccepted()
01159 {
01160    ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession);
01161    if (uac)
01162    {
01163       uac->onForkAccepted();
01164    }
01165 }
01166 
01167 void 
01168 Dialog::possiblyDie()
01169 {
01170    if (!mDestroying)
01171    {
01172       if (mClientSubscriptions.empty() &&
01173           mServerSubscriptions.empty() &&
01174           !mInviteSession)
01175       {
01176          mDestroying = true;
01177          mDum.destroy(this);
01178       }
01179    }
01180 }
01181 
01182 void
01183 Dialog::flowTerminated()
01184 {
01185    // Clear the network association
01186    mNetworkAssociation.clear();
01187    
01188    // notify server subscirption dialogs
01189    std::list<ServerSubscription*> tempServerList = mServerSubscriptions;  // Create copy since subscription can be deleted
01190    for (std::list<ServerSubscription*>::iterator is=tempServerList.begin();
01191         is != tempServerList.end(); ++is)
01192    {
01193       (*is)->flowTerminated();
01194    }
01195 
01196    // notify client subscription dialogs
01197    std::list<ClientSubscription*> tempClientList = mClientSubscriptions;  // Create copy since subscription can be deleted
01198    for (std::list<ClientSubscription*>::iterator ic=tempClientList.begin();
01199         ic != tempClientList.end(); ++ic)
01200    {
01201       (*ic)->flowTerminated();
01202    }
01203 
01204    // notify invite session dialog
01205    if (mInviteSession)
01206    {
01207       mInviteSession->flowTerminated();
01208    }
01209 }
01210 
01211 EncodeStream&
01212 resip::operator<<(EncodeStream& strm, const Dialog& dialog)
01213 {
01214    strm
01215       << "mClientSubscriptions("
01216       << dialog.mClientSubscriptions.size()
01217       << "), "
01218       << "mServerSubscriptions("
01219       << dialog.mServerSubscriptions.size()
01220       << ")";
01221    return strm;
01222 }
01223 
01224 
01225 /* ====================================================================
01226  * The Vovida Software License, Version 1.0
01227  *
01228  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
01229  *
01230  * Redistribution and use in source and binary forms, with or without
01231  * modification, are permitted provided that the following conditions
01232  * are met:
01233  *
01234  * 1. Redistributions of source code must retain the above copyright
01235  *    notice, this list of conditions and the following disclaimer.
01236  *
01237  * 2. Redistributions in binary form must reproduce the above copyright
01238  *    notice, this list of conditions and the following disclaimer in
01239  *    the documentation and/or other materials provided with the
01240  *    distribution.
01241  *
01242  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
01243  *    and "Vovida Open Communication Application Library (VOCAL)" must
01244  *    not be used to endorse or promote products derived from this
01245  *    software without prior written permission. For written
01246  *    permission, please contact vocal@vovida.org.
01247  *
01248  * 4. Products derived from this software may not be called "VOCAL", nor
01249  *    may "VOCAL" appear in their name, without prior written
01250  *    permission of Vovida Networks, Inc.
01251  *
01252  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
01253  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
01254  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
01255  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
01256  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
01257  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
01258  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
01259  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
01260  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
01261  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
01262  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
01263  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
01264  * DAMAGE.
01265  *
01266  * ====================================================================
01267  *
01268  * This software consists of voluntary contributions made by Vovida
01269  * Networks, Inc. and many individuals on behalf of Vovida Networks,
01270  * Inc.  For more information on Vovida Networks, Inc., please see
01271  * <http://www.vovida.org/>.
01272  *
01273  */
01274 
01275 
01276