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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2991 - (show annotations) (download)
Tue Jun 15 08:09:24 2004 UTC (15 years, 6 months ago) by derek
Original Path: main/sip/resiprocate/dum/Dialog.cxx
File size: 23089 byte(s)
moved ClientAuthManager related logic to Dialog instead of DialogSet

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/ClientOutOfDialogReq.hxx"
9 #include "resiprocate/dum/ClientRegistration.hxx"
10 #include "resiprocate/dum/ClientSubscription.hxx"
11 #include "resiprocate/dum/Dialog.hxx"
12 #include "resiprocate/dum/DialogUsageManager.hxx"
13 #include "resiprocate/dum/InviteSessionCreator.hxx"
14 #include "resiprocate/dum/ServerInviteSession.hxx"
15 #include "resiprocate/dum/ServerOutOfDialogReq.hxx"
16 #include "resiprocate/dum/ServerRegistration.hxx"
17 #include "resiprocate/dum/ServerSubscription.hxx"
18 #include "resiprocate/dum/ClientPublication.hxx"
19 #include "resiprocate/dum/ServerPublication.hxx"
20 #include "resiprocate/os/Logger.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 : mId(msg),
29 mDum(dum),
30 mDialogSet(ds),
31 mClientSubscriptions(),
32 mServerSubscription(0),
33 mInviteSession(0),
34 mClientRegistration(0),
35 mServerRegistration(0),
36 mClientPublication(0),
37 mServerPublication(0),
38 mClientOutOfDialogRequests(),
39 mServerOutOfDialogRequest(0),
40 mType(Fake),
41 mCallId(msg.header(h_CallID)),
42 mRouteSet(),
43 mLocalContact(),
44 mLocalCSeq(0),
45 mRemoteCSeq(0),
46 mRemoteTarget(),
47 mDestroying(false)
48 {
49 assert(msg.isExternal());
50
51
52 if (msg.isRequest()) // UAS
53 {
54 const SipMessage& request = msg;
55
56 switch (request.header(h_CSeq).method())
57 {
58 case INVITE:
59 mType = Invitation;
60 break;
61
62 case SUBSCRIBE:
63 case REFER:
64 case NOTIFY:
65 mType = Subscription;
66 break;
67
68 default:
69 mType = Fake;
70 }
71
72 mRouteSet = request.header(h_RecordRoutes); // !jf! is this right order
73
74 switch (request.header(h_CSeq).method())
75 {
76 case INVITE:
77 case SUBSCRIBE:
78 case REFER:
79 if (request.exists(h_Contacts) && request.header(h_Contacts).size() == 1)
80 {
81 const NameAddr& contact = request.header(h_Contacts).front();
82 if (isEqualNoCase(contact.uri().scheme(), Symbols::Sips) ||
83 isEqualNoCase(contact.uri().scheme(), Symbols::Sip))
84 {
85 mLocalContact = NameAddr(request.header(h_RequestLine).uri()); // update later when send a request
86 mRemoteTarget = contact;
87 }
88 else
89 {
90 InfoLog(<< "Got an INVITE or SUBSCRIBE with invalid scheme");
91 DebugLog(<< request);
92 throw Exception("Invalid scheme in request", __FILE__, __LINE__);
93 }
94 }
95 else
96 {
97 InfoLog (<< "Got an INVITE or SUBSCRIBE that doesn't have exactly one contact");
98 DebugLog (<< request);
99 throw Exception("Too many (or no contact) contacts in request", __FILE__, __LINE__);
100 }
101 break;
102 default:
103 break;
104 }
105
106 mRemoteCSeq = request.header(h_CSeq).sequence();
107 mLocalCSeq = 1;
108
109 }
110 else if (msg.isResponse())
111 {
112 const SipMessage& response = msg;
113
114 switch (msg.header(h_CSeq).method())
115 {
116 case INVITE:
117 mType = Invitation;
118 break;
119
120 case SUBSCRIBE:
121 case REFER:
122 mType = Subscription;
123 break;
124
125 default:
126 mType = Fake;
127 }
128
129 if (response.exists(h_RecordRoutes))
130 {
131 mRouteSet = response.header(h_RecordRoutes).reverse();
132 }
133
134 switch (response.header(h_CSeq).method())
135 {
136 case INVITE:
137 case SUBSCRIBE:
138 case REFER:
139 if (response.header(h_StatusLine).statusCode() > 100 &&
140 response.header(h_StatusLine).statusCode() < 300)
141 {
142
143 if (response.exists(h_Contacts) && response.header(h_Contacts).size() == 1)
144 {
145 const NameAddr& contact = response.header(h_Contacts).front();
146 if (isEqualNoCase(contact.uri().scheme(), Symbols::Sips) ||
147 isEqualNoCase(contact.uri().scheme(), Symbols::Sip))
148 {
149 BaseCreator* creator = mDum.findCreator(mId);
150 assert(creator);// !jf! throw or something here
151
152 mLocalContact = creator->getLastRequest().header(h_Contacts).front();
153 mRemoteTarget = contact;
154 }
155 else
156 {
157 InfoLog (<< "Got an INVITE or SUBSCRIBE with invalid scheme");
158 DebugLog (<< response);
159 throw Exception("Bad scheme in contact in response", __FILE__, __LINE__);
160 }
161 }
162 else
163 {
164 InfoLog (<< "Got an INVITE or SUBSCRIBE that doesn't have exactly one contact");
165 DebugLog (<< response);
166 throw Exception("Too many contacts (or no contact) in response", __FILE__, __LINE__);
167 }
168 break;
169 default:
170 break;
171 }
172 }
173
174 mLocalCSeq = response.header(h_CSeq).sequence();
175 mRemoteCSeq = 0;
176
177 }
178 mDialogSet.addDialog(this);
179 }
180
181 Dialog::~Dialog()
182 {
183 mDestroying = true;
184 //does removing an elemnt from a list invalidate iterators?
185 for(std::list<ClientSubscription*>::iterator it = mClientSubscriptions.begin();
186 it != mClientSubscriptions.end(); it++)
187 {
188 delete *it;
189 }
190 for(std::list<ClientOutOfDialogReq*>::iterator it = mClientOutOfDialogRequests.begin();
191 it != mClientOutOfDialogRequests.end(); it++)
192 {
193 delete *it;
194 }
195 delete mServerSubscription;
196 delete mInviteSession;
197 delete mClientRegistration;
198 delete mServerRegistration;
199 delete mClientPublication;
200 delete mServerPublication;
201 delete mServerOutOfDialogRequest;
202
203 mDialogSet.mDialogs.erase(this->getId());
204 delete mAppDialog;
205 mDialogSet.possiblyDie();
206 }
207
208 DialogId
209 Dialog::getId() const
210 {
211 return mId;
212 }
213
214 void
215 Dialog::cancel()
216 {
217 mInviteSession->end();
218 }
219
220 void
221 Dialog::dispatch(const SipMessage& msg)
222 {
223 InfoLog ( << "Dialog::dispatch: " << msg.brief());
224 if (msg.isRequest())
225 {
226 const SipMessage& request = msg;
227 switch (request.header(h_CSeq).method())
228 {
229 case INVITE: // new INVITE
230 if (mInviteSession == 0)
231 {
232 mInviteSession = makeServerInviteSession(request);
233 }
234 mInviteSession->dispatch(request);
235 break;
236
237 case ACK:
238 case CANCEL:
239 if (mInviteSession == 0)
240 {
241 InfoLog (<< "Drop stray ACK or CANCEL in dialog on the floor");
242 DebugLog (<< request);
243 }
244 else
245 {
246 mInviteSession->dispatch(request);
247 }
248 break;
249
250 case SUBSCRIBE:
251 case REFER: //!jf! does this create a server subs?
252 if (mServerSubscription == 0)
253 {
254 mServerSubscription = makeServerSubscription(request);
255 }
256
257 mServerSubscription->dispatch(request);
258 break;
259
260 case NOTIFY:
261 if (request.header(h_To).exists(p_tag))
262 {
263 ClientSubscription* client = findMatchingClientSub(request);
264 if (client)
265 {
266 client->dispatch(request);
267 }
268 else
269 {
270 BaseCreator* creator = mDum.findCreator(mId);
271 if (creator)
272 {
273 ClientSubscription* sub = makeClientSubscription(request);
274 mClientSubscriptions.push_back(sub);
275 sub->dispatch(request);
276 }
277 else
278 {
279 SipMessage failure;
280 makeResponse(failure, request, 481);
281 mDum.sendResponse(failure);
282 return;
283 }
284 }
285 }
286 else // no to tag - unsolicited notify
287 {
288 assert(mServerOutOfDialogRequest == 0);
289 mServerOutOfDialogRequest = makeServerOutOfDialog(request);
290 mServerOutOfDialogRequest->dispatch(request);
291 }
292 break;
293
294 case PUBLISH:
295 if (mServerPublication == 0)
296 {
297 mServerPublication = makeServerPublication(request);
298 }
299 mServerPublication->dispatch(request);
300 break;
301
302 case REGISTER:
303 if (mServerRegistration == 0)
304 {
305 mServerRegistration = makeServerRegistration(request);
306 }
307 mServerRegistration->dispatch(request);
308 break;
309
310 default:
311 // only can be one ServerOutOfDialogReq at a time
312 assert(mServerOutOfDialogRequest == 0);
313 mServerOutOfDialogRequest = makeServerOutOfDialog(request);
314 mServerOutOfDialogRequest->dispatch(request);
315 break;
316 }
317 }
318 else if (msg.isResponse())
319 {
320 //Auth related
321 if (mDum.mClientAuthManager && !mDialogSet.mCancelled)
322 {
323 if (mDialogSet.getCreator())
324 {
325 if ( mDum.mClientAuthManager->handle( mDialogSet.getCreator()->getLastRequest(), msg))
326 {
327 InfoLog( << "about to retransmit request with digest credentials" );
328 InfoLog( << mDialogSet.getCreator()->getLastRequest() );
329
330 mDum.send(mDialogSet.getCreator()->getLastRequest());
331 return;
332 }
333 }
334 else
335 {
336 SipMessage* lastRequest = 0;
337 switch (msg.header(h_CSeq).method())
338 {
339 case INVITE:
340 case CANCEL:
341 case REFER:
342 if (mInviteSession == 0)
343 {
344 return;
345 }
346 else
347 {
348 lastRequest = &mInviteSession->mLastRequest;
349 }
350 break;
351 case REGISTER:
352 if (mClientRegistration == 0)
353 {
354 return;
355 }
356 else
357 {
358 lastRequest = &mClientRegistration->mLastRequest;
359 }
360 break;
361 default:
362 break;
363 }
364 if ( lastRequest && mDum.mClientAuthManager->handle( *lastRequest, msg ) )
365 {
366 InfoLog( << "about to retransmit request with digest credentials" );
367 InfoLog( << *lastRequest );
368
369 mDum.send(*lastRequest);
370 return;
371 }
372 }
373 }
374
375 const SipMessage& response = msg;
376 // !jf! should this only be for 2xx responses? !jf! Propose no as an
377 // answer !dcm! what is he on?
378 switch (response.header(h_CSeq).method())
379 {
380 case INVITE:
381 if (mInviteSession == 0)
382 {
383 // #if!jf! don't think creator needs a dispatch
384 //BaseCreator* creator = mDum.findCreator(mId);
385 //assert (creator); // stray responses have been rejected already
386 //creator->dispatch(response);
387 // #endif!jf!
388
389 mInviteSession = makeClientInviteSession(response);
390 mInviteSession->dispatch(response);
391 }
392 else
393 {
394 mInviteSession->dispatch(response);
395 }
396 break;
397
398 case ACK:
399 case CANCEL:
400 if (mInviteSession != 0)
401 {
402 mInviteSession->dispatch(response);
403 }
404 // else drop on the floor
405 break;
406
407 case SUBSCRIBE:
408 case REFER:
409 {
410 ClientSubscription* client = findMatchingClientSub(response);
411 if (client)
412 {
413 client->dispatch(response);
414 }
415 else
416 {
417 ClientSubscription* sub = makeClientSubscription(response);
418 mClientSubscriptions.push_back(sub);
419 sub->dispatch(response);
420 }
421 break;
422 }
423
424 case PUBLISH:
425 // !jf! could assert that no other usages exist
426 if (mClientPublication == 0)
427 {
428 mClientPublication = makeClientPublication(response);
429 }
430 mClientPublication->dispatch(response);
431 break;
432
433 case REGISTER:
434 // !jf! could assert that no other usages exist
435 if (mClientRegistration == 0)
436 {
437 mClientRegistration = makeClientRegistration(response);
438 }
439 mClientRegistration->dispatch(response);
440 break;
441
442 // unsolicited - not allowed but commonly implemented
443 // by large companies with a bridge as their logo
444 case NOTIFY:
445 case INFO:
446
447 default:
448 {
449 ClientOutOfDialogReq* req = findMatchingClientOutOfDialogReq(response);
450 if (req == 0)
451 {
452 req = makeClientOutOfDialogReq(response);
453 mClientOutOfDialogRequests.push_back(req);
454 }
455 req->dispatch(response);
456 break;
457 }
458 }
459 }
460 }
461
462
463
464
465 ClientSubscription*
466 Dialog::findMatchingClientSub(const SipMessage& msg)
467 {
468 for (std::list<ClientSubscription*>::iterator i=mClientSubscriptions.begin();
469 i != mClientSubscriptions.end(); ++i)
470 {
471 if ((*i)->matches(msg))
472 {
473 return *i;
474 }
475 }
476 return 0;
477 }
478
479 ClientOutOfDialogReq*
480 Dialog::findMatchingClientOutOfDialogReq(const SipMessage& msg)
481 {
482 for (std::list<ClientOutOfDialogReq*>::iterator i=mClientOutOfDialogRequests.begin();
483 i != mClientOutOfDialogRequests.end(); ++i)
484 {
485 if ((*i)->matches(msg))
486 {
487 return *i;
488 }
489 }
490 return 0;
491 }
492
493
494 InviteSessionHandle
495 Dialog::findInviteSession()
496 {
497 if (mInviteSession)
498 {
499 return mInviteSession->getSessionHandle();
500 }
501 else
502 {
503 throw BaseUsage::Exception("no such invite session",
504 __FILE__, __LINE__);
505 }
506 }
507
508 std::vector<ClientSubscriptionHandle>
509 Dialog::findClientSubscriptions()
510 {
511 std::vector<ClientSubscriptionHandle> handles;
512
513 for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
514 i != mClientSubscriptions.end(); ++i)
515 {
516 handles.push_back((*i)->getHandle());
517 }
518
519 return handles;
520 }
521
522 ClientRegistrationHandle
523 Dialog::findClientRegistration()
524 {
525 if (mClientRegistration)
526 {
527 return mClientRegistration->getHandle();
528 }
529 else
530 {
531 throw BaseUsage::Exception("no such client registration",
532 __FILE__, __LINE__);
533 }
534 }
535
536 ServerRegistrationHandle
537 Dialog::findServerRegistration()
538 {
539 if (mServerRegistration)
540 {
541 return mServerRegistration->getHandle();
542 }
543 else
544 {
545 throw BaseUsage::Exception("no such server registration",
546 __FILE__, __LINE__);
547 }
548 }
549
550 ClientPublicationHandle
551 Dialog::findClientPublication()
552 {
553 if (mClientPublication)
554 {
555 return mClientPublication->getHandle();
556 }
557 else
558 {
559 throw BaseUsage::Exception("no such client publication",
560 __FILE__, __LINE__);
561 }
562 }
563
564 ServerPublicationHandle
565 Dialog::findServerPublication()
566 {
567 if (mServerPublication)
568 {
569 return mServerPublication->getHandle();
570 }
571 else
572 {
573 throw BaseUsage::Exception("no such server publication",
574 __FILE__, __LINE__);
575 }
576 }
577
578 #if 0
579 ClientOutOfDialogReqHandle
580 Dialog::findClientOutOfDialog()
581 {
582 if (mClientOutOfDialogRequests)
583 {
584 return mClientOutOfDialogReq->getHandle();
585 }
586 else
587 {
588 throw BaseUsage::Exception("no such client out of dialog",
589 __FILE__, __LINE__);
590 }
591 }
592 #endif
593
594 ServerOutOfDialogReqHandle
595 Dialog::findServerOutOfDialog()
596 {
597 if (mServerOutOfDialogRequest)
598 {
599 return mServerOutOfDialogRequest->getHandle();
600 }
601 else
602 {
603 throw BaseUsage::Exception("no such server out of dialog",
604 __FILE__, __LINE__);
605 }
606 }
607
608 #if 0
609 void
610 Dialog::processNotify(const SipMessage& notify)
611 {
612 if (notify.isRequest())
613 {
614 if (findSubscriptions().empty())
615 {
616 SubscriptionCreator* creator = dynamic_cast<SubscriptionCreator*>(DialogSetId(notify).getCreator());
617 if (creator)
618 {
619 creator->makeNewSubscription(notify);
620 }
621 }
622 else
623 {
624 for (std::list<BaseUsage*>::iterator i=mUsages.begin(); i!=mUsages.end(); i++)
625 {
626 ClientSubscription* sub = dynamic_cast<ClientSubscription*>(*i);
627 if (sub && sub->matches(notify))
628 {
629 sub->process(notify);
630 break;
631 }
632 }
633 }
634 }
635 }
636 #endif
637
638
639 void
640 Dialog::makeRequest(SipMessage& request, MethodTypes method)
641 {
642 RequestLine rLine(method);
643
644 rLine.uri() = mRemoteTarget.uri();
645
646 request.header(h_RequestLine) = rLine;
647 request.header(h_To) = mRemoteTarget;
648 request.header(h_To).param(p_tag) = mId.getRemoteTag();
649 request.header(h_From) = mLocalContact;
650 request.header(h_From).param(p_tag) = mId.getLocalTag();
651
652 request.header(h_CallId) = mCallId;
653 request.header(h_Routes) = mRouteSet;
654 request.header(h_Contacts).push_front(mLocalContact);
655 request.header(h_CSeq).method() = method;
656 request.header(h_MaxForwards).value() = 70;
657
658 //must keep old via for cancel
659 if (method != CANCEL)
660 {
661 Via via;
662 via.param(p_branch); // will create the branch
663 request.header(h_Vias).push_front(via);
664 }
665 else
666 {
667 assert(request.exists(h_Vias));
668 }
669 //don'y increment CSeq for ACK
670 if (method != ACK)
671 {
672 request.header(h_CSeq).sequence() = ++mLocalCSeq;
673 }
674 }
675
676 void
677 Dialog::makeCancel(SipMessage& request)
678 {
679 makeRequest(request, CANCEL);
680
681 //not allowed in a CANCEL
682 request.remove(h_Requires);
683 request.remove(h_ProxyRequires);
684 }
685
686 void
687 Dialog::makeResponse(SipMessage& response, const SipMessage& request, int code)
688 {
689 assert( code >= 100 );
690 response.header(h_To).param(p_tag) = mId.getLocalTag();
691 if ( (code < 300) && (code > 100) )
692 {
693 assert(request.isRequest());
694 assert(request.header(h_RequestLine).getMethod() == INVITE ||
695 request.header(h_RequestLine).getMethod() == SUBSCRIBE);
696
697 assert (request.header(h_Contacts).size() == 1);
698 response.header(h_To).param(p_tag) = mId.getLocalTag();
699
700 Helper::makeResponse(response, request, code);
701
702 if (!request.exists(h_Contacts) && request.header(h_Contacts).size() != 1)
703 {
704 InfoLog (<< "Request doesn't have a contact header or more than one contact, so can't create dialog");
705 DebugLog (<< request);
706 throw Exception("Invalid or missing contact header in request", __FILE__,__LINE__);
707 }
708
709 assert (response.header(h_To).exists(p_tag));
710 }
711 else
712 {
713 Helper::makeResponse(response, request, code, mLocalContact);
714 }
715 }
716
717
718 ClientInviteSession*
719 Dialog::makeClientInviteSession(const SipMessage& response)
720 {
721 InviteSessionCreator* creator = dynamic_cast<InviteSessionCreator*>(mDialogSet.getCreator());
722 assert(creator); // !jf! this maybe can assert by evil UAS
723 //return mDum.createAppClientInviteSession(*this, *creator);
724 return new ClientInviteSession(mDum, *this, creator->getLastRequest(), creator->getInitialOffer());
725 }
726
727 ClientRegistration*
728 Dialog::makeClientRegistration(const SipMessage& response)
729 {
730 BaseCreator* creator = mDialogSet.getCreator();
731 assert(creator);
732 return new ClientRegistration(mDum, *this, creator->getLastRequest());
733 }
734
735 ClientPublication*
736 Dialog::makeClientPublication(const SipMessage& response)
737 {
738 BaseCreator* creator = mDialogSet.getCreator();
739 assert(creator);
740 return new ClientPublication(mDum, *this, creator->getLastRequest());
741 }
742
743 ClientSubscription*
744 Dialog::makeClientSubscription(const SipMessage& response)
745 {
746 BaseCreator* creator = mDialogSet.getCreator();
747 assert(creator);
748 return new ClientSubscription(mDum, *this, creator->getLastRequest());
749 }
750
751 ClientOutOfDialogReq*
752 Dialog::makeClientOutOfDialogReq(const SipMessage& response)
753 {
754 BaseCreator* creator = mDialogSet.getCreator();
755 assert(creator);
756 return new ClientOutOfDialogReq(mDum, *this, creator->getLastRequest());
757 }
758
759 ServerInviteSession*
760 Dialog::makeServerInviteSession(const SipMessage& request)
761 {
762 return new ServerInviteSession(mDum, *this, request);
763 }
764
765 ServerSubscription*
766 Dialog::makeServerSubscription(const SipMessage& request)
767 {
768 return new ServerSubscription(mDum, *this, request);
769 }
770
771 ServerRegistration*
772 Dialog::makeServerRegistration(const SipMessage& request)
773 {
774 return new ServerRegistration(mDum, *this, request);
775 }
776
777 ServerPublication*
778 Dialog::makeServerPublication(const SipMessage& request)
779 {
780 return new ServerPublication(mDum, *this, request);
781 }
782
783 ServerOutOfDialogReq*
784 Dialog::makeServerOutOfDialog(const SipMessage& request)
785 {
786 return new ServerOutOfDialogReq(mDum, *this, request);
787 }
788
789 Dialog::Exception::Exception(const Data& msg, const Data& file, int line)
790 : BaseException(msg, file, line)
791 {
792 }
793
794 void
795 Dialog::update(const SipMessage& msg)
796 {
797 }
798
799 #if 0
800 void
801 Dialog::setLocalContact(const NameAddr& localContact)
802 {
803 mLocalContact = localContact;
804 }
805
806 void
807 Dialog::setRemoteTarget(const NameAddr& remoteTarget)
808 {
809 mRemoteTarget = remoteTarget;
810 }
811 #endif
812
813 void Dialog::possiblyDie()
814 {
815 if (!mDestroying)
816 {
817 if (mClientSubscriptions.empty() &&
818 mClientOutOfDialogRequests.empty() &&
819 !(mServerSubscription ||
820 mInviteSession ||
821 mClientRegistration ||
822 mServerRegistration ||
823 mClientPublication ||
824 mServerPublication ||
825 mServerOutOfDialogRequest))
826 {
827 delete this;
828 }
829 }
830 }
831
832 ostream&
833 resip::operator<<(ostream& strm, const Dialog& dialog)
834 {
835
836 return strm;
837 }
838

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27