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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7116 - (show annotations) (download)
Wed May 23 21:51:39 2007 UTC (12 years, 6 months ago) by sgodin
File MIME type: text/plain
File size: 37876 byte(s)
-added end() for subscriptions if Dialog::end is called - this allows AppDialogSet::end to end subscriptions
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 }
580
581 // !jf! should this only be for 2xx responses? !jf! Propose no as an
582 // answer !dcm! what is he on?
583 switch (response.header(h_CSeq).method())
584 {
585 case INVITE:
586 if (mInviteSession == 0)
587 {
588 DebugLog ( << "Dialog::dispatch -- Created new client invite session" << msg.brief());
589
590 mInviteSession = makeClientInviteSession(response);
591 mInviteSession->dispatch(response);
592 }
593 else
594 {
595 mInviteSession->dispatch(response);
596 }
597 break;
598 case BYE:
599 case ACK:
600 case CANCEL:
601 case INFO:
602 case MESSAGE:
603 case UPDATE:
604 if (mInviteSession)
605 {
606 mInviteSession->dispatch(response);
607 }
608 // else drop on the floor
609 break;
610
611 case REFER:
612 if(mInviteSession)
613 {
614 mInviteSession->mSentRefer = false;
615
616 if (code >= 300)
617 {
618 mDum.mInviteSessionHandler->onReferRejected(mInviteSession->getSessionHandle(), msg);
619 }
620 else
621 {
622 //!dys! the OR condition below is not draft compliant.
623 if (!mInviteSession->mReferSub &&
624 ((msg.exists(h_ReferSub) && msg.header(h_ReferSub).value()=="false") ||
625 !msg.exists(h_ReferSub)))
626 {
627 DebugLog(<< "refer accepted with norefersub");
628 mDum.mInviteSessionHandler->onReferAccepted(mInviteSession->getSessionHandle(), ClientSubscriptionHandle::NotValid(), msg);
629 }
630 // else no need for action - first Notify will cause onReferAccepted to be called
631 }
632 break;
633 }
634 // fall through, out of dialog refer was sent.
635
636 case SUBSCRIBE:
637 {
638 int code = response.header(h_StatusLine).statusCode();
639 ClientSubscription* client = findMatchingClientSub(response);
640 if (client)
641 {
642 client->dispatch(response);
643 }
644 else if (code < 300)
645 {
646 /*
647 we're capturing the value from the expires header off
648 the 2xx because the ClientSubscription is only created
649 after receiving the NOTIFY that comes (usually) after
650 this 2xx. We really should be creating the
651 ClientSubscription at either the 2xx or the NOTIFY
652 whichever arrives first. .mjf.
653 Note: we're capturing a duration here (not the
654 absolute time because all the inputs to
655 ClientSubscription desling with the expiration are expecting
656 duration type values from the headers. .mjf.
657 */
658 mDefaultSubExpiration = response.header(h_Expires).value();
659 return;
660 }
661 else
662 {
663 //!dcm! -- can't subscribe in an existing Dialog, this is all
664 //a bit of a hack; currently, spurious failure messages may cause callbacks
665 BaseCreator* creator = mDialogSet.getCreator();
666 if (!creator || !creator->getLastRequest()->exists(h_Event))
667 {
668 return;
669 }
670 else
671 {
672 ClientSubscriptionHandler* handler =
673 mDum.getClientSubscriptionHandler(creator->getLastRequest()->header(h_Event).value());
674 if (handler)
675 {
676 ClientSubscription* sub = makeClientSubscription(*creator->getLastRequest());
677 mClientSubscriptions.push_back(sub);
678 sub->dispatch(response);
679 }
680 }
681 }
682
683 }
684 break;
685 case NOTIFY:
686 {
687 //2xx responses are treated as retransmission quenchers(handled by
688 //the stack). Failures are dispatched to all ServerSubsscriptions,
689 //which may not be correct.
690
691 int code = msg.header(h_StatusLine).statusCode();
692 if (code >= 300)
693 {
694 //!dcm! -- ick, write guard
695 mDestroying = true;
696 for (list<ServerSubscription*>::iterator it = mServerSubscriptions.begin();
697 it != mServerSubscriptions.end(); )
698 {
699 ServerSubscription* s = *it;
700 it++;
701 s->dispatch(msg);
702 }
703 mDestroying = false;
704 possiblyDie();
705 }
706 // ServerSubscription* server = findMatchingServerSub(response);
707 // if (server)
708 // {
709 // server->dispatch(response);
710 // }
711 }
712 break;
713 default:
714 assert(0);
715 return;
716 }
717
718 #if 0 // merged from head back to teltel-branch
719 if (msg.header(h_StatusLine).statusCode() >= 400
720 && Helper::determineFailureMessageEffect(msg) == Helper::DialogTermination)
721 {
722 //kill all usages
723 mDestroying = true;
724
725 for (list<ServerSubscription*>::iterator it = mServerSubscriptions.begin();
726 it != mServerSubscriptions.end(); )
727 {
728 ServerSubscription* s = *it;
729 it++;
730 s->dialogDestroyed(msg);
731 }
732
733 for (list<ClientSubscription*>::iterator it = mClientSubscriptions.begin();
734 it != mClientSubscriptions.end(); )
735 {
736 ClientSubscription* s = *it;
737 it++;
738 s->dialogDestroyed(msg);
739 }
740 if (mInviteSession)
741 {
742 mInviteSession->dialogDestroyed(msg);
743 }
744 mDestroying = false;
745 possiblyDie(); //should aways result in destruction of this
746 return;
747 }
748 #endif
749 }
750 }
751
752 ServerSubscription*
753 Dialog::findMatchingServerSub(const SipMessage& msg)
754 {
755 for (std::list<ServerSubscription*>::iterator i=mServerSubscriptions.begin();
756 i != mServerSubscriptions.end(); ++i)
757 {
758 if ((*i)->matches(msg))
759 {
760 return *i;
761 }
762 }
763 return 0;
764 }
765
766 ClientSubscription*
767 Dialog::findMatchingClientSub(const SipMessage& msg)
768 {
769 for (std::list<ClientSubscription*>::iterator i=mClientSubscriptions.begin();
770 i != mClientSubscriptions.end(); ++i)
771 {
772 if ((*i)->matches(msg))
773 {
774 return *i;
775 }
776 }
777 return 0;
778 }
779
780 InviteSessionHandle
781 Dialog::getInviteSession()
782 {
783 if (mInviteSession)
784 {
785 return mInviteSession->getSessionHandle();
786 }
787 else
788 {
789 return InviteSessionHandle::NotValid();
790 }
791 }
792
793 std::vector<ClientSubscriptionHandle>
794 Dialog::findClientSubscriptions(const Data& event)
795 {
796 std::vector<ClientSubscriptionHandle> handles;
797
798 for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
799 i != mClientSubscriptions.end(); ++i)
800 {
801 if ( (*i)->getEventType() == event)
802 {
803 handles.push_back((*i)->getHandle());
804 }
805 }
806 return handles;
807 }
808
809 std::vector<ServerSubscriptionHandle>
810 Dialog::findServerSubscriptions(const Data& event)
811 {
812 std::vector<ServerSubscriptionHandle> handles;
813
814 for (std::list<ServerSubscription*>::const_iterator i = mServerSubscriptions.begin();
815 i != mServerSubscriptions.end(); ++i)
816 {
817 if ( (*i)->getEventType() == event)
818 {
819 handles.push_back((*i)->getHandle());
820 }
821 }
822 return handles;
823 }
824
825 std::vector<ClientSubscriptionHandle>
826 Dialog::getClientSubscriptions()
827 {
828 std::vector<ClientSubscriptionHandle> handles;
829
830 for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
831 i != mClientSubscriptions.end(); ++i)
832 {
833 handles.push_back((*i)->getHandle());
834 }
835
836 return handles;
837 }
838
839 std::vector<ServerSubscriptionHandle>
840 Dialog::getServerSubscriptions()
841 {
842 std::vector<ServerSubscriptionHandle> handles;
843
844 for (std::list<ServerSubscription*>::const_iterator i = mServerSubscriptions.begin();
845 i != mServerSubscriptions.end(); ++i)
846 {
847 handles.push_back((*i)->getHandle());
848 }
849
850 return handles;
851 }
852
853 void
854 Dialog::redirected(const SipMessage& msg)
855 {
856 //Established dialogs are not destroyed by a redirect
857 if (!mClientSubscriptions.empty() || !mServerSubscriptions.empty())
858 {
859 return;
860 }
861 if (mInviteSession)
862 {
863 ClientInviteSession* cInv = dynamic_cast<ClientInviteSession*>(mInviteSession);
864 if (cInv)
865 {
866 cInv->handleRedirect(msg);
867 mReUseDialogSet = true; // Set flag so that DialogSet will not be destroyed and new Request can use it
868 }
869 }
870 }
871
872 void
873 Dialog::makeRequest(SipMessage& request, MethodTypes method)
874 {
875 RequestLine rLine(method);
876
877 rLine.uri() = mRemoteTarget.uri();
878
879 request.header(h_RequestLine) = rLine;
880 request.header(h_To) = mRemoteNameAddr;
881 // request.header(h_To).param(p_tag) = mId.getRemoteTag();
882 request.header(h_From) = mLocalNameAddr;
883 // request.header(h_From).param(p_tag) = mId.getLocalTag();
884
885 request.header(h_CallId) = mCallId;
886
887 request.remove(h_RecordRoutes); //!dcm! -- all of this is rather messy
888 request.remove(h_Replaces);
889
890 request.remove(h_Contacts);
891 request.header(h_Contacts).push_front(mLocalContact);
892
893 request.header(h_CSeq).method() = method;
894 request.header(h_MaxForwards).value() = 70;
895
896 //must keep old via for cancel
897 if (method != CANCEL)
898 {
899 request.header(h_Routes) = mRouteSet;
900 request.remove(h_Vias);
901 Via via;
902 via.param(p_branch); // will create the branch
903 request.header(h_Vias).push_front(via);
904 }
905 else
906 {
907 assert(request.exists(h_Vias));
908 }
909
910 //don't increment CSeq for ACK or CANCEL
911 if (method != ACK && method != CANCEL)
912 {
913 request.header(h_CSeq).sequence() = ++mLocalCSeq;
914 }
915 else
916 {
917 // ACK and cancel have a minimal header set
918 request.remove(h_Accepts);
919 request.remove(h_AcceptEncodings);
920 request.remove(h_AcceptLanguages);
921 request.remove(h_Allows);
922 request.remove(h_Requires);
923 request.remove(h_ProxyRequires);
924 request.remove(h_Supporteds);
925 // request.header(h_CSeq).sequence() = ?; // Caller should provide original request, or modify CSeq to proper value after calling this method
926 }
927
928 // If method is INVITE then advertise required headers
929 if(method == INVITE || method == UPDATE)
930 {
931 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Allow)) request.header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods();
932 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptEncoding)) request.header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings();
933 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptLanguage)) request.header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages();
934 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AllowEvents)) request.header(h_AllowEvents) = mDum.getMasterProfile()->getAllowedEvents();
935 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Supported)) request.header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags();
936 }
937
938 if (mDialogSet.mUserProfile->isAnonymous())
939 {
940 request.header(h_Privacys).push_back(Token(Symbols::id));
941 }
942
943 DebugLog ( << "Dialog::makeRequest: " << std::endl << std::endl << request );
944 }
945
946
947 void
948 Dialog::makeResponse(SipMessage& response, const SipMessage& request, int code)
949 {
950 assert( code >= 100 );
951 response.remove(h_Contacts);
952 if (code < 300 && code > 100)
953 {
954 assert(request.isRequest());
955 assert(request.header(h_RequestLine).getMethod() == INVITE ||
956 request.header(h_RequestLine).getMethod() == SUBSCRIBE ||
957 request.header(h_RequestLine).getMethod() == BYE ||
958 request.header(h_RequestLine).getMethod() == CANCEL ||
959 request.header(h_RequestLine).getMethod() == REFER ||
960 request.header(h_RequestLine).getMethod() == MESSAGE ||
961 request.header(h_RequestLine).getMethod() == NOTIFY ||
962 request.header(h_RequestLine).getMethod() == INFO ||
963 request.header(h_RequestLine).getMethod() == OPTIONS ||
964 request.header(h_RequestLine).getMethod() == UPDATE
965 );
966
967 // assert (request.header(h_RequestLine).getMethod() == CANCEL || // Contact header is not required for Requests that do not form a dialog
968 // request.header(h_RequestLine).getMethod() == BYE ||
969 // request.header(h_Contacts).size() == 1);
970 Helper::makeResponse(response, request, code, mLocalContact);
971 response.header(h_To).param(p_tag) = mId.getLocalTag();
972
973 if((request.header(h_RequestLine).getMethod() == INVITE ||
974 request.header(h_RequestLine).getMethod() == UPDATE)
975 && code >= 200 && code < 300)
976 {
977 // Check if we should add our capabilites to the invite success response
978 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Allow)) response.header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods();
979 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptEncoding)) response.header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings();
980 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptLanguage)) response.header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages();
981 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AllowEvents)) response.header(h_AllowEvents) = mDum.getMasterProfile()->getAllowedEvents();
982 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Supported)) response.header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags();
983 }
984 }
985 else
986 {
987 Helper::makeResponse(response, request, code);
988 response.header(h_To).param(p_tag) = mId.getLocalTag();
989 }
990
991 DebugLog ( << "Dialog::makeResponse: " << std::endl << std::endl << response);
992 }
993
994
995 ClientInviteSession*
996 Dialog::makeClientInviteSession(const SipMessage& response)
997 {
998 InviteSessionCreator* creator = dynamic_cast<InviteSessionCreator*>(mDialogSet.getCreator());
999 assert(creator); // !jf! this maybe can assert by evil UAS
1000 //return mDum.createAppClientInviteSession(*this, *creator);
1001 return new ClientInviteSession(mDum, *this, creator->getLastRequest(),
1002 creator->getInitialOffer(), creator->getEncryptionLevel(), creator->getServerSubscription());
1003 }
1004
1005
1006
1007 ClientSubscription*
1008 Dialog::makeClientSubscription(const SipMessage& request)
1009 {
1010 return new ClientSubscription(mDum, *this, request, mDefaultSubExpiration);
1011 }
1012
1013
1014 ServerInviteSession*
1015 Dialog::makeServerInviteSession(const SipMessage& request)
1016 {
1017 return new ServerInviteSession(mDum, *this, request);
1018 }
1019
1020 ServerSubscription*
1021 Dialog::makeServerSubscription(const SipMessage& request)
1022 {
1023 return new ServerSubscription(mDum, *this, request);
1024 }
1025
1026 Dialog::Exception::Exception(const Data& msg, const Data& file, int line)
1027 : BaseException(msg, file, line)
1028 {
1029 }
1030
1031
1032 void
1033 Dialog::send(SharedPtr<SipMessage> msg)
1034 {
1035 if (msg->isRequest() && msg->header(h_CSeq).method() != ACK)
1036 {
1037 mRequests[msg->header(h_CSeq).sequence()] = msg;
1038 }
1039 mDum.send(msg);
1040 }
1041
1042 void
1043 Dialog::onForkAccepted()
1044 {
1045 ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession);
1046 if (uac)
1047 {
1048 uac->onForkAccepted();
1049 }
1050 }
1051
1052 void Dialog::possiblyDie()
1053 {
1054 // !slg! Note: dialogs should really stick around for 32s, in order to ensure that all 2xx retransmissions get Ack'd, then BYE'd correctly
1055 if (!mDestroying)
1056 {
1057 if (mClientSubscriptions.empty() &&
1058 mServerSubscriptions.empty() &&
1059 !mInviteSession)
1060 {
1061 mDestroying = true;
1062 mDum.destroy(this);
1063 }
1064 }
1065 }
1066
1067 ostream&
1068 resip::operator<<(ostream& strm, const Dialog& dialog)
1069 {
1070 strm
1071 << "mClientSubscriptions("
1072 << dialog.mClientSubscriptions.size()
1073 << "), "
1074 << "mServerSubscriptions("
1075 << dialog.mServerSubscriptions.size()
1076 << ")";
1077 return strm;
1078 }
1079
1080
1081 /* ====================================================================
1082 * The Vovida Software License, Version 1.0
1083 *
1084 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1085 *
1086 * Redistribution and use in source and binary forms, with or without
1087 * modification, are permitted provided that the following conditions
1088 * are met:
1089 *
1090 * 1. Redistributions of source code must retain the above copyright
1091 * notice, this list of conditions and the following disclaimer.
1092 *
1093 * 2. Redistributions in binary form must reproduce the above copyright
1094 * notice, this list of conditions and the following disclaimer in
1095 * the documentation and/or other materials provided with the
1096 * distribution.
1097 *
1098 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1099 * and "Vovida Open Communication Application Library (VOCAL)" must
1100 * not be used to endorse or promote products derived from this
1101 * software without prior written permission. For written
1102 * permission, please contact vocal@vovida.org.
1103 *
1104 * 4. Products derived from this software may not be called "VOCAL", nor
1105 * may "VOCAL" appear in their name, without prior written
1106 * permission of Vovida Networks, Inc.
1107 *
1108 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1109 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1110 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1111 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1112 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1113 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1114 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1115 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1116 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1117 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1118 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1119 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1120 * DAMAGE.
1121 *
1122 * ====================================================================
1123 *
1124 * This software consists of voluntary contributions made by Vovida
1125 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1126 * Inc. For more information on Vovida Networks, Inc., please see
1127 * <http://www.vovida.org/>.
1128 *
1129 */
1130
1131

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