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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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