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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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