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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2992 - (show annotations) (download)
Tue Jun 15 19:41:56 2004 UTC (15 years, 5 months ago) by derek
Original Path: main/sip/resiprocate/dum/Dialog.cxx
File size: 22928 byte(s)
more fixes
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 InfoLog ( << "Dialog::dispatch -- Created new server invite session" << msg.brief());
233 mInviteSession = makeServerInviteSession(request);
234 }
235 mInviteSession->dispatch(request);
236 break;
237
238 case ACK:
239 case CANCEL:
240 if (mInviteSession == 0)
241 {
242 InfoLog (<< "Drop stray ACK or CANCEL in dialog on the floor");
243 DebugLog (<< request);
244 }
245 else
246 {
247 mInviteSession->dispatch(request);
248 }
249 break;
250
251 case SUBSCRIBE:
252 case REFER: //!jf! does this create a server subs?
253 if (mServerSubscription == 0)
254 {
255 mServerSubscription = makeServerSubscription(request);
256 }
257
258 mServerSubscription->dispatch(request);
259 break;
260
261 case NOTIFY:
262 if (request.header(h_To).exists(p_tag))
263 {
264 ClientSubscription* client = findMatchingClientSub(request);
265 if (client)
266 {
267 client->dispatch(request);
268 }
269 else
270 {
271 BaseCreator* creator = mDum.findCreator(mId);
272 if (creator)
273 {
274 ClientSubscription* sub = makeClientSubscription(request);
275 mClientSubscriptions.push_back(sub);
276 sub->dispatch(request);
277 }
278 else
279 {
280 SipMessage failure;
281 makeResponse(failure, request, 481);
282 mDum.sendResponse(failure);
283 return;
284 }
285 }
286 }
287 else // no to tag - unsolicited notify
288 {
289 assert(mServerOutOfDialogRequest == 0);
290 mServerOutOfDialogRequest = makeServerOutOfDialog(request);
291 mServerOutOfDialogRequest->dispatch(request);
292 }
293 break;
294
295 case PUBLISH:
296 if (mServerPublication == 0)
297 {
298 mServerPublication = makeServerPublication(request);
299 }
300 mServerPublication->dispatch(request);
301 break;
302
303 case REGISTER:
304 if (mServerRegistration == 0)
305 {
306 mServerRegistration = makeServerRegistration(request);
307 }
308 mServerRegistration->dispatch(request);
309 break;
310
311 default:
312 // only can be one ServerOutOfDialogReq at a time
313 assert(mServerOutOfDialogRequest == 0);
314 mServerOutOfDialogRequest = makeServerOutOfDialog(request);
315 mServerOutOfDialogRequest->dispatch(request);
316 break;
317 }
318 }
319 else if (msg.isResponse())
320 {
321 //Auth related
322 if (mDum.mClientAuthManager && !mDialogSet.mCancelled)
323 {
324 if (mDialogSet.getCreator())
325 {
326 if ( mDum.mClientAuthManager->handle( mDialogSet.getCreator()->getLastRequest(), msg))
327 {
328 InfoLog( << "about to retransmit request with digest credentials" );
329 InfoLog( << mDialogSet.getCreator()->getLastRequest() );
330
331 mDum.send(mDialogSet.getCreator()->getLastRequest());
332 return;
333 }
334 }
335 else
336 {
337 SipMessage* lastRequest = 0;
338 switch (msg.header(h_CSeq).method())
339 {
340 case INVITE:
341 case CANCEL:
342 case REFER:
343 if (mInviteSession == 0)
344 {
345 return;
346 }
347 else
348 {
349 lastRequest = &mInviteSession->mLastRequest;
350 }
351 break;
352 case REGISTER:
353 if (mClientRegistration == 0)
354 {
355 return;
356 }
357 else
358 {
359 lastRequest = &mClientRegistration->mLastRequest;
360 }
361 break;
362 default:
363 break;
364 }
365 if ( lastRequest && mDum.mClientAuthManager->handle( *lastRequest, msg ) )
366 {
367 InfoLog( << "about to retransmit request with digest credentials" );
368 InfoLog( << *lastRequest );
369
370 mDum.send(*lastRequest);
371 return;
372 }
373 }
374 }
375
376 const SipMessage& response = msg;
377 // !jf! should this only be for 2xx responses? !jf! Propose no as an
378 // answer !dcm! what is he on?
379 switch (response.header(h_CSeq).method())
380 {
381 case INVITE:
382 if (mInviteSession == 0)
383 {
384 // #if!jf! don't think creator needs a dispatch
385 //BaseCreator* creator = mDum.findCreator(mId);
386 //assert (creator); // stray responses have been rejected already
387 //creator->dispatch(response);
388 // #endif!jf!
389 InfoLog ( << "Dialog::dispatch -- Created new client invite session" << msg.brief());
390
391 mInviteSession = makeClientInviteSession(response);
392 mInviteSession->dispatch(response);
393 }
394 else
395 {
396 mInviteSession->dispatch(response);
397 }
398 break;
399
400 case ACK:
401 case CANCEL:
402 if (mInviteSession != 0)
403 {
404 mInviteSession->dispatch(response);
405 }
406 // else drop on the floor
407 break;
408
409 case SUBSCRIBE:
410 case REFER:
411 {
412 ClientSubscription* client = findMatchingClientSub(response);
413 if (client)
414 {
415 client->dispatch(response);
416 }
417 else
418 {
419 ClientSubscription* sub = makeClientSubscription(response);
420 mClientSubscriptions.push_back(sub);
421 sub->dispatch(response);
422 }
423 break;
424 }
425
426 case PUBLISH:
427 // !jf! could assert that no other usages exist
428 if (mClientPublication == 0)
429 {
430 mClientPublication = makeClientPublication(response);
431 }
432 mClientPublication->dispatch(response);
433 break;
434
435 case REGISTER:
436 // !jf! could assert that no other usages exist
437 if (mClientRegistration == 0)
438 {
439 mClientRegistration = makeClientRegistration(response);
440 }
441 mClientRegistration->dispatch(response);
442 break;
443
444 // unsolicited - not allowed but commonly implemented
445 // by large companies with a bridge as their logo
446 case NOTIFY:
447 case INFO:
448
449 default:
450 {
451 ClientOutOfDialogReq* req = findMatchingClientOutOfDialogReq(response);
452 if (req == 0)
453 {
454 req = makeClientOutOfDialogReq(response);
455 mClientOutOfDialogRequests.push_back(req);
456 }
457 req->dispatch(response);
458 break;
459 }
460 }
461 }
462 }
463
464
465
466
467 ClientSubscription*
468 Dialog::findMatchingClientSub(const SipMessage& msg)
469 {
470 for (std::list<ClientSubscription*>::iterator i=mClientSubscriptions.begin();
471 i != mClientSubscriptions.end(); ++i)
472 {
473 if ((*i)->matches(msg))
474 {
475 return *i;
476 }
477 }
478 return 0;
479 }
480
481 ClientOutOfDialogReq*
482 Dialog::findMatchingClientOutOfDialogReq(const SipMessage& msg)
483 {
484 for (std::list<ClientOutOfDialogReq*>::iterator i=mClientOutOfDialogRequests.begin();
485 i != mClientOutOfDialogRequests.end(); ++i)
486 {
487 if ((*i)->matches(msg))
488 {
489 return *i;
490 }
491 }
492 return 0;
493 }
494
495
496 InviteSessionHandle
497 Dialog::findInviteSession()
498 {
499 if (mInviteSession)
500 {
501 return mInviteSession->getSessionHandle();
502 }
503 else
504 {
505 throw BaseUsage::Exception("no such invite session",
506 __FILE__, __LINE__);
507 }
508 }
509
510 std::vector<ClientSubscriptionHandle>
511 Dialog::findClientSubscriptions()
512 {
513 std::vector<ClientSubscriptionHandle> handles;
514
515 for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
516 i != mClientSubscriptions.end(); ++i)
517 {
518 handles.push_back((*i)->getHandle());
519 }
520
521 return handles;
522 }
523
524 ClientRegistrationHandle
525 Dialog::findClientRegistration()
526 {
527 if (mClientRegistration)
528 {
529 return mClientRegistration->getHandle();
530 }
531 else
532 {
533 throw BaseUsage::Exception("no such client registration",
534 __FILE__, __LINE__);
535 }
536 }
537
538 ServerRegistrationHandle
539 Dialog::findServerRegistration()
540 {
541 if (mServerRegistration)
542 {
543 return mServerRegistration->getHandle();
544 }
545 else
546 {
547 throw BaseUsage::Exception("no such server registration",
548 __FILE__, __LINE__);
549 }
550 }
551
552 ClientPublicationHandle
553 Dialog::findClientPublication()
554 {
555 if (mClientPublication)
556 {
557 return mClientPublication->getHandle();
558 }
559 else
560 {
561 throw BaseUsage::Exception("no such client publication",
562 __FILE__, __LINE__);
563 }
564 }
565
566 ServerPublicationHandle
567 Dialog::findServerPublication()
568 {
569 if (mServerPublication)
570 {
571 return mServerPublication->getHandle();
572 }
573 else
574 {
575 throw BaseUsage::Exception("no such server publication",
576 __FILE__, __LINE__);
577 }
578 }
579
580 #if 0
581 ClientOutOfDialogReqHandle
582 Dialog::findClientOutOfDialog()
583 {
584 if (mClientOutOfDialogRequests)
585 {
586 return mClientOutOfDialogReq->getHandle();
587 }
588 else
589 {
590 throw BaseUsage::Exception("no such client out of dialog",
591 __FILE__, __LINE__);
592 }
593 }
594 #endif
595
596 ServerOutOfDialogReqHandle
597 Dialog::findServerOutOfDialog()
598 {
599 if (mServerOutOfDialogRequest)
600 {
601 return mServerOutOfDialogRequest->getHandle();
602 }
603 else
604 {
605 throw BaseUsage::Exception("no such server out of dialog",
606 __FILE__, __LINE__);
607 }
608 }
609
610 #if 0
611 void
612 Dialog::processNotify(const SipMessage& notify)
613 {
614 if (notify.isRequest())
615 {
616 if (findSubscriptions().empty())
617 {
618 SubscriptionCreator* creator = dynamic_cast<SubscriptionCreator*>(DialogSetId(notify).getCreator());
619 if (creator)
620 {
621 creator->makeNewSubscription(notify);
622 }
623 }
624 else
625 {
626 for (std::list<BaseUsage*>::iterator i=mUsages.begin(); i!=mUsages.end(); i++)
627 {
628 ClientSubscription* sub = dynamic_cast<ClientSubscription*>(*i);
629 if (sub && sub->matches(notify))
630 {
631 sub->process(notify);
632 break;
633 }
634 }
635 }
636 }
637 }
638 #endif
639
640
641 void
642 Dialog::makeRequest(SipMessage& request, MethodTypes method)
643 {
644 RequestLine rLine(method);
645
646 rLine.uri() = mRemoteTarget.uri();
647
648 request.header(h_RequestLine) = rLine;
649 request.header(h_To) = mRemoteTarget;
650 request.header(h_To).param(p_tag) = mId.getRemoteTag();
651 request.header(h_From) = mLocalContact;
652 request.header(h_From).param(p_tag) = mId.getLocalTag();
653
654 request.header(h_CallId) = mCallId;
655 request.header(h_Routes) = mRouteSet;
656 request.header(h_Contacts) = mLocalContact;
657 request.header(h_CSeq).method() = method;
658 request.header(h_MaxForwards).value() = 70;
659
660 //must keep old via for cancel
661 if (method != CANCEL)
662 {
663 request.remove(h_Vias);
664 Via via;
665 via.param(p_branch); // will create the branch
666 request.header(h_Vias).push_front(via);
667 }
668 else
669 {
670 assert(request.exists(h_Vias));
671 }
672 //don'y increment CSeq for ACK
673 if (method != ACK)
674 {
675 request.header(h_CSeq).sequence() = ++mLocalCSeq;
676 }
677 }
678
679 void
680 Dialog::makeCancel(SipMessage& request)
681 {
682 makeRequest(request, CANCEL);
683
684 //not allowed in a CANCEL
685 request.remove(h_Requires);
686 request.remove(h_ProxyRequires);
687 }
688
689 void
690 Dialog::makeResponse(SipMessage& response, const SipMessage& request, int code)
691 {
692 assert( code >= 100 );
693 if (code < 300 && code > 100)
694 {
695 assert(request.isRequest());
696 assert(request.header(h_RequestLine).getMethod() == INVITE ||
697 request.header(h_RequestLine).getMethod() == SUBSCRIBE);
698
699 assert (request.header(h_Contacts).size() == 1);
700 Helper::makeResponse(response, request, code, mLocalContact);
701 response.header(h_To).param(p_tag) = mId.getLocalTag();
702 }
703 else
704 {
705 Helper::makeResponse(response, request, code, mLocalContact);
706 }
707 InfoLog ( << "Dialog::makeResponse: " << response);
708 }
709
710
711 ClientInviteSession*
712 Dialog::makeClientInviteSession(const SipMessage& response)
713 {
714 InviteSessionCreator* creator = dynamic_cast<InviteSessionCreator*>(mDialogSet.getCreator());
715 assert(creator); // !jf! this maybe can assert by evil UAS
716 //return mDum.createAppClientInviteSession(*this, *creator);
717 return new ClientInviteSession(mDum, *this, creator->getLastRequest(), creator->getInitialOffer());
718 }
719
720 ClientRegistration*
721 Dialog::makeClientRegistration(const SipMessage& response)
722 {
723 BaseCreator* creator = mDialogSet.getCreator();
724 assert(creator);
725 return new ClientRegistration(mDum, *this, creator->getLastRequest());
726 }
727
728 ClientPublication*
729 Dialog::makeClientPublication(const SipMessage& response)
730 {
731 BaseCreator* creator = mDialogSet.getCreator();
732 assert(creator);
733 return new ClientPublication(mDum, *this, creator->getLastRequest());
734 }
735
736 ClientSubscription*
737 Dialog::makeClientSubscription(const SipMessage& response)
738 {
739 BaseCreator* creator = mDialogSet.getCreator();
740 assert(creator);
741 return new ClientSubscription(mDum, *this, creator->getLastRequest());
742 }
743
744 ClientOutOfDialogReq*
745 Dialog::makeClientOutOfDialogReq(const SipMessage& response)
746 {
747 BaseCreator* creator = mDialogSet.getCreator();
748 assert(creator);
749 return new ClientOutOfDialogReq(mDum, *this, creator->getLastRequest());
750 }
751
752 ServerInviteSession*
753 Dialog::makeServerInviteSession(const SipMessage& request)
754 {
755 return new ServerInviteSession(mDum, *this, request);
756 }
757
758 ServerSubscription*
759 Dialog::makeServerSubscription(const SipMessage& request)
760 {
761 return new ServerSubscription(mDum, *this, request);
762 }
763
764 ServerRegistration*
765 Dialog::makeServerRegistration(const SipMessage& request)
766 {
767 return new ServerRegistration(mDum, *this, request);
768 }
769
770 ServerPublication*
771 Dialog::makeServerPublication(const SipMessage& request)
772 {
773 return new ServerPublication(mDum, *this, request);
774 }
775
776 ServerOutOfDialogReq*
777 Dialog::makeServerOutOfDialog(const SipMessage& request)
778 {
779 return new ServerOutOfDialogReq(mDum, *this, request);
780 }
781
782 Dialog::Exception::Exception(const Data& msg, const Data& file, int line)
783 : BaseException(msg, file, line)
784 {
785 }
786
787 void
788 Dialog::update(const SipMessage& msg)
789 {
790 }
791
792 #if 0
793 void
794 Dialog::setLocalContact(const NameAddr& localContact)
795 {
796 mLocalContact = localContact;
797 }
798
799 void
800 Dialog::setRemoteTarget(const NameAddr& remoteTarget)
801 {
802 mRemoteTarget = remoteTarget;
803 }
804 #endif
805
806 void Dialog::possiblyDie()
807 {
808 if (!mDestroying)
809 {
810 if (mClientSubscriptions.empty() &&
811 mClientOutOfDialogRequests.empty() &&
812 !(mServerSubscription ||
813 mInviteSession ||
814 mClientRegistration ||
815 mServerRegistration ||
816 mClientPublication ||
817 mServerPublication ||
818 mServerOutOfDialogRequest))
819 {
820 delete this;
821 }
822 }
823 }
824
825 ostream&
826 resip::operator<<(ostream& strm, const Dialog& dialog)
827 {
828
829 return strm;
830 }
831

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27