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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7466 - (show annotations) (download)
Wed Nov 28 19:02:25 2007 UTC (12 years ago) by bcampen
File MIME type: text/plain
File size: 38643 byte(s)
Work from resiprocate-1.2-sipit-ctpc, plus a tweak to kill a warning.

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

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