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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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