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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27