/[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 2867 - (show annotations) (download)
Sun May 30 16:38:27 2004 UTC (15 years, 8 months ago) by derek
File size: 17504 byte(s)


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 DialogId
184 Dialog::getId() const
185 {
186 return mId;
187 }
188
189 void
190 Dialog::dispatch(const SipMessage& msg)
191 {
192 if (msg.isRequest())
193 {
194 const SipMessage& request = msg;
195 switch (request.header(h_CSeq).method())
196 {
197 case INVITE: // new INVITE
198 if (mInviteSession == 0)
199 {
200 mInviteSession = mDum.makeServerInviteSession(*this, request);
201 }
202 mInviteSession->dispatch(request);
203 break;
204
205 case ACK:
206 case CANCEL:
207 if (mInviteSession == 0)
208 {
209 InfoLog (<< "Drop stray ACK or CANCEL in dialog on the floor");
210 DebugLog (<< request);
211 }
212 else
213 {
214 mInviteSession->dispatch(request);
215 }
216 break;
217
218 case SUBSCRIBE:
219 case REFER: //!jf! does this create a server subs?
220 if (mServerSubscription == 0)
221 {
222 mServerSubscription = mDum.makeServerSubscription(*this, request);
223 }
224
225 mServerSubscription->dispatch(request);
226 break;
227
228 case NOTIFY:
229 if (request.header(h_To).exists(p_tag))
230 {
231 ClientSubscription* client = findMatchingClientSub(request);
232 if (client)
233 {
234 client->dispatch(request);
235 }
236 else
237 {
238 BaseCreator* creator = mDum.findCreator(mId);
239 if (creator)
240 {
241 ClientSubscription* sub = mDum.makeClientSubscription(*this, request);
242 mClientSubscriptions.push_back(sub);
243 sub->dispatch(request);
244 }
245 else
246 {
247 std::auto_ptr<SipMessage> failure(Helper::makeResponse(request, 481));
248 mDum.send(*failure);
249 return;
250 }
251 }
252 }
253 else // no to tag - unsolicited notify
254 {
255 assert(mServerOutOfDialogRequest == 0);
256 mServerOutOfDialogRequest = mDum.makeServerOutOfDialog(*this, request);
257 mServerOutOfDialogRequest->dispatch(request);
258 }
259 break;
260
261 case PUBLISH:
262 if (mServerPublication == 0)
263 {
264 mServerPublication = mDum.makeServerPublication(*this, request);
265 }
266 mServerPublication->dispatch(request);
267 break;
268
269 case REGISTER:
270 if (mServerRegistration == 0)
271 {
272 mServerRegistration = mDum.makeServerRegistration(*this, request);
273 }
274 mServerRegistration->dispatch(request);
275 break;
276
277 default:
278 // only can be one ServerOutOfDialogReq at a time
279 assert(mServerOutOfDialogRequest == 0);
280 mServerOutOfDialogRequest = mDum.makeServerOutOfDialog(*this, request);
281 mServerOutOfDialogRequest->dispatch(request);
282 break;
283 }
284 }
285 else if (msg.isResponse())
286 {
287 const SipMessage& response = msg;
288 // !jf! should this only be for 2xx responses?
289 switch (response.header(h_CSeq).method())
290 {
291 case INVITE:
292 if (mInviteSession == 0)
293 {
294 BaseCreator* creator = mDum.findCreator(mId);
295 assert (creator);
296 creator->dispatch(response);
297 if (response.header(h_StatusLine).statusCode() != 100)
298 {
299 mInviteSession = mDum.makeClientInviteSession(*this, response);
300 mInviteSession->dispatch(response);
301 }
302 }
303 else
304 {
305 mInviteSession->dispatch(response);
306 }
307 break;
308
309 case ACK:
310 case CANCEL:
311 if (mInviteSession != 0)
312 {
313 mInviteSession->dispatch(response);
314 }
315 // else drop on the floor
316 break;
317
318 case SUBSCRIBE:
319 case REFER:
320 {
321 ClientSubscription* client = findMatchingClientSub(response);
322 if (client)
323 {
324 client->dispatch(response);
325 }
326 else
327 {
328 ClientSubscription* sub = mDum.makeClientSubscription(*this, response);
329 mClientSubscriptions.push_back(sub);
330 sub->dispatch(response);
331 }
332 break;
333 }
334
335 case PUBLISH:
336 if (mClientPublication == 0)
337 {
338 mClientPublication = mDum.makeClientPublication(*this, response);
339 }
340 mClientPublication->dispatch(response);
341 break;
342
343 case REGISTER:
344 if (mClientRegistration == 0)
345 {
346 mClientRegistration = mDum.makeClientRegistration(*this, response);
347 }
348 mClientRegistration->dispatch(response);
349 break;
350
351 // unsolicited - not allowed but commonly implemented
352 // by large companies with a bridge as their logo
353 case NOTIFY:
354 case INFO:
355
356 default:
357 {
358 ClientOutOfDialogReq* req = findMatchingClientOutOfDialogReq(response);
359 if (req == 0)
360 {
361 req = mDum.makeClientOutOfDialogReq(*this, response);
362 mClientOutOfDialogRequests.push_back(req);
363 }
364 req->dispatch(response);
365 break;
366 }
367 }
368 }
369 }
370
371
372 ClientSubscription*
373 Dialog::findMatchingClientSub(const SipMessage& msg)
374 {
375 for (std::list<ClientSubscription*>::iterator i=mClientSubscriptions.begin();
376 i != mClientSubscriptions.end(); ++i)
377 {
378 if ((*i)->matches(msg))
379 {
380 return *i;
381 }
382 }
383 return 0;
384 }
385
386 ClientOutOfDialogReq*
387 Dialog::findMatchingClientOutOfDialogReq(const SipMessage& msg)
388 {
389 for (std::list<ClientOutOfDialogReq*>::iterator i=mClientOutOfDialogRequests.begin();
390 i != mClientOutOfDialogRequests.end(); ++i)
391 {
392 if ((*i)->matches(msg))
393 {
394 return *i;
395 }
396 }
397 return 0;
398 }
399
400
401 InviteSession::Handle
402 Dialog::findInviteSession()
403 {
404 if (mInviteSession)
405 {
406 return mInviteSession->getSessionHandle();
407 }
408 else
409 {
410 throw BaseUsage::Exception("no such invite session",
411 __FILE__, __LINE__);
412 }
413 }
414
415 std::vector<ClientSubscription::Handle>
416 Dialog::findClientSubscriptions()
417 {
418 std::vector<ClientSubscription::Handle> handles;
419
420 for (std::list<ClientSubscription*>::const_iterator i = mClientSubscriptions.begin();
421 i != mClientSubscriptions.end(); ++i)
422 {
423 handles.push_back((*i)->getHandle());
424 }
425
426 return handles;
427 }
428
429 ClientRegistration::Handle
430 Dialog::findClientRegistration()
431 {
432 if (mClientRegistration)
433 {
434 return mClientRegistration->getHandle();
435 }
436 else
437 {
438 throw BaseUsage::Exception("no such client registration",
439 __FILE__, __LINE__);
440 }
441 }
442
443 ServerRegistration::Handle
444 Dialog::findServerRegistration()
445 {
446 if (mServerRegistration)
447 {
448 return mServerRegistration->getHandle();
449 }
450 else
451 {
452 throw BaseUsage::Exception("no such server registration",
453 __FILE__, __LINE__);
454 }
455 }
456
457 ClientPublication::Handle
458 Dialog::findClientPublication()
459 {
460 if (mClientPublication)
461 {
462 return mClientPublication->getHandle();
463 }
464 else
465 {
466 throw BaseUsage::Exception("no such client publication",
467 __FILE__, __LINE__);
468 }
469 }
470
471 ServerPublication::Handle
472 Dialog::findServerPublication()
473 {
474 if (mServerPublication)
475 {
476 return mServerPublication->getHandle();
477 }
478 else
479 {
480 throw BaseUsage::Exception("no such server publication",
481 __FILE__, __LINE__);
482 }
483 }
484
485 #if 0
486 ClientOutOfDialogReq::Handle
487 Dialog::findClientOutOfDialog()
488 {
489 if (mClientOutOfDialogRequests)
490 {
491 return mClientOutOfDialogReq->getHandle();
492 }
493 else
494 {
495 throw BaseUsage::Exception("no such client out of dialog",
496 __FILE__, __LINE__);
497 }
498 }
499 #endif
500
501 ServerOutOfDialogReq::Handle
502 Dialog::findServerOutOfDialog()
503 {
504 if (mServerOutOfDialogRequest)
505 {
506 return mServerOutOfDialogRequest->getHandle();
507 }
508 else
509 {
510 throw BaseUsage::Exception("no such server out of dialog",
511 __FILE__, __LINE__);
512 }
513 }
514
515 #if 0
516 void
517 Dialog::processNotify(const SipMessage& notify)
518 {
519 if (notify.isRequest())
520 {
521 if (findSubscriptions().empty())
522 {
523 SubscriptionCreator* creator = dynamic_cast<SubscriptionCreator*>(DialogSetId(notify).getCreator());
524 if (creator)
525 {
526 creator->makeNewSubscription(notify);
527 }
528 }
529 else
530 {
531 for (std::list<BaseUsage*>::iterator i=mUsages.begin(); i!=mUsages.end(); i++)
532 {
533 ClientSubscription* sub = dynamic_cast<ClientSubscription*>(*i);
534 if (sub && sub->matches(notify))
535 {
536 sub->process(notify);
537 break;
538 }
539 }
540 }
541 }
542 }
543 #endif
544
545
546 void
547 Dialog::makeRequest(SipMessage& request, MethodTypes method)
548 {
549 RequestLine rLine(method);
550
551 rLine.uri() = mRemoteTarget.uri();
552
553 request.header(h_RequestLine) = rLine;
554 request.header(h_To) = mRemoteTarget;
555 request.header(h_To).param(p_tag) = mRemoteTag;
556 request.header(h_From) = mLocalContact;
557 request.header(h_From).param(p_tag) = mLocalTag;
558
559 request.header(h_CallId) = mCallId;
560 request.header(h_Routes) = mRouteSet;
561 request.header(h_Contacts).push_front(mLocalContact);
562 request.header(h_CSeq).method() = method;
563 request.header(h_MaxForwards).value() = 70;
564
565 Via via;
566 via.param(p_branch); // will create the branch
567 request.header(h_Vias).push_front(via);
568
569 request.header(h_CSeq).sequence() = ++mLocalCSeq;
570 }
571
572
573 void
574 Dialog::makeResponse(const SipMessage& request, SipMessage& response, int code)
575 {
576 assert( code >= 100 );
577 response.header(h_To).param(p_tag) = mLocalTag;
578 if ( (code < 300) && (code > 100) )
579 {
580 assert(request.isRequest());
581 assert(request.header(h_RequestLine).getMethod() == INVITE ||
582 request.header(h_RequestLine).getMethod() == SUBSCRIBE);
583
584 assert (request.header(h_Contacts).size() == 1);
585 response.header(h_To).param(p_tag) = mLocalTag;
586
587 Helper::makeResponse(response, request, code);
588
589 if (!request.exists(h_Contacts) && request.header(h_Contacts).size() != 1)
590 {
591 InfoLog (<< "Request doesn't have a contact header or more than one contact, so can't create dialog");
592 DebugLog (<< request);
593 throw Exception("Invalid or missing contact header in request", __FILE__,__LINE__);
594 }
595
596 assert (response.header(h_To).exists(p_tag));
597 }
598 else
599 {
600 Helper::makeResponse(response, request, code, mLocalContact);
601 }
602 }
603
604 Dialog::Exception::Exception(const Data& msg, const Data& file, int line)
605 : BaseException(msg, file, line)
606 {}
607
608 void
609 Dialog::update(const SipMessage& msg)
610 {
611 }
612
613 #if 0
614 void
615 Dialog::setLocalContact(const NameAddr& localContact)
616 {
617 mLocalContact = localContact;
618 }
619
620 void
621 Dialog::setRemoteTarget(const NameAddr& remoteTarget)
622 {
623 mRemoteTarget = remoteTarget;
624 }
625 #endif
626
627 bool
628 Dialog::shouldMerge(const SipMessage& request) const
629 {
630 return false;
631 }
632
633 void Dialog::possiblyDie()
634 {
635 if (mClientSubscriptions.empty() &&
636 mClientOutOfDialogRequests.empty() &&
637 !(mServerSubscription ||
638 mInviteSession ||
639 mClientRegistration ||
640 mServerRegistration ||
641 mClientPublication ||
642 mServerPublication ||
643 mServerOutOfDialogRequest))
644 {
645 delete this;
646 }
647 }
648

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27