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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2868 - (hide annotations) (download)
Sun May 30 16:59:23 2004 UTC (15 years, 6 months ago) by jason
Original Path: main/sip/resiprocate/dum/Dialog.cxx
File size: 17564 byte(s)
fix vtable link error

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

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27