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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6160 - (show annotations) (download)
Tue Apr 18 20:17:30 2006 UTC (13 years, 9 months ago) by moetje
File MIME type: text/plain
File size: 35583 byte(s)
- made setOverrideHostAndPort effective also for UAS situations as discussed on the list
- corrected my previous checkin to use spaces instead of tabs

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

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