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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27