/[resiprocate]/main/resip/dum/DialogEventStateManager.cxx
ViewVC logotype

Contents of /main/resip/dum/DialogEventStateManager.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8973 - (show annotations) (download)
Mon Jan 17 22:14:07 2011 UTC (8 years, 9 months ago) by bcampen
File size: 18348 byte(s)
Fixing a few crashes. Fixing all of the non-threadsafe accesses to DUM
stuff is going to take a _while_.

1 #include "resip/dum/DialogEventStateManager.hxx"
2 #include "rutil/Random.hxx"
3 #include "rutil/Logger.hxx"
4
5 namespace resip
6 {
7
8 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
9
10 DialogEventStateManager::DialogEventStateManager()
11 : mDialogEventHandler(0)
12 {
13 }
14
15 DialogEventStateManager::~DialogEventStateManager()
16 {
17 }
18
19 // we've received an INVITE
20 void
21 DialogEventStateManager::onTryingUas(Dialog& dialog, const SipMessage& invite)
22 {
23 DialogEventInfo* eventInfo = new DialogEventInfo();
24 eventInfo->mDialogEventId = Random::getVersion4UuidUrn(); // !jjg! is this right?
25 eventInfo->mDialogId = dialog.getId();
26 eventInfo->mDirection = DialogEventInfo::Recipient;
27 eventInfo->mCreationTimeSeconds = Timer::getTimeSecs();
28 eventInfo->mInviteSession = InviteSessionHandle::NotValid();
29 eventInfo->mRemoteOfferAnswer = (invite.getContents() != NULL ? std::auto_ptr<Contents>(invite.getContents()->clone()) : std::auto_ptr<Contents>());
30 eventInfo->mLocalIdentity = dialog.getLocalNameAddr();
31 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
32 eventInfo->mRemoteIdentity = dialog.getRemoteNameAddr();
33 eventInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri()));
34 eventInfo->mRouteSet = dialog.getRouteSet();
35 eventInfo->mState = DialogEventInfo::Trying;
36
37 if (invite.exists(h_Replaces) &&
38 invite.header(h_Replaces).isWellFormed())
39 {
40 Data replacesToTag = invite.header(h_Replaces).exists(p_toTag) ? invite.header(h_Replaces).param(p_toTag) : Data::Empty;
41 Data replacesFromTag = invite.header(h_Replaces).exists(p_fromTag) ? invite.header(h_Replaces).param(p_fromTag) : Data::Empty;
42
43 eventInfo->mReplacesId = std::auto_ptr<DialogId>(new DialogId(invite.header(h_Replaces).value(),
44 replacesToTag,
45 replacesFromTag));
46
47 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.find(*(eventInfo->mReplacesId));
48 if (it != mDialogIdToEventInfo.end())
49 {
50 it->second->mReplaced = true;
51 }
52 }
53 if (invite.exists(h_ReferredBy) &&
54 invite.header(h_ReferredBy).isWellFormed())
55 {
56 eventInfo->mReferredBy = std::auto_ptr<NameAddr>(new NameAddr(invite.header(h_ReferredBy)));
57 }
58
59 mDialogIdToEventInfo[dialog.getId()] = eventInfo;
60
61 TryingDialogEvent evt(*eventInfo, invite);
62 mDialogEventHandler->onTrying(evt);
63 }
64
65 // we've sent an INVITE
66 void
67 DialogEventStateManager::onTryingUac(DialogSet& dialogSet, const SipMessage& invite)
68 {
69 DialogId fakeId(dialogSet.getId(), Data::Empty);
70 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.find(fakeId);
71
72 DialogEventInfo* eventInfo = 0;
73
74 if (it != mDialogIdToEventInfo.end())
75 {
76 // .jjg. we will get in here if our INVITE gets challenged; just swallow the onTrying event in this case
77 eventInfo = it->second;
78 if (eventInfo->mState == DialogEventInfo::Trying)
79 {
80 return;
81 }
82 }
83 else
84 {
85 eventInfo = new DialogEventInfo();
86 }
87
88 eventInfo->mDialogEventId = Random::getVersion4UuidUrn();
89 eventInfo->mDialogId = DialogId(dialogSet.getId(), Data::Empty);
90 eventInfo->mDirection = DialogEventInfo::Initiator;
91 eventInfo->mCreationTimeSeconds = Timer::getTimeSecs();
92 eventInfo->mInviteSession = InviteSessionHandle::NotValid();
93 eventInfo->mLocalIdentity = invite.header(h_From);
94 // ?bwc? Has something already checked for well-formedness here?
95 // Maybe DialogSet? We need to be absolutely certain that this exists and is
96 // well-formed. Assert for now.
97 assert(!invite.empty(h_Contacts));
98 assert(invite.header(h_Contacts).front().isWellFormed());
99 eventInfo->mLocalTarget = invite.header(h_Contacts).front().uri();
100 eventInfo->mRemoteIdentity = invite.header(h_To);
101 eventInfo->mLocalOfferAnswer = (invite.getContents() != NULL ? std::auto_ptr<Contents>(invite.getContents()->clone()) : std::auto_ptr<Contents>());
102 eventInfo->mState = DialogEventInfo::Trying;
103
104 if (invite.exists(h_ReferredBy) &&
105 invite.header(h_ReferredBy).isWellFormed())
106 {
107 eventInfo->mReferredBy = std::auto_ptr<NameAddr>(new NameAddr(invite.header(h_ReferredBy)));
108 }
109
110 mDialogIdToEventInfo[eventInfo->mDialogId] = eventInfo;
111
112 TryingDialogEvent evt(*eventInfo, invite);
113 mDialogEventHandler->onTrying(evt);
114 }
115
116 // we've received a 1xx response without a remote tag
117 void
118 DialogEventStateManager::onProceedingUac(const DialogSet& dialogSet, const SipMessage& response)
119 {
120 DialogId fakeId(dialogSet.getId(), Data::Empty);
121 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.lower_bound(fakeId);
122 if (it != mDialogIdToEventInfo.end() &&
123 it->first.getDialogSetId() == dialogSet.getId())
124 {
125 if (it->first.getRemoteTag().empty())
126 {
127 // happy day case; no forks yet; e.g INVITE/1xx (no tag)/1xx (no tag)
128 DialogEventInfo* eventInfo = it->second;
129 eventInfo->mState = DialogEventInfo::Proceeding;
130 if (!response.empty(h_Contacts))
131 {
132 // ?bwc? Has something already checked for well-formedness here?
133 // Maybe DialogSet? Assert for now.
134 assert(response.header(h_Contacts).front().isWellFormed());
135 eventInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(response.header(h_Contacts).front().uri()));
136 }
137 ProceedingDialogEvent evt(*eventInfo);
138 mDialogEventHandler->onProceeding(evt);
139 }
140 else
141 {
142 // forking; e.g. INVITE/180 (tag #1)/180 (no tag)
143
144 // .jjg. The remote sender of the 180 (no tag) should either 'put up or shut up' as Byron put it
145 // so we'll just ignore this...
146 }
147 }
148 }
149
150 // UAC: we've received a 1xx response WITH a remote tag
151 // UAS: we've sent a 1xx response WITH a local tag
152 void
153 DialogEventStateManager::onEarly(const Dialog& dialog, InviteSessionHandle is)
154 {
155 DialogEventInfo* eventInfo = findOrCreateDialogInfo(dialog);
156
157 if (eventInfo)
158 {
159 eventInfo->mState = DialogEventInfo::Early;
160 eventInfo->mRouteSet = dialog.getRouteSet();
161 eventInfo->mInviteSession = is;
162
163 // local or remote target might change due to an UPDATE or re-INVITE
164 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
165 eventInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri()));
166
167 EarlyDialogEvent evt(*eventInfo);
168 mDialogEventHandler->onEarly(evt);
169 }
170 }
171
172 void
173 DialogEventStateManager::onConfirmed(const Dialog& dialog, InviteSessionHandle is)
174 {
175 DialogEventInfo* eventInfo = findOrCreateDialogInfo(dialog);
176
177 if (eventInfo)
178 {
179 eventInfo->mInviteSession = is;
180 eventInfo->mRouteSet = dialog.getRouteSet(); // won't change due to re-INVITEs, but is
181 // needed for the Trying --> Confirmed transition
182 eventInfo->mState = DialogEventInfo::Confirmed;
183
184 // local or remote target might change due to an UPDATE or re-INVITE
185 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
186 eventInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri()));
187
188 // for the dialog that got the 200 OK
189 SharedPtr<ConfirmedDialogEvent> confirmedEvt(new ConfirmedDialogEvent(*eventInfo));
190
191 //mDialogEventHandler->onConfirmed(confirmedEvt);
192 MultipleEventDialogEvent::EventVector events;
193
194 // kill off any other dialogs in this dialog set, since certain proxy/registrars (like SER and sipX)
195 // won't bother giving us updates on their status anyways!
196 const DialogSetId& dialogSetId = dialog.getId().getDialogSetId();
197 DialogId fakeId(dialogSetId, Data::Empty);
198 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.lower_bound(fakeId);
199 while (it != mDialogIdToEventInfo.end() &&
200 it->first.getDialogSetId() == dialogSetId)
201 {
202 DialogEventInfo::State dialogState = it->second->getState();
203 if (dialogState == DialogEventInfo::Proceeding || dialogState == DialogEventInfo::Early)
204 {
205 // .jjg. we're killing a *specific* dialog *after* the successful completion of the initial INVITE transaction;
206 // so just elminate this dialog, not the entire dialogset
207 SharedPtr<TerminatedDialogEvent> evt(onDialogTerminatedImpl(it->second, InviteSessionHandler::RemoteCancel));
208 events.push_back(evt);
209 delete it->second;
210 mDialogIdToEventInfo.erase(it++);
211 }
212 else
213 {
214 it++;
215 }
216 }
217
218 if (events.size() > 0)
219 {
220 events.push_back(confirmedEvt);
221 MultipleEventDialogEvent multipleEvt(events);
222 mDialogEventHandler->onMultipleEvents(multipleEvt);
223 }
224 else
225 {
226 mDialogEventHandler->onConfirmed(*confirmedEvt);
227 }
228 }
229 }
230
231 void
232 DialogEventStateManager::onTerminated(const Dialog& dialog, const SipMessage& msg, InviteSessionHandler::TerminatedReason reason)
233 {
234 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.find(dialog.getId());
235 if (it != mDialogIdToEventInfo.end())
236 {
237 DialogEventInfo::State dialogState = it->second->getState();
238 if (dialogState == DialogEventInfo::Confirmed)
239 {
240 // .jjg. we're killing a *specific* dialog *after* the successful completion of the initial INVITE transaction;
241 // so just elminate this dialog, not the entire dialogset
242 std::auto_ptr<TerminatedDialogEvent> evt(onDialogTerminatedImpl(it->second, reason, getResponseCode(msg), getFrontContact(msg)));
243 mDialogEventHandler->onTerminated(*evt);
244 delete it->second;
245 mDialogIdToEventInfo.erase(it++);
246 }
247 else
248 {
249 onDialogSetTerminatedImpl(dialog.getId().getDialogSetId(), msg, reason);
250 }
251 }
252 else
253 {
254 onDialogSetTerminatedImpl(dialog.getId().getDialogSetId(), msg, reason);
255 }
256 }
257
258 void
259 DialogEventStateManager::onTerminated(const DialogSet& dialogSet, const SipMessage& msg, InviteSessionHandler::TerminatedReason reason)
260 {
261 onDialogSetTerminatedImpl(dialogSet.getId(), msg, reason);
262 }
263
264 void
265 DialogEventStateManager::onDialogSetTerminatedImpl(const DialogSetId& dialogSetId, const SipMessage& msg, InviteSessionHandler::TerminatedReason reason)
266 {
267 DialogEventInfo* eventInfo = NULL;
268
269 /**
270 * cases:
271 * 1) UAC: INVITE/180 (tag #1)/180 (tag #2)/486 (tag #2)
272 * 2) UAS: INVITE/100/486 (tag #1)
273 * 3) UAS: INVITE/100/180 (tag #1)/486 (tag #1)
274 */
275
276 //find dialogSet. All non-confirmed dialogs are destroyed by this event.
277 //Confirmed dialogs are only destroyed by an exact match.
278
279 DialogId fakeId(dialogSetId, Data::Empty);
280 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.lower_bound(fakeId);
281
282 while (it != mDialogIdToEventInfo.end() &&
283 it->first.getDialogSetId() == dialogSetId)
284 {
285 eventInfo = it->second;
286 std::auto_ptr<TerminatedDialogEvent> evt(onDialogTerminatedImpl(eventInfo, reason, getResponseCode(msg), getFrontContact(msg)));
287 mDialogEventHandler->onTerminated(*evt);
288 delete it->second;
289 mDialogIdToEventInfo.erase(it++);
290 }
291 }
292
293 TerminatedDialogEvent*
294 DialogEventStateManager::onDialogTerminatedImpl(DialogEventInfo* eventInfo,
295 InviteSessionHandler::TerminatedReason reason,
296 int responseCode,
297 Uri* remoteTarget)
298 {
299 eventInfo->mState = DialogEventInfo::Terminated;
300
301 // .jjg. when we get an INVITE w/Replaces, we mark the replaced dialog event info
302 // as 'replaced' (see onTryingUas);
303 // when the replaced dialog is ended, it will be ended normally with a BYE or CANCEL,
304 // but since we've marked it as 'replaced' we can update the termination reason
305 InviteSessionHandler::TerminatedReason actualReason = reason;
306
307 if (eventInfo->mReplaced)
308 {
309 actualReason = InviteSessionHandler::Replaced;
310 }
311
312 if (remoteTarget)
313 {
314 eventInfo->mRemoteTarget = std::auto_ptr<Uri>(remoteTarget);
315 }
316
317 TerminatedDialogEvent* evt = new TerminatedDialogEvent(*eventInfo, actualReason, responseCode);
318 return evt;
319 //mDialogEventHandler->onTerminated(evt);
320 }
321
322 int
323 DialogEventStateManager::getResponseCode(const SipMessage& msg)
324 {
325 int respCode = 0;
326 if (msg.isResponse())
327 {
328 respCode = msg.header(h_StatusLine).responseCode();
329 }
330 return respCode;
331 }
332
333 Uri*
334 DialogEventStateManager::getFrontContact(const SipMessage& msg)
335 {
336 Uri* pContact = NULL;
337 if (msg.isResponse())
338 {
339 if (!msg.empty(h_Contacts))
340 {
341 // ?bwc? Has something already checked for well-formedness here?
342 // Maybe DialogSet? Assert for now.
343 assert(msg.header(h_Contacts).front().isWellFormed());
344 pContact = new Uri(msg.header(h_Contacts).front().uri());
345 }
346 }
347 return pContact;
348 }
349
350 DialogEventStateManager::DialogEventInfos
351 DialogEventStateManager::getDialogEventInfo() const
352 {
353 DialogEventStateManager::DialogEventInfos infos;
354 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::const_iterator it = mDialogIdToEventInfo.begin();
355 for (; it != mDialogIdToEventInfo.end(); it++)
356 {
357 infos.push_back(*(it->second));
358 }
359 return infos;
360 }
361
362 DialogEventInfo*
363 DialogEventStateManager::findOrCreateDialogInfo(const Dialog& dialog)
364 {
365 DialogEventInfo* eventInfo = NULL;
366
367 /**
368 * cases:
369 * 1) INVITE/180 (no tag)/183 (tag)
370 * 2) INVITE/180 (tag)
371 * 3) INVITE/180 (tag #1)/180 (tag #2)
372 *
373 */
374
375 std::map<DialogId, DialogEventInfo*, DialogIdComparator>::iterator it = mDialogIdToEventInfo.find(dialog.getId());
376
377 if (it != mDialogIdToEventInfo.end())
378 {
379 return it->second;
380 }
381 else
382 {
383 // either we have a dialog set id with an empty remote tag, or we have other dialog(s) with different
384 // remote tag(s)
385 DialogId fakeId(dialog.getId().getDialogSetId(), Data::Empty);
386 it = mDialogIdToEventInfo.lower_bound(fakeId);
387
388 if (it != mDialogIdToEventInfo.end() &&
389 it->first.getDialogSetId() == dialog.getId().getDialogSetId())
390 {
391 if (it->first.getRemoteTag().empty())
392 {
393 // convert this bad boy into a full on Dialog
394 eventInfo = it->second;
395 mDialogIdToEventInfo.erase(it);
396 eventInfo->mDialogId = dialog.getId();
397 }
398 else
399 {
400 // clone this fellow member dialog, initializing it with a new id and creation time
401 DialogEventInfo* newForkInfo = new DialogEventInfo(*(it->second));
402 newForkInfo->mDialogEventId = Random::getVersion4UuidUrn();
403 newForkInfo->mCreationTimeSeconds = Timer::getTimeSecs();
404 newForkInfo->mDialogId = dialog.getId();
405 newForkInfo->mRemoteIdentity = dialog.getRemoteNameAddr();
406 newForkInfo->mRemoteTarget = std::auto_ptr<Uri>(new Uri(dialog.getRemoteTarget().uri()));
407 newForkInfo->mRouteSet = dialog.getRouteSet();
408 eventInfo = newForkInfo;
409 }
410 }
411 else
412 {
413 // .jjg. this can happen if onTryingUax(..) wasn't called yet for this dialog (set) id
414 DebugLog(<< "DialogSetId " << fakeId << " was not found! This indicates a bug; onTryingUax() should have been called first!");
415 return 0;
416 }
417 }
418
419 mDialogIdToEventInfo[dialog.getId()] = eventInfo;
420
421 return eventInfo;
422 }
423
424 } // namespace resip
425
426 /* ====================================================================
427 * The Vovida Software License, Version 1.0
428 *
429 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
430 *
431 * Redistribution and use in source and binary forms, with or without
432 * modification, are permitted provided that the following conditions
433 * are met:
434 *
435 * 1. Redistributions of source code must retain the above copyright
436 * notice, this list of conditions and the following disclaimer.
437 *
438 * 2. Redistributions in binary form must reproduce the above copyright
439 * notice, this list of conditions and the following disclaimer in
440 * the documentation and/or other materials provided with the
441 * distribution.
442 *
443 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
444 * and "Vovida Open Communication Application Library (VOCAL)" must
445 * not be used to endorse or promote products derived from this
446 * software without prior written permission. For written
447 * permission, please contact vocal@vovida.org.
448 *
449 * 4. Products derived from this software may not be called "VOCAL", nor
450 * may "VOCAL" appear in their name, without prior written
451 * permission of Vovida Networks, Inc.
452 *
453 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
454 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
455 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
456 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
457 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
458 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
459 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
460 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
461 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
462 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
463 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
464 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
465 * DAMAGE.
466 *
467 * ====================================================================
468 *
469 * This software consists of voluntary contributions made by Vovida
470 * Networks, Inc. and many individuals on behalf of Vovida Networks,
471 * Inc. For more information on Vovida Networks, Inc., please see
472 * <http://www.vovida.org/>.
473 *
474 */

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27