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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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