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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8928 - (show annotations) (download)
Tue Dec 28 18:19:01 2010 UTC (8 years, 11 months ago) by sgodin
File MIME type: text/plain
File size: 40448 byte(s)
-extended dum profile to allow user agent capabilities to be provided by the application and used in
 contact headers
-modified MOH server to use the following user agent capabilities in it's contact headers as
 specified in RFC 5359  - ;automaton;+sip.byeless;+sip.rendering="no"


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

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