|
reSIProcate/DialogUsageManager
9680
|
00001 #include "resip/dum/DialogEventStateManager.hxx" 00002 #include "rutil/Random.hxx" 00003 #include "rutil/Logger.hxx" 00004 00005 namespace resip 00006 { 00007 00008 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM 00009 00010 DialogEventStateManager::DialogEventStateManager() 00011 : mDialogEventHandler(0) 00012 { 00013 } 00014 00015 DialogEventStateManager::~DialogEventStateManager() 00016 { 00017 } 00018 00019 // we've received an INVITE 00020 void 00021 DialogEventStateManager::onTryingUas(Dialog& dialog, const SipMessage& invite) 00022 { 00023 DialogEventInfo* eventInfo = new DialogEventInfo(); 00024 eventInfo->mDialogEventId = Random::getVersion4UuidUrn(); // !jjg! is this right? 00025 eventInfo->mDialogId = dialog.getId(); 00026 eventInfo->mDirection = DialogEventInfo::Recipient; 00027 eventInfo->mCreationTimeSeconds = Timer::getTimeSecs(); 00028 eventInfo->mInviteSession = InviteSessionHandle::NotValid(); 00029 eventInfo->mRemoteOfferAnswer = (invite.getContents() != NULL ? std::auto_ptr<Contents>(invite.getContents()->clone()) : std::auto_ptr<Contents>()); 00030 eventInfo->mLocalIdentity = dialog.getLocalNameAddr(); 00031 eventInfo->mLocalTarget = dialog.getLocalContact().uri(); // !slg! TODO - fix me - the Dialog stored local contact has an empty hostname so that the stack will fill it in 00032 eventInfo->mRemoteIdentity = dialog.getRemoteNameAddr(); 00033 eventInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri())); 00034 eventInfo->mRouteSet = dialog.getRouteSet(); 00035 eventInfo->mState = DialogEventInfo::Trying; 00036 00037 if (invite.exists(h_Replaces) && 00038 invite.header(h_Replaces).isWellFormed()) 00039 { 00040 Data replacesToTag = invite.header(h_Replaces).exists(p_toTag) ? invite.header(h_Replaces).param(p_toTag) : Data::Empty; 00041 Data replacesFromTag = invite.header(h_Replaces).exists(p_fromTag) ? invite.header(h_Replaces).param(p_fromTag) : Data::Empty; 00042 00043 eventInfo->mReplacesId = std::auto_ptr<DialogId>(new DialogId(invite.header(h_Replaces).value(), 00044 replacesToTag, 00045 replacesFromTag)); 00046 00047 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.find(*(eventInfo->mReplacesId)); 00048 if (it != mDialogIdToEventInfo.end()) 00049 { 00050 it->second->mReplaced = true; 00051 } 00052 } 00053 if (invite.exists(h_ReferredBy) && 00054 invite.header(h_ReferredBy).isWellFormed()) 00055 { 00056 eventInfo->mReferredBy = std::auto_ptr<NameAddr>(new NameAddr(invite.header(h_ReferredBy))); 00057 } 00058 00059 mDialogIdToEventInfo[dialog.getId()] = eventInfo; 00060 00061 TryingDialogEvent evt(*eventInfo, invite); 00062 mDialogEventHandler->onTrying(evt); 00063 } 00064 00065 // we've sent an INVITE 00066 void 00067 DialogEventStateManager::onTryingUac(DialogSet& dialogSet, const SipMessage& invite) 00068 { 00069 DialogId fakeId(dialogSet.getId(), Data::Empty); 00070 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.find(fakeId); 00071 00072 DialogEventInfo* eventInfo = 0; 00073 00074 if (it != mDialogIdToEventInfo.end()) 00075 { 00076 // .jjg. we will get in here if our INVITE gets challenged; just swallow the onTrying event in this case 00077 eventInfo = it->second; 00078 if (eventInfo->mState == DialogEventInfo::Trying) 00079 { 00080 return; 00081 } 00082 } 00083 else 00084 { 00085 eventInfo = new DialogEventInfo(); 00086 } 00087 00088 eventInfo->mDialogEventId = Random::getVersion4UuidUrn(); 00089 eventInfo->mDialogId = DialogId(dialogSet.getId(), Data::Empty); 00090 eventInfo->mDirection = DialogEventInfo::Initiator; 00091 eventInfo->mCreationTimeSeconds = Timer::getTimeSecs(); 00092 eventInfo->mInviteSession = InviteSessionHandle::NotValid(); 00093 eventInfo->mLocalIdentity = invite.header(h_From); 00094 // ?bwc? Has something already checked for well-formedness here? 00095 // Maybe DialogSet? We need to be absolutely certain that this exists and is 00096 // well-formed. Assert for now. 00097 assert(!invite.empty(h_Contacts)); 00098 assert(invite.header(h_Contacts).front().isWellFormed()); 00099 eventInfo->mLocalTarget = invite.header(h_Contacts).front().uri(); 00100 eventInfo->mRemoteIdentity = invite.header(h_To); 00101 eventInfo->mLocalOfferAnswer = (invite.getContents() != NULL ? std::auto_ptr<Contents>(invite.getContents()->clone()) : std::auto_ptr<Contents>()); 00102 eventInfo->mState = DialogEventInfo::Trying; 00103 00104 if (invite.exists(h_ReferredBy) && 00105 invite.header(h_ReferredBy).isWellFormed()) 00106 { 00107 eventInfo->mReferredBy = std::auto_ptr<NameAddr>(new NameAddr(invite.header(h_ReferredBy))); 00108 } 00109 00110 mDialogIdToEventInfo[eventInfo->mDialogId] = eventInfo; 00111 00112 TryingDialogEvent evt(*eventInfo, invite); 00113 mDialogEventHandler->onTrying(evt); 00114 } 00115 00116 // we've received a 1xx response without a remote tag 00117 void 00118 DialogEventStateManager::onProceedingUac(const DialogSet& dialogSet, const SipMessage& response) 00119 { 00120 DialogId fakeId(dialogSet.getId(), Data::Empty); 00121 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.lower_bound(fakeId); 00122 if (it != mDialogIdToEventInfo.end() && 00123 it->first.getDialogSetId() == dialogSet.getId()) 00124 { 00125 if (it->first.getRemoteTag().empty()) 00126 { 00127 // happy day case; no forks yet; e.g INVITE/1xx (no tag)/1xx (no tag) 00128 DialogEventInfo* eventInfo = it->second; 00129 eventInfo->mState = DialogEventInfo::Proceeding; 00130 if (!response.empty(h_Contacts)) 00131 { 00132 // ?bwc? Has something already checked for well-formedness here? 00133 // Maybe DialogSet? Assert for now. 00134 assert(response.header(h_Contacts).front().isWellFormed()); 00135 eventInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(response.header(h_Contacts).front().uri())); 00136 } 00137 ProceedingDialogEvent evt(*eventInfo); 00138 mDialogEventHandler->onProceeding(evt); 00139 } 00140 else 00141 { 00142 // forking; e.g. INVITE/180 (tag #1)/180 (no tag) 00143 00144 // .jjg. The remote sender of the 180 (no tag) should either 'put up or shut up' as Byron put it 00145 // so we'll just ignore this... 00146 } 00147 } 00148 } 00149 00150 // UAC: we've received a 1xx response WITH a remote tag 00151 // UAS: we've sent a 1xx response WITH a local tag 00152 void 00153 DialogEventStateManager::onEarly(const Dialog& dialog, InviteSessionHandle is) 00154 { 00155 DialogEventInfo* eventInfo = findOrCreateDialogInfo(dialog); 00156 00157 if (eventInfo) 00158 { 00159 eventInfo->mState = DialogEventInfo::Early; 00160 eventInfo->mRouteSet = dialog.getRouteSet(); 00161 eventInfo->mInviteSession = is; 00162 00163 // local or remote target might change due to an UPDATE or re-INVITE 00164 eventInfo->mLocalTarget = dialog.getLocalContact().uri(); // !slg! TODO - fix me - the Dialog stored local contact has an empty hostname so that the stack will fill it in 00165 eventInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri())); 00166 00167 EarlyDialogEvent evt(*eventInfo); 00168 mDialogEventHandler->onEarly(evt); 00169 } 00170 } 00171 00172 void 00173 DialogEventStateManager::onConfirmed(const Dialog& dialog, InviteSessionHandle is) 00174 { 00175 DialogEventInfo* eventInfo = findOrCreateDialogInfo(dialog); 00176 00177 if (eventInfo) 00178 { 00179 eventInfo->mInviteSession = is; 00180 eventInfo->mRouteSet = dialog.getRouteSet(); // won't change due to re-INVITEs, but is 00181 // needed for the Trying --> Confirmed transition 00182 eventInfo->mState = DialogEventInfo::Confirmed; 00183 00184 // local or remote target might change due to an UPDATE or re-INVITE 00185 eventInfo->mLocalTarget = dialog.getLocalContact().uri(); // !slg! TODO - fix me - the Dialog stored local contact has an empty hostname so that the stack will fill it in 00186 eventInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri())); 00187 00188 // for the dialog that got the 200 OK 00189 SharedPtr<ConfirmedDialogEvent> confirmedEvt(new ConfirmedDialogEvent(*eventInfo)); 00190 00191 //mDialogEventHandler->onConfirmed(confirmedEvt); 00192 MultipleEventDialogEvent::EventVector events; 00193 00194 // kill off any other dialogs in this dialog set, since certain proxy/registrars (like SER and sipX) 00195 // won't bother giving us updates on their status anyways! 00196 const DialogSetId& dialogSetId = dialog.getId().getDialogSetId(); 00197 DialogId fakeId(dialogSetId, Data::Empty); 00198 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.lower_bound(fakeId); 00199 while (it != mDialogIdToEventInfo.end() && 00200 it->first.getDialogSetId() == dialogSetId) 00201 { 00202 DialogEventInfo::State dialogState = it->second->getState(); 00203 if (dialogState == DialogEventInfo::Proceeding || dialogState == DialogEventInfo::Early) 00204 { 00205 // .jjg. we're killing a *specific* dialog *after* the successful completion of the initial INVITE transaction; 00206 // so just elminate this dialog, not the entire dialogset 00207 SharedPtr<TerminatedDialogEvent> evt(onDialogTerminatedImpl(it->second, InviteSessionHandler::RemoteCancel)); 00208 events.push_back(evt); 00209 delete it->second; 00210 mDialogIdToEventInfo.erase(it++); 00211 } 00212 else 00213 { 00214 it++; 00215 } 00216 } 00217 00218 if (events.size() > 0) 00219 { 00220 events.push_back(confirmedEvt); 00221 MultipleEventDialogEvent multipleEvt(events); 00222 mDialogEventHandler->onMultipleEvents(multipleEvt); 00223 } 00224 else 00225 { 00226 mDialogEventHandler->onConfirmed(*confirmedEvt); 00227 } 00228 } 00229 } 00230 00231 void 00232 DialogEventStateManager::onTerminated(const Dialog& dialog, const SipMessage& msg, InviteSessionHandler::TerminatedReason reason) 00233 { 00234 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.find(dialog.getId()); 00235 if (it != mDialogIdToEventInfo.end()) 00236 { 00237 DialogEventInfo::State dialogState = it->second->getState(); 00238 if (dialogState == DialogEventInfo::Confirmed) 00239 { 00240 // .jjg. we're killing a *specific* dialog *after* the successful completion of the initial INVITE transaction; 00241 // so just elminate this dialog, not the entire dialogset 00242 std::auto_ptr<TerminatedDialogEvent> evt(onDialogTerminatedImpl(it->second, reason, getResponseCode(msg), getFrontContact(msg))); 00243 mDialogEventHandler->onTerminated(*evt); 00244 delete it->second; 00245 mDialogIdToEventInfo.erase(it++); 00246 } 00247 else 00248 { 00249 onDialogSetTerminatedImpl(dialog.getId().getDialogSetId(), msg, reason); 00250 } 00251 } 00252 else 00253 { 00254 onDialogSetTerminatedImpl(dialog.getId().getDialogSetId(), msg, reason); 00255 } 00256 } 00257 00258 void 00259 DialogEventStateManager::onTerminated(const DialogSet& dialogSet, const SipMessage& msg, InviteSessionHandler::TerminatedReason reason) 00260 { 00261 onDialogSetTerminatedImpl(dialogSet.getId(), msg, reason); 00262 } 00263 00264 void 00265 DialogEventStateManager::onDialogSetTerminatedImpl(const DialogSetId& dialogSetId, const SipMessage& msg, InviteSessionHandler::TerminatedReason reason) 00266 { 00267 DialogEventInfo* eventInfo = NULL; 00268 00276 //find dialogSet. All non-confirmed dialogs are destroyed by this event. 00277 //Confirmed dialogs are only destroyed by an exact match. 00278 00279 DialogId fakeId(dialogSetId, Data::Empty); 00280 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.lower_bound(fakeId); 00281 00282 while (it != mDialogIdToEventInfo.end() && 00283 it->first.getDialogSetId() == dialogSetId) 00284 { 00285 eventInfo = it->second; 00286 std::auto_ptr<TerminatedDialogEvent> evt(onDialogTerminatedImpl(eventInfo, reason, getResponseCode(msg), getFrontContact(msg))); 00287 mDialogEventHandler->onTerminated(*evt); 00288 delete it->second; 00289 mDialogIdToEventInfo.erase(it++); 00290 } 00291 } 00292 00293 TerminatedDialogEvent* 00294 DialogEventStateManager::onDialogTerminatedImpl(DialogEventInfo* eventInfo, 00295 InviteSessionHandler::TerminatedReason reason, 00296 int responseCode, 00297 Uri* remoteTarget) 00298 { 00299 eventInfo->mState = DialogEventInfo::Terminated; 00300 00301 // .jjg. when we get an INVITE w/Replaces, we mark the replaced dialog event info 00302 // as 'replaced' (see onTryingUas); 00303 // when the replaced dialog is ended, it will be ended normally with a BYE or CANCEL, 00304 // but since we've marked it as 'replaced' we can update the termination reason 00305 InviteSessionHandler::TerminatedReason actualReason = reason; 00306 00307 if (eventInfo->mReplaced) 00308 { 00309 actualReason = InviteSessionHandler::Replaced; 00310 } 00311 00312 if (remoteTarget) 00313 { 00314 eventInfo->mRemoteTarget = std::auto_ptr<Uri>(remoteTarget); 00315 } 00316 00317 TerminatedDialogEvent* evt = new TerminatedDialogEvent(*eventInfo, actualReason, responseCode); 00318 return evt; 00319 //mDialogEventHandler->onTerminated(evt); 00320 } 00321 00322 int 00323 DialogEventStateManager::getResponseCode(const SipMessage& msg) 00324 { 00325 int respCode = 0; 00326 if (msg.isResponse()) 00327 { 00328 respCode = msg.header(h_StatusLine).responseCode(); 00329 } 00330 return respCode; 00331 } 00332 00333 Uri* 00334 DialogEventStateManager::getFrontContact(const SipMessage& msg) 00335 { 00336 Uri* pContact = NULL; 00337 if (msg.isResponse()) 00338 { 00339 if (!msg.empty(h_Contacts)) 00340 { 00341 // ?bwc? Has something already checked for well-formedness here? 00342 // Maybe DialogSet? Assert for now. 00343 assert(msg.header(h_Contacts).front().isWellFormed()); 00344 pContact = new Uri(msg.header(h_Contacts).front().uri()); 00345 } 00346 } 00347 return pContact; 00348 } 00349 00350 DialogEventStateManager::DialogEventInfos 00351 DialogEventStateManager::getDialogEventInfo() const 00352 { 00353 DialogEventStateManager::DialogEventInfos infos; 00354 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::const_iterator it = mDialogIdToEventInfo.begin(); 00355 for (; it != mDialogIdToEventInfo.end(); it++) 00356 { 00357 infos.push_back(*(it->second)); 00358 } 00359 return infos; 00360 } 00361 00362 DialogEventInfo* 00363 DialogEventStateManager::findOrCreateDialogInfo(const Dialog& dialog) 00364 { 00365 DialogEventInfo* eventInfo = NULL; 00366 00375 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.find(dialog.getId()); 00376 00377 if (it != mDialogIdToEventInfo.end()) 00378 { 00379 return it->second; 00380 } 00381 else 00382 { 00383 // either we have a dialog set id with an empty remote tag, or we have other dialog(s) with different 00384 // remote tag(s) 00385 DialogId fakeId(dialog.getId().getDialogSetId(), Data::Empty); 00386 it = mDialogIdToEventInfo.lower_bound(fakeId); 00387 00388 if (it != mDialogIdToEventInfo.end() && 00389 it->first.getDialogSetId() == dialog.getId().getDialogSetId()) 00390 { 00391 if (it->first.getRemoteTag().empty()) 00392 { 00393 // convert this bad boy into a full on Dialog 00394 eventInfo = it->second; 00395 mDialogIdToEventInfo.erase(it); 00396 eventInfo->mDialogId = dialog.getId(); 00397 } 00398 else 00399 { 00400 // clone this fellow member dialog, initializing it with a new id and creation time 00401 DialogEventInfo* newForkInfo = new DialogEventInfo(*(it->second)); 00402 newForkInfo->mDialogEventId = Random::getVersion4UuidUrn(); 00403 newForkInfo->mCreationTimeSeconds = Timer::getTimeSecs(); 00404 newForkInfo->mDialogId = dialog.getId(); 00405 newForkInfo->mRemoteIdentity = dialog.getRemoteNameAddr(); 00406 newForkInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri())); 00407 newForkInfo->mRouteSet = dialog.getRouteSet(); 00408 eventInfo = newForkInfo; 00409 } 00410 } 00411 else 00412 { 00413 // .jjg. this can happen if onTryingUax(..) wasn't called yet for this dialog (set) id 00414 DebugLog(<< "DialogSetId " << fakeId << " was not found! This indicates a bug; onTryingUax() should have been called first!"); 00415 return 0; 00416 } 00417 } 00418 00419 mDialogIdToEventInfo[dialog.getId()] = eventInfo; 00420 00421 return eventInfo; 00422 } 00423 00424 } // namespace resip 00425 00426 /* ==================================================================== 00427 * The Vovida Software License, Version 1.0 00428 * 00429 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. 00430 * 00431 * Redistribution and use in source and binary forms, with or without 00432 * modification, are permitted provided that the following conditions 00433 * are met: 00434 * 00435 * 1. Redistributions of source code must retain the above copyright 00436 * notice, this list of conditions and the following disclaimer. 00437 * 00438 * 2. Redistributions in binary form must reproduce the above copyright 00439 * notice, this list of conditions and the following disclaimer in 00440 * the documentation and/or other materials provided with the 00441 * distribution. 00442 * 00443 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 00444 * and "Vovida Open Communication Application Library (VOCAL)" must 00445 * not be used to endorse or promote products derived from this 00446 * software without prior written permission. For written 00447 * permission, please contact vocal@vovida.org. 00448 * 00449 * 4. Products derived from this software may not be called "VOCAL", nor 00450 * may "VOCAL" appear in their name, without prior written 00451 * permission of Vovida Networks, Inc. 00452 * 00453 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 00454 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00455 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 00456 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 00457 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 00458 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 00459 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00460 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00461 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 00462 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00463 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 00464 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 00465 * DAMAGE. 00466 * 00467 * ==================================================================== 00468 * 00469 * This software consists of voluntary contributions made by Vovida 00470 * Networks, Inc. and many individuals on behalf of Vovida Networks, 00471 * Inc. For more information on Vovida Networks, Inc., please see 00472 * <http://www.vovida.org/>. 00473 * 00474 */
1.7.5.1