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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27