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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10126 - (show annotations) (download)
Thu Apr 11 13:49:29 2013 UTC (6 years, 8 months ago) by fjoanis
File MIME type: text/plain
File size: 42609 byte(s)
Added ServerSubscriptionHandler::onNotifyAccepted callback.

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

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