|
reSIProcate/DialogUsageManager
9680
|
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
1.7.5.1