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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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