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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10975 - (show annotations) (download)
Sun Feb 16 20:04:10 2014 UTC (5 years, 9 months ago) by sgodin
File MIME type: text/plain
File size: 41376 byte(s)
-removed use of raw transport pointers in Tuple and SipMessage (finally!!)
 -required repro record route logic to be modified - no longer store transport specific
  record routes in the Transport class - the Proxy class now tracks these
 -removed SipMessage::getReceivedTransport and added isFromWire method that can be used in
  it's place in various locations

1 #include "resip/stack/Contents.hxx"
2 #include "resip/stack/Helper.hxx"
3 #include "resip/stack/SipMessage.hxx"
4 #include "resip/dum/AppDialog.hxx"
5 #include "resip/dum/BaseCreator.hxx"
6 #include "resip/dum/ClientAuthManager.hxx"
7 #include "resip/dum/ClientInviteSession.hxx"
8 #include "resip/dum/ClientSubscription.hxx"
9 #include "resip/dum/Dialog.hxx"
10 #include "resip/dum/DialogUsageManager.hxx"
11 #include "resip/dum/MasterProfile.hxx"
12 #include "resip/dum/InviteSessionCreator.hxx"
13 #include "resip/dum/InviteSessionHandler.hxx"
14 #include "resip/dum/ServerInviteSession.hxx"
15 #include "resip/dum/ServerSubscription.hxx"
16 #include "resip/dum/SubscriptionHandler.hxx"
17 #include "resip/dum/UsageUseException.hxx"
18 #include "rutil/Logger.hxx"
19 #include "rutil/Inserter.hxx"
20 #include "rutil/TransportType.hxx"
21 #include "rutil/WinLeakCheck.hxx"
22
23 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
24
25 using namespace resip;
26 using namespace std;
27
28 Dialog::Dialog(DialogUsageManager& dum, const SipMessage& msg, DialogSet& ds)
29 : mDum(dum),
30 mDialogSet(ds),
31 mId("INVALID", "INVALID", "INVALID"),
32 mClientSubscriptions(),
33 mServerSubscriptions(),
34 mInviteSession(0),
35 mType(Fake),
36 mRouteSet(),
37 mLocalContact(),
38 mLocalCSeq(0),
39 mRemoteCSeq(0),
40 mRemoteTarget(),
41 mLocalNameAddr(),
42 mRemoteNameAddr(),
43 mCallId(msg.header(h_CallID)),
44 mDefaultSubExpiration(0),
45 mAppDialog(0),
46 mDestroying(false),
47 mReUseDialogSet(false)
48 {
49 assert(msg.isExternal());
50
51 assert(msg.header(h_CSeq).method() != MESSAGE);
52 assert(msg.header(h_CSeq).method() != REGISTER);
53 assert(msg.header(h_CSeq).method() != PUBLISH);
54
55 mNetworkAssociation.setDum(&dum);
56
57 if (msg.isRequest()) // UAS
58 {
59 const SipMessage& request = msg;
60
61 switch (request.header(h_CSeq).method())
62 {
63 case INVITE:
64 mType = Invitation;
65 break;
66
67 case SUBSCRIBE:
68 case REFER:
69 case NOTIFY:
70 //!dcm! -- event header check
71 mType = Subscription;
72 break;
73
74 default:
75 mType = Fake;
76 }
77 if (request.exists(h_RecordRoutes))
78 {
79 mRouteSet = request.header(h_RecordRoutes);
80 }
81
82 switch (request.header(h_CSeq).method())
83 {
84 case INVITE:
85 case SUBSCRIBE:
86 case REFER:
87 case NOTIFY:
88 DebugLog ( << "UAS dialog ID creation, DS: " << ds.getId());
89 mId = DialogId(ds.getId(),
90 request.header(h_From).exists(p_tag) ? request.header(h_From).param(p_tag) : Data::Empty);
91
92 mRemoteNameAddr = request.header(h_From);
93 mLocalNameAddr = request.header(h_To);
94 mLocalNameAddr.param(p_tag) = mId.getLocalTag();
95 if (request.exists(h_Contacts) && request.header(h_Contacts).size() == 1)
96 {
97 const NameAddr& contact = request.header(h_Contacts).front();
98 if (isEqualNoCase(contact.uri().scheme(), Symbols::Sips) ||
99 isEqualNoCase(contact.uri().scheme(), Symbols::Sip))
100 {
101 // Store Remote Target
102 mRemoteTarget = contact;
103
104 // Create Local Contact
105 if(mDialogSet.mUserProfile->hasUserAgentCapabilities())
106 {
107 mLocalContact = mDialogSet.mUserProfile->getUserAgentCapabilities();
108 }
109 if(!mDialogSet.mUserProfile->isAnonymous() && mDialogSet.mUserProfile->hasPublicGruu())
110 {
111 mLocalContact.uri() = mDialogSet.mUserProfile->getPublicGruu();
112 }
113 else if(mDialogSet.mUserProfile->isAnonymous() && mDialogSet.mUserProfile->hasTempGruu())
114 {
115 mLocalContact.uri() = mDialogSet.mUserProfile->getTempGruu();
116 }
117 else
118 {
119 if (mDialogSet.mUserProfile->hasOverrideHostAndPort())
120 {
121 mLocalContact.uri() = mDialogSet.mUserProfile->getOverrideHostAndPort();
122 }
123 if(request.header(h_RequestLine).uri().user().empty())
124 {
125 mLocalContact.uri().user() = request.header(h_To).uri().user();
126 }
127 else
128 {
129 mLocalContact.uri().user() = request.header(h_RequestLine).uri().user();
130 }
131 const Data& instanceId = mDialogSet.mUserProfile->getInstanceId();
132 if (!contact.uri().exists(p_gr) && !instanceId.empty())
133 {
134 mLocalContact.param(p_Instance) = instanceId;
135 }
136 }
137 if(mDialogSet.mUserProfile->clientOutboundEnabled())
138 {
139 // Add ;ob parm to non-register requests - RFC5626 pg17
140 mLocalContact.uri().param(p_ob);
141 }
142 }
143 else
144 {
145 InfoLog(<< "Got an INVITE or SUBSCRIBE with invalid scheme");
146 InfoLog(<< request);
147 throw Exception("Invalid scheme in request", __FILE__, __LINE__);
148 }
149 }
150 else
151 {
152 InfoLog (<< "Got an INVITE or SUBSCRIBE that doesn't have exactly one contact");
153 InfoLog (<< request);
154 throw Exception("Too many (or no contact) contacts in request", __FILE__, __LINE__);
155 }
156 break;
157 default:
158 break;
159 }
160
161 mRemoteCSeq = request.header(h_CSeq).sequence();
162
163 // This may actually be a UAC dialogset - ie. the case where the first NOTIFY creates the
164 // SUBSCRIPTION dialog, instead of the 200/SUB. If so, then we need to make sure the local
165 // CSeq is correct - it's value may be greator than 1, if the original request (SUBSCRIBE)
166 // got digest challenged.
167 BaseCreator* creator = mDialogSet.getCreator();
168 if(creator)
169 {
170 mLocalCSeq = creator->getLastRequest()->header(h_CSeq).sequence();
171 }
172 else
173 {
174 mLocalCSeq = 1;
175 }
176
177 DebugLog ( << "************** Created Dialog as UAS **************" );
178 DebugLog ( << "mRemoteNameAddr: " << mRemoteNameAddr );
179 DebugLog ( << "mLocalNameAddr: " << mLocalNameAddr );
180 DebugLog ( << "mLocalContact: " << mLocalContact );
181 DebugLog ( << "mRemoteTarget: " << mRemoteTarget );
182 }
183 else if (msg.isResponse())
184 {
185 mId = DialogId(msg);
186 const SipMessage& response = msg;
187 mRemoteNameAddr = response.header(h_To);
188 mLocalNameAddr = response.header(h_From);
189
190 switch (msg.header(h_CSeq).method())
191 {
192 case INVITE:
193 mType = Invitation;
194 break;
195
196 case SUBSCRIBE:
197 case REFER:
198 mType = Subscription;
199 break;
200
201 default:
202 mType = Fake;
203 }
204
205 if (response.exists(h_RecordRoutes))
206 {
207 mRouteSet = response.header(h_RecordRoutes).reverse();
208 }
209
210 switch (response.header(h_CSeq).method())
211 {
212 case INVITE:
213 case SUBSCRIBE:
214 case REFER:
215 if (response.header(h_StatusLine).statusCode() > 100 &&
216 response.header(h_StatusLine).statusCode() < 300)
217 {
218
219 if (response.exists(h_Contacts) && response.header(h_Contacts).size() == 1)
220 {
221 const NameAddr& contact = response.header(h_Contacts).front();
222 if (isEqualNoCase(contact.uri().scheme(), Symbols::Sips) ||
223 isEqualNoCase(contact.uri().scheme(), Symbols::Sip))
224 {
225 BaseCreator* creator = mDialogSet.getCreator();
226 if(0 == creator)
227 {
228 ErrLog(<< "BaseCreator is null for DialogSet");
229 ErrLog(<< response);
230 throw Exception("BaseCreator is null for DialogSet", __FILE__, __LINE__);
231 }
232
233 SharedPtr<SipMessage> lastRequest(creator->getLastRequest());
234
235 if( 0 == lastRequest.get() ||
236 !lastRequest->exists(h_Contacts) ||
237 lastRequest->header(h_Contacts).empty())
238 {
239 InfoLog(<< "lastRequest does not contain a valid contact");
240 InfoLog(<< response);
241 throw Exception("lastRequest does not contain a valid contact.", __FILE__, __LINE__);
242 }
243 mLocalContact = creator->getLastRequest()->header(h_Contacts).front();
244 mRemoteTarget = contact;
245 }
246 else
247 {
248 InfoLog (<< "Got an INVITE or SUBSCRIBE with invalid scheme");
249 DebugLog (<< response);
250 throw Exception("Bad scheme in contact in response", __FILE__, __LINE__);
251 }
252 }
253 else
254 {
255 InfoLog (<< "Got an INVITE or SUBSCRIBE that doesn't have exactly one contact");
256 DebugLog (<< response);
257 throw Exception("Too many contacts (or no contact) in response", __FILE__, __LINE__);
258 }
259 break;
260 default:
261 break;
262 }
263 }
264
265 mLocalCSeq = response.header(h_CSeq).sequence();
266 mRemoteCSeq = 0;
267 DebugLog ( << "************** Created Dialog as UAC **************" );
268 DebugLog ( << "mRemoteNameAddr: " << mRemoteNameAddr );
269 DebugLog ( << "mLocalNameAddr: " << mLocalNameAddr );
270 DebugLog ( << "mLocalContact: " << mLocalContact );
271 DebugLog ( << "mRemoteTarget: " << mRemoteTarget );
272 }
273 mDialogSet.addDialog(this);
274 DebugLog ( <<"Dialog::Dialog " << mId);
275 }
276
277 Dialog::~Dialog()
278 {
279 DebugLog ( <<"Dialog::~Dialog() ");
280
281 mDestroying = true;
282
283 while (!mClientSubscriptions.empty())
284 {
285 delete *mClientSubscriptions.begin();
286 }
287
288 while (!mServerSubscriptions.empty())
289 {
290 delete *mServerSubscriptions.begin();
291 }
292
293 delete mInviteSession;
294 mDialogSet.mDialogs.erase(this->getId());
295 delete mAppDialog;
296 if(!mReUseDialogSet)
297 {
298 mDialogSet.possiblyDie();
299 }
300 }
301
302 const DialogId&
303 Dialog::getId() const
304 {
305 return mId;
306 }
307
308 const NameAddr&
309 Dialog::getLocalNameAddr() const
310 {
311 return mLocalNameAddr;
312 }
313
314 const NameAddr&
315 Dialog::getLocalContact() const
316 {
317 return mLocalContact;
318 }
319
320 const NameAddr&
321 Dialog::getRemoteNameAddr() const
322 {
323 return mRemoteNameAddr;
324 }
325
326 const NameAddr&
327 Dialog::getRemoteTarget() const
328 {
329 return mRemoteTarget;
330 }
331
332 const NameAddrs&
333 Dialog::getRouteSet() const
334 {
335 return mRouteSet;
336 }
337
338 void
339 Dialog::cancel()
340 {
341 assert(mType == Invitation);
342 ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession);
343 assert (uac);
344 uac->cancel();
345 }
346
347 void
348 Dialog::end()
349 {
350 if (mInviteSession)
351 {
352 mInviteSession->end();
353 }
354
355 // End Subscriptions
356 // !jrm! WARN ClientSubscription and ServerSubscription have access to this dialog and will remove themselves
357 // from the m<client|server>Subscriptions collections in the call to end().
358 for (list<ClientSubscription*>::iterator it(mClientSubscriptions.begin());
359 it != mClientSubscriptions.end();)
360 {
361 ClientSubscription* c = *it;
362 it++;
363 c->end();
364 }
365
366 for (list<ServerSubscription*>::iterator it2(mServerSubscriptions.begin());
367 it2 != mServerSubscriptions.end();)
368 {
369 ServerSubscription* s = *it2;
370 it2++;
371 s->end();
372 }
373 }
374
375 void
376 Dialog::handleTargetRefresh(const SipMessage& msg)
377 {
378 switch(msg.header(h_CSeq).method())
379 {
380 case INVITE:
381 case UPDATE:
382 if (msg.isRequest() || (msg.isResponse() && msg.header(h_StatusLine).statusCode()/100 == 2))
383 {
384 //?dcm? modify local target; 12.2.2 of 3261 implies that the remote
385 //target is immediately modified. Should we wait until a 2xx class
386 //reponse is sent to a re-invite(easy when all send requests go
387 //through Dialog)
388 if (msg.exists(h_Contacts))
389 {
390 //.dcm. replace or check then replace
391 mRemoteTarget = msg.header(h_Contacts).front();
392 }
393 }
394 break;
395 default:
396 return;
397 }
398 }
399
400 void
401 Dialog::dispatch(const SipMessage& msg)
402 {
403 // !jf! Should be checking for messages with out of order CSeq and rejecting
404
405 DebugLog ( << "Dialog::dispatch: " << msg.brief());
406
407 if(msg.isFromWire())
408 {
409 TransportType receivedTransport = toTransportType(
410 msg.header(h_Vias).front().transport());
411 int keepAliveTime = 0;
412 if(isReliable(receivedTransport))
413 {
414 keepAliveTime = mDialogSet.mUserProfile->getKeepAliveTimeForStream();
415 }
416 else
417 {
418 keepAliveTime = mDialogSet.mUserProfile->getKeepAliveTimeForDatagram();
419 }
420
421 if(keepAliveTime > 0)
422 {
423 mNetworkAssociation.update(msg, keepAliveTime, false /* targetSupportsOutbound */); // target supports outbound is detected in registration responses only
424 }
425 }
426
427 handleTargetRefresh(msg);
428 if (msg.isRequest())
429 {
430 const SipMessage& request = msg;
431 switch (request.header(h_CSeq).method())
432 {
433 case INVITE: // new INVITE
434 if (mInviteSession == 0)
435 {
436 DebugLog ( << "Dialog::dispatch -- Created new server invite session" << msg.brief());
437 mInviteSession = makeServerInviteSession(request);
438 }
439 mInviteSession->dispatch(request);
440 break;
441 //refactor, send bad request for BYE, INFO, CANCEL?
442 case BYE:
443 if (mInviteSession == 0)
444 {
445 InfoLog ( << "Spurious BYE" );
446 return;
447 }
448 else
449 {
450 mInviteSession->dispatch(request);
451 }
452 break;
453 case UPDATE:
454 if (mInviteSession == 0)
455 {
456 InfoLog ( << "Spurious UPDATE" );
457 return;
458 }
459 else
460 {
461 mInviteSession->dispatch(request);
462 }
463 break;
464 case INFO:
465 if (mInviteSession == 0)
466 {
467 InfoLog ( << "Spurious INFO" );
468 return;
469 }
470 else
471 {
472 mInviteSession->dispatch(request);
473 }
474 break;
475 case MESSAGE:
476 if (mInviteSession == 0)
477 {
478 InfoLog ( << "Spurious MESSAGE" );
479 return;
480 }
481 else
482 {
483 mInviteSession->dispatch(request);
484 }
485 break;
486 case PRACK:
487 if (mInviteSession == 0)
488 {
489 InfoLog ( << "Spurious PRACK" );
490 return;
491 }
492 else
493 {
494 mInviteSession->dispatch(request);
495 }
496 break;
497 case ACK:
498 case CANCEL:
499 if (mInviteSession == 0)
500 {
501 InfoLog (<< "Drop stray ACK or CANCEL in dialog on the floor");
502 DebugLog (<< request);
503 }
504 else
505 {
506 mInviteSession->dispatch(request);
507 }
508 break;
509 case SUBSCRIBE:
510 {
511 ServerSubscription* server = findMatchingServerSub(request);
512 if (server)
513 {
514 server->dispatch(request);
515 }
516 else
517 {
518 if (request.exists(h_Event) && request.header(h_Event).value() == "refer")
519 {
520 InfoLog (<< "Received a subscribe to a non-existent refer subscription: " << request.brief());
521 SipMessage failure;
522 makeResponse(failure, request, 403);
523 mDum.sendResponse(failure);
524 return;
525 }
526 else
527 {
528 if (mDum.checkEventPackage(request))
529 {
530 server = makeServerSubscription(request);
531 mServerSubscriptions.push_back(server);
532 server->dispatch(request);
533 }
534 }
535 }
536 }
537 break;
538 case REFER:
539 {
540 // if (mInviteSession == 0)
541 // {
542 // InfoLog (<< "Received an in dialog refer in a non-invite dialog: " << request.brief());
543 // SipMessage failure;
544 // makeResponse(failure, request, 603);
545 // mDum.sendResponse(failure);
546 // return;
547 // }
548 // else
549
550 if (!request.exists(h_ReferTo))
551 {
552 InfoLog (<< "Received refer w/out a Refer-To: " << request.brief());
553 SipMessage failure;
554 makeResponse(failure, request, 400);
555 mDum.sendResponse(failure);
556 return;
557 }
558 else
559 {
560 if ((request.exists(h_ReferSub) &&
561 request.header(h_ReferSub).isWellFormed() &&
562 request.header(h_ReferSub).value()=="false") ||
563 (request.exists(h_Requires) &&
564 request.header(h_Requires).find(Token("norefersub"))))
565 {
566 assert(mInviteSession);
567 mInviteSession->referNoSub(msg);
568 }
569 else
570 {
571 ServerSubscription* server = findMatchingServerSub(request);
572 ServerSubscriptionHandle serverHandle;
573 if (server)
574 {
575 serverHandle = server->getHandle();
576 server->dispatch(request);
577 }
578 else
579 {
580 server = makeServerSubscription(request);
581 mServerSubscriptions.push_back(server);
582 serverHandle = server->getHandle();
583 server->dispatch(request);
584 }
585
586 if (mInviteSession)
587 {
588 mDum.mInviteSessionHandler->onRefer(mInviteSession->getSessionHandle(), serverHandle, msg);
589 }
590
591 }
592 }
593 }
594 break;
595 case NOTIFY:
596 {
597 ClientSubscription* client = findMatchingClientSub(request);
598 if (client)
599 {
600 client->dispatch(request);
601 }
602 else
603 {
604 BaseCreator* creator = mDialogSet.getCreator();
605 if (creator && (creator->getLastRequest()->header(h_RequestLine).method() == SUBSCRIBE ||
606 creator->getLastRequest()->header(h_RequestLine).method() == REFER))
607 {
608 DebugLog (<< "Making subscription (from creator) request: " << *creator->getLastRequest());
609 ClientSubscription* sub = makeClientSubscription(*creator->getLastRequest());
610 mClientSubscriptions.push_back(sub);
611 sub->dispatch(request);
612 }
613 else
614 {
615 if (mInviteSession != 0 && (!msg.exists(h_Event) || msg.header(h_Event).value() == "refer") &&
616 mDum.getClientSubscriptionHandler("refer")!=0)
617 {
618 DebugLog (<< "Making subscription from NOTIFY: " << msg);
619 ClientSubscription* sub = makeClientSubscription(msg);
620 mClientSubscriptions.push_back(sub);
621 ClientSubscriptionHandle client = sub->getHandle();
622 mDum.mInviteSessionHandler->onReferAccepted(mInviteSession->getSessionHandle(), client, msg);
623 sub->dispatch(request);
624 }
625 else
626 {
627 SharedPtr<SipMessage> response(new SipMessage);
628 makeResponse(*response, msg, 406);
629 send(response);
630 }
631 }
632 }
633 }
634 break;
635 default:
636 assert(0);
637 return;
638 }
639 }
640 else if (msg.isResponse())
641 {
642 // !jf! There is a substantial change in how this works in teltel-branch
643 // from how it worked in main branch pre merge.
644 // If the response doesn't match a cseq for a request I've sent, ignore
645 // the response
646 {//scope 'r' as it is invalidated below
647 RequestMap::iterator r = mRequests.find(msg.header(h_CSeq).sequence());
648 if (r != mRequests.end())
649 {
650 bool handledByAuth = false;
651 if (mDum.mClientAuthManager.get() &&
652 mDum.mClientAuthManager->handle(*mDialogSet.mUserProfile, *r->second, msg))
653 {
654 InfoLog( << "about to re-send request with digest credentials" << r->second->brief());
655
656 assert (r->second->isRequest());
657
658 mLocalCSeq++;
659 send(r->second);
660 handledByAuth = true;
661 }
662 mRequests.erase(r);
663 if (handledByAuth) return;
664 }
665 }
666
667 const SipMessage& response = msg;
668 int code = response.header(h_StatusLine).statusCode();
669 // If this is a 200 response to the initial request, then store the routeset (if present)
670 BaseCreator* creator = mDialogSet.getCreator();
671 if (creator && (creator->getLastRequest()->header(h_CSeq) == response.header(h_CSeq)) && code >=200 && code < 300)
672 {
673 if (response.exists(h_RecordRoutes))
674 {
675 mRouteSet = response.header(h_RecordRoutes).reverse();
676 }
677 else
678 {
679 // Ensure that if the route-set in the 200 is empty, then we overwrite any existing route-sets
680 mRouteSet.clear();
681 }
682 }
683
684 // !jf! should this only be for 2xx responses? !jf! Propose no as an
685 // answer !dcm! what is he on?
686 switch (response.header(h_CSeq).method())
687 {
688 case INVITE:
689 if (mInviteSession == 0)
690 {
691 DebugLog ( << "Dialog::dispatch -- Created new client invite session" << msg.brief());
692
693 mInviteSession = makeClientInviteSession(response);
694 if (mInviteSession)
695 {
696 mInviteSession->dispatch(response);
697 }
698 else
699 {
700 ErrLog( << "Dialog::dispatch -- Unable to create invite session from response" << msg.brief());
701 }
702 }
703 else
704 {
705 mInviteSession->dispatch(response);
706 }
707 break;
708 case BYE:
709 case ACK:
710 case CANCEL:
711 case INFO:
712 case MESSAGE:
713 case UPDATE:
714 case PRACK:
715 if (mInviteSession)
716 {
717 mInviteSession->dispatch(response);
718 }
719 // else drop on the floor
720 break;
721
722 case REFER:
723 if(mInviteSession)
724 {
725 if (code >= 300)
726 {
727 mDum.mInviteSessionHandler->onReferRejected(mInviteSession->getSessionHandle(), msg);
728 }
729 else
730 {
731 //!dys! the OR condition below is not draft compliant.
732 if (!mInviteSession->mReferSub &&
733 ((msg.exists(h_ReferSub) && msg.header(h_ReferSub).value()=="false") ||
734 !msg.exists(h_ReferSub)))
735 {
736 DebugLog(<< "refer accepted with norefersub");
737 mDum.mInviteSessionHandler->onReferAccepted(mInviteSession->getSessionHandle(), ClientSubscriptionHandle::NotValid(), msg);
738 }
739 // else no need for action - first Notify will cause onReferAccepted to be called
740 }
741 mInviteSession->nitComplete();
742 break;
743 }
744 // fall through, out of dialog refer was sent.
745
746 case SUBSCRIBE:
747 {
748 int code = response.header(h_StatusLine).statusCode();
749 ClientSubscription* client = findMatchingClientSub(response);
750 if (client)
751 {
752 client->dispatch(response);
753 }
754 else if (code < 300)
755 {
756 /*
757 we're capturing the value from the expires header off
758 the 2xx because the ClientSubscription is only created
759 after receiving the NOTIFY that comes (usually) after
760 this 2xx. We really should be creating the
761 ClientSubscription at either the 2xx or the NOTIFY
762 whichever arrives first. .mjf.
763 Note: we're capturing a duration here (not the
764 absolute time because all the inputs to
765 ClientSubscription desling with the expiration are expecting
766 duration type values from the headers. .mjf.
767 */
768 if(response.exists(h_Expires))
769 {
770 mDefaultSubExpiration = response.header(h_Expires).value();
771 }
772 else
773 {
774 //?dcm? defaults to 3600 in ClientSubscription if no expires value
775 //is provided anywhere...should we assume the value from the
776 //sub in the basecreator if it exists?
777 mDefaultSubExpiration = 0;
778 }
779 return;
780 }
781 else
782 {
783 //!dcm! -- can't subscribe in an existing Dialog, this is all
784 //a bit of a hack; currently, spurious failure messages may cause callbacks
785 BaseCreator* creator = mDialogSet.getCreator();
786 if (!creator || !creator->getLastRequest()->exists(h_Event))
787 {
788 return;
789 }
790 else
791 {
792 ClientSubscriptionHandler* handler =
793 mDum.getClientSubscriptionHandler(creator->getLastRequest()->header(h_Event).value());
794 if (handler)
795 {
796 ClientSubscription* sub = makeClientSubscription(*creator->getLastRequest());
797 mClientSubscriptions.push_back(sub);
798 sub->dispatch(response);
799 }
800 }
801 }
802
803 }
804 break;
805 case NOTIFY:
806 {
807 //Failures are dispatched to all ServerSubsscriptions,
808 //which may not be correct as per RFC 5057.
809
810 int code = msg.header(h_StatusLine).statusCode();
811 if (code >= 300)
812 {
813 //!dcm! -- ick, write guard
814 mDestroying = true;
815 for (list<ServerSubscription*>::iterator it = mServerSubscriptions.begin();
816 it != mServerSubscriptions.end(); )
817 {
818 ServerSubscription* s = *it;
819 it++;
820 s->dispatch(msg);
821 }
822 mDestroying = false;
823 possiblyDie();
824 }
825 else if (code >= 200)
826 {
827 ServerSubscription* server = findMatchingServerSub(response);
828 if (server)
829 {
830 server->dispatch(response);
831 }
832 }
833 }
834 break;
835 default:
836 assert(0);
837 return;
838 }
839
840 #if 0 // merged from head back to teltel-branch
841 if (msg.header(h_StatusLine).statusCode() >= 400
842 && Helper::determineFailureMessageEffect(msg) == Helper::DialogTermination)
843 {
844 //kill all usages
845 mDestroying = true;
846
847 for (list<ServerSubscription*>::iterator it = mServerSubscriptions.begin();
848 it != mServerSubscriptions.end(); )
849 {
850 ServerSubscription* s = *it;
851 it++;
852 s->dialogDestroyed(msg);
853 }
854
855 for (list<ClientSubscription*>::iterator it = mClientSubscriptions.begin();
856 it != mClientSubscriptions.end(); )
857 {
858 ClientSubscription* s = *it;
859 it++;
860 s->dialogDestroyed(msg);
861 }
862 if (mInviteSession)
863 {
864 mInviteSession->dialogDestroyed(msg);
865 }
866 mDestroying = false;
867 possiblyDie(); //should aways result in destruction of this
868 return;
869 }
870 #endif
871 }
872 }
873
874 ServerSubscription*
875 Dialog::findMatchingServerSub(const SipMessage& msg)
876 {
877 for (std::list<ServerSubscription*>::iterator i=mServerSubscriptions.begin();
878 i != mServerSubscriptions.end(); ++i)
879 {
880 if ((*i)->matches(msg))
881 {
882 return *i;
883 }
884 }
885 return 0;
886 }
887
888 ClientSubscription*
889 Dialog::findMatchingClientSub(const SipMessage& msg)
890 {
891 for (std::list<ClientSubscription*>::iterator i=mClientSubscriptions.begin();
892 i != mClientSubscriptions.end(); ++i)
893 {
894 if ((*i)->matches(msg))
895 {
896 return *i;
897 }
898 }
899 return 0;
900 }
901
902 InviteSessionHandle
903 Dialog::getInviteSession()
904 {
905 if (mInviteSession)
906 {
907 return mInviteSession->getSessionHandle();
908 }
909 else
910 {
911 return InviteSessionHandle::NotValid();
912 }
913 }
914
915 std::vector<ClientSubscriptionHandle>
916 Dialog::findClientSubscriptions(const Data& event)
917 {
918 std::vector<ClientSubscriptionHandle> handles;
919
920 for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
921 i != mClientSubscriptions.end(); ++i)
922 {
923 if ( (*i)->getEventType() == event)
924 {
925 handles.push_back((*i)->getHandle());
926 }
927 }
928 return handles;
929 }
930
931 std::vector<ServerSubscriptionHandle>
932 Dialog::findServerSubscriptions(const Data& event)
933 {
934 std::vector<ServerSubscriptionHandle> handles;
935
936 for (std::list<ServerSubscription*>::const_iterator i = mServerSubscriptions.begin();
937 i != mServerSubscriptions.end(); ++i)
938 {
939 if ( (*i)->getEventType() == event)
940 {
941 handles.push_back((*i)->getHandle());
942 }
943 }
944 return handles;
945 }
946
947 std::vector<ClientSubscriptionHandle>
948 Dialog::getClientSubscriptions()
949 {
950 std::vector<ClientSubscriptionHandle> handles;
951
952 for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
953 i != mClientSubscriptions.end(); ++i)
954 {
955 handles.push_back((*i)->getHandle());
956 }
957
958 return handles;
959 }
960
961 std::vector<ServerSubscriptionHandle>
962 Dialog::getServerSubscriptions()
963 {
964 std::vector<ServerSubscriptionHandle> handles;
965
966 for (std::list<ServerSubscription*>::const_iterator i = mServerSubscriptions.begin();
967 i != mServerSubscriptions.end(); ++i)
968 {
969 handles.push_back((*i)->getHandle());
970 }
971
972 return handles;
973 }
974
975 void
976 Dialog::redirected(const SipMessage& msg)
977 {
978 //Established dialogs are not destroyed by a redirect
979 if (!mClientSubscriptions.empty() || !mServerSubscriptions.empty())
980 {
981 return;
982 }
983 if (mInviteSession)
984 {
985 ClientInviteSession* cInv = dynamic_cast<ClientInviteSession*>(mInviteSession);
986 if (cInv)
987 {
988 cInv->handleRedirect(msg);
989 mReUseDialogSet = true; // Set flag so that DialogSet will not be destroyed and new Request can use it
990 }
991 }
992 }
993
994 void
995 Dialog::makeRequest(SipMessage& request, MethodTypes method)
996 {
997 RequestLine rLine(method);
998
999 rLine.uri() = mRemoteTarget.uri();
1000
1001 request.header(h_RequestLine) = rLine;
1002 request.header(h_To) = mRemoteNameAddr;
1003 // request.header(h_To).param(p_tag) = mId.getRemoteTag();
1004 request.header(h_From) = mLocalNameAddr;
1005 // request.header(h_From).param(p_tag) = mId.getLocalTag();
1006
1007 request.header(h_CallId) = mCallId;
1008
1009 request.remove(h_RecordRoutes); //!dcm! -- all of this is rather messy
1010 request.remove(h_Replaces);
1011
1012 request.remove(h_Contacts);
1013 request.header(h_Contacts).push_front(mLocalContact);
1014
1015 request.header(h_CSeq).method() = method;
1016 request.header(h_MaxForwards).value() = 70;
1017
1018 //must keep old via for cancel
1019 if (method != CANCEL)
1020 {
1021 request.header(h_Routes) = mRouteSet;
1022 request.remove(h_Vias);
1023 Via via;
1024 via.param(p_branch); // will create the branch
1025 request.header(h_Vias).push_front(via);
1026 }
1027 else
1028 {
1029 assert(request.exists(h_Vias));
1030 }
1031
1032 //don't increment CSeq for ACK or CANCEL
1033 if (method != ACK && method != CANCEL)
1034 {
1035 request.header(h_CSeq).sequence() = ++mLocalCSeq;
1036 }
1037 else
1038 {
1039 // ACK and cancel have a minimal header set
1040 request.remove(h_Accepts);
1041 request.remove(h_AcceptEncodings);
1042 request.remove(h_AcceptLanguages);
1043 request.remove(h_Allows);
1044 request.remove(h_Requires);
1045 request.remove(h_ProxyRequires);
1046 request.remove(h_Supporteds);
1047 // request.header(h_CSeq).sequence() = ?; // Caller should provide original request, or modify CSeq to proper value after calling this method
1048 }
1049
1050 // If method is INVITE then advertise required headers
1051 if(method == INVITE || method == UPDATE)
1052 {
1053 // Add Advertised Capabilities
1054 mDum.setAdvertisedCapabilities(request, mDialogSet.mUserProfile);
1055 }
1056
1057 if (mDialogSet.mUserProfile->isAnonymous())
1058 {
1059 request.header(h_Privacys).push_back(PrivacyCategory(Symbols::id));
1060 }
1061
1062 DebugLog ( << "Dialog::makeRequest: " << std::endl << std::endl << request );
1063 }
1064
1065
1066 void
1067 Dialog::makeResponse(SipMessage& response, const SipMessage& request, int code)
1068 {
1069 assert( code >= 100 );
1070 response.remove(h_Contacts);
1071 if (code < 300 && code > 100)
1072 {
1073 assert(request.isRequest());
1074 assert(request.header(h_RequestLine).getMethod() == INVITE ||
1075 request.header(h_RequestLine).getMethod() == SUBSCRIBE ||
1076 request.header(h_RequestLine).getMethod() == BYE ||
1077 request.header(h_RequestLine).getMethod() == CANCEL ||
1078 request.header(h_RequestLine).getMethod() == REFER ||
1079 request.header(h_RequestLine).getMethod() == MESSAGE ||
1080 request.header(h_RequestLine).getMethod() == NOTIFY ||
1081 request.header(h_RequestLine).getMethod() == INFO ||
1082 request.header(h_RequestLine).getMethod() == OPTIONS ||
1083 request.header(h_RequestLine).getMethod() == PRACK ||
1084 request.header(h_RequestLine).getMethod() == UPDATE
1085 );
1086
1087 // assert (request.header(h_RequestLine).getMethod() == CANCEL || // Contact header is not required for Requests that do not form a dialog
1088 // request.header(h_RequestLine).getMethod() == BYE ||
1089 // request.header(h_Contacts).size() == 1);
1090 Helper::makeResponse(response, request, code, mLocalContact);
1091 response.header(h_To).param(p_tag) = mId.getLocalTag();
1092
1093 if((request.header(h_RequestLine).getMethod() == INVITE ||
1094 request.header(h_RequestLine).getMethod() == PRACK ||
1095 request.header(h_RequestLine).getMethod() == UPDATE)
1096 && code >= 200 && code < 300)
1097 {
1098 // Add Advertised Capabilities
1099 mDum.setAdvertisedCapabilities(response, mDialogSet.mUserProfile);
1100 }
1101 }
1102 else
1103 {
1104 Helper::makeResponse(response, request, code);
1105 response.header(h_To).param(p_tag) = mId.getLocalTag();
1106 }
1107
1108 DebugLog ( << "Dialog::makeResponse: " << std::endl << std::endl << response);
1109 }
1110
1111
1112 ClientInviteSession*
1113 Dialog::makeClientInviteSession(const SipMessage& response)
1114 {
1115 InviteSessionCreator* creator = dynamic_cast<InviteSessionCreator*>(mDialogSet.getCreator());
1116 if (!creator)
1117 {
1118 assert(0); // !jf! this maybe can assert by evil UAS
1119 return 0;
1120 }
1121 //return mDum.createAppClientInviteSession(*this, *creator);
1122 return new ClientInviteSession(mDum, *this, creator->getLastRequest(),
1123 creator->getInitialOffer(), creator->getEncryptionLevel(), creator->getServerSubscription());
1124 }
1125
1126
1127
1128 ClientSubscription*
1129 Dialog::makeClientSubscription(const SipMessage& request)
1130 {
1131 return new ClientSubscription(mDum, *this, request, mDefaultSubExpiration);
1132 }
1133
1134
1135 ServerInviteSession*
1136 Dialog::makeServerInviteSession(const SipMessage& request)
1137 {
1138 return new ServerInviteSession(mDum, *this, request);
1139 }
1140
1141 ServerSubscription*
1142 Dialog::makeServerSubscription(const SipMessage& request)
1143 {
1144 return new ServerSubscription(mDum, *this, request);
1145 }
1146
1147 Dialog::Exception::Exception(const Data& msg, const Data& file, int line)
1148 : BaseException(msg, file, line)
1149 {
1150 }
1151
1152
1153 void
1154 Dialog::send(SharedPtr<SipMessage> msg)
1155 {
1156 if (msg->isRequest() && msg->header(h_CSeq).method() != ACK)
1157 {
1158 mRequests[msg->header(h_CSeq).sequence()] = msg;
1159 }
1160 mDum.send(msg);
1161 }
1162
1163 void
1164 Dialog::onForkAccepted()
1165 {
1166 ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession);
1167 if (uac)
1168 {
1169 uac->onForkAccepted();
1170 }
1171 }
1172
1173 void
1174 Dialog::possiblyDie()
1175 {
1176 if (!mDestroying)
1177 {
1178 if (mClientSubscriptions.empty() &&
1179 mServerSubscriptions.empty() &&
1180 !mInviteSession)
1181 {
1182 mDestroying = true;
1183 mDum.destroy(this);
1184 }
1185 }
1186 }
1187
1188 void
1189 Dialog::flowTerminated()
1190 {
1191 // Clear the network association
1192 mNetworkAssociation.clear();
1193
1194 // notify server subscirption dialogs
1195 std::list<ServerSubscription*> tempServerList = mServerSubscriptions; // Create copy since subscription can be deleted
1196 for (std::list<ServerSubscription*>::iterator is=tempServerList.begin();
1197 is != tempServerList.end(); ++is)
1198 {
1199 (*is)->flowTerminated();
1200 }
1201
1202 // notify client subscription dialogs
1203 std::list<ClientSubscription*> tempClientList = mClientSubscriptions; // Create copy since subscription can be deleted
1204 for (std::list<ClientSubscription*>::iterator ic=tempClientList.begin();
1205 ic != tempClientList.end(); ++ic)
1206 {
1207 (*ic)->flowTerminated();
1208 }
1209
1210 // notify invite session dialog
1211 if (mInviteSession)
1212 {
1213 mInviteSession->flowTerminated();
1214 }
1215 }
1216
1217 EncodeStream&
1218 resip::operator<<(EncodeStream& strm, const Dialog& dialog)
1219 {
1220 strm
1221 << "mClientSubscriptions("
1222 << dialog.mClientSubscriptions.size()
1223 << "), "
1224 << "mServerSubscriptions("
1225 << dialog.mServerSubscriptions.size()
1226 << ")";
1227 return strm;
1228 }
1229
1230
1231 /* ====================================================================
1232 * The Vovida Software License, Version 1.0
1233 *
1234 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1235 *
1236 * Redistribution and use in source and binary forms, with or without
1237 * modification, are permitted provided that the following conditions
1238 * are met:
1239 *
1240 * 1. Redistributions of source code must retain the above copyright
1241 * notice, this list of conditions and the following disclaimer.
1242 *
1243 * 2. Redistributions in binary form must reproduce the above copyright
1244 * notice, this list of conditions and the following disclaimer in
1245 * the documentation and/or other materials provided with the
1246 * distribution.
1247 *
1248 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1249 * and "Vovida Open Communication Application Library (VOCAL)" must
1250 * not be used to endorse or promote products derived from this
1251 * software without prior written permission. For written
1252 * permission, please contact vocal@vovida.org.
1253 *
1254 * 4. Products derived from this software may not be called "VOCAL", nor
1255 * may "VOCAL" appear in their name, without prior written
1256 * permission of Vovida Networks, Inc.
1257 *
1258 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1259 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1260 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1261 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1262 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1263 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1264 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1265 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1266 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1267 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1268 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1269 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1270 * DAMAGE.
1271 *
1272 * ====================================================================
1273 *
1274 * This software consists of voluntary contributions made by Vovida
1275 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1276 * Inc. For more information on Vovida Networks, Inc., please see
1277 * <http://www.vovida.org/>.
1278 *
1279 */
1280
1281
1282

Properties

Name Value
svn:eol-style native
svn:mime-type text/plain

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27