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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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