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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6872 - (hide annotations) (download)
Mon Dec 11 17:09:07 2006 UTC (13 years ago) by jmatthewsr
File MIME type: text/plain
File size: 36905 byte(s)
fix for crash an invalid dialog creation when receiving a response to a request other than the initial invite request.  Example: incoming response to a re-invite contains a modified to: tag (illegal mid-dialog fork).
1 derek 5283 #include "resip/stack/Contents.hxx"
2     #include "resip/stack/Helper.hxx"
3     #include "resip/stack/SipMessage.hxx"
4 jason 5276 #include "resip/dum/AppDialog.hxx"
5     #include "resip/dum/BaseCreator.hxx"
6     #include "resip/dum/ClientAuthManager.hxx"
7     #include "resip/dum/ClientInviteSession.hxx"
8     #include "resip/dum/ClientSubscription.hxx"
9     #include "resip/dum/Dialog.hxx"
10     #include "resip/dum/DialogUsageManager.hxx"
11     #include "resip/dum/MasterProfile.hxx"
12     #include "resip/dum/InviteSessionCreator.hxx"
13     #include "resip/dum/InviteSessionHandler.hxx"
14     #include "resip/dum/ServerInviteSession.hxx"
15     #include "resip/dum/ServerSubscription.hxx"
16     #include "resip/dum/SubscriptionHandler.hxx"
17     #include "resip/dum/UsageUseException.hxx"
18     #include "rutil/Logger.hxx"
19     #include "rutil/Inserter.hxx"
20     #include "rutil/WinLeakCheck.hxx"
21 davidb 2603
22     #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
23    
24 ken 2520 using namespace resip;
25     using namespace std;
26    
27 jason 4010 Dialog::Dialog(DialogUsageManager& dum, const SipMessage& msg, DialogSet& ds)
28 derek 2995 : mDum(dum),
29 derek 2867 mDialogSet(ds),
30 derek 3089 mId("INVALID", "INVALID", "INVALID"),
31 jason 2588 mClientSubscriptions(),
32 derek 3041 mServerSubscriptions(),
33 jason 2588 mInviteSession(0),
34     mType(Fake),
35     mRouteSet(),
36 jason 2611 mLocalContact(),
37 jason 2577 mLocalCSeq(0),
38     mRemoteCSeq(0),
39 derek 2981 mRemoteTarget(),
40 derek 2995 mLocalNameAddr(),
41     mRemoteNameAddr(),
42     mCallId(msg.header(h_CallID)),
43 mfroman 6495 mDefaultSubExpiration(0),
44 derek 3308 mAppDialog(0),
45 sgodin 5265 mDestroying(false),
46     mReUseDialogSet(false)
47 jason 2577 {
48 davidb 2603 assert(msg.isExternal());
49 jason 2577
50 jason 4010 assert(msg.header(h_CSeq).method() != MESSAGE);
51 derek 3750 assert(msg.header(h_CSeq).method() != REGISTER);
52     assert(msg.header(h_CSeq).method() != PUBLISH);
53    
54 derek 4062 mNetworkAssociation.setDum(&dum);
55    
56 jason 2577 if (msg.isRequest()) // UAS
57     {
58     const SipMessage& request = msg;
59    
60     switch (request.header(h_CSeq).method())
61     {
62 jason 3433 case INVITE:
63 jason 2611 mType = Invitation;
64     break;
65 jason 4010
66 jason 3433 case SUBSCRIBE:
67     case REFER:
68     case NOTIFY:
69 derek 3041 //!dcm! -- event header check
70 jason 2611 mType = Subscription;
71     break;
72    
73     default:
74     mType = Fake;
75     }
76 derek 3024 if (request.exists(h_RecordRoutes))
77     {
78     mRouteSet = request.header(h_RecordRoutes); // !jf! is this right order
79     }
80 jason 2611
81     switch (request.header(h_CSeq).method())
82     {
83 jason 3433 case INVITE:
84     case SUBSCRIBE:
85     case REFER:
86     case NOTIFY:
87 jason 4010 DebugLog ( << "UAS dialog ID creation, DS: " << ds.getId());
88 derek 6410 mId = DialogId(ds.getId(),
89     request.header(h_From).exists(p_tag) ? request.header(h_From).param(p_tag) : Data::Empty);
90    
91 derek 2995 mRemoteNameAddr = request.header(h_From);
92     mLocalNameAddr = request.header(h_To);
93     mLocalNameAddr.param(p_tag) = mId.getLocalTag();
94 jason 2577 if (request.exists(h_Contacts) && request.header(h_Contacts).size() == 1)
95     {
96 davidb 2603 const NameAddr& contact = request.header(h_Contacts).front();
97 jason 2577 if (isEqualNoCase(contact.uri().scheme(), Symbols::Sips) ||
98     isEqualNoCase(contact.uri().scheme(), Symbols::Sip))
99     {
100 jason 4010 mLocalContact = NameAddr(request.header(h_RequestLine).uri()); // update later when send a request
101 jason 2577 mRemoteTarget = contact;
102 moetje 6160 if (mDialogSet.getUserProfile()->hasOverrideHostAndPort())
103     {
104     mLocalContact.uri().host() = mDialogSet.getUserProfile()->getOverrideHostAndPort().host();
105     mLocalContact.uri().port() = mDialogSet.getUserProfile()->getOverrideHostAndPort().port();
106     }
107 jason 2577 }
108     else
109     {
110 jason 3433 InfoLog(<< "Got an INVITE or SUBSCRIBE with invalid scheme");
111 jason 3483 InfoLog(<< request);
112 jason 2611 throw Exception("Invalid scheme in request", __FILE__, __LINE__);
113 jason 2577 }
114     }
115     else
116     {
117 jason 3433 InfoLog (<< "Got an INVITE or SUBSCRIBE that doesn't have exactly one contact");
118 jason 3483 InfoLog (<< request);
119 jason 2611 throw Exception("Too many (or no contact) contacts in request", __FILE__, __LINE__);
120 jason 2577 }
121     break;
122 davidb 2603 default:
123     break;
124 jason 2577 }
125 jason 4010
126 jason 2577 mRemoteCSeq = request.header(h_CSeq).sequence();
127 jason 2611 mLocalCSeq = 1;
128 derek 2995
129 jason 4010 DebugLog ( << "************** Created Dialog as UAS **************" );
130     DebugLog ( << "mRemoteNameAddr: " << mRemoteNameAddr );
131     DebugLog ( << "mLocalNameAddr: " << mLocalNameAddr );
132 jason 3156 DebugLog ( << "mLocalContact: " << mLocalContact );
133     DebugLog ( << "mRemoteTarget: " << mRemoteTarget );
134 jason 2577 }
135     else if (msg.isResponse())
136     {
137 jason 4010 mId = DialogId(msg);
138 jason 2577 const SipMessage& response = msg;
139 derek 2995 mRemoteNameAddr = response.header(h_To);
140     mLocalNameAddr = response.header(h_From);
141 jason 2611
142     switch (msg.header(h_CSeq).method())
143     {
144 jason 3433 case INVITE:
145 jason 2611 mType = Invitation;
146     break;
147 jason 4010
148 jason 3433 case SUBSCRIBE:
149     case REFER:
150 jason 2611 mType = Subscription;
151     break;
152    
153     default:
154     mType = Fake;
155     }
156    
157 jason 2577 if (response.exists(h_RecordRoutes))
158     {
159     mRouteSet = response.header(h_RecordRoutes).reverse();
160     }
161    
162     switch (response.header(h_CSeq).method())
163     {
164 jason 3433 case INVITE:
165     case SUBSCRIBE:
166     case REFER:
167 derek 2983 if (response.header(h_StatusLine).statusCode() > 100 &&
168     response.header(h_StatusLine).statusCode() < 300)
169 jason 2577 {
170 jason 4010
171 derek 2983 if (response.exists(h_Contacts) && response.header(h_Contacts).size() == 1)
172 jason 2577 {
173 derek 2983 const NameAddr& contact = response.header(h_Contacts).front();
174     if (isEqualNoCase(contact.uri().scheme(), Symbols::Sips) ||
175     isEqualNoCase(contact.uri().scheme(), Symbols::Sip))
176     {
177 jmatthewsr 6872 BaseCreator* creator = mDialogSet.getCreator();
178    
179     if( 0 == creator )
180     {
181     ErrLog(<< "BaseCreator is null for DialogSet");
182     ErrLog(<< response);
183     throw Exception("BaseCreator is null for DialogSet", __FILE__, __LINE__);
184     }
185    
186     SharedPtr<SipMessage> lastRequest(creator->getLastRequest());
187    
188     if( 0 == lastRequest ||
189     !lastRequest->exists(h_Contacts) ||
190     lastRequest->header(h_Contacts).empty())
191     {
192     InfoLog(<< "lastRequest does not contain a valid contact");
193     InfoLog(<< response);
194     throw Exception("lastRequest does not contain a valid contact.", __FILE__, __LINE__);
195     }
196 daniel 5757 mLocalContact = creator->getLastRequest()->header(h_Contacts).front();
197 derek 2983 mRemoteTarget = contact;
198     }
199     else
200     {
201 jason 3433 InfoLog (<< "Got an INVITE or SUBSCRIBE with invalid scheme");
202 derek 2983 DebugLog (<< response);
203     throw Exception("Bad scheme in contact in response", __FILE__, __LINE__);
204     }
205 jason 2577 }
206     else
207     {
208 jason 3433 InfoLog (<< "Got an INVITE or SUBSCRIBE that doesn't have exactly one contact");
209 jason 2577 DebugLog (<< response);
210 derek 2983 throw Exception("Too many contacts (or no contact) in response", __FILE__, __LINE__);
211 jason 2577 }
212 derek 2983 break;
213     default:
214     break;
215 jason 2577 }
216     }
217 jason 4010
218 jason 2577 mLocalCSeq = response.header(h_CSeq).sequence();
219 jason 2611 mRemoteCSeq = 0;
220 jason 4010 DebugLog ( << "************** Created Dialog as UAC **************" );
221     DebugLog ( << "mRemoteNameAddr: " << mRemoteNameAddr );
222     DebugLog ( << "mLocalNameAddr: " << mLocalNameAddr );
223 jason 3156 DebugLog ( << "mLocalContact: " << mLocalContact );
224     DebugLog ( << "mRemoteTarget: " << mRemoteTarget );
225 derek 2995
226 jason 4010
227 jason 2577 }
228 derek 2867 mDialogSet.addDialog(this);
229 derek 3081 DebugLog ( <<"Dialog::Dialog " << mId);
230 jason 2577 }
231    
232 jason 2868 Dialog::~Dialog()
233     {
234 derek 3081 DebugLog ( <<"Dialog::~Dialog() ");
235 jason 4010
236 derek 2981 mDestroying = true;
237 derek 3089
238     while (!mClientSubscriptions.empty())
239 derek 2981 {
240 derek 3089 delete *mClientSubscriptions.begin();
241 derek 2981 }
242 derek 3089
243     while (!mServerSubscriptions.empty())
244 derek 3041 {
245 derek 3089 delete *mServerSubscriptions.begin();
246 derek 3041 }
247 derek 3089
248 derek 2981 delete mInviteSession;
249 jason 2884 mDialogSet.mDialogs.erase(this->getId());
250 derek 2976 delete mAppDialog;
251 sgodin 5265 if(!mReUseDialogSet)
252     {
253     mDialogSet.possiblyDie();
254     }
255 jason 2868 }
256    
257 cktam 4408 const DialogId&
258 jason 2588 Dialog::getId() const
259     {
260     return mId;
261     }
262    
263 davidb 2604 void
264 jason 4010 Dialog::cancel()
265     {
266     assert(mType == Invitation);
267     ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession);
268     assert (uac);
269     uac->cancel();
270     }
271    
272     void
273 derek 3716 Dialog::end()
274 jason 2891 {
275 derek 3006 if (mInviteSession)
276     {
277 jason 3425 mInviteSession->end();
278 derek 3006 }
279     else
280     {
281 derek 3716 //!dcm! -- end subscriptions
282 derek 3006 }
283 jason 2891 }
284    
285     void
286 jason 3934 Dialog::handleTargetRefresh(const SipMessage& msg)
287     {
288     switch(msg.header(h_CSeq).method())
289     {
290     case INVITE:
291     case UPDATE:
292     if (msg.isRequest() || (msg.isResponse() && msg.header(h_StatusLine).statusCode()/100 == 2))
293     {
294     //?dcm? modify local target; 12.2.2 of 3261 implies that the remote
295     //target is immediately modified. Should we wait until a 2xx class
296     //reponse is sent to a re-invite(easy when all send requests go
297     //through Dialog)
298     if (msg.exists(h_Contacts))
299     {
300     //.dcm. replace or check then replace
301     mRemoteTarget = msg.header(h_Contacts).front();
302     }
303     }
304     break;
305     default:
306     return;
307     }
308     }
309    
310     void
311 davidb 2604 Dialog::dispatch(const SipMessage& msg)
312     {
313 jason 4010 // !jf! Should be checking for messages with out of order CSeq and rejecting
314    
315 jason 3156 DebugLog ( << "Dialog::dispatch: " << msg.brief());
316 daniel 5599
317 sgodin 6093 if(msg.isExternal())
318 sgodin 4113 {
319 sgodin 6093 const Data& receivedTransport = msg.header(h_Vias).front().transport();
320 daniel 5599 int keepAliveTime = 0;
321 sgodin 6093 if(receivedTransport == Symbols::TCP ||
322     receivedTransport == Symbols::TLS ||
323     receivedTransport == Symbols::SCTP)
324 daniel 5599 {
325     keepAliveTime = mDialogSet.getUserProfile()->getKeepAliveTimeForStream();
326     }
327     else
328     {
329     keepAliveTime = mDialogSet.getUserProfile()->getKeepAliveTimeForDatagram();
330     }
331    
332     if(keepAliveTime > 0)
333     {
334     mNetworkAssociation.update(msg, keepAliveTime);
335     }
336 sgodin 4113 }
337 daniel 5599
338 jason 3934 handleTargetRefresh(msg);
339 jason 2614 if (msg.isRequest())
340 jason 2583 {
341 jason 2614 const SipMessage& request = msg;
342     switch (request.header(h_CSeq).method())
343 jason 4010 {
344 jason 3433 case INVITE: // new INVITE
345 jason 2614 if (mInviteSession == 0)
346     {
347 jason 3156 DebugLog ( << "Dialog::dispatch -- Created new server invite session" << msg.brief());
348 jason 2885 mInviteSession = makeServerInviteSession(request);
349 jason 2614 }
350     mInviteSession->dispatch(request);
351     break;
352 jason 3433 //refactor, send bad request for BYE, INFO, CANCEL?
353     case BYE:
354 derek 2997 if (mInviteSession == 0)
355     {
356 jason 3433 InfoLog ( << "Spurious BYE" );
357 jason 4010 return;
358 derek 2997 }
359     else
360     {
361     mInviteSession->dispatch(request);
362     }
363     break;
364 jason 4010 case UPDATE:
365     if (mInviteSession == 0)
366     {
367     InfoLog ( << "Spurious UPDATE" );
368     return;
369     }
370     else
371     {
372     mInviteSession->dispatch(request);
373     }
374     break;
375 jason 3433 case INFO:
376 derek 3255 if (mInviteSession == 0)
377     {
378     InfoLog ( << "Spurious INFO" );
379 jason 4010 return;
380 derek 3255 }
381     else
382     {
383     mInviteSession->dispatch(request);
384     }
385     break;
386 sgodin 5265 case MESSAGE:
387     if (mInviteSession == 0)
388     {
389     InfoLog ( << "Spurious MESSAGE" );
390     return;
391     }
392     else
393     {
394     mInviteSession->dispatch(request);
395     }
396     break;
397 jason 3433 case ACK:
398     case CANCEL:
399 jason 2614 if (mInviteSession == 0)
400     {
401 jason 3433 InfoLog (<< "Drop stray ACK or CANCEL in dialog on the floor");
402 jason 2614 DebugLog (<< request);
403     }
404     else
405     {
406     mInviteSession->dispatch(request);
407     }
408     break;
409 jason 3433 case SUBSCRIBE:
410 derek 3041 {
411     ServerSubscription* server = findMatchingServerSub(request);
412     if (server)
413 jason 2614 {
414 derek 3041 server->dispatch(request);
415 jason 2614 }
416 derek 3041 else
417     {
418 sgodin 3493 if (request.exists(h_Event) && request.header(h_Event).value() == "refer")
419 derek 3101 {
420     InfoLog (<< "Received a subscribe to a non-existent refer subscription: " << request.brief());
421     SipMessage failure;
422     makeResponse(failure, request, 403);
423     mDum.sendResponse(failure);
424     return;
425     }
426     else
427     {
428 daniel 5738 if (mDum.checkEventPackage(request))
429     {
430     server = makeServerSubscription(request);
431     mServerSubscriptions.push_back(server);
432     server->dispatch(request);
433     }
434 derek 3101 }
435 derek 3041 }
436     }
437     break;
438 jason 3433 case REFER:
439 derek 3101 {
440 daniel 6126 // if (mInviteSession == 0)
441     // {
442     // InfoLog (<< "Received an in dialog refer in a non-invite dialog: " << request.brief());
443     // SipMessage failure;
444     // makeResponse(failure, request, 603);
445     // mDum.sendResponse(failure);
446     // return;
447     // }
448     // else
449    
450     if (!request.exists(h_ReferTo))
451 derek 3101 {
452     InfoLog (<< "Received refer w/out a Refer-To: " << request.brief());
453     SipMessage failure;
454     makeResponse(failure, request, 400);
455     mDum.sendResponse(failure);
456     return;
457     }
458     else
459     {
460 daniel 5830 if (request.exists(h_ReferSub) && request.header(h_ReferSub).value()=="false")
461 derek 3101 {
462 daniel 6126 assert(mInviteSession);
463 daniel 5830 mInviteSession->referNoSub(msg);
464 derek 3101 }
465     else
466     {
467 daniel 5830 ServerSubscription* server = findMatchingServerSub(request);
468     ServerSubscriptionHandle serverHandle;
469     if (server)
470     {
471     serverHandle = server->getHandle();
472     server->dispatch(request);
473     }
474     else
475     {
476     server = makeServerSubscription(request);
477     mServerSubscriptions.push_back(server);
478     serverHandle = server->getHandle();
479     server->dispatch(request);
480     }
481 daniel 6126
482     if (mInviteSession)
483     {
484     mDum.mInviteSessionHandler->onRefer(mInviteSession->getSessionHandle(), serverHandle, msg);
485     }
486    
487 derek 3101 }
488     }
489     }
490     break;
491 jason 3433 case NOTIFY:
492 derek 3089 {
493     ClientSubscription* client = findMatchingClientSub(request);
494     if (client)
495 jason 2614 {
496 derek 3089 client->dispatch(request);
497     }
498     else
499     {
500 jason 3182 BaseCreator* creator = mDialogSet.getCreator();
501 daniel 5757 if (creator && (creator->getLastRequest()->header(h_RequestLine).method() == SUBSCRIBE ||
502 daniel 5830 creator->getLastRequest()->header(h_RequestLine).method() == REFER))
503 jason 2612 {
504 daniel 5757 DebugLog (<< "Making subscription (from creator) request: " << *creator->getLastRequest());
505     ClientSubscription* sub = makeClientSubscription(*creator->getLastRequest());
506 derek 3089 mClientSubscriptions.push_back(sub);
507     sub->dispatch(request);
508 jason 2612 }
509     else
510     {
511 jason 4010 if (mInviteSession != 0 && (!msg.exists(h_Event) || msg.header(h_Event).value() == "refer"))
512     {
513     DebugLog (<< "Making subscription from NOTIFY: " << msg);
514     ClientSubscription* sub = makeClientSubscription(msg);
515     mClientSubscriptions.push_back(sub);
516 derek 6119 ClientSubscriptionHandle client = sub->getHandle();
517     mDum.mInviteSessionHandler->onReferAccepted(mInviteSession->getSessionHandle(), client, msg);
518     mInviteSession->mSentRefer = false;
519 jason 4010 sub->dispatch(request);
520     }
521     else
522     {
523 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
524     makeResponse(*response, msg, 406);
525 jason 4010 send(response);
526     }
527     }
528 jason 2614 }
529 derek 3089 }
530     break;
531     default:
532     assert(0);
533     return;
534 jason 2583 }
535 jason 2614 }
536     else if (msg.isResponse())
537     {
538 jason 4010 // !jf! There is a substantial change in how this works in teltel-branch
539     // from how it worked in main branch pre merge.
540     // If the response doesn't match a cseq for a request I've sent, ignore
541     // the response
542     RequestMap::iterator r = mRequests.find(msg.header(h_CSeq).sequence());
543     if (r != mRequests.end())
544 derek 3089 {
545 sgodin 6197 bool handledByAuth = false;
546 derek 4803 if (mDum.mClientAuthManager.get() &&
547 daniel 5757 mDum.mClientAuthManager->handle(*mDialogSet.getUserProfile(), *r->second, msg))
548 derek 3089 {
549 daniel 5757 InfoLog( << "about to re-send request with digest credentials" << r->second->brief());
550 jason 4010
551 daniel 5757 assert (r->second->isRequest());
552 jason 4010
553     mLocalCSeq++;
554     send(r->second);
555 sgodin 6197 handledByAuth = true;
556 derek 3089 }
557 jason 4010 mRequests.erase(r);
558 sgodin 6197 if (handledByAuth) return;
559 derek 3089 }
560 derek 5642
561 jason 2614 const SipMessage& response = msg;
562 derek 3112 int code = response.header(h_StatusLine).statusCode();
563     if (code >=200 && code < 300)
564     {
565     if (response.exists(h_RecordRoutes))
566     {
567     mRouteSet = response.header(h_RecordRoutes).reverse();
568     }
569     }
570 jason 4010
571 jason 2885 // !jf! should this only be for 2xx responses? !jf! Propose no as an
572     // answer !dcm! what is he on?
573 jason 2614 switch (response.header(h_CSeq).method())
574 jason 2583 {
575 jason 3433 case INVITE:
576 jason 2614 if (mInviteSession == 0)
577     {
578 jason 3156 DebugLog ( << "Dialog::dispatch -- Created new client invite session" << msg.brief());
579 derek 2992
580 jason 2885 mInviteSession = makeClientInviteSession(response);
581     mInviteSession->dispatch(response);
582 jason 2614 }
583     else
584     {
585     mInviteSession->dispatch(response);
586     }
587     break;
588 jason 3433 case BYE:
589     case ACK:
590     case CANCEL:
591     case INFO:
592 sgodin 5265 case MESSAGE:
593 jason 4010 case UPDATE:
594     if (mInviteSession)
595 jason 2614 {
596     mInviteSession->dispatch(response);
597     }
598     // else drop on the floor
599 jason 4010 break;
600    
601     case REFER:
602 sgodin 4021 if(mInviteSession)
603 jason 2612 {
604 sgodin 4021 mInviteSession->mSentRefer = false;
605    
606     if (code >= 300)
607     {
608     mDum.mInviteSessionHandler->onReferRejected(mInviteSession->getSessionHandle(), msg);
609     }
610 daniel 5830 else
611     {
612 daniel 6074 //!dys! the OR condition below is not draft compliant.
613     if (!mInviteSession->mReferSub &&
614     ((msg.exists(h_ReferSub) && msg.header(h_ReferSub).value()=="false") ||
615     !msg.exists(h_ReferSub)))
616 daniel 5830 {
617 daniel 6074 DebugLog(<< "refer accepted with norefersub");
618 daniel 5830 mDum.mInviteSessionHandler->onReferAccepted(mInviteSession->getSessionHandle(), ClientSubscriptionHandle::NotValid(), msg);
619     }
620     // else no need for action - first Notify will cause onReferAccepted to be called
621     }
622 daniel 6126 break;
623 jason 4010 }
624 daniel 6126 // fall through, out of dialog refer was sent.
625 mfroman 6495
626 jason 3433 case SUBSCRIBE:
627 derek 3058 {
628     int code = response.header(h_StatusLine).statusCode();
629 daniel 5767 ClientSubscription* client = findMatchingClientSub(response);
630     if (client)
631 derek 3058 {
632 daniel 5767 client->dispatch(response);
633     }
634     else if (code < 300)
635     {
636 mfroman 6495 /*
637     we're capturing the value from the expires header off
638     the 2xx because the ClientSubscription is only created
639     after receiving the NOTIFY that comes (usually) after
640     this 2xx. We really should be creating the
641     ClientSubscription at either the 2xx or the NOTIFY
642     whichever arrives first. .mjf.
643     Note: we're capturing a duration here (not the
644     absolute time because all the inputs to
645     ClientSubscription desling with the expiration are expecting
646     duration type values from the headers. .mjf.
647     */
648     mDefaultSubExpiration = response.header(h_Expires).value();
649 derek 3058 return;
650 jason 4010 }
651 derek 3058 else
652     {
653 daniel 5767 //!dcm! -- can't subscribe in an existing Dialog, this is all
654     //a bit of a hack; currently, spurious failure messages may cause callbacks
655     BaseCreator* creator = mDialogSet.getCreator();
656     if (!creator || !creator->getLastRequest()->exists(h_Event))
657 derek 3058 {
658 daniel 5767 return;
659 derek 3058 }
660 derek 3082 else
661     {
662 daniel 5767 ClientSubscriptionHandler* handler =
663     mDum.getClientSubscriptionHandler(creator->getLastRequest()->header(h_Event).value());
664     if (handler)
665 derek 3274 {
666 daniel 5767 ClientSubscription* sub = makeClientSubscription(*creator->getLastRequest());
667     mClientSubscriptions.push_back(sub);
668     sub->dispatch(response);
669 derek 3274 }
670 derek 3082 }
671 jason 2614 }
672 daniel 5767
673 jason 2614 }
674 derek 3058 break;
675 jason 3433 case NOTIFY:
676 derek 3101 {
677 derek 3274 //2xx responses are treated as retransmission quenchers(handled by
678     //the stack). Failures are dispatched to all ServerSubsscriptions,
679     //which may not be correct.
680    
681     int code = msg.header(h_StatusLine).statusCode();
682     if (code >= 300)
683 derek 3101 {
684 derek 3274 //!dcm! -- ick, write guard
685 jason 4010 mDestroying = true;
686 derek 3274 for (list<ServerSubscription*>::iterator it = mServerSubscriptions.begin();
687     it != mServerSubscriptions.end(); )
688     {
689     ServerSubscription* s = *it;
690     it++;
691     s->dispatch(msg);
692     }
693     mDestroying = false;
694     possiblyDie();
695 derek 3101 }
696 derek 3274 // ServerSubscription* server = findMatchingServerSub(response);
697     // if (server)
698     // {
699     // server->dispatch(response);
700     // }
701 derek 3101 }
702 jason 4010 break;
703 derek 3101 default:
704     assert(0);
705     return;
706 jason 2583 }
707 jason 4010
708     #if 0 // merged from head back to teltel-branch
709     if (msg.header(h_StatusLine).statusCode() >= 400
710 derek 3750 && Helper::determineFailureMessageEffect(msg) == Helper::DialogTermination)
711     {
712     //kill all usages
713 jason 4010 mDestroying = true;
714    
715 derek 3750 for (list<ServerSubscription*>::iterator it = mServerSubscriptions.begin();
716     it != mServerSubscriptions.end(); )
717     {
718     ServerSubscription* s = *it;
719     it++;
720     s->dialogDestroyed(msg);
721 jason 4010 }
722 derek 3750
723     for (list<ClientSubscription*>::iterator it = mClientSubscriptions.begin();
724     it != mClientSubscriptions.end(); )
725     {
726     ClientSubscription* s = *it;
727     it++;
728     s->dialogDestroyed(msg);
729     }
730     if (mInviteSession)
731     {
732     mInviteSession->dialogDestroyed(msg);
733     }
734     mDestroying = false;
735     possiblyDie(); //should aways result in destruction of this
736 jason 4010 return;
737     }
738 derek 3750 #endif
739 jason 2583 }
740 jason 2578 }
741    
742 jason 4010 ServerSubscription*
743 derek 3041 Dialog::findMatchingServerSub(const SipMessage& msg)
744     {
745 jason 4010 for (std::list<ServerSubscription*>::iterator i=mServerSubscriptions.begin();
746 derek 3041 i != mServerSubscriptions.end(); ++i)
747     {
748     if ((*i)->matches(msg))
749     {
750     return *i;
751     }
752     }
753     return 0;
754     }
755 jason 2612
756 jason 4010 ClientSubscription*
757 jason 2612 Dialog::findMatchingClientSub(const SipMessage& msg)
758 jason 2583 {
759 jason 4010 for (std::list<ClientSubscription*>::iterator i=mClientSubscriptions.begin();
760 jason 2612 i != mClientSubscriptions.end(); ++i)
761 jason 2583 {
762 jason 2614 if ((*i)->matches(msg))
763 jason 2612 {
764 jason 2614 return *i;
765 jason 2612 }
766     }
767 jason 2614 return 0;
768 jason 2612 }
769 jason 2585
770 jason 2941 InviteSessionHandle
771 derek 3041 Dialog::getInviteSession()
772 ken 2520 {
773 davidb 2603 if (mInviteSession)
774     {
775     return mInviteSession->getSessionHandle();
776     }
777     else
778     {
779 derek 3041 return InviteSessionHandle::NotValid();
780 davidb 2603 }
781 ken 2520 }
782    
783 jason 4010 std::vector<ClientSubscriptionHandle>
784 derek 3041 Dialog::findClientSubscriptions(const Data& event)
785 ken 2520 {
786 jason 2941 std::vector<ClientSubscriptionHandle> handles;
787 jason 4010
788 derek 2858 for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
789 davidb 2603 i != mClientSubscriptions.end(); ++i)
790     {
791 derek 3041 if ( (*i)->getEventType() == event)
792     {
793     handles.push_back((*i)->getHandle());
794     }
795     }
796     return handles;
797     }
798    
799 jason 4010 std::vector<ServerSubscriptionHandle>
800 derek 3041 Dialog::findServerSubscriptions(const Data& event)
801     {
802     std::vector<ServerSubscriptionHandle> handles;
803 jason 4010
804 derek 3041 for (std::list<ServerSubscription*>::const_iterator i = mServerSubscriptions.begin();
805     i != mServerSubscriptions.end(); ++i)
806     {
807     if ( (*i)->getEventType() == event)
808     {
809     handles.push_back((*i)->getHandle());
810     }
811     }
812     return handles;
813     }
814    
815 jason 4010 std::vector<ClientSubscriptionHandle>
816 derek 3041 Dialog::getClientSubscriptions()
817     {
818     std::vector<ClientSubscriptionHandle> handles;
819 jason 4010
820 derek 3041 for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
821     i != mClientSubscriptions.end(); ++i)
822     {
823 davidb 2603 handles.push_back((*i)->getHandle());
824     }
825    
826     return handles;
827 ken 2520 }
828    
829 jason 4010 std::vector<ServerSubscriptionHandle>
830 derek 3041 Dialog::getServerSubscriptions()
831     {
832     std::vector<ServerSubscriptionHandle> handles;
833 jason 4010
834 derek 3041 for (std::list<ServerSubscription*>::const_iterator i = mServerSubscriptions.begin();
835     i != mServerSubscriptions.end(); ++i)
836     {
837     handles.push_back((*i)->getHandle());
838     }
839    
840     return handles;
841     }
842    
843 jason 4010 void
844 derek 3179 Dialog::redirected(const SipMessage& msg)
845     {
846     //Established dialogs are not destroyed by a redirect
847     if (!mClientSubscriptions.empty() || !mServerSubscriptions.empty())
848     {
849     return;
850     }
851     if (mInviteSession)
852     {
853     ClientInviteSession* cInv = dynamic_cast<ClientInviteSession*>(mInviteSession);
854     if (cInv)
855     {
856 jason 4010 cInv->handleRedirect(msg);
857 sgodin 5265 mReUseDialogSet = true; // Set flag so that DialogSet will not be destroyed and new Request can use it
858 derek 3179 }
859     }
860     }
861 ken 2520
862 jason 2539 void
863 derek 2813 Dialog::makeRequest(SipMessage& request, MethodTypes method)
864     {
865     RequestLine rLine(method);
866    
867 derek 2817 rLine.uri() = mRemoteTarget.uri();
868 jason 4010
869 derek 2813 request.header(h_RequestLine) = rLine;
870 jason 4010 request.header(h_To) = mRemoteNameAddr;
871 derek 2995 // request.header(h_To).param(p_tag) = mId.getRemoteTag();
872 jason 4010 request.header(h_From) = mLocalNameAddr;
873     // request.header(h_From).param(p_tag) = mId.getLocalTag();
874 derek 2813
875     request.header(h_CallId) = mCallId;
876 derek 2997
877     request.remove(h_RecordRoutes); //!dcm! -- all of this is rather messy
878 sgodin 6198 request.remove(h_Replaces);
879 derek 2997
880 jason 4010 request.remove(h_Contacts);
881     request.header(h_Contacts).push_front(mLocalContact);
882    
883 derek 2813 request.header(h_CSeq).method() = method;
884     request.header(h_MaxForwards).value() = 70;
885    
886 derek 2961 //must keep old via for cancel
887 jason 3433 if (method != CANCEL)
888 derek 2961 {
889 derek 3024 request.header(h_Routes) = mRouteSet;
890 jason 4010 request.remove(h_Vias);
891 derek 2961 Via via;
892     via.param(p_branch); // will create the branch
893     request.header(h_Vias).push_front(via);
894     }
895     else
896     {
897     assert(request.exists(h_Vias));
898     }
899 sgodin 3392
900 jason 3433 //don't increment CSeq for ACK or CANCEL
901     if (method != ACK && method != CANCEL)
902 derek 2965 {
903     request.header(h_CSeq).sequence() = ++mLocalCSeq;
904     }
905 sgodin 3383 else
906     {
907 jason 3433 // ACK and cancel have a minimal header set
908 sgodin 3383 request.remove(h_Accepts);
909     request.remove(h_AcceptEncodings);
910     request.remove(h_AcceptLanguages);
911     request.remove(h_Allows);
912     request.remove(h_Requires);
913     request.remove(h_ProxyRequires);
914     request.remove(h_Supporteds);
915 sgodin 5586 // request.header(h_CSeq).sequence() = ?; // Caller should provide original request, or modify CSeq to proper value after calling this method
916 sgodin 3383 }
917 sgodin 3392
918 jason 3433 // If method is INVITE then advertise required headers
919 jason 4010 if(method == INVITE || method == UPDATE)
920 sgodin 3392 {
921 jason 4010 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Allow)) request.header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods();
922     if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptEncoding)) request.header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings();
923     if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptLanguage)) request.header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages();
924 jason 5459 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AllowEvents)) request.header(h_AllowEvents) = mDum.getMasterProfile()->getAllowedEvents();
925 jason 4010 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Supported)) request.header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags();
926 sgodin 3392 }
927    
928 jason 6075 if (mDialogSet.mUserProfile->isAnonymous())
929     {
930     request.header(h_Privacys).push_back(Token(Symbols::id));
931     }
932    
933 jmatthewsr 6643 DebugLog ( << "Dialog::makeRequest: " << std::endl << std::endl << request );
934 derek 2813 }
935    
936 derek 3138
937 jason 4010 void
938 jason 2887 Dialog::makeResponse(SipMessage& response, const SipMessage& request, int code)
939 derek 2813 {
940     assert( code >= 100 );
941 jason 4010 response.remove(h_Contacts);
942 derek 2992 if (code < 300 && code > 100)
943 derek 2813 {
944     assert(request.isRequest());
945 jason 3433 assert(request.header(h_RequestLine).getMethod() == INVITE ||
946     request.header(h_RequestLine).getMethod() == SUBSCRIBE ||
947     request.header(h_RequestLine).getMethod() == BYE ||
948     request.header(h_RequestLine).getMethod() == CANCEL ||
949     request.header(h_RequestLine).getMethod() == REFER ||
950     request.header(h_RequestLine).getMethod() == MESSAGE ||
951     request.header(h_RequestLine).getMethod() == NOTIFY ||
952     request.header(h_RequestLine).getMethod() == INFO ||
953 jason 4010 request.header(h_RequestLine).getMethod() == OPTIONS ||
954     request.header(h_RequestLine).getMethod() == UPDATE
955 derek 3082 );
956 jason 4010
957 derek 3289 // assert (request.header(h_RequestLine).getMethod() == CANCEL || // Contact header is not required for Requests that do not form a dialog
958 jason 3433 // request.header(h_RequestLine).getMethod() == BYE ||
959 derek 3289 // request.header(h_Contacts).size() == 1);
960 derek 2992 Helper::makeResponse(response, request, code, mLocalContact);
961 derek 2936 response.header(h_To).param(p_tag) = mId.getLocalTag();
962 jason 4010
963     if((request.header(h_RequestLine).getMethod() == INVITE ||
964     request.header(h_RequestLine).getMethod() == UPDATE)
965     && code >= 200 && code < 300)
966     {
967     // Check if we should add our capabilites to the invite success response
968     if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Allow)) response.header(h_Allows) = mDum.getMasterProfile()->getAllowedMethods();
969     if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptEncoding)) response.header(h_AcceptEncodings) = mDum.getMasterProfile()->getSupportedEncodings();
970     if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AcceptLanguage)) response.header(h_AcceptLanguages) = mDum.getMasterProfile()->getSupportedLanguages();
971 jason 5459 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::AllowEvents)) response.header(h_AllowEvents) = mDum.getMasterProfile()->getAllowedEvents();
972 jason 4010 if(mDialogSet.getUserProfile()->isAdvertisedCapability(Headers::Supported)) response.header(h_Supporteds) = mDum.getMasterProfile()->getSupportedOptionTags();
973     }
974 derek 2813 }
975     else
976     {
977 derek 3274 Helper::makeResponse(response, request, code);
978 derek 3006 response.header(h_To).param(p_tag) = mId.getLocalTag();
979 derek 2813 }
980 moetje 6159
981 jmatthewsr 6643 DebugLog ( << "Dialog::makeResponse: " << std::endl << std::endl << response);
982 derek 2813 }
983    
984 jason 2885
985     ClientInviteSession*
986     Dialog::makeClientInviteSession(const SipMessage& response)
987     {
988     InviteSessionCreator* creator = dynamic_cast<InviteSessionCreator*>(mDialogSet.getCreator());
989     assert(creator); // !jf! this maybe can assert by evil UAS
990 jason 2941 //return mDum.createAppClientInviteSession(*this, *creator);
991 jason 4010 return new ClientInviteSession(mDum, *this, creator->getLastRequest(),
992 daniel 5068 creator->getInitialOffer(), creator->getEncryptionLevel(), creator->getServerSubscription());
993 jason 2885 }
994    
995    
996    
997     ClientSubscription*
998 derek 3058 Dialog::makeClientSubscription(const SipMessage& request)
999 jason 2885 {
1000 mfroman 6495 return new ClientSubscription(mDum, *this, request, mDefaultSubExpiration);
1001 jason 2885 }
1002    
1003    
1004     ServerInviteSession*
1005     Dialog::makeServerInviteSession(const SipMessage& request)
1006     {
1007 jason 2941 return new ServerInviteSession(mDum, *this, request);
1008 jason 2885 }
1009    
1010 jason 4010 ServerSubscription*
1011 jason 2885 Dialog::makeServerSubscription(const SipMessage& request)
1012     {
1013 jason 2941 return new ServerSubscription(mDum, *this, request);
1014 jason 2885 }
1015    
1016 davidb 2603 Dialog::Exception::Exception(const Data& msg, const Data& file, int line)
1017     : BaseException(msg, file, line)
1018 jason 2885 {
1019     }
1020 davidb 2603
1021 jason 4010
1022 jason 2853 void
1023 daniel 5757 Dialog::send(SharedPtr<SipMessage> msg)
1024 jason 2853 {
1025 daniel 5757 if (msg->isRequest() && msg->header(h_CSeq).method() != ACK)
1026 jason 4010 {
1027 daniel 5757 mRequests[msg->header(h_CSeq).sequence()] = msg;
1028 jason 4010 }
1029 daniel 5383 mDum.send(msg);
1030 jason 2853 }
1031    
1032 jason 4010 void
1033     Dialog::onForkAccepted()
1034 derek 2839 {
1035 jason 4010 ClientInviteSession* uac = dynamic_cast<ClientInviteSession*>(mInviteSession);
1036     if (uac)
1037     {
1038     uac->onForkAccepted();
1039     }
1040 derek 2839 }
1041    
1042 derek 2858 void Dialog::possiblyDie()
1043     {
1044 sgodin 5596 // !slg! Note: dialogs should really stick around for 32s, in order to ensure that all 2xx retransmissions get 481 correctly
1045 derek 2981 if (!mDestroying)
1046 derek 2858 {
1047 derek 2981 if (mClientSubscriptions.empty() &&
1048 derek 3041 mServerSubscriptions.empty() &&
1049 derek 3089 !mInviteSession)
1050 derek 2981 {
1051 sgodin 5042 mDestroying = true;
1052 jason 4010 mDum.destroy(this);
1053 derek 2981 }
1054 derek 3308 }
1055     }
1056    
1057 jason 4010 ostream&
1058 jason 2884 resip::operator<<(ostream& strm, const Dialog& dialog)
1059     {
1060 jason 4010 strm
1061     << "mClientSubscriptions("
1062     << dialog.mClientSubscriptions.size()
1063     << "), "
1064     << "mServerSubscriptions("
1065     << dialog.mServerSubscriptions.size()
1066     << ")";
1067 jason 2884 return strm;
1068     }
1069    
1070 derek 3716
1071 jason 4010 /* ====================================================================
1072     * The Vovida Software License, Version 1.0
1073     *
1074     * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1075     *
1076     * Redistribution and use in source and binary forms, with or without
1077     * modification, are permitted provided that the following conditions
1078     * are met:
1079     *
1080     * 1. Redistributions of source code must retain the above copyright
1081     * notice, this list of conditions and the following disclaimer.
1082     *
1083     * 2. Redistributions in binary form must reproduce the above copyright
1084     * notice, this list of conditions and the following disclaimer in
1085     * the documentation and/or other materials provided with the
1086     * distribution.
1087     *
1088     * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1089     * and "Vovida Open Communication Application Library (VOCAL)" must
1090     * not be used to endorse or promote products derived from this
1091     * software without prior written permission. For written
1092     * permission, please contact vocal@vovida.org.
1093     *
1094     * 4. Products derived from this software may not be called "VOCAL", nor
1095     * may "VOCAL" appear in their name, without prior written
1096     * permission of Vovida Networks, Inc.
1097     *
1098     * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1099     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1100     * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1101     * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1102     * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1103     * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1104     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1105     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1106     * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1107     * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1108     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1109     * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1110     * DAMAGE.
1111     *
1112     * ====================================================================
1113     *
1114     * This software consists of voluntary contributions made by Vovida
1115     * Networks, Inc. and many individuals on behalf of Vovida Networks,
1116     * Inc. For more information on Vovida Networks, Inc., please see
1117     * <http://www.vovida.org/>.
1118     *
1119     */
1120 derek 3716
1121 jason 5459

Properties

Name Value
svn:eol-style native
svn:mime-type text/plain

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27