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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27