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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27