|
reSIProcate/DialogUsageManager
9680
|
00001 00002 #include "resip/stack/Helper.hxx" 00003 #include "resip/dum/AppDialog.hxx" 00004 #include "resip/dum/AppDialogSet.hxx" 00005 #include "resip/dum/BaseCreator.hxx" 00006 #include "resip/dum/ClientAuthManager.hxx" 00007 #include "resip/dum/ClientOutOfDialogReq.hxx" 00008 #include "resip/dum/ClientPublication.hxx" 00009 #include "resip/dum/ClientRegistration.hxx" 00010 #include "resip/dum/ClientPagerMessage.hxx" 00011 #include "resip/dum/ServerPagerMessage.hxx" 00012 #include "resip/dum/Dialog.hxx" 00013 #include "resip/dum/DialogSet.hxx" 00014 #include "resip/dum/DialogSetHandler.hxx" 00015 #include "resip/dum/DialogEventStateManager.hxx" 00016 #include "resip/dum/DialogUsageManager.hxx" 00017 #include "resip/dum/MasterProfile.hxx" 00018 #include "resip/dum/RedirectManager.hxx" 00019 #include "resip/dum/UsageUseException.hxx" 00020 #include "resip/dum/ServerOutOfDialogReq.hxx" 00021 #include "resip/dum/ServerRegistration.hxx" 00022 #include "resip/dum/DumHelper.hxx" 00023 #include "resip/dum/SubscriptionCreator.hxx" 00024 #include "rutil/Logger.hxx" 00025 #include "rutil/Inserter.hxx" 00026 #include "rutil/WinLeakCheck.hxx" 00027 00028 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM 00029 00030 using namespace resip; 00031 using namespace std; 00032 00033 // UAC 00034 DialogSet::DialogSet(BaseCreator* creator, DialogUsageManager& dum) : 00035 mMergeKey(), 00036 mDialogs(), 00037 mCreator(creator), 00038 mId(*creator->getLastRequest()), 00039 mDum(dum), 00040 mAppDialogSet(0), 00041 mState(Initial), 00042 mClientRegistration(0), 00043 mServerRegistration(0), 00044 mClientPublication(0), 00045 mClientOutOfDialogRequests(), 00046 mServerOutOfDialogRequest(0), 00047 mClientPagerMessage(0), 00048 mServerPagerMessage(0) 00049 { 00050 setUserProfile(creator->getUserProfile()); 00051 assert(!creator->getLastRequest()->isExternal()); 00052 DebugLog ( << " ************* Created DialogSet(UAC) -- " << mId << "*************" ); 00053 } 00054 00055 // UAS 00056 DialogSet::DialogSet(const SipMessage& request, DialogUsageManager& dum) : 00057 mMergeKey(request, dum.getMasterProfile()->checkReqUriInMergeDetectionEnabled()), 00058 mDialogs(), 00059 mCreator(0), 00060 mId(request), 00061 mDum(dum), 00062 mAppDialogSet(0), 00063 mState(Established), 00064 mClientRegistration(0), 00065 mServerRegistration(0), 00066 mClientPublication(0), 00067 mClientOutOfDialogRequests(), 00068 mServerOutOfDialogRequest(0), 00069 mClientPagerMessage(0), 00070 mServerPagerMessage(0) 00071 { 00072 assert(request.isRequest()); 00073 assert(request.isExternal()); 00074 mDum.mMergedRequests.insert(mMergeKey); 00075 if (request.header(h_RequestLine).method() == INVITE) 00076 { 00077 if(mDum.mCancelMap.count(request.getTransactionId()) != 0) 00078 { 00079 WarningLog ( << "An endpoint is using the same tid in multiple INVITE requests, ability to match CANCEL requests correctly may be comprimised, tid=" << request.getTransactionId() ); 00080 } 00081 mCancelKey = request.getTransactionId(); 00082 mDum.mCancelMap[mCancelKey] = this; 00083 } 00084 DebugLog ( << " ************* Created DialogSet(UAS) *************: " << mId); 00085 } 00086 00087 DialogSet::~DialogSet() 00088 { 00089 if (mDum.mClientAuthManager.get()) 00090 { 00091 mDum.mClientAuthManager->dialogSetDestroyed(getId()); 00092 } 00093 00094 if (mMergeKey != MergedRequestKey::Empty) 00095 { 00096 mDum.requestMergedRequestRemoval(mMergeKey); 00097 } 00098 00099 if (!mCancelKey.empty()) 00100 { 00101 mDum.mCancelMap.erase(mCancelKey); 00102 } 00103 00104 delete mCreator; 00105 while(!mDialogs.empty()) 00106 { 00107 delete mDialogs.begin()->second; 00108 } 00109 00110 delete mClientRegistration; 00111 delete mServerRegistration; 00112 delete mClientPublication; 00113 delete mServerOutOfDialogRequest; 00114 delete mClientPagerMessage; 00115 delete mServerPagerMessage; 00116 00117 while (!mClientOutOfDialogRequests.empty()) 00118 { 00119 delete *mClientOutOfDialogRequests.begin(); 00120 } 00121 00122 DebugLog ( << " ********** DialogSet::~DialogSet: " << mId << "*************" ); 00123 // !dcm! -- very delicate code, change the order things go horribly wrong 00124 00125 mDum.removeDialogSet(this->getId()); 00126 if (mAppDialogSet) 00127 { 00128 mAppDialogSet->destroy(); 00129 } 00130 } 00131 00132 void DialogSet::possiblyDie() 00133 { 00134 if(mState != Destroying && 00135 mDialogs.empty() && 00136 // The following check ensures we are not a UAC DialogSet in the Initial or 00137 // ReceivedProvisional states. 00138 // .slg. this check fixes a case where we might receive a short term usuage 00139 // request (such as OPTIONS) in the same dialogset as a UAC dialogset 00140 // for which we have not created any Dialogs yet - in this case 00141 // we don't want the dialogset to die, since the UAC usage is not complete. 00142 (mCreator == 0 || (mState != Initial && mState != ReceivedProvisional)) && 00143 mClientOutOfDialogRequests.empty() && 00144 !(mClientPublication || 00145 mServerOutOfDialogRequest || 00146 mClientPagerMessage || 00147 mServerPagerMessage || 00148 mClientRegistration || 00149 mServerRegistration)) 00150 { 00151 mState = Destroying; 00152 mDum.destroy(this); 00153 } 00154 } 00155 00156 DialogSetId 00157 DialogSet::getId() const 00158 { 00159 return mId; 00160 } 00161 00162 void 00163 DialogSet::addDialog(Dialog *dialog) 00164 { 00165 mDialogs[dialog->getId()] = dialog; 00166 } 00167 00168 BaseCreator* 00169 DialogSet::getCreator() 00170 { 00171 return mCreator; 00172 } 00173 00174 Dialog* 00175 DialogSet::findDialog(const SipMessage& msg) 00176 { 00177 if (msg.isResponse() && msg.header(h_StatusLine).statusCode() == 100) 00178 { 00179 return 0; 00180 } 00181 return findDialog(DialogId(msg)); 00182 #if 0 00183 DialogId id(msg); 00184 Dialog* dlog = findDialog(id); 00185 //vonage/2543 matching here 00186 if (dlog) 00187 { 00188 return dlog; 00189 } 00190 //match off transaction ID 00191 else if (msg.isResponse() && !msg.header(h_To).exists(p_tag)) 00192 { 00193 for(DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++) 00194 { 00195 if (it->second->matches(msg)) 00196 { 00197 return it->second; 00198 } 00199 } 00200 } 00201 else if (msg.exists(h_Contacts) && !msg.header(h_Contacts).empty() 00202 && msg.isResponse() 00203 && mDum.getProfile()->looseToTagMatching() 00204 && msg.header(h_To).exists(p_tag)) 00205 { 00206 const Uri& contact = msg.header(h_Contacts).front().uri(); 00207 00208 //match by contact 00209 for(DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++) 00210 { 00211 if (it->second->mRemoteTarget.uri() == msg.header(h_Contacts).front().uri()) 00212 { 00213 // !dcm! in the vonage case, the to tag should be updated to match the fake 00214 //vonage tag introduced in the 200 which is also used for the BYE. 00215 //find out how deep this rabbit hole goes, may just have a pugabble 00216 //filter api that can be added for dialog matching if things get any 00217 //more specific--this is the VonageKludgeFilter 00218 Dialog* dialog = it->second; 00219 DialogId old = dialog->getId(); 00220 dialog->mId = DialogId(old.getCallId(), old.getLocalTag(), msg.header(h_To).param(p_tag)); 00221 dialog->mRemoteNameAddr.param(p_tag) = msg.header(h_To).param(p_tag); 00222 mDialogs.erase(it); 00223 mDialogs[dialog->getId()] = dialog; 00224 return dialog; 00225 } 00226 } 00227 } 00228 return 0; 00229 #endif 00230 } 00231 00232 bool 00233 DialogSet::empty() const 00234 { 00235 return mDialogs.empty(); 00236 } 00237 00238 bool 00239 DialogSet::handledByAuthOrRedirect(const SipMessage& msg) 00240 { 00241 if (msg.isResponse() && !(mState == Terminating || 00242 mState == WaitingToEnd || 00243 mState == Destroying || 00244 mState == Cancelling)) 00245 { 00246 // !dcm! -- multiple usage grief...only one of each method type allowed 00247 if (getCreator() && 00248 msg.header(h_CSeq) == getCreator()->getLastRequest()->header(h_CSeq)) 00249 { 00250 if (mDum.mClientAuthManager.get()) 00251 { 00252 if (mDum.mClientAuthManager->handle(*getUserProfile().get(), *getCreator()->getLastRequest(), msg)) 00253 { 00254 // Note: ClientAuthManager->handle will end up incrementing the CSeq sequence of getLastRequest 00255 DebugLog( << "about to re-send request with digest credentials" ); 00256 StackLog( << getCreator()->getLastRequest() ); 00257 00258 mDum.send(getCreator()->getLastRequest()); 00259 return true; 00260 } 00261 } 00262 // !dcm! -- need to protect against 3xx highjacking a dialogset which 00263 //has a fully established dialog. also could case strange behaviour 00264 //by sending 401/407 at the wrong time. 00265 if (mDum.mRedirectManager.get() && mState != Established) // !slg! for now don't handle redirect in established dialogs - alternatively we could treat as a target referesh (using 1st Contact) and reissue request 00266 { 00267 if (mDum.mRedirectManager->handle(*this, *getCreator()->getLastRequest(), msg)) 00268 { 00269 //terminating existing dialogs(branches) as this is a final 00270 //response--?dcm?--merge w/ forking logic somehow? 00271 // !dcm! -- really, really horrible. Should make a don't die 00272 //scoped guard 00273 mState = Initial; 00274 for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end();) 00275 { 00276 (it++)->second->redirected(msg); 00277 } 00278 00279 if (mDialogs.size() == 0) 00280 { 00281 if (mDum.mDialogEventStateManager) 00282 { 00283 mDum.mDialogEventStateManager->onTerminated(*this, msg, InviteSessionHandler::Rejected); 00284 } 00285 } 00286 00287 InfoLog( << "about to re-send request to redirect destination" ); 00288 DebugLog( << getCreator()->getLastRequest() ); 00289 00290 mDum.send(getCreator()->getLastRequest()); 00291 return true; 00292 } 00293 00294 // Check if a 422 response to initial Invite (RFC4028) 00295 if(msg.header(h_StatusLine).statusCode() == 422 && msg.exists(h_MinSE)) 00296 { 00297 // Change interval to min from 422 response 00298 getCreator()->getLastRequest()->header(h_SessionExpires).value() = msg.header(h_MinSE).value(); 00299 getCreator()->getLastRequest()->header(h_MinSE).value() = msg.header(h_MinSE).value(); 00300 getCreator()->getLastRequest()->header(h_CSeq).sequence()++; 00301 00302 InfoLog( << "about to re-send request with new session expiration time" ); 00303 DebugLog( << getCreator()->getLastRequest() ); 00304 00305 mDum.send(getCreator()->getLastRequest()); 00306 return true; 00307 } 00308 } 00309 } 00310 } 00311 return false; 00312 } 00313 00314 00315 void 00316 DialogSet::dispatch(const SipMessage& msg) 00317 { 00318 if(!mAppDialogSet) 00319 { 00320 // !bwc! There are conditions where reuse of the AppDialogSet will cause 00321 // us to hit this code. This is because the teardown of DialogSets is not 00322 // atomic, causing the DialogSet to hang around for a short time after it 00323 // has given up its AppDialogSet. Also, if we have multiple Usages in 00324 // this DialogSet, one of the Usages may decide to re-establish itself in 00325 // a new Dialog, and take the AppDialogSet with it, leaving all the others 00326 // high and dry. This is a design issue that will take some real effort to 00327 // fix properly. This is a band-aid for now. 00328 // TODO fix this properly 00329 if(msg.isRequest()) 00330 { 00331 if(msg.method() != ACK) 00332 { 00333 SipMessage err; 00334 Helper::makeResponse(err, msg, 500, "DialogSet: My AppDialogSet is " 00335 "missing!"); 00336 mDum.sendResponse(err); 00337 } 00338 } 00339 else 00340 { 00341 ErrLog(<<"Response came in, but no AppDialogSet! Dropping this is very" 00342 "likely to cause leaks, but continuing to process it is " 00343 "likely to cause a core. Taking the lesser of two evils..."); 00344 } 00345 return; 00346 } 00347 00348 assert(msg.isRequest() || msg.isResponse()); 00349 00350 if (mState == WaitingToEnd) 00351 { 00352 assert(mDialogs.empty()); 00353 if (msg.isResponse()) 00354 { 00355 int code = msg.header(h_StatusLine).statusCode(); 00356 switch(mCreator->getLastRequest()->header(h_CSeq).method()) 00357 { 00358 case INVITE: 00359 if (code / 100 == 1) 00360 { 00361 mState = ReceivedProvisional; 00362 end(); 00363 } 00364 else if (code / 100 == 2) 00365 { 00366 Dialog dialog(mDum, msg, *this); 00367 00368 SharedPtr<SipMessage> ack(new SipMessage); 00369 dialog.makeRequest(*ack, ACK); 00370 ack->header(h_CSeq).sequence() = msg.header(h_CSeq).sequence(); 00371 dialog.send(ack); 00372 00373 SharedPtr<SipMessage> bye(new SipMessage); 00374 dialog.makeRequest(*bye, BYE); 00375 dialog.send(bye); 00376 00377 if (mDum.mDialogEventStateManager) 00378 { 00379 mDum.mDialogEventStateManager->onTerminated(dialog, *bye, InviteSessionHandler::LocalBye); 00380 } 00381 // Note: Destruction of this dialog object will cause DialogSet::possiblyDie to be called thus invoking mDum.destroy 00382 } 00383 else 00384 { 00385 if (mDum.mDialogEventStateManager) 00386 { 00387 mDum.mDialogEventStateManager->onTerminated(*this, msg, InviteSessionHandler::Rejected); 00388 } 00389 mState = Destroying; 00390 mDum.destroy(this); 00391 } 00392 break; 00393 case SUBSCRIBE: 00394 if (code / 100 == 1) 00395 { 00396 // do nothing - wait for final response 00397 } 00398 else if (code / 100 == 2) 00399 { 00400 Dialog dialog(mDum, msg, *this); 00401 00402 SharedPtr<SipMessage> unsubscribe(new SipMessage(*mCreator->getLastRequest().get())); // create message from initial request so we get proper headers 00403 dialog.makeRequest(*unsubscribe, SUBSCRIBE); 00404 unsubscribe->header(h_Expires).value() = 0; 00405 dialog.send(unsubscribe); 00406 00407 // Note: Destruction of this dialog object will cause DialogSet::possiblyDie to be called thus invoking mDum.destroy 00408 } 00409 else 00410 { 00411 mState = Destroying; 00412 mDum.destroy(this); 00413 } 00414 break; 00415 case PUBLISH: 00416 if (code / 100 == 1) 00417 { 00418 // do nothing - wait for final response 00419 } 00420 else if (code / 100 == 2) 00421 { 00422 Dialog dialog(mDum, msg, *this); 00423 00424 SharedPtr<SipMessage> unpublish(new SipMessage(*mCreator->getLastRequest().get())); // create message from initial request so we get proper headers 00425 dialog.makeRequest(*unpublish, PUBLISH); 00426 unpublish->header(h_Expires).value() = 0; 00427 dialog.send(unpublish); 00428 00429 // Note: Destruction of this dialog object will cause DialogSet::possiblyDie to be called thus invoking mDum.destroy 00430 } 00431 else 00432 { 00433 mState = Destroying; 00434 mDum.destroy(this); 00435 } 00436 break; 00437 // ?slg? shouldn't we handle register, ood and refer here too? 00438 default: 00439 mState = Destroying; 00440 mDum.destroy(this); 00441 break; 00442 } 00443 } 00444 else 00445 { 00446 SharedPtr<SipMessage> response(new SipMessage); 00447 mDum.makeResponse(*response, msg, 481); 00448 mDum.send(response); 00449 } 00450 return; 00451 } 00452 else if(mState == Cancelling) 00453 { 00454 assert(mDialogs.empty()); 00455 if (msg.isResponse()) 00456 { 00457 int code = msg.header(h_StatusLine).statusCode(); 00458 if(mCreator->getLastRequest()->header(h_CSeq).method() == INVITE) 00459 { 00460 if (code / 100 == 1) 00461 { 00462 // do nothing - wait for final response 00463 } 00464 // 200/Inv crossing CANCEL case 00465 else if (code / 100 == 2) 00466 { 00467 Dialog dialog(mDum, msg, *this); 00468 00469 SharedPtr<SipMessage> ack(new SipMessage); 00470 dialog.makeRequest(*ack, ACK); 00471 ack->header(h_CSeq).sequence() = msg.header(h_CSeq).sequence(); 00472 dialog.send(ack); 00473 00474 SharedPtr<SipMessage> bye(new SipMessage); 00475 dialog.makeRequest(*bye, BYE); 00476 dialog.send(bye); 00477 00478 // Note: Destruction of this dialog object will cause DialogSet::possiblyDie to be called thus invoking mDum.destroy 00479 } 00480 else 00481 { 00482 mState = Destroying; 00483 mDum.destroy(this); 00484 } 00485 } 00486 } 00487 else // is a request 00488 { 00489 SharedPtr<SipMessage> response(new SipMessage); 00490 mDum.makeResponse(*response, msg, 481); 00491 mDum.send(response); 00492 } 00493 return; 00494 } 00495 00496 if (handledByAuthOrRedirect(msg)) 00497 { 00498 return; 00499 } 00500 00501 Dialog* dialog = 0; 00502 if (!(msg.isResponse() && msg.header(h_StatusLine).statusCode() == 100)) // Don't look for dialog if msg is a 100 response 00503 { 00504 DialogMap::iterator i = mDialogs.find(DialogId(msg)); 00505 if (i != mDialogs.end()) 00506 { 00507 dialog = i->second; 00508 } 00509 } 00510 if (dialog) 00511 { 00512 if(dialog->isDestroying()) 00513 { 00514 if( msg.isRequest() ) 00515 { 00516 StackLog (<< "Matching dialog is destroying, sending 481 " << endl << msg); 00517 SharedPtr<SipMessage> response(new SipMessage); 00518 mDum.makeResponse(*response, msg, 481); 00519 mDum.send(response); 00520 } 00521 else 00522 { 00523 StackLog (<< "Matching dialog is destroying, dropping response message " << endl << msg); 00524 } 00525 return; 00526 } 00527 else 00528 { 00529 DebugLog (<< "Found matching dialog " << *dialog << " for " << endl << endl << msg); 00530 } 00531 } 00532 else 00533 { 00534 StackLog (<< "No matching dialog for " << endl << endl << msg); 00535 } 00536 00537 if (msg.isRequest()) 00538 { 00539 const SipMessage& request = msg; 00540 switch (request.header(h_CSeq).method()) 00541 { 00542 case INVITE: 00543 case CANCEL: //cancel needs work 00544 case SUBSCRIBE: 00545 break; //dialog creating/handled by dialog 00546 00547 case BYE: 00548 case INFO: 00549 case ACK: 00550 case UPDATE: 00551 if(!dialog) 00552 { 00553 SharedPtr<SipMessage> response(new SipMessage); 00554 mDum.makeResponse(*response, msg, 481); 00555 mDum.send(response); 00556 return; 00557 } 00558 break; 00559 00560 case REFER: 00561 if (request.header(h_To).exists(p_tag) || findDialog(request)) 00562 { 00563 DebugLog(<< "in dialog refer request"); 00564 break; // in dialog 00565 } 00566 else if((request.exists(h_ReferSub) && 00567 request.header(h_ReferSub).isWellFormed() && 00568 request.header(h_ReferSub).value()=="false") || 00569 (request.exists(h_Requires) && 00570 request.header(h_Requires).find(Token("norefersub"))))// out of dialog & noReferSub=true 00571 { 00572 DebugLog(<< "out of dialog refer request with norefersub"); 00573 assert(mServerOutOfDialogRequest == 0); 00574 mServerOutOfDialogRequest = makeServerOutOfDialog(request); 00575 mServerOutOfDialogRequest->dispatch(request); 00576 return; 00577 } 00578 else 00579 { 00580 DebugLog(<< "out of dialog refer request with refer sub"); 00581 break; // dialog creating 00582 } 00583 break; 00584 case NOTIFY: 00585 00586 // !jf! there shouldn't be a dialogset for ServerOutOfDialogReq 00587 if (request.header(h_To).exists(p_tag) || findDialog(request)) 00588 { 00589 break; //dialog creating/handled by dialog 00590 } 00591 else // no to tag - unsolicited notify 00592 { 00593 // unsolicited - not allowed but commonly implemented 00594 // by large companies with a bridge as their logo 00595 assert(mServerOutOfDialogRequest == 0); 00596 mServerOutOfDialogRequest = makeServerOutOfDialog(request); 00597 mServerOutOfDialogRequest->dispatch(request); 00598 return; 00599 } 00600 break; 00601 00602 case PUBLISH: 00603 assert(false); // handled in DialogUsageManager 00604 return; 00605 00606 case REGISTER: 00607 // !jf! move this to DialogUsageManager 00608 if (mServerRegistration == 0) 00609 { 00610 mServerRegistration = makeServerRegistration(request); 00611 } 00612 mServerRegistration->dispatch(request); 00613 return; 00614 00615 case MESSAGE: 00616 // !jf! move this to DialogUsageManager 00617 if(!dialog) 00618 { 00619 mServerPagerMessage = makeServerPagerMessage(request); 00620 mServerPagerMessage->dispatch(request); 00621 return; 00622 } 00623 break; 00624 00625 default: 00626 // !jf! move this to DialogUsageManager 00627 DebugLog ( << "In DialogSet::dispatch, default(ServerOutOfDialogRequest), msg: " << msg ); 00628 // only can be one ServerOutOfDialogReq at a time 00629 assert(mServerOutOfDialogRequest == 0); 00630 mServerOutOfDialogRequest = makeServerOutOfDialog(request); 00631 mServerOutOfDialogRequest->dispatch(request); 00632 return; 00633 } 00634 } 00635 else // the message is a response 00636 { 00637 const SipMessage& response = msg; 00638 00639 int code = msg.header(h_StatusLine).statusCode(); 00640 if (code == 423 00641 && msg.header(h_CSeq).method() == SUBSCRIBE 00642 && msg.exists(h_MinExpires) 00643 && getCreator() 00644 && msg.header(h_CSeq) == getCreator()->getLastRequest()->header(h_CSeq)) 00645 { 00646 getCreator()->getLastRequest()->header(h_CSeq).sequence()++; 00647 getCreator()->getLastRequest()->header(h_Expires).value() = msg.header(h_MinExpires).value(); 00648 DebugLog( << "Re sending inital(dialog forming) SUBSCRIBE due to 423, MinExpires is: " << msg.header(h_MinExpires).value()); 00649 mDum.send(getCreator()->getLastRequest()); 00650 return; 00651 } 00652 00653 // We should only do DialogState processing if this is a response to our initial request 00654 if(getCreator() && 00655 msg.header(h_CSeq) == getCreator()->getLastRequest()->header(h_CSeq)) 00656 { 00657 switch(mState) 00658 { 00659 case Initial: 00660 if (code < 200) 00661 { 00662 mState = ReceivedProvisional; 00663 } 00664 else if(code < 300) 00665 { 00666 mState = Established; 00667 } 00668 else 00669 { 00670 mState = Established; 00671 if (!mDialogs.empty()) 00672 { 00673 dispatchToAllDialogs(msg); 00674 return; 00675 } 00676 } 00677 break; 00678 case ReceivedProvisional: 00679 if (code < 200) 00680 { 00681 // fall through 00682 } 00683 else if (code < 300) 00684 { 00685 mState = Established; 00686 for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++) 00687 { 00688 if (it->second != dialog) // this is dialog that accepted 00689 { 00690 it->second->onForkAccepted(); 00691 } 00692 } 00693 } 00694 else // failure response 00695 { 00696 mState = Established; 00697 if (!mDialogs.empty()) 00698 { 00699 dispatchToAllDialogs(msg); 00700 return; 00701 } 00702 } 00703 break; 00704 default: 00705 // !jf! 00706 break; 00707 } 00708 } 00709 00710 if (response.header(h_StatusLine).statusCode() == 100) 00711 { 00712 if (mDum.mDialogSetHandler) 00713 { 00714 mDum.mDialogSetHandler->onTrying(mAppDialogSet->getHandle(), msg); 00715 } 00716 return; 00717 } 00718 00719 switch (response.header(h_CSeq).method()) 00720 { 00721 case INVITE: 00722 case SUBSCRIBE: 00723 case BYE: 00724 case ACK: 00725 case CANCEL: 00726 break; 00727 00728 case PUBLISH: 00729 if (mClientPublication == 0) 00730 { 00731 mClientPublication = makeClientPublication(response); 00732 } 00733 mClientPublication->dispatch(response); 00734 return; 00735 00736 case REGISTER: 00737 if (mClientRegistration == 0) 00738 { 00739 mClientRegistration = makeClientRegistration(response); 00740 } 00741 mClientRegistration->dispatch(response); 00742 return; 00743 00744 case MESSAGE: 00745 if (dialog) 00746 { 00747 break; 00748 } 00749 else if (mClientPagerMessage) 00750 { 00751 mClientPagerMessage->dispatch(response); 00752 } 00753 return; 00754 00755 case INFO: 00756 case UPDATE: 00757 if (dialog) 00758 { 00759 break; 00760 } 00761 else // not allowed 00762 { 00763 return; 00764 } 00765 case REFER: 00766 if (dynamic_cast<SubscriptionCreator*>(getCreator())) 00767 { 00768 break; 00769 } 00770 case NOTIFY: 00771 if (dialog) 00772 { 00773 break; 00774 } 00775 00776 default: 00777 { 00778 ClientOutOfDialogReq* req = findMatchingClientOutOfDialogReq(response); 00779 if (req == 0) 00780 { 00781 req = makeClientOutOfDialogReq(response); 00782 mClientOutOfDialogRequests.push_back(req); 00783 } 00784 req->dispatch(response); 00785 return; 00786 } 00787 } 00788 } 00789 00790 if (dialog == 0) 00791 { 00792 if (msg.isRequest() && msg.header(h_RequestLine).method() == CANCEL) 00793 { 00794 dispatchToAllDialogs(msg); 00795 return; 00796 } 00797 00798 if (msg.isResponse()) 00799 { 00800 if( mCreator ) 00801 { 00802 SharedPtr<SipMessage> lastRequest(mCreator->getLastRequest()); 00803 if( 0 != lastRequest.get() && !(lastRequest->header(h_CSeq) == msg.header(h_CSeq))) 00804 { 00805 InfoLog(<< "Cannot create a dialog, cseq does not match initial dialog request (illegal mid-dialog fork? see 3261 14.1)."); 00806 return; 00807 } 00808 } 00809 else 00810 { 00811 ErrLog(<< "Can’t create a dialog, on a UAS response."); 00812 return; 00813 } 00814 00815 int code = msg.header(h_StatusLine).statusCode(); 00816 00817 if (code > 100 && code < 200 && 00818 (!msg.exists(h_Contacts) || 00819 !msg.exists(h_To) || !msg.header(h_To).exists(p_tag))) 00820 { 00821 InfoLog ( << "Cannot create a dialog, no Contact or To tag in 1xx." ); 00822 if (mDum.mDialogSetHandler) 00823 { 00824 if (mDum.mDialogEventStateManager) 00825 { 00826 mDum.mDialogEventStateManager->onProceedingUac(*this, msg); 00827 } 00828 mDum.mDialogSetHandler->onNonDialogCreatingProvisional(mAppDialogSet->getHandle(), msg); 00829 } 00830 return; 00831 } 00832 // If failure response and no dialogs, create a dialog, otherwise 00833 else if (code >= 300 && !mDialogs.empty()) 00834 { 00835 dispatchToAllDialogs(msg); 00836 return; 00837 } 00838 } 00839 00840 DebugLog ( << "mState == " << mState << " Creating a new Dialog from msg: " << std::endl << std::endl <<msg); 00841 try 00842 { 00843 // !jf! This could throw due to bad header in msg, should we catch and rethrow 00844 dialog = new Dialog(mDum, msg, *this); 00845 } 00846 catch(BaseException& e) 00847 { 00848 InfoLog( << "Unable to create dialog: " << e.getMessage()); 00849 if (msg.isResponse()) 00850 { 00851 //don't delete on provisional responses, as FWD will eventually send a 00852 //valid 200 00853 if(mDialogs.empty() && 00854 msg.header(h_StatusLine).statusCode() >= 200) 00855 { 00856 // really we should wait around 32s before deleting this 00857 if (mDum.mDialogEventStateManager) 00858 { 00859 mDum.mDialogEventStateManager->onTerminated(*this, msg, InviteSessionHandler::Error); 00860 } 00861 00862 mState = Destroying; 00863 mDum.destroy(this); 00864 } 00865 } 00866 else 00867 { 00868 // !jf! derek thinks we should destroy only on invalid CANCEL or 00869 // BYE, hmmphh. see draft-sparks-sipping-dialogusage-01.txt 00870 SharedPtr<SipMessage> response(new SipMessage); 00871 mDum.makeResponse(*response, msg, 400); 00872 mDum.send(response); 00873 if(mDialogs.empty()) 00874 { 00875 if (mDum.mDialogEventStateManager) 00876 { 00877 mDum.mDialogEventStateManager->onTerminated(*this, msg, InviteSessionHandler::Error); 00878 } 00879 mState = Destroying; 00880 mDum.destroy(this); 00881 } 00882 } 00883 return; 00884 } 00885 00886 assert(mState != WaitingToEnd); 00887 DebugLog ( << "### Calling CreateAppDialog ###: " << std::endl << std::endl <<msg); 00888 AppDialog* appDialog = mAppDialogSet->createAppDialog(msg); 00889 dialog->mAppDialog = appDialog; 00890 appDialog->mDialog = dialog; 00891 dialog->dispatch(msg); 00892 } 00893 else 00894 { 00895 dialog->dispatch(msg); 00896 } 00897 } 00898 00899 00900 ClientOutOfDialogReq* 00901 DialogSet::findMatchingClientOutOfDialogReq(const SipMessage& msg) 00902 { 00903 for (std::list<ClientOutOfDialogReq*>::iterator i=mClientOutOfDialogRequests.begin(); 00904 i != mClientOutOfDialogRequests.end(); ++i) 00905 { 00906 if ((*i)->matches(msg)) 00907 { 00908 return *i; 00909 } 00910 } 00911 return 0; 00912 } 00913 00914 Dialog* 00915 DialogSet::findDialog(const DialogId id) 00916 { 00917 StackLog (<< "findDialog: " << id << " in " << InserterP(mDialogs)); 00918 00919 DialogMap::iterator i = mDialogs.find(id); 00920 if (i == mDialogs.end()) 00921 { 00922 return 0; 00923 } 00924 else 00925 { 00926 if(i->second->isDestroying()) 00927 { 00928 return 0; 00929 } 00930 else 00931 { 00932 return i->second; 00933 } 00934 } 00935 } 00936 00937 void 00938 DialogSet::end() 00939 { 00940 switch(mState) 00941 { 00942 case Initial: 00943 mState = WaitingToEnd; 00944 break; 00945 case WaitingToEnd: 00946 break; 00947 case ReceivedProvisional: 00948 { 00949 assert (mCreator->getLastRequest()->header(h_CSeq).method() == INVITE); 00950 mState = Terminating; 00951 // !jf! this should be made exception safe 00952 SharedPtr<SipMessage> cancel(Helper::makeCancel(*getCreator()->getLastRequest())); 00953 mDum.send(cancel); 00954 00955 if (mDum.mDialogEventStateManager) 00956 { 00957 mDum.mDialogEventStateManager->onTerminated(*this, *cancel, InviteSessionHandler::LocalCancel); 00958 } 00959 00960 if (mDialogs.empty()) 00961 { 00962 mState = Cancelling; 00963 } 00964 else 00965 { 00966 //need to lag and do last element ouside of look as this DialogSet will be 00967 //deleted if all dialogs are destroyed 00968 for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++) 00969 { 00970 try 00971 { 00972 it->second->cancel(); 00973 } 00974 catch(UsageUseException& e) 00975 { 00976 InfoLog (<< "Caught: " << e); 00977 } 00978 } 00979 } 00980 } 00981 break; 00982 case Established: 00983 { 00984 for (DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); ++it) 00985 { 00986 try 00987 { 00988 it->second->end(); 00989 } 00990 catch(UsageUseException& e) 00991 { 00992 InfoLog (<< "Caught: " << e); 00993 } 00994 } 00995 mState = Terminating; 00996 break; 00997 } 00998 case Terminating: 00999 case Cancelling: 01000 case Destroying: 01001 DebugLog (<< "DialogSet::end() called on a DialogSet that is already Terminating"); 01002 //assert(0); 01003 } 01004 } 01005 01006 01007 ClientRegistrationHandle 01008 DialogSet::getClientRegistration() 01009 { 01010 if (mClientRegistration) 01011 { 01012 return mClientRegistration->getHandle(); 01013 } 01014 else 01015 { 01016 return ClientRegistrationHandle::NotValid(); 01017 } 01018 } 01019 01020 ServerRegistrationHandle 01021 DialogSet::getServerRegistration() 01022 { 01023 if (mServerRegistration) 01024 { 01025 return mServerRegistration->getHandle(); 01026 } 01027 else 01028 { 01029 return ServerRegistrationHandle::NotValid(); 01030 } 01031 } 01032 01033 ClientPublicationHandle 01034 DialogSet::getClientPublication() 01035 { 01036 if (mClientPublication) 01037 { 01038 return mClientPublication->getHandle(); 01039 } 01040 else 01041 { 01042 return ClientPublicationHandle::NotValid(); 01043 } 01044 } 01045 01046 ClientRegistration* 01047 DialogSet::makeClientRegistration(const SipMessage& response) 01048 { 01049 BaseCreator* creator = getCreator(); 01050 assert(creator); 01051 return new ClientRegistration(mDum, *this, creator->getLastRequest()); 01052 } 01053 01054 ClientPublication* 01055 DialogSet::makeClientPublication(const SipMessage& response) 01056 { 01057 BaseCreator* creator = getCreator(); 01058 assert(creator); 01059 return new ClientPublication(mDum, *this, creator->getLastRequest()); 01060 } 01061 01062 ClientOutOfDialogReq* 01063 DialogSet::makeClientOutOfDialogReq(const SipMessage& response) 01064 { 01065 BaseCreator* creator = getCreator(); 01066 assert(creator); 01067 return new ClientOutOfDialogReq(mDum, *this, *creator->getLastRequest()); 01068 } 01069 01070 ServerRegistration* 01071 DialogSet::makeServerRegistration(const SipMessage& request) 01072 { 01073 return new ServerRegistration(mDum, *this, request); 01074 } 01075 01076 ServerOutOfDialogReq* 01077 DialogSet::makeServerOutOfDialog(const SipMessage& request) 01078 { 01079 return new ServerOutOfDialogReq(mDum, *this, request); 01080 } 01081 01082 ServerPagerMessage* 01083 DialogSet::makeServerPagerMessage(const SipMessage& request) 01084 { 01085 return new ServerPagerMessage(mDum, *this, request); 01086 } 01087 01088 ServerOutOfDialogReqHandle 01089 DialogSet::getServerOutOfDialog() 01090 { 01091 if (mServerOutOfDialogRequest) 01092 { 01093 return mServerOutOfDialogRequest->getHandle(); 01094 } 01095 else 01096 { 01097 return ServerOutOfDialogReqHandle::NotValid(); 01098 } 01099 } 01100 01101 void DialogSet::dispatchToAllDialogs(const SipMessage& msg) 01102 { 01103 if (!mDialogs.empty()) 01104 { 01105 for(DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++) 01106 { 01107 it->second->dispatch(msg); 01108 } 01109 } 01110 } 01111 01112 SharedPtr<UserProfile> 01113 DialogSet::getUserProfile() const 01114 { 01115 if(mUserProfile.get()) 01116 { 01117 return mUserProfile; 01118 } 01119 else 01120 { 01121 // If no UserProfile set then use UserProfile of the MasterProfile 01122 return mDum.getMasterUserProfile(); 01123 } 01124 } 01125 01126 void 01127 DialogSet::setUserProfile(SharedPtr<UserProfile> userProfile) 01128 { 01129 assert(userProfile.get()); 01130 mUserProfile = userProfile; 01131 } 01132 01133 void 01134 DialogSet::flowTerminated(const Tuple& flow) 01135 { 01136 // The flow has failed - clear the flow key/tuple in the UserProfile 01137 mUserProfile->clearClientOutboundFlowTuple(); 01138 01139 // If this profile is configured for client outbound and the connectionTerminated 01140 // matches the connection stored in the profile, then notify the client registration 01141 // and all dialogs in this dialogset that the flow has terminated 01142 // Check other usage types that we send requests on 01143 if(mClientRegistration) 01144 { 01145 mClientRegistration->flowTerminated(); 01146 } 01147 01148 for(DialogMap::iterator it = mDialogs.begin(); it != mDialogs.end(); it++) 01149 { 01150 it->second->flowTerminated(); 01151 } 01152 } 01153 01154 EncodeStream& 01155 resip::operator<<(EncodeStream& strm, const DialogSet& ds) 01156 { 01157 // Used in Inserter, so keeping brief (ie. Id is already logged by Inserter) 01158 strm << "state=" << ds.mState; 01159 return strm; 01160 } 01161 01162 01163 /* ==================================================================== 01164 * The Vovida Software License, Version 1.0 01165 * 01166 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. 01167 * 01168 * Redistribution and use in source and binary forms, with or without 01169 * modification, are permitted provided that the following conditions 01170 * are met: 01171 * 01172 * 1. Redistributions of source code must retain the above copyright 01173 * notice, this list of conditions and the following disclaimer. 01174 * 01175 * 2. Redistributions in binary form must reproduce the above copyright 01176 * notice, this list of conditions and the following disclaimer in 01177 * the documentation and/or other materials provided with the 01178 * distribution. 01179 * 01180 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 01181 * and "Vovida Open Communication Application Library (VOCAL)" must 01182 * not be used to endorse or promote products derived from this 01183 * software without prior written permission. For written 01184 1 * permission, please contact vocal@vovida.org. 01185 * 01186 * 4. Products derived from this software may not be called "VOCAL", nor 01187 * may "VOCAL" appear in their name, without prior written 01188 * permission of Vovida Networks, Inc. 01189 * 01190 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 01191 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 01192 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 01193 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 01194 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 01195 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 01196 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 01197 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 01198 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 01199 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 01200 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 01201 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 01202 * DAMAGE. 01203 * 01204 * ==================================================================== 01205 * 01206 * This software consists of voluntary contributions made by Vovida 01207 * Networks, Inc. and many individuals on behalf of Vovida Networks, 01208 * Inc. For more information on Vovida Networks, Inc., please see 01209 * <http://www.vovida.org/>. 01210 * 01211 */
1.7.5.1