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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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