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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5586 - (show annotations) (download)
Fri Oct 28 21:01:13 2005 UTC (14 years, 1 month ago) by sgodin
File size: 34062 byte(s)
- modified ACK handling
  - mAckId is no longer tracked by Dialog.cxx - all logic is in InviteSession.cxx
  - Authorization and Proxy-Authorization headers are copied to acks from the InviteSession.cxx
  - 2xx retransmission is now detected and handled properly - no more incorrect handler callbacks
- DialogSet destruction bug fixed
- onStaleCallTimeout callback no has a default handler to send a BYE - app can override and send a CANCEL if desired
- 

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 int keepAliveTime = mDialogSet.getUserProfile()->getKeepAliveTime();
294 if(keepAliveTime > 0)
295 {
296 mNetworkAssociation.update(msg, keepAliveTime);
297 }
298 handleTargetRefresh(msg);
299 if (msg.isRequest())
300 {
301 const SipMessage& request = msg;
302 switch (request.header(h_CSeq).method())
303 {
304 case INVITE: // new INVITE
305 if (mInviteSession == 0)
306 {
307 DebugLog ( << "Dialog::dispatch -- Created new server invite session" << msg.brief());
308 mInviteSession = makeServerInviteSession(request);
309 }
310 mInviteSession->dispatch(request);
311 break;
312 //refactor, send bad request for BYE, INFO, CANCEL?
313 case BYE:
314 if (mInviteSession == 0)
315 {
316 InfoLog ( << "Spurious BYE" );
317 return;
318 }
319 else
320 {
321 mInviteSession->dispatch(request);
322 }
323 break;
324 case UPDATE:
325 if (mInviteSession == 0)
326 {
327 InfoLog ( << "Spurious UPDATE" );
328 return;
329 }
330 else
331 {
332 mInviteSession->dispatch(request);
333 }
334 break;
335 case INFO:
336 if (mInviteSession == 0)
337 {
338 InfoLog ( << "Spurious INFO" );
339 return;
340 }
341 else
342 {
343 mInviteSession->dispatch(request);
344 }
345 break;
346 case MESSAGE:
347 if (mInviteSession == 0)
348 {
349 InfoLog ( << "Spurious MESSAGE" );
350 return;
351 }
352 else
353 {
354 mInviteSession->dispatch(request);
355 }
356 break;
357 case ACK:
358 case CANCEL:
359 if (mInviteSession == 0)
360 {
361 InfoLog (<< "Drop stray ACK or CANCEL in dialog on the floor");
362 DebugLog (<< request);
363 }
364 else
365 {
366 mInviteSession->dispatch(request);
367 }
368 break;
369 case SUBSCRIBE:
370 {
371 ServerSubscription* server = findMatchingServerSub(request);
372 if (server)
373 {
374 server->dispatch(request);
375 }
376 else
377 {
378 if (request.exists(h_Event) && request.header(h_Event).value() == "refer")
379 {
380 InfoLog (<< "Received a subscribe to a non-existent refer subscription: " << request.brief());
381 SipMessage failure;
382 makeResponse(failure, request, 403);
383 mDum.sendResponse(failure);
384 return;
385 }
386 else
387 {
388 server = makeServerSubscription(request);
389 mServerSubscriptions.push_back(server);
390 server->dispatch(request);
391 }
392 }
393 }
394 break;
395 case REFER:
396 {
397 if (mInviteSession == 0)
398 {
399 InfoLog (<< "Received an in dialog refer in a non-invite dialog: " << request.brief());
400 SipMessage failure;
401 makeResponse(failure, request, 603);
402 mDum.sendResponse(failure);
403 return;
404 }
405 else if (!request.exists(h_ReferTo))
406 {
407 InfoLog (<< "Received refer w/out a Refer-To: " << request.brief());
408 SipMessage failure;
409 makeResponse(failure, request, 400);
410 mDum.sendResponse(failure);
411 return;
412 }
413 else
414 {
415 ServerSubscription* server = findMatchingServerSub(request);
416 ServerSubscriptionHandle serverHandle;
417 if (server)
418 {
419 serverHandle = server->getHandle();
420 server->dispatch(request);
421 }
422 else
423 {
424 server = makeServerSubscription(request);
425 mServerSubscriptions.push_back(server);
426 serverHandle = server->getHandle();
427 server->dispatch(request);
428 }
429 mDum.mInviteSessionHandler->onRefer(mInviteSession->getSessionHandle(), serverHandle, msg);
430 }
431 }
432 break;
433 case NOTIFY:
434 {
435 ClientSubscription* client = findMatchingClientSub(request);
436 if (client)
437 {
438 client->dispatch(request);
439 }
440 else
441 {
442 BaseCreator* creator = mDialogSet.getCreator();
443 if (creator && (creator->getLastRequest().header(h_RequestLine).method() == SUBSCRIBE ||
444 creator->getLastRequest().header(h_RequestLine).method() == REFER)) // ?slg? OOD Refer? Click-to-Call?
445 {
446 DebugLog (<< "Making subscription (from creator) request: " << creator->getLastRequest());
447 ClientSubscription* sub = makeClientSubscription(creator->getLastRequest());
448 mClientSubscriptions.push_back(sub);
449 sub->dispatch(request);
450 }
451 else
452 {
453 if (mInviteSession != 0 && (!msg.exists(h_Event) || msg.header(h_Event).value() == "refer"))
454 {
455 DebugLog (<< "Making subscription from NOTIFY: " << msg);
456 ClientSubscription* sub = makeClientSubscription(msg);
457 mClientSubscriptions.push_back(sub);
458 ClientSubscriptionHandle client = sub->getHandle();
459 sub->dispatch(request);
460 mInviteSession->mSentRefer = false;
461 if (client.isValid())
462 {
463 mDum.mInviteSessionHandler->onReferAccepted(mInviteSession->getSessionHandle(), client, msg);
464 }
465 else
466 {
467 mDum.mInviteSessionHandler->onReferRejected(mInviteSession->getSessionHandle(), msg);
468 }
469 }
470 else
471 {
472 SipMessage response;
473 makeResponse(response, msg, 406);
474 send(response);
475 }
476 }
477 }
478 }
479 break;
480 default:
481 assert(0);
482 return;
483 }
484 }
485 else if (msg.isResponse())
486 {
487 // !jf! There is a substantial change in how this works in teltel-branch
488 // from how it worked in main branch pre merge.
489 // If the response doesn't match a cseq for a request I've sent, ignore
490 // the response
491 RequestMap::iterator r = mRequests.find(msg.header(h_CSeq).sequence());
492 if (r != mRequests.end())
493 {
494 bool handledByAuth = false;
495 if (mDum.mClientAuthManager.get() &&
496 mDum.mClientAuthManager->handle(*mDialogSet.getUserProfile(), r->second, msg))
497 {
498 InfoLog( << "about to re-send request with digest credentials" );
499 InfoLog( << r->second );
500
501 assert (r->second.isRequest());
502
503 mLocalCSeq++;
504 send(r->second);
505 handledByAuth = true;
506
507 if((r->second.header(h_RequestLine).method() == INVITE || r->second.header(h_RequestLine).method() == UPDATE) &&
508 mInviteSession != 0)
509 {
510 // Copy INVITE or UPDATE with Authorization headers back to InviteSession - needed to populate ACKs with Authoriziation headers
511 mInviteSession->mLastSessionModification = r->second;
512 }
513 }
514 mRequests.erase(r);
515 if (handledByAuth) return;
516 }
517
518 const SipMessage& response = msg;
519 int code = response.header(h_StatusLine).statusCode();
520 if (code >=200 && code < 300)
521 {
522 if (response.exists(h_RecordRoutes))
523 {
524 mRouteSet = response.header(h_RecordRoutes).reverse();
525 }
526 }
527
528 // !jf! should this only be for 2xx responses? !jf! Propose no as an
529 // answer !dcm! what is he on?
530 switch (response.header(h_CSeq).method())
531 {
532 case INVITE:
533 if (mInviteSession == 0)
534 {
535 DebugLog ( << "Dialog::dispatch -- Created new client invite session" << msg.brief());
536
537 mInviteSession = makeClientInviteSession(response);
538 mInviteSession->dispatch(response);
539 }
540 else
541 {
542 mInviteSession->dispatch(response);
543 }
544 break;
545 case BYE:
546 case ACK:
547 case CANCEL:
548 case INFO:
549 case MESSAGE:
550 case UPDATE:
551 if (mInviteSession)
552 {
553 mInviteSession->dispatch(response);
554 }
555 // else drop on the floor
556 break;
557
558 case REFER:
559 if(mInviteSession)
560 {
561 mInviteSession->mSentRefer = false;
562
563 if (code >= 300)
564 {
565 mDum.mInviteSessionHandler->onReferRejected(mInviteSession->getSessionHandle(), msg);
566 }
567 // else no need for action - first Notify will cause onReferAccepted to be called
568 }
569 break;
570
571 case SUBSCRIBE:
572 {
573 int code = response.header(h_StatusLine).statusCode();
574 if (code < 300)
575 {
576 // throw it away
577 return;
578 }
579 else
580 {
581 ClientSubscription* client = findMatchingClientSub(response);
582 if (client)
583 {
584 client->dispatch(response);
585 }
586 else
587 {
588 //!dcm! -- can't subscribe in an existing Dialog, this is all
589 //a bit of a hack; currently, spurious failure messages may cause callbacks
590 BaseCreator* creator = mDialogSet.getCreator();
591 if (!creator || !creator->getLastRequest().exists(h_Event))
592 {
593 return;
594 }
595 else
596 {
597 ClientSubscriptionHandler* handler =
598 mDum.getClientSubscriptionHandler(creator->getLastRequest().header(h_Event).value());
599 if (handler)
600 {
601 ClientSubscription* sub = makeClientSubscription(creator->getLastRequest());
602 mClientSubscriptions.push_back(sub);
603 sub->dispatch(response);
604 }
605 }
606 }
607 }
608 }
609 break;
610 case NOTIFY:
611 {
612 //2xx responses are treated as retransmission quenchers(handled by
613 //the stack). Failures are dispatched to all ServerSubsscriptions,
614 //which may not be correct.
615
616 int code = msg.header(h_StatusLine).statusCode();
617 if (code >= 300)
618 {
619 //!dcm! -- ick, write guard
620 mDestroying = true;
621 for (list<ServerSubscription*>::iterator it = mServerSubscriptions.begin();
622 it != mServerSubscriptions.end(); )
623 {
624 ServerSubscription* s = *it;
625 it++;
626 s->dispatch(msg);
627 }
628 mDestroying = false;
629 possiblyDie();
630 }
631 // ServerSubscription* server = findMatchingServerSub(response);
632 // if (server)
633 // {
634 // server->dispatch(response);
635 // }
636 }
637 break;
638 default:
639 assert(0);
640 return;
641 }
642
643 #if 0 // merged from head back to teltel-branch
644 if (msg.header(h_StatusLine).statusCode() >= 400
645 && Helper::determineFailureMessageEffect(msg) == Helper::DialogTermination)
646 {
647 //kill all usages
648 mDestroying = true;
649
650 for (list<ServerSubscription*>::iterator it = mServerSubscriptions.begin();
651 it != mServerSubscriptions.end(); )
652 {
653 ServerSubscription* s = *it;
654 it++;
655 s->dialogDestroyed(msg);
656 }
657
658 for (list<ClientSubscription*>::iterator it = mClientSubscriptions.begin();
659 it != mClientSubscriptions.end(); )
660 {
661 ClientSubscription* s = *it;
662 it++;
663 s->dialogDestroyed(msg);
664 }
665 if (mInviteSession)
666 {
667 mInviteSession->dialogDestroyed(msg);
668 }
669 mDestroying = false;
670 possiblyDie(); //should aways result in destruction of this
671 return;
672 }
673 #endif
674 }
675 }
676
677 ServerSubscription*
678 Dialog::findMatchingServerSub(const SipMessage& msg)
679 {
680 for (std::list<ServerSubscription*>::iterator i=mServerSubscriptions.begin();
681 i != mServerSubscriptions.end(); ++i)
682 {
683 if ((*i)->matches(msg))
684 {
685 return *i;
686 }
687 }
688 return 0;
689 }
690
691 ClientSubscription*
692 Dialog::findMatchingClientSub(const SipMessage& msg)
693 {
694 for (std::list<ClientSubscription*>::iterator i=mClientSubscriptions.begin();
695 i != mClientSubscriptions.end(); ++i)
696 {
697 if ((*i)->matches(msg))
698 {
699 return *i;
700 }
701 }
702 return 0;
703 }
704
705 InviteSessionHandle
706 Dialog::getInviteSession()
707 {
708 if (mInviteSession)
709 {
710 return mInviteSession->getSessionHandle();
711 }
712 else
713 {
714 return InviteSessionHandle::NotValid();
715 }
716 }
717
718 std::vector<ClientSubscriptionHandle>
719 Dialog::findClientSubscriptions(const Data& event)
720 {
721 std::vector<ClientSubscriptionHandle> handles;
722
723 for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
724 i != mClientSubscriptions.end(); ++i)
725 {
726 if ( (*i)->getEventType() == event)
727 {
728 handles.push_back((*i)->getHandle());
729 }
730 }
731 return handles;
732 }
733
734 std::vector<ServerSubscriptionHandle>
735 Dialog::findServerSubscriptions(const Data& event)
736 {
737 std::vector<ServerSubscriptionHandle> handles;
738
739 for (std::list<ServerSubscription*>::const_iterator i = mServerSubscriptions.begin();
740 i != mServerSubscriptions.end(); ++i)
741 {
742 if ( (*i)->getEventType() == event)
743 {
744 handles.push_back((*i)->getHandle());
745 }
746 }
747 return handles;
748 }
749
750 std::vector<ClientSubscriptionHandle>
751 Dialog::getClientSubscriptions()
752 {
753 std::vector<ClientSubscriptionHandle> handles;
754
755 for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
756 i != mClientSubscriptions.end(); ++i)
757 {
758 handles.push_back((*i)->getHandle());
759 }
760
761 return handles;
762 }
763
764 std::vector<ServerSubscriptionHandle>
765 Dialog::getServerSubscriptions()
766 {
767 std::vector<ServerSubscriptionHandle> handles;
768
769 for (std::list<ServerSubscription*>::const_iterator i = mServerSubscriptions.begin();
770 i != mServerSubscriptions.end(); ++i)
771 {
772 handles.push_back((*i)->getHandle());
773 }
774
775 return handles;
776 }
777
778 void
779 Dialog::redirected(const SipMessage& msg)
780 {
781 //Established dialogs are not destroyed by a redirect
782 if (!mClientSubscriptions.empty() || !mServerSubscriptions.empty())
783 {
784 return;
785 }
786 if (mInviteSession)
787 {
788 ClientInviteSession* cInv = dynamic_cast<ClientInviteSession*>(mInviteSession);
789 if (cInv)
790 {
791 cInv->handleRedirect(msg);
792 mReUseDialogSet = true; // Set flag so that DialogSet will not be destroyed and new Request can use it
793 }
794 }
795 }
796
797 void
798 Dialog::makeRequest(SipMessage& request, MethodTypes method)
799 {
800 RequestLine rLine(method);
801
802 rLine.uri() = mRemoteTarget.uri();
803
804 request.header(h_RequestLine) = rLine;
805 request.header(h_To) = mRemoteNameAddr;
806 // request.header(h_To).param(p_tag) = mId.getRemoteTag();
807 request.header(h_From) = mLocalNameAddr;
808 // request.header(h_From).param(p_tag) = mId.getLocalTag();
809
810 request.header(h_CallId) = mCallId;
811
812 request.remove(h_RecordRoutes); //!dcm! -- all of this is rather messy
813
814 request.remove(h_Contacts);
815 request.header(h_Contacts).push_front(mLocalContact);
816
817 request.header(h_CSeq).method() = method;
818 request.header(h_MaxForwards).value() = 70;
819
820 //must keep old via for cancel
821 if (method != CANCEL)
822 {
823 request.header(h_Routes) = mRouteSet;
824 request.remove(h_Vias);
825 Via via;
826 via.param(p_branch); // will create the branch
827 request.header(h_Vias).push_front(via);
828 }
829 else
830 {
831 assert(request.exists(h_Vias));
832 }
833
834 //don't increment CSeq for ACK or CANCEL
835 if (method != ACK && method != CANCEL)
836 {
837 request.header(h_CSeq).sequence() = ++mLocalCSeq;
838 }
839 else
840 {
841 // ACK and cancel have a minimal header set
842 request.remove(h_Accepts);
843 request.remove(h_AcceptEncodings);
844 request.remove(h_AcceptLanguages);
845 request.remove(h_Allows);
846 request.remove(h_Requires);
847 request.remove(h_ProxyRequires);
848 request.remove(h_Supporteds);
849 // request.header(h_CSeq).sequence() = ?; // Caller should provide original request, or modify CSeq to proper value after calling this method
850 }
851
852 // If method is INVITE then advertise required headers
853 if(method == INVITE || method == UPDATE)
854 {
855 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Allow)) request.header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods();
856 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptEncoding)) request.header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings();
857 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptLanguage)) request.header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages();
858 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AllowEvents)) request.header(h_AllowEvents) = mDum.getMasterProfile()->getAllowedEvents();
859 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Supported)) request.header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags();
860 }
861
862 DebugLog ( << "Dialog::makeRequest: " << request );
863 }
864
865
866 void
867 Dialog::makeResponse(SipMessage& response, const SipMessage& request, int code)
868 {
869 assert( code >= 100 );
870 response.remove(h_Contacts);
871 if (code < 300 && code > 100)
872 {
873 assert(request.isRequest());
874 assert(request.header(h_RequestLine).getMethod() == INVITE ||
875 request.header(h_RequestLine).getMethod() == SUBSCRIBE ||
876 request.header(h_RequestLine).getMethod() == BYE ||
877 request.header(h_RequestLine).getMethod() == CANCEL ||
878 request.header(h_RequestLine).getMethod() == REFER ||
879 request.header(h_RequestLine).getMethod() == MESSAGE ||
880 request.header(h_RequestLine).getMethod() == NOTIFY ||
881 request.header(h_RequestLine).getMethod() == INFO ||
882 request.header(h_RequestLine).getMethod() == OPTIONS ||
883 request.header(h_RequestLine).getMethod() == UPDATE
884 );
885
886 // assert (request.header(h_RequestLine).getMethod() == CANCEL || // Contact header is not required for Requests that do not form a dialog
887 // request.header(h_RequestLine).getMethod() == BYE ||
888 // request.header(h_Contacts).size() == 1);
889 Helper::makeResponse(response, request, code, mLocalContact);
890 response.header(h_To).param(p_tag) = mId.getLocalTag();
891
892 if((request.header(h_RequestLine).getMethod() == INVITE ||
893 request.header(h_RequestLine).getMethod() == UPDATE)
894 && code >= 200 && code < 300)
895 {
896 // Check if we should add our capabilites to the invite success response
897 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Allow)) response.header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods();
898 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptEncoding)) response.header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings();
899 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptLanguage)) response.header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages();
900 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AllowEvents)) response.header(h_AllowEvents) = mDum.getMasterProfile()->getAllowedEvents();
901 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Supported)) response.header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags();
902 }
903 }
904 else
905 {
906 Helper::makeResponse(response, request, code);
907 response.header(h_To).param(p_tag) = mId.getLocalTag();
908 }
909 DebugLog ( << "Dialog::makeResponse: " << response);
910 }
911
912
913 ClientInviteSession*
914 Dialog::makeClientInviteSession(const SipMessage& response)
915 {
916 InviteSessionCreator* creator = dynamic_cast<InviteSessionCreator*>(mDialogSet.getCreator());
917 assert(creator); // !jf! this maybe can assert by evil UAS
918 //return mDum.createAppClientInviteSession(*this, *creator);
919 return new ClientInviteSession(mDum, *this, creator->getLastRequest(),
920 creator->getInitialOffer(), creator->getEncryptionLevel(), creator->getServerSubscription());
921 }
922
923
924
925 ClientSubscription*
926 Dialog::makeClientSubscription(const SipMessage& request)
927 {
928 return new ClientSubscription(mDum, *this, request);
929 }
930
931
932 ServerInviteSession*
933 Dialog::makeServerInviteSession(const SipMessage& request)
934 {
935 return new ServerInviteSession(mDum, *this, request);
936 }
937
938 ServerSubscription*
939 Dialog::makeServerSubscription(const SipMessage& request)
940 {
941 return new ServerSubscription(mDum, *this, request);
942 }
943
944 Dialog::Exception::Exception(const Data& msg, const Data& file, int line)
945 : BaseException(msg, file, line)
946 {
947 }
948
949
950 void
951 Dialog::send(SipMessage& msg)
952 {
953 if (msg.isRequest() && msg.header(h_CSeq).method() != ACK)
954 {
955 mRequests[msg.header(h_CSeq).sequence()] = msg;
956 }
957 mDum.send(msg);
958 }
959
960 void
961 Dialog::onForkAccepted()
962 {
963 ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession);
964 if (uac)
965 {
966 uac->onForkAccepted();
967 }
968 }
969
970 void Dialog::possiblyDie()
971 {
972 if (!mDestroying)
973 {
974 if (mClientSubscriptions.empty() &&
975 mServerSubscriptions.empty() &&
976 !mInviteSession)
977 {
978 mDestroying = true;
979 mDum.destroy(this);
980 }
981 }
982 }
983
984 ostream&
985 resip::operator<<(ostream& strm, const Dialog& dialog)
986 {
987 strm
988 << "mClientSubscriptions("
989 << dialog.mClientSubscriptions.size()
990 << "), "
991 << "mServerSubscriptions("
992 << dialog.mServerSubscriptions.size()
993 << ")";
994 return strm;
995 }
996
997
998 /* ====================================================================
999 * The Vovida Software License, Version 1.0
1000 *
1001 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1002 *
1003 * Redistribution and use in source and binary forms, with or without
1004 * modification, are permitted provided that the following conditions
1005 * are met:
1006 *
1007 * 1. Redistributions of source code must retain the above copyright
1008 * notice, this list of conditions and the following disclaimer.
1009 *
1010 * 2. Redistributions in binary form must reproduce the above copyright
1011 * notice, this list of conditions and the following disclaimer in
1012 * the documentation and/or other materials provided with the
1013 * distribution.
1014 *
1015 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1016 * and "Vovida Open Communication Application Library (VOCAL)" must
1017 * not be used to endorse or promote products derived from this
1018 * software without prior written permission. For written
1019 * permission, please contact vocal@vovida.org.
1020 *
1021 * 4. Products derived from this software may not be called "VOCAL", nor
1022 * may "VOCAL" appear in their name, without prior written
1023 * permission of Vovida Networks, Inc.
1024 *
1025 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1026 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1027 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1028 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1029 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1030 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1031 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1032 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1033 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1034 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1035 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1036 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1037 * DAMAGE.
1038 *
1039 * ====================================================================
1040 *
1041 * This software consists of voluntary contributions made by Vovida
1042 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1043 * Inc. For more information on Vovida Networks, Inc., please see
1044 * <http://www.vovida.org/>.
1045 *
1046 */
1047
1048

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27