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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27