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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7144 - (hide annotations) (download)
Thu Jun 7 22:51:36 2007 UTC (12 years, 6 months ago) by derek
File MIME type: text/plain
File size: 38051 byte(s)
Merge PRACK branch to main.  UAC PRACK support only.

svn merge -r r7071:7143
https://svn.resiprocate.org/rep/resiprocate/branches/b-dum-prack-20070410


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