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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27