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

Contents of /main/sip/resiprocate/dum/Dialog.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2868 - (show annotations) (download)
Sun May 30 16:59:23 2004 UTC (15 years, 7 months ago) by jason
File size: 17564 byte(s)
fix vtable link error

1 #include "resiprocate/SipMessage.hxx"
2 #include "resiprocate/Contents.hxx"
3 #include "resiprocate/Helper.hxx"
4 #include "resiprocate/os/Logger.hxx"
5
6 #include "BaseCreator.hxx"
7 #include "Dialog.hxx"
8 #include "DialogUsageManager.hxx"
9 #include "ClientOutOfDialogReq.hxx"
10
11 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
12
13 using namespace resip;
14 using namespace std;
15
16 class ServerInviteSession;
17
18 Dialog::Dialog(DialogUsageManager& dum, const SipMessage& msg, DialogSet& ds)
19 : mId(msg),
20 mDum(dum),
21 mDialogSet(ds),
22 mClientSubscriptions(),
23 mServerSubscription(0),
24 mInviteSession(0),
25 mClientRegistration(0),
26 mServerRegistration(0),
27 mClientPublication(0),
28 mServerPublication(0),
29 mClientOutOfDialogRequests(),
30 mServerOutOfDialogRequest(0),
31 mType(Fake),
32 mLocalTag(),
33 mRemoteTag(),
34 mCallId(msg.header(h_CallID)),
35 mRouteSet(),
36 mLocalContact(),
37 mLocalCSeq(0),
38 mRemoteCSeq(0),
39 mRemoteTarget()
40 {
41 assert(msg.isExternal());
42
43 if (msg.isRequest()) // UAS
44 {
45 const SipMessage& request = msg;
46
47 switch (request.header(h_CSeq).method())
48 {
49 case INVITE:
50 mType = Invitation;
51 break;
52
53 case SUBSCRIBE:
54 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 if (request.exists(h_Contacts) && request.header(h_Contacts).size() == 1)
71 {
72 const NameAddr& contact = request.header(h_Contacts).front();
73 if (isEqualNoCase(contact.uri().scheme(), Symbols::Sips) ||
74 isEqualNoCase(contact.uri().scheme(), Symbols::Sip))
75 {
76 mLocalContact = NameAddr(request.header(h_RequestLine).uri()); // update later when send a request
77 mRemoteTarget = contact;
78 }
79 else
80 {
81 InfoLog(<< "Got an INVITE or SUBSCRIBE with invalid scheme");
82 DebugLog(<< request);
83 throw Exception("Invalid scheme in request", __FILE__, __LINE__);
84 }
85 }
86 else
87 {
88 InfoLog (<< "Got an INVITE or SUBSCRIBE that doesn't have exactly one contact");
89 DebugLog (<< request);
90 throw Exception("Too many (or no contact) contacts in request", __FILE__, __LINE__);
91 }
92 break;
93 default:
94 break;
95 }
96
97 mRemoteCSeq = request.header(h_CSeq).sequence();
98 mLocalCSeq = 1;
99
100 if (request.header(h_From).exists(p_tag) ) // 2543 compat
101 {
102 mRemoteTag = request.header(h_From).param(p_tag);
103 }
104 if ( request.header(h_To).exists(p_tag) ) // 2543 compat
105 {
106 mLocalTag = request.header(h_To).param(p_tag);
107 }
108 }
109 else if (msg.isResponse())
110 {
111 const SipMessage& response = msg;
112
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 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 case SUBSCRIBE:
137 case REFER:
138 if (response.exists(h_Contacts) && response.header(h_Contacts).size() == 1)
139 {
140 const NameAddr& contact = response.header(h_Contacts).front();
141 if (isEqualNoCase(contact.uri().scheme(), Symbols::Sips) ||
142 isEqualNoCase(contact.uri().scheme(), Symbols::Sip))
143 {
144 BaseCreator* creator = mDum.findCreator(mId);
145 assert(creator);// !jf! throw or something here
146
147 mLocalContact = creator->getLastRequest().header(h_Contacts).front();
148 mRemoteTarget = contact;
149 }
150 else
151 {
152 InfoLog (<< "Got an INVITE or SUBSCRIBE with invalid scheme");
153 DebugLog (<< response);
154 throw Exception("Bad scheme in contact in response", __FILE__, __LINE__);
155 }
156 }
157 else
158 {
159 InfoLog (<< "Got an INVITE or SUBSCRIBE that doesn't have exactly one contact");
160 DebugLog (<< response);
161 throw Exception("Too many contacts (or no contact) in response", __FILE__, __LINE__);
162 }
163 break;
164 default:
165 break;
166 }
167
168 mLocalCSeq = response.header(h_CSeq).sequence();
169 mRemoteCSeq = 0;
170
171 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 mDialogSet.addDialog(this);
181 }
182
183 Dialog::~Dialog()
184 {
185 mDialogSet.mDialogs.remove(this);
186 }
187
188 DialogId
189 Dialog::getId() const
190 {
191 return mId;
192 }
193
194 void
195 Dialog::dispatch(const SipMessage& msg)
196 {
197 if (msg.isRequest())
198 {
199 const SipMessage& request = msg;
200 switch (request.header(h_CSeq).method())
201 {
202 case INVITE: // new INVITE
203 if (mInviteSession == 0)
204 {
205 mInviteSession = mDum.makeServerInviteSession(*this, request);
206 }
207 mInviteSession->dispatch(request);
208 break;
209
210 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 {
239 client->dispatch(request);
240 }
241 else
242 {
243 BaseCreator* creator = mDum.findCreator(mId);
244 if (creator)
245 {
246 ClientSubscription* sub = mDum.makeClientSubscription(*this, request);
247 mClientSubscriptions.push_back(sub);
248 sub->dispatch(request);
249 }
250 else
251 {
252 std::auto_ptr<SipMessage> failure(Helper::makeResponse(request, 481));
253 mDum.send(*failure);
254 return;
255 }
256 }
257 }
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
266 case PUBLISH:
267 if (mServerPublication == 0)
268 {
269 mServerPublication = mDum.makeServerPublication(*this, request);
270 }
271 mServerPublication->dispatch(request);
272 break;
273
274 case REGISTER:
275 if (mServerRegistration == 0)
276 {
277 mServerRegistration = mDum.makeServerRegistration(*this, request);
278 }
279 mServerRegistration->dispatch(request);
280 break;
281
282 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 }
289 }
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 {
296 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 {
304 mInviteSession = mDum.makeClientInviteSession(*this, response);
305 mInviteSession->dispatch(response);
306 }
307 }
308 else
309 {
310 mInviteSession->dispatch(response);
311 }
312 break;
313
314 case ACK:
315 case CANCEL:
316 if (mInviteSession != 0)
317 {
318 mInviteSession->dispatch(response);
319 }
320 // else drop on the floor
321 break;
322
323 case SUBSCRIBE:
324 case REFER:
325 {
326 ClientSubscription* client = findMatchingClientSub(response);
327 if (client)
328 {
329 client->dispatch(response);
330 }
331 else
332 {
333 ClientSubscription* sub = mDum.makeClientSubscription(*this, response);
334 mClientSubscriptions.push_back(sub);
335 sub->dispatch(response);
336 }
337 break;
338 }
339
340 case PUBLISH:
341 if (mClientPublication == 0)
342 {
343 mClientPublication = mDum.makeClientPublication(*this, response);
344 }
345 mClientPublication->dispatch(response);
346 break;
347
348 case REGISTER:
349 if (mClientRegistration == 0)
350 {
351 mClientRegistration = mDum.makeClientRegistration(*this, response);
352 }
353 mClientRegistration->dispatch(response);
354 break;
355
356 // unsolicited - not allowed but commonly implemented
357 // by large companies with a bridge as their logo
358 case NOTIFY:
359 case INFO:
360
361 default:
362 {
363 ClientOutOfDialogReq* req = findMatchingClientOutOfDialogReq(response);
364 if (req == 0)
365 {
366 req = mDum.makeClientOutOfDialogReq(*this, response);
367 mClientOutOfDialogRequests.push_back(req);
368 }
369 req->dispatch(response);
370 break;
371 }
372 }
373 }
374 }
375
376
377 ClientSubscription*
378 Dialog::findMatchingClientSub(const SipMessage& msg)
379 {
380 for (std::list<ClientSubscription*>::iterator i=mClientSubscriptions.begin();
381 i != mClientSubscriptions.end(); ++i)
382 {
383 if ((*i)->matches(msg))
384 {
385 return *i;
386 }
387 }
388 return 0;
389 }
390
391 ClientOutOfDialogReq*
392 Dialog::findMatchingClientOutOfDialogReq(const SipMessage& msg)
393 {
394 for (std::list<ClientOutOfDialogReq*>::iterator i=mClientOutOfDialogRequests.begin();
395 i != mClientOutOfDialogRequests.end(); ++i)
396 {
397 if ((*i)->matches(msg))
398 {
399 return *i;
400 }
401 }
402 return 0;
403 }
404
405
406 InviteSession::Handle
407 Dialog::findInviteSession()
408 {
409 if (mInviteSession)
410 {
411 return mInviteSession->getSessionHandle();
412 }
413 else
414 {
415 throw BaseUsage::Exception("no such invite session",
416 __FILE__, __LINE__);
417 }
418 }
419
420 std::vector<ClientSubscription::Handle>
421 Dialog::findClientSubscriptions()
422 {
423 std::vector<ClientSubscription::Handle> handles;
424
425 for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
426 i != mClientSubscriptions.end(); ++i)
427 {
428 handles.push_back((*i)->getHandle());
429 }
430
431 return handles;
432 }
433
434 ClientRegistration::Handle
435 Dialog::findClientRegistration()
436 {
437 if (mClientRegistration)
438 {
439 return mClientRegistration->getHandle();
440 }
441 else
442 {
443 throw BaseUsage::Exception("no such client registration",
444 __FILE__, __LINE__);
445 }
446 }
447
448 ServerRegistration::Handle
449 Dialog::findServerRegistration()
450 {
451 if (mServerRegistration)
452 {
453 return mServerRegistration->getHandle();
454 }
455 else
456 {
457 throw BaseUsage::Exception("no such server registration",
458 __FILE__, __LINE__);
459 }
460 }
461
462 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
476 ServerPublication::Handle
477 Dialog::findServerPublication()
478 {
479 if (mServerPublication)
480 {
481 return mServerPublication->getHandle();
482 }
483 else
484 {
485 throw BaseUsage::Exception("no such server publication",
486 __FILE__, __LINE__);
487 }
488 }
489
490 #if 0
491 ClientOutOfDialogReq::Handle
492 Dialog::findClientOutOfDialog()
493 {
494 if (mClientOutOfDialogRequests)
495 {
496 return mClientOutOfDialogReq->getHandle();
497 }
498 else
499 {
500 throw BaseUsage::Exception("no such client out of dialog",
501 __FILE__, __LINE__);
502 }
503 }
504 #endif
505
506 ServerOutOfDialogReq::Handle
507 Dialog::findServerOutOfDialog()
508 {
509 if (mServerOutOfDialogRequest)
510 {
511 return mServerOutOfDialogRequest->getHandle();
512 }
513 else
514 {
515 throw BaseUsage::Exception("no such server out of dialog",
516 __FILE__, __LINE__);
517 }
518 }
519
520 #if 0
521 void
522 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 #endif
549
550
551 void
552 Dialog::makeRequest(SipMessage& request, MethodTypes method)
553 {
554 RequestLine rLine(method);
555
556 rLine.uri() = mRemoteTarget.uri();
557
558 request.header(h_RequestLine) = rLine;
559 request.header(h_To) = mRemoteTarget;
560 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 Helper::makeResponse(response, request, code);
593
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 assert (response.header(h_To).exists(p_tag));
602 }
603 else
604 {
605 Helper::makeResponse(response, request, code, mLocalContact);
606 }
607 }
608
609 Dialog::Exception::Exception(const Data& msg, const Data& file, int line)
610 : BaseException(msg, file, line)
611 {}
612
613 void
614 Dialog::update(const SipMessage& msg)
615 {
616 }
617
618 #if 0
619 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 #endif
631
632 bool
633 Dialog::shouldMerge(const SipMessage& request) const
634 {
635 return false;
636 }
637
638 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

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27