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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5214 - (show annotations) (download)
Tue Aug 9 18:16:29 2005 UTC (14 years, 5 months ago) by daniel
File size: 53284 byte(s)
bug fixes.
1 #include "resiprocate/MultipartMixedContents.hxx"
2 #include "resiprocate/MultipartAlternativeContents.hxx"
3 #include "resiprocate/SdpContents.hxx"
4 #include "resiprocate/SipMessage.hxx"
5 #include "resiprocate/Helper.hxx"
6 #include "resiprocate/dum/Dialog.hxx"
7 #include "resiprocate/dum/DialogUsageManager.hxx"
8 #include "resiprocate/dum/InviteSession.hxx"
9 #include "resiprocate/dum/ServerInviteSession.hxx"
10 #include "resiprocate/dum/ClientSubscription.hxx"
11 #include "resiprocate/dum/ServerSubscription.hxx"
12 #include "resiprocate/dum/ClientInviteSession.hxx"
13 #include "resiprocate/dum/InviteSessionHandler.hxx"
14 #include "resiprocate/dum/MasterProfile.hxx"
15 #include "resiprocate/dum/UsageUseException.hxx"
16 #include "resiprocate/os/Inserter.hxx"
17 #include "resiprocate/os/Logger.hxx"
18 #include "resiprocate/os/Timer.hxx"
19 #include "resiprocate/os/Random.hxx"
20 #include "resiprocate/os/compat.hxx"
21 #include "resiprocate/os/WinLeakCheck.hxx"
22
23 // Remove warning about 'this' use in initiator list - pointer is only stored
24 #if defined(WIN32)
25 #pragma warning( disable : 4355 ) // using this in base member initializer list
26 #pragma warning( disable : 4800 ) // forcing value to bool (performance warning)
27 #endif
28
29 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
30 #define THROW(msg) throw DialogUsage::Exception(msg, __FILE__,__LINE__);
31
32 using namespace resip;
33 using namespace std;
34
35 InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog)
36 : DialogUsage(dum, dialog),
37 mState(Undefined),
38 mNitState(NitComplete),
39 mCurrentRetransmit200(0),
40 mSessionInterval(0),
41 mMinSE(90),
42 mSessionRefresher(false),
43 mSessionTimerSeq(0),
44 mSentRefer(false),
45 mCurrentEncryptionLevel(DialogUsageManager::None),
46 mProposedEncryptionLevel(DialogUsageManager::None)
47 {
48 DebugLog ( << "^^^ InviteSession::InviteSession " << this);
49 assert(mDum.mInviteSessionHandler);
50 }
51
52 InviteSession::~InviteSession()
53 {
54 DebugLog ( << "^^^ InviteSession::~InviteSession " << this);
55 mDialog.mInviteSession = 0;
56 }
57
58 void
59 InviteSession::dialogDestroyed(const SipMessage& msg)
60 {
61 assert(0);
62
63 // !jf! Is this correct? Merged from main...
64 // !jf! what reason - guessed for now?
65 //mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, msg);
66 //delete this;
67 }
68
69 const SdpContents&
70 InviteSession::getLocalSdp() const
71 {
72 return *mCurrentLocalSdp;
73 }
74
75 const SdpContents&
76 InviteSession::getRemoteSdp() const
77 {
78 return *mCurrentRemoteSdp;
79 }
80
81 const Data&
82 InviteSession::getDialogId() const
83 {
84 return mDialog.getId().getCallId();
85 }
86
87 InviteSessionHandle
88 InviteSession::getSessionHandle()
89 {
90 return InviteSessionHandle(mDum, getBaseHandle().getId());
91 }
92
93 void InviteSession::storePeerCapabilities(const SipMessage& msg)
94 {
95 // !slg! ToDo - add methods to get this data, App may be interested
96 if (msg.exists(h_Allows))
97 {
98 mPeerSupportedMethods = msg.header(h_Allows);
99 }
100 if (msg.exists(h_Supporteds))
101 {
102 mPeerSupportedOptionTags = msg.header(h_Supporteds);
103 }
104 if (msg.exists(h_AcceptEncodings))
105 {
106 mPeerSupportedEncodings = msg.header(h_AcceptEncodings);
107 }
108 if (msg.exists(h_AcceptLanguages))
109 {
110 mPeerSupportedLanguages = msg.header(h_AcceptLanguages);
111 }
112 if (msg.exists(h_Accepts))
113 {
114 mPeerSupportedMimeTypes = msg.header(h_Accepts);
115 }
116 }
117
118 bool
119 InviteSession::updateMethodSupported() const
120 {
121 // Check if Update is supported locally
122 if(mDum.getMasterProfile()->isMethodSupported(UPDATE))
123 {
124 // Check if peer supports UPDATE
125 return mPeerSupportedMethods.find(Token("UPDATE"));
126 }
127 return false;
128 }
129
130 const NameAddr&
131 InviteSession::myAddr() const
132 {
133 return mDialog.mLocalNameAddr;
134 }
135
136 const NameAddr&
137 InviteSession::peerAddr() const
138 {
139 return mDialog.mRemoteNameAddr;
140 }
141
142 bool
143 InviteSession::isConnected() const
144 {
145 switch (mState)
146 {
147 case Connected:
148 case SentUpdate:
149 case SentUpdateGlare:
150 case SentReinvite:
151 case SentReinviteGlare:
152 case ReceivedUpdate:
153 case ReceivedReinvite:
154 case ReceivedReinviteNoOffer:
155 case Answered:
156 case WaitingToOffer:
157 return true;
158
159 default:
160 return false;
161 }
162 }
163
164 bool
165 InviteSession::isEarly() const
166 {
167 switch (mState)
168 {
169 case UAC_Start:
170 case UAC_Early:
171 case UAC_EarlyWithOffer:
172 case UAC_EarlyWithAnswer:
173 //case UAC_Answered:
174 //case UAC_Terminated:
175 case UAC_SentUpdateEarly:
176 case UAC_SentUpdateConnected:
177 case UAC_ReceivedUpdateEarly:
178 //case UAC_SentAnswer:
179 case UAC_QueuedUpdate:
180 return true;
181
182 default:
183 return false;
184 }
185 }
186
187
188 bool
189 InviteSession::isTerminated() const
190 {
191 switch (mState)
192 {
193 case Terminated:
194 case WaitingToTerminate:
195 case UAC_Cancelled:
196 case UAS_WaitingToTerminate:
197 case UAS_WaitingToHangup:
198 return true;
199 default:
200 return false;
201 }
202 }
203
204 std::ostream&
205 InviteSession::dump(std::ostream& strm) const
206 {
207 strm << "INVITE: " << mId
208 << " " << toData(mState)
209 << " ADDR=" << myAddr()
210 << " PEER=" << peerAddr();
211 return strm;
212 }
213
214 void
215 InviteSession::provideOffer(const SdpContents& offer,
216 DialogUsageManager::EncryptionLevel level,
217 const SdpContents* alternative)
218 {
219 switch (mState)
220 {
221 case Connected:
222 case WaitingToOffer:
223 case UAS_WaitingToOffer:
224 if (updateMethodSupported())
225 {
226 transition(SentUpdate);
227 mDialog.makeRequest(mLastSessionModification, UPDATE);
228 }
229 else
230 {
231 transition(SentReinvite);
232 mDialog.makeRequest(mLastSessionModification, INVITE);
233 }
234 setSessionTimerHeaders(mLastSessionModification);
235
236 InfoLog (<< "Sending " << mLastSessionModification.brief());
237 InviteSession::setSdp(mLastSessionModification, offer, alternative);
238 mProposedLocalSdp = InviteSession::makeSdp(offer, alternative);
239 mProposedEncryptionLevel = level;
240 mDialog.send(mLastSessionModification, mProposedEncryptionLevel);
241 break;
242
243 case Answered:
244 // queue the offer to be sent after the ACK is received
245 transition(WaitingToOffer);
246 mProposedEncryptionLevel = level;
247 mProposedLocalSdp = InviteSession::makeSdp(offer, alternative);
248 break;
249
250 // ?slg? Can we handle all of the states listed in isConnected() ???
251 default:
252 WarningLog (<< "Can't provideOffer when not in Connected state");
253 throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
254 }
255 }
256
257 void
258 InviteSession::provideOffer(const SdpContents& offer)
259 {
260 return provideOffer(offer, mCurrentEncryptionLevel, 0);
261 }
262
263 void
264 InviteSession::provideAnswer(const SdpContents& answer)
265 {
266 switch (mState)
267 {
268 case ReceivedReinvite:
269 transition(Connected);
270 mDialog.makeResponse(mInvite200, mLastSessionModification, 200);
271 handleSessionTimerRequest(mInvite200, mLastSessionModification);
272 InviteSession::setSdp(mInvite200, answer, 0);
273 mCurrentLocalSdp = InviteSession::makeSdp(answer);
274 mCurrentRemoteSdp = mProposedRemoteSdp;
275 InfoLog (<< "Sending " << mInvite200.brief());
276 mDialog.send(mInvite200, mCurrentEncryptionLevel);
277 startRetransmit200Timer();
278 break;
279
280 case ReceivedUpdate: // same as ReceivedReinvite case.
281 {
282 transition(Connected);
283
284 SipMessage response;
285 mDialog.makeResponse(response, mLastSessionModification, 200);
286 handleSessionTimerRequest(response, mLastSessionModification);
287 InviteSession::setSdp(response, answer, 0);
288 mCurrentLocalSdp = InviteSession::makeSdp(answer);
289 mCurrentRemoteSdp = mProposedRemoteSdp;
290 InfoLog (<< "Sending " << response.brief());
291 mDialog.send(response, mCurrentEncryptionLevel);
292 break;
293 }
294
295 default:
296 WarningLog (<< "Can't provideAnswer when not in Connected state");
297 throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
298 }
299 }
300
301 void
302 InviteSession::end()
303 {
304 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
305
306 switch (mState)
307 {
308 case Connected:
309 {
310 // !jf! do we need to store the BYE somewhere?
311 sendBye();
312 transition(Terminated);
313 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
314 break;
315 }
316
317 case SentUpdate:
318 sendBye();
319 transition(Terminated);
320 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
321 break;
322
323 case SentReinvite:
324 transition(WaitingToTerminate);
325 break;
326
327 case ReceivedUpdate:
328 case ReceivedReinvite:
329 case ReceivedReinviteNoOffer:
330 {
331 SipMessage response;
332 mDialog.makeResponse(response, mLastSessionModification, 488);
333 InfoLog (<< "Sending " << response.brief());
334 mDialog.send(response);
335
336 sendBye();
337 transition(Terminated);
338 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
339 break;
340 }
341
342 case WaitingToTerminate:
343 {
344 sendBye();
345 transition(Terminated);
346 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
347 break;
348 }
349
350 case Terminated:
351 // no-op.
352 break;
353
354 default:
355 assert(0);
356 break;
357 }
358 }
359
360 void
361 InviteSession::reject(int statusCode, WarningCategory *warning)
362 {
363 switch (mState)
364 {
365 case ReceivedUpdate:
366 case ReceivedReinvite:
367 case ReceivedReinviteNoOffer:
368 {
369 transition(Connected);
370
371 SipMessage response;
372 mDialog.makeResponse(response, mLastSessionModification, statusCode);
373 if(warning)
374 {
375 response.header(h_Warnings).push_back(*warning);
376 }
377 InfoLog (<< "Sending " << response.brief());
378 mDialog.send(response);
379 break;
380 }
381
382 default:
383 assert(0);
384 break;
385 }
386 }
387
388 void
389 InviteSession::targetRefresh(const NameAddr& localUri)
390 {
391 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
392 {
393 // !jf! add interface to Dialog
394 //mDialog.setLocalContact(localUri);
395 provideOffer(*mCurrentLocalSdp);
396 }
397 else
398 {
399 WarningLog (<< "Can't targetRefresh before Connected");
400 assert(0);
401 throw UsageUseException("targetRefresh not allowed in this context", __FILE__, __LINE__);
402 }
403 }
404
405 void
406 InviteSession::refer(const NameAddr& referTo)
407 {
408 if (mSentRefer)
409 {
410 throw UsageUseException("Attempted to send overlapping refer", __FILE__, __LINE__);
411 }
412
413 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
414 {
415 mSentRefer = true;
416 SipMessage refer;
417 mDialog.makeRequest(refer, REFER);
418 refer.header(h_ReferTo) = referTo;
419 refer.header(h_ReferredBy) = mDialog.mLocalContact; // !slg! is it ok to do this - should it be an option?
420 mDialog.send(refer);
421 }
422 else
423 {
424 WarningLog (<< "Can't refer before Connected");
425 assert(0);
426 throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
427 }
428 }
429
430 void
431 InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace)
432 {
433 if (!sessionToReplace.isValid())
434 {
435 throw UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__);
436 }
437
438 if (mSentRefer)
439 {
440 throw UsageUseException("Attempted to send overlapping refer", __FILE__, __LINE__);
441 }
442
443 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
444 {
445 mSentRefer = true;
446 SipMessage refer;
447 mDialog.makeRequest(refer, REFER);
448
449 refer.header(h_ReferTo) = referTo;
450 refer.header(h_ReferredBy) = mDialog.mLocalContact; // ?slg? is it ok to do this - should it be an option?
451 CallId replaces;
452 DialogId id = sessionToReplace->mDialog.getId();
453 replaces.value() = id.getCallId();
454 replaces.param(p_toTag) = id.getRemoteTag();
455 replaces.param(p_fromTag) = id.getLocalTag();
456
457 refer.header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces;
458 mDialog.send(refer);
459 }
460 else
461 {
462 WarningLog (<< "Can't refer before Connected");
463 assert(0);
464 throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
465 }
466 }
467
468 void
469 InviteSession::info(const Contents& contents)
470 {
471 if (mNitState == NitComplete)
472 {
473 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
474 {
475 mNitState = NitProceeding;
476 SipMessage info;
477 mDialog.makeRequest(info, INFO);
478 // !jf! handle multipart here
479 info.setContents(&contents);
480 mDialog.send(info, mCurrentEncryptionLevel);
481 }
482 else
483 {
484 WarningLog (<< "Can't send INFO before Connected");
485 assert(0);
486 throw UsageUseException("Can't send INFO before Connected", __FILE__, __LINE__);
487 }
488 }
489 else
490 {
491 throw UsageUseException("Cannot start a non-invite transaction until the previous one has completed",
492 __FILE__, __LINE__);
493 }
494 }
495
496 void
497 InviteSession::dispatch(const SipMessage& msg)
498 {
499 // !jf! do we need to handle 3xx here or is it handled elsewhere?
500 switch (mState)
501 {
502 case Connected:
503 dispatchConnected(msg);
504 break;
505 case SentUpdate:
506 dispatchSentUpdate(msg);
507 break;
508 case SentReinvite:
509 dispatchSentReinvite(msg);
510 break;
511 case SentUpdateGlare:
512 case SentReinviteGlare:
513 // The behavior is the same except for timer which is handled in dispatch(Timer)
514 dispatchGlare(msg);
515 break;
516 case ReceivedUpdate:
517 case ReceivedReinvite:
518 case ReceivedReinviteNoOffer:
519 dispatchReceivedUpdateOrReinvite(msg);
520 break;
521 case Answered:
522 dispatchAnswered(msg);
523 break;
524 case WaitingToOffer:
525 dispatchWaitingToOffer(msg);
526 break;
527 case WaitingToTerminate:
528 dispatchWaitingToTerminate(msg);
529 break;
530 case Terminated:
531 dispatchTerminated(msg);
532 break;
533 case Undefined:
534 default:
535 assert(0);
536 break;
537 }
538 }
539
540 void
541 InviteSession::dispatch(const DumTimeout& timeout)
542 {
543 if (timeout.type() == DumTimeout::Retransmit200)
544 {
545 if (mCurrentRetransmit200)
546 {
547 InfoLog (<< "Retransmitting: " << endl << mInvite200);
548 mDialog.send(mInvite200, mCurrentEncryptionLevel);
549 mCurrentRetransmit200 *= 2;
550 mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq());
551 }
552 }
553 else if (timeout.type() == DumTimeout::WaitForAck)
554 {
555 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet
556 {
557 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
558
559 // this is so the app can decided to ignore this. default implementation
560 // will call end next
561 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
562
563 // If we are waiting for an Ack and it times out, then end with a BYE
564 if(mState == UAS_WaitingToHangup)
565 {
566 sendBye();
567 transition(Terminated);
568 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
569 }
570 }
571 }
572 else if (timeout.type() == DumTimeout::Glare)
573 {
574 if (mState == SentUpdateGlare)
575 {
576 transition(SentUpdate);
577
578 InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
579 mDialog.send(mLastSessionModification, DialogUsageManager::None);
580 }
581 else if (mState == SentReinviteGlare)
582 {
583 transition(SentReinvite);
584
585 InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");
586 mDialog.send(mLastSessionModification, DialogUsageManager::None);
587 }
588 }
589 else if (timeout.type() == DumTimeout::SessionExpiration)
590 {
591 if(timeout.seq() == mSessionTimerSeq)
592 {
593 // this is so the app can decided to ignore this. default implementation
594 // will call end next
595 mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());
596 }
597 }
598 else if (timeout.type() == DumTimeout::SessionRefresh)
599 {
600 if(timeout.seq() == mSessionTimerSeq)
601 {
602 if(mState == Connected) // Note: If not connected then we must be issueing a reinvite/update or receiving one - in either case the session timer stuff will get reset/renegotiated - thus just ignore this referesh
603 {
604 sessionRefresh();
605 }
606 }
607 }
608 }
609
610 void
611 InviteSession::dispatchConnected(const SipMessage& msg)
612 {
613 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
614 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
615
616 switch (toEvent(msg, sdp.get()))
617 {
618 case OnInvite:
619 case OnInviteReliable:
620 mLastSessionModification = msg;
621 transition(ReceivedReinviteNoOffer);
622 //handler->onDialogModified(getSessionHandle(), None, msg);
623 handler->onOfferRequired(getSessionHandle(), msg);
624 break;
625
626 case OnInviteOffer:
627 case OnInviteReliableOffer:
628 mLastSessionModification = msg;
629 transition(ReceivedReinvite);
630 mCurrentEncryptionLevel = getEncryptionLevel(msg);
631 //handler->onDialogModified(getSessionHandle(), Offer, msg);
632 handler->onOffer(getSessionHandle(), msg, *sdp);
633 break;
634
635 case On2xx:
636 case On2xxOffer:
637 case On2xxAnswer:
638 // retransmission of 200I
639 // !jf! Need to include the answer here.
640 sendAck();
641 break;
642
643 case OnUpdateOffer:
644 transition(ReceivedUpdate);
645
646 // !kh!
647 // Find out if it's an UPDATE requiring state change.
648 // See rfc3311 5.2, 4th paragraph.
649 mLastSessionModification = msg;
650 mCurrentEncryptionLevel = getEncryptionLevel(msg);
651 handler->onOffer(getSessionHandle(), msg, *sdp);
652 break;
653
654 case OnUpdate:
655 {
656 // ?slg? no sdp in update - just responsd immediately (likely session timer) - do we need a callback?
657 SipMessage response;
658 mLastSessionModification = msg;
659 mDialog.makeResponse(response, mLastSessionModification, 200);
660 handleSessionTimerRequest(response, mLastSessionModification);
661 send(response);
662 break;
663 }
664
665 case OnUpdateRejected:
666 case On200Update:
667 WarningLog (<< "DUM delivered an UPDATE response in an incorrect state " << endl << msg);
668 assert(0);
669 break;
670
671 case OnAck:
672 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
673 break;
674
675 default:
676 dispatchOthers(msg);
677 break;
678 }
679 }
680
681 void
682 InviteSession::dispatchSentUpdate(const SipMessage& msg)
683 {
684 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
685 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
686
687 switch (toEvent(msg, sdp.get()))
688 {
689 case OnInvite:
690 case OnInviteReliable:
691 case OnInviteOffer:
692 case OnInviteReliableOffer:
693 case OnUpdate:
694 case OnUpdateOffer:
695 {
696 // glare
697 SipMessage response;
698 mDialog.makeResponse(response, msg, 491);
699 send(response);
700 break;
701 }
702
703 case On200Update:
704 transition(Connected);
705 handleSessionTimerResponse(msg);
706 if (sdp.get())
707 {
708 mCurrentEncryptionLevel = getEncryptionLevel(msg);
709 setCurrentLocalSdp(msg);
710 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
711 handler->onAnswer(getSessionHandle(), msg, *sdp);
712 }
713 else if(mProposedLocalSdp.get())
714 {
715 // If we sent an offer in the Update Request and no answer is received
716 handler->onIllegalNegotiation(getSessionHandle(), msg);
717 mProposedLocalSdp.release();
718 mProposedEncryptionLevel = DialogUsageManager::None;
719 }
720 break;
721
722 case On491Update:
723 transition(SentUpdateGlare);
724 start491Timer();
725 break;
726
727 case On422Update: // session timer
728 if(msg.exists(h_MinSE))
729 {
730 // Change interval to min from 422 response
731 mSessionInterval = msg.header(h_MinSE).value();
732 mMinSE = mSessionInterval;
733 sessionRefresh();
734 }
735 else
736 {
737 // Response must contact Min_SE - if not - just ignore
738 // ?slg? callback?
739 transition(Connected);
740 mProposedLocalSdp.release();
741 mProposedEncryptionLevel = DialogUsageManager::None;
742 }
743 break;
744
745 case OnUpdateRejected:
746 // !jf! - callback?
747 mProposedLocalSdp.release();
748 mProposedEncryptionLevel = DialogUsageManager::None;
749 transition(Connected);
750 break;
751
752 case OnGeneralFailure:
753 sendBye();
754 transition(Terminated);
755 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
756 break;
757
758 default:
759 dispatchOthers(msg);
760 break;
761 }
762 }
763
764 void
765 InviteSession::dispatchSentReinvite(const SipMessage& msg)
766 {
767 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
768 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
769
770 switch (toEvent(msg, sdp.get()))
771 {
772 case OnInvite:
773 case OnInviteReliable:
774 case OnInviteOffer:
775 case OnInviteReliableOffer:
776 case OnUpdate:
777 case OnUpdateOffer:
778 {
779 SipMessage response;
780 mDialog.makeResponse(response, msg, 491);
781 send(response);
782 break;
783 }
784
785 case On1xx:
786 case On1xxEarly:
787 // Some UA's send a 100 response to a ReInvite - just ignore it
788 break;
789
790 case On2xxAnswer:
791 case On2xxOffer:
792 {
793 transition(Connected);
794 handleSessionTimerResponse(msg);
795 setCurrentLocalSdp(msg);
796 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
797 mCurrentEncryptionLevel = getEncryptionLevel(msg);
798 // !jf! I need to potentially include an answer in the ACK here
799 sendAck();
800 handler->onAnswer(getSessionHandle(), msg, *sdp);
801
802
803 // !jf! do I need to allow a reINVITE overlapping the retransmission of
804 // the ACK when a 200I is received? If yes, then I need to store all
805 // ACK messages for 64*T1
806 break;
807 }
808 case On2xx:
809 sendAck();
810 transition(Connected);
811 handleSessionTimerResponse(msg);
812 handler->onIllegalNegotiation(getSessionHandle(), msg);
813 mProposedLocalSdp.release();
814 mProposedEncryptionLevel = DialogUsageManager::None;
815 break;
816
817 case On422Invite:
818 if(msg.exists(h_MinSE))
819 {
820 // Change interval to min from 422 response
821 mSessionInterval = msg.header(h_MinSE).value();
822 mMinSE = mSessionInterval;
823 sessionRefresh();
824 }
825 else
826 {
827 // Response must contact Min_SE - if not - just ignore
828 // ?slg? callback?
829 transition(Connected);
830 mProposedLocalSdp.release();
831 mProposedEncryptionLevel = DialogUsageManager::None;
832 }
833 break;
834
835 case On491Invite:
836 transition(SentReinviteGlare);
837 start491Timer();
838 break;
839
840 case OnGeneralFailure:
841 sendBye();
842 transition(Terminated);
843 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
844 break;
845
846 case OnInviteFailure:
847 case On487Invite:
848 case On489Invite:
849 transition(Connected);
850 mProposedLocalSdp.release();
851 handler->onOfferRejected(getSessionHandle(), msg);
852 break;
853
854 default:
855 dispatchOthers(msg);
856 break;
857 }
858 }
859
860 void
861 InviteSession::dispatchGlare(const SipMessage& msg)
862 {
863 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
864 MethodTypes method = msg.header(h_CSeq).method();
865 if (method == INVITE && msg.isRequest())
866 {
867 // Received inbound reinvite, when waiting to resend outbound reinvite or update
868 transition(ReceivedReinvite);
869 handler->onOfferRejected(getSessionHandle(), msg);
870 }
871 else if (method == UPDATE && msg.isRequest())
872 {
873 // Received inbound update, when waiting to resend outbound reinvite or update
874 transition(ReceivedUpdate);
875 handler->onOfferRejected(getSessionHandle(), msg);
876 }
877 else
878 {
879 dispatchOthers(msg);
880 }
881 }
882
883 void
884 InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
885 {
886 MethodTypes method = msg.header(h_CSeq).method();
887 if (method == INVITE || method == UPDATE)
888 {
889 // Means that the UAC has sent us a second reINVITE or UPDATE before we
890 // responded to the first one. Bastard!
891 SipMessage response;
892 mDialog.makeResponse(response, msg, 500);
893 response.header(h_RetryAfter).value() = Random::getRandom() % 10;
894 mDialog.send(response);
895 }
896 else
897 {
898 dispatchOthers(msg);
899 }
900 }
901
902
903 void
904 InviteSession::dispatchAnswered(const SipMessage& msg)
905 {
906 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
907 {
908 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
909 transition(Connected);
910 }
911 else
912 {
913 dispatchOthers(msg);
914 }
915 }
916
917 void
918 InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
919 {
920 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
921 {
922
923 assert(mProposedLocalSdp.get());
924 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
925 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
926 {
927 provideOffer( *(dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back())),
928 mProposedEncryptionLevel,
929 dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()));
930 }
931 else
932 {
933 provideOffer(*(dynamic_cast<SdpContents*>(mProposedLocalSdp.get())), mProposedEncryptionLevel, 0);
934 }
935 }
936 else
937 {
938 dispatchOthers(msg);
939 }
940 }
941
942 void
943 InviteSession::dispatchWaitingToTerminate(const SipMessage& msg)
944 {
945 if (msg.isResponse() &&
946 msg.header(h_CSeq).method() == INVITE)
947 {
948 if(msg.header(h_StatusLine).statusCode() / 200 == 1) // Note: stack ACK's non-2xx final responses only
949 {
950 // !jf! Need to include the answer here.
951 sendAck();
952 }
953 sendBye();
954 transition(Terminated);
955 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
956 }
957 }
958
959 void
960 InviteSession::dispatchTerminated(const SipMessage& msg)
961 {
962 InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief());
963
964 if (msg.isRequest())
965 {
966 SipMessage response;
967 mDialog.makeResponse(response, msg, 481);
968 mDialog.send(response);
969
970 // !jf! means the peer sent BYE while we are waiting for response to BYE
971 //mDum.destroy(this);
972 }
973 else
974 {
975 mDum.destroy(this);
976 }
977 }
978
979 void
980 InviteSession::dispatchOthers(const SipMessage& msg)
981 {
982 // handle OnGeneralFailure
983 // handle OnRedirect
984
985 switch (msg.header(h_CSeq).method())
986 {
987 case PRACK:
988 dispatchPrack(msg);
989 break;
990 case CANCEL:
991 dispatchCancel(msg);
992 break;
993 case BYE:
994 dispatchBye(msg);
995 break;
996 case INFO:
997 dispatchInfo(msg);
998 break;
999 case ACK:
1000 // Ignore duplicate ACKs from 2xx reTransmissions
1001 break;
1002 default:
1003 // handled in Dialog
1004 WarningLog (<< "DUM delivered a "
1005 << msg.header(h_CSeq).unknownMethodName()
1006 << " to the InviteSession "
1007 << endl
1008 << msg);
1009 assert(0);
1010 break;
1011 }
1012 }
1013
1014 void
1015 InviteSession::dispatchUnhandledInvite(const SipMessage& msg)
1016 {
1017 assert(msg.isRequest());
1018 assert(msg.header(h_CSeq).method() == INVITE);
1019
1020 // If we get an INVITE request from the wire and we are not in
1021 // Connected state, reject the request and send a BYE
1022 SipMessage response;
1023 mDialog.makeResponse(response, msg, 400); // !jf! what code to use?
1024 InfoLog (<< "Sending " << response.brief());
1025 mDialog.send(response);
1026
1027 sendBye();
1028 transition(Terminated);
1029 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1030 }
1031
1032 void
1033 InviteSession::dispatchPrack(const SipMessage& msg)
1034 {
1035 assert(msg.header(h_CSeq).method() == PRACK);
1036 if(msg.isRequest())
1037 {
1038 SipMessage rsp;
1039 mDialog.makeResponse(rsp, msg, 481);
1040 mDialog.send(rsp);
1041
1042 sendBye();
1043 // !jf! should we make some other callback here
1044 transition(Terminated);
1045 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1046 }
1047 else
1048 {
1049 // ignore. could be PRACK/200
1050 }
1051 }
1052
1053 void
1054 InviteSession::dispatchCancel(const SipMessage& msg)
1055 {
1056 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1057 assert(msg.header(h_CSeq).method() == CANCEL);
1058 if(msg.isRequest())
1059 {
1060 SipMessage rsp;
1061 mDialog.makeResponse(rsp, msg, 200);
1062 mDialog.send(rsp);
1063
1064 sendBye();
1065 // !jf! should we make some other callback here
1066 transition(Terminated);
1067 handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1068 }
1069 else
1070 {
1071 WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg);
1072 assert(0);
1073 }
1074 }
1075
1076 void
1077 InviteSession::dispatchBye(const SipMessage& msg)
1078 {
1079 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1080
1081 if (msg.isRequest())
1082 {
1083
1084 SipMessage rsp;
1085 InfoLog (<< "Received " << msg.brief());
1086 mDialog.makeResponse(rsp, msg, 200);
1087 mDialog.send(rsp);
1088
1089 // !jf! should we make some other callback here
1090 transition(Terminated);
1091 handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1092 mDum.destroy(this);
1093 }
1094 else
1095 {
1096 WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg);
1097 assert(0);
1098 }
1099 }
1100
1101 void
1102 InviteSession::dispatchInfo(const SipMessage& msg)
1103 {
1104 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1105 if (msg.isRequest())
1106 {
1107 InfoLog (<< "Received " << msg.brief());
1108 mDialog.makeResponse(mLastNitResponse, msg, 200);
1109 handler->onInfo(getSessionHandle(), msg);
1110 }
1111 else
1112 {
1113 assert(mNitState == NitProceeding);
1114 mNitState = NitComplete;
1115 //!dcm! -- toss away 1xx to an info?
1116 if (msg.header(h_StatusLine).statusCode() >= 300)
1117 {
1118 handler->onInfoFailure(getSessionHandle(), msg);
1119 }
1120 else if (msg.header(h_StatusLine).statusCode() >= 200)
1121 {
1122 handler->onInfoSuccess(getSessionHandle(), msg);
1123 }
1124 }
1125 }
1126
1127 void
1128 InviteSession::acceptInfo(int statusCode)
1129 {
1130 if (statusCode / 100 != 2)
1131 {
1132 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
1133 }
1134
1135 mLastNitResponse.header(h_StatusLine).statusCode() = statusCode;
1136 send(mLastNitResponse);
1137 }
1138
1139 void
1140 InviteSession::rejectInfo(int statusCode)
1141 {
1142 if (statusCode < 400)
1143 {
1144 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
1145 }
1146 mLastNitResponse.header(h_StatusLine).statusCode() = statusCode;
1147 send(mLastNitResponse);
1148 }
1149
1150 void
1151 InviteSession::startRetransmit200Timer()
1152 {
1153 mCurrentRetransmit200 = Timer::T1;
1154 int seq = mLastSessionModification.header(h_CSeq).sequence();
1155 mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
1156 mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
1157 }
1158
1159 void
1160 InviteSession::start491Timer()
1161 {
1162 int seq = mLastSessionModification.header(h_CSeq).sequence();
1163 int timer = Random::getRandom() % 4000;
1164 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
1165 }
1166
1167 void
1168 InviteSession::setSessionTimerHeaders(SipMessage &msg)
1169 {
1170 if(mSessionInterval >= 90) // If mSessionInterval is 0 then SessionTimers are considered disabled
1171 {
1172 msg.header(h_SessionExpires).value() = mSessionInterval;
1173 if(msg.isRequest())
1174 {
1175 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uac" : "uas");
1176 }
1177 else
1178 {
1179 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uas" : "uac");
1180 }
1181 msg.header(h_MinSE).value() = mMinSE;
1182 }
1183 else
1184 {
1185 msg.remove(h_SessionExpires);
1186 msg.remove(h_MinSE);
1187 }
1188 }
1189
1190 void
1191 InviteSession::sessionRefresh()
1192 {
1193 if (updateMethodSupported())
1194 {
1195 transition(SentUpdate);
1196 mDialog.makeRequest(mLastSessionModification, UPDATE);
1197 mLastSessionModification.releaseContents(); // Don't send SDP
1198 }
1199 else
1200 {
1201 transition(SentReinvite);
1202 mDialog.makeRequest(mLastSessionModification, INVITE);
1203 InviteSession::setSdp(mLastSessionModification, mCurrentLocalSdp.get());
1204 mProposedLocalSdp = InviteSession::makeSdp(*mCurrentLocalSdp.get(), 0);
1205 }
1206 setSessionTimerHeaders(mLastSessionModification);
1207
1208 InfoLog (<< "sessionRefresh: Sending " << mLastSessionModification.brief());
1209 mDialog.send(mLastSessionModification, mCurrentEncryptionLevel);
1210 }
1211
1212 void
1213 InviteSession::setSessionTimerPreferences()
1214 {
1215 mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if remote doesn't request a time
1216 if(mSessionInterval != 0)
1217 {
1218 // If session timers are no disabled then ensure interval is greater than or equal to MinSE
1219 mSessionInterval = resipMax(mMinSE, mSessionInterval);
1220 }
1221 switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
1222 {
1223 case Profile::PreferLocalRefreshes:
1224 mSessionRefresher = true; // Default refresher is Local
1225 break;
1226 case Profile::PreferRemoteRefreshes:
1227 mSessionRefresher = false; // Default refresher is Remote
1228 break;
1229 case Profile::PreferUASRefreshes:
1230 mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is UAS (for the session) - callee
1231 break;
1232 case Profile::PreferUACRefreshes:
1233 mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is UAC (for the session) - caller
1234 break;
1235 }
1236 }
1237
1238 void
1239 InviteSession::startSessionTimer()
1240 {
1241 if(mSessionInterval >= 90) // 90 is the absolute minimum - RFC4028
1242 {
1243 // Check if we are the refresher
1244 if(mSessionRefresher)
1245 {
1246 // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by RFC4028)
1247 mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
1248 }
1249 else
1250 {
1251 // Start Session-Expiration Timer to mSessionInterval - BYE should be sent a minimum of 32 and one third of the SessionInterval, seconds before the session expires (recommended by RFC4028)
1252 mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin(32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
1253 }
1254 }
1255 else // Session Interval less than 90 - consider timers disabled
1256 {
1257 ++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled
1258 }
1259 }
1260
1261 void
1262 InviteSession::handleSessionTimerResponse(const SipMessage& msg)
1263 {
1264 assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
1265
1266 // If session timers are locally supported then handle response
1267 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1268 {
1269 setSessionTimerPreferences();
1270
1271 if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer))
1272 && !msg.exists(h_SessionExpires))
1273 {
1274 // If no Session Expires in response and Requires header is present then session timer is to be 'turned off'
1275 mSessionInterval = 0;
1276 }
1277 // Process Session Timer headers
1278 else if(msg.exists(h_SessionExpires))
1279 {
1280 mSessionInterval = msg.header(h_SessionExpires).value();
1281 if(msg.header(h_SessionExpires).exists(p_refresher))
1282 {
1283 // Remote end specified refresher preference
1284 mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac"));
1285 }
1286 }
1287 else
1288 {
1289 // Note: If no Requires or Session-Expires, then UAS does not support Session Timers
1290 // - we are free to use our SessionInterval settings (set above as a default)
1291 // If far end doesn't support then refresher must be local
1292 mSessionRefresher = true;
1293 }
1294
1295 // Update MinSE if specified and longer than current value
1296 if(msg.exists(h_MinSE))
1297 {
1298 mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value());
1299 }
1300
1301 startSessionTimer();
1302 }
1303 }
1304
1305 void
1306 InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
1307 {
1308 assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
1309
1310 // If session timers are locally supported then add necessary headers to response
1311 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1312 {
1313 setSessionTimerPreferences();
1314
1315 // Check if far-end supports
1316 bool farEndSupportsTimer = false;
1317 if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer)))
1318 {
1319 farEndSupportsTimer = true;
1320 if(request.exists(h_SessionExpires))
1321 {
1322 // Use Session Interval requested by remote - if none then use local settings
1323 mSessionInterval = request.header(h_SessionExpires).value();
1324 if(request.header(h_SessionExpires).exists(p_refresher))
1325 {
1326 mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
1327 }
1328 }
1329
1330 // Update MinSE if specified and longer than current value
1331 if(request.exists(h_MinSE))
1332 {
1333 mMinSE = resipMax(mMinSE, request.header(h_MinSE).value());
1334 }
1335 }
1336 else
1337 {
1338 // If far end doesn't support then refresher must be local
1339 mSessionRefresher = true;
1340 }
1341
1342 // Add Session-Expires to response if required
1343 if(mSessionInterval >= 90)
1344 {
1345 if(farEndSupportsTimer)
1346 {
1347 // If far end supports session-timer then require it, if not already present
1348 if(!response.header(h_Requires).find(Token(Symbols::Timer)))
1349 {
1350 response.header(h_Requires).push_back(Token(Symbols::Timer));
1351 }
1352 }
1353 setSessionTimerHeaders(response);
1354 }
1355
1356 startSessionTimer();
1357 }
1358 }
1359
1360 Data
1361 InviteSession::toData(State state)
1362 {
1363 switch (state)
1364 {
1365 case Undefined:
1366 return "InviteSession::Undefined";
1367 case Connected:
1368 return "InviteSession::Connected";
1369 case SentUpdate:
1370 return "InviteSession::SentUpdate";
1371 case SentUpdateGlare:
1372 return "InviteSession::SentUpdateGlare";
1373 case SentReinvite:
1374 return "InviteSession::SentReinvite";
1375 case SentReinviteGlare:
1376 return "InviteSession::SentReinviteGlare";
1377 case ReceivedUpdate:
1378 return "InviteSession::ReceivedUpdate";
1379 case ReceivedReinvite:
1380 return "InviteSession::ReceivedReinvite";
1381 case ReceivedReinviteNoOffer:
1382 return "InviteSession::ReceivedReinviteNoOffer";
1383 case Answered:
1384 return "InviteSession::Answered";
1385 case WaitingToOffer:
1386 return "InviteSession::WaitingToOffer";
1387 case WaitingToTerminate:
1388 return "InviteSession::WaitingToTerminate";
1389 case Terminated:
1390 return "InviteSession::Terminated";
1391
1392 case UAC_Start:
1393 return "UAC_Start";
1394 case UAS_Offer:
1395 return "UAS_Offer";
1396 case UAS_OfferProvidedAnswer:
1397 return "UAS_OfferProvidedAnswer";
1398 case UAS_EarlyOffer:
1399 return "UAS_EarlyOffer";
1400 case UAS_EarlyProvidedAnswer:
1401 return "UAS_EarlyProvidedAnswer";
1402 case UAS_NoOffer:
1403 return "UAS_NoOffer";
1404 case UAS_ProvidedOffer:
1405 return "UAS_ProvidedOffer";
1406 case UAS_EarlyNoOffer:
1407 return "UAS_EarlyNoOffer";
1408 case UAS_EarlyProvidedOffer:
1409 return "UAS_EarlyProvidedOffer";
1410 case UAS_Accepted:
1411 return "UAS_Accepted";
1412 case UAS_WaitingToOffer:
1413 return "UAS_WaitingToOffer";
1414 case UAS_AcceptedWaitingAnswer:
1415 return "UAS_AcceptedWaitingAnswer";
1416 case UAC_Early:
1417 return "UAC_Early";
1418 case UAC_EarlyWithOffer:
1419 return "UAC_EarlyWithOffer";
1420 case UAC_EarlyWithAnswer:
1421 return "UAC_EarlyWithAnswer";
1422 case UAC_Answered:
1423 return "UAC_Answered";
1424 case UAC_SentUpdateEarly:
1425 return "UAC_SentUpdateEarly";
1426 case UAC_SentUpdateConnected:
1427 return "UAC_SentUpdateConnected";
1428 case UAC_ReceivedUpdateEarly:
1429 return "UAC_ReceivedUpdateEarly";
1430 case UAC_SentAnswer:
1431 return "UAC_SentAnswer";
1432 case UAC_QueuedUpdate:
1433 return "UAC_QueuedUpdate";
1434 case UAC_Cancelled:
1435 return "UAC_Cancelled";
1436
1437 case UAS_Start:
1438 return "UAS_Start";
1439 case UAS_OfferReliable:
1440 return "UAS_OfferReliable";
1441 case UAS_NoOfferReliable:
1442 return "UAS_NoOfferReliable";
1443 case UAS_FirstSentOfferReliable:
1444 return "UAS_FirstSentOfferReliable";
1445 case UAS_FirstEarlyReliable:
1446 return "UAS_FirstEarlyReliable";
1447 case UAS_EarlyReliable:
1448 return "UAS_EarlyReliable";
1449 case UAS_SentUpdate:
1450 return "UAS_SentUpdate";
1451 case UAS_SentUpdateAccepted:
1452 return "UAS_SentUpdateAccepted";
1453 case UAS_ReceivedUpdate:
1454 return "UAS_ReceivedUpdate";
1455 case UAS_ReceivedUpdateWaitingAnswer:
1456 return "UAS_ReceivedUpdateWaitingAnswer";
1457 case UAS_WaitingToTerminate:
1458 return "UAS_WaitingToTerminate";
1459 case UAS_WaitingToHangup:
1460 return "UAS_WaitingToHangup";
1461 }
1462 assert(0);
1463 return "Undefined";
1464 }
1465
1466
1467 void
1468 InviteSession::transition(State target)
1469 {
1470 InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
1471 mState = target;
1472 }
1473
1474 bool
1475 InviteSession::isReliable(const SipMessage& msg)
1476 {
1477 // Ensure supported both locally and remotely
1478 return msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel)) &&
1479 mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::C100rel));
1480 }
1481
1482 std::auto_ptr<SdpContents>
1483 InviteSession::getSdp(const SipMessage& msg)
1484 {
1485 // !jf! this code doesn't yet work - definitely if USE_SSL=false
1486 //Helper::ContentsSecAttrs attrs = Helper::extractFromPkcs7(msg, mDum.getSecurity());
1487 //return std::auto_ptr<SdpContents>(dynamic_cast<SdpContents*>(attrs.mContents.get()));
1488 SdpContents* sdp = dynamic_cast<SdpContents*>(msg.getContents());
1489 if (sdp)
1490 {
1491 SdpContents* cloned = static_cast<SdpContents*>(sdp->clone());
1492 return std::auto_ptr<SdpContents>(cloned);
1493 }
1494 else
1495 {
1496 static std::auto_ptr<SdpContents> empty;
1497 return empty;
1498 }
1499 }
1500
1501 std::auto_ptr<SdpContents>
1502 InviteSession::makeSdp(const SdpContents& sdp)
1503 {
1504 return std::auto_ptr<SdpContents>(static_cast<SdpContents*>(sdp.clone()));
1505 }
1506
1507 auto_ptr<Contents>
1508 InviteSession::makeSdp(const SdpContents& sdp,
1509 const SdpContents* alternative)
1510 {
1511 if (alternative)
1512 {
1513 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
1514 mac->parts().push_back(alternative->clone());
1515 mac->parts().push_back(sdp.clone());
1516 return auto_ptr<Contents>(mac);
1517 }
1518 else
1519 {
1520 return auto_ptr<Contents>(sdp.clone());
1521 }
1522 }
1523
1524 void
1525 InviteSession::setSdp(SipMessage& msg, const SdpContents& sdp, const SdpContents* alternative)
1526 {
1527 // !jf! should deal with multipart here
1528
1529 // This will clone the sdp since the InviteSession also wants to keep its own
1530 // copy of the sdp around for the application to access
1531 if (alternative)
1532 {
1533 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
1534 mac->parts().push_back(alternative->clone());
1535 mac->parts().push_back(sdp.clone());
1536 msg.setContents(auto_ptr<Contents>(mac));
1537 }
1538 else
1539 {
1540 msg.setContents(&sdp);
1541 }
1542 }
1543
1544 void
1545 InviteSession::setSdp(SipMessage& msg, const Contents* sdp)
1546 {
1547 assert(sdp);
1548 msg.setContents(sdp);
1549 }
1550
1551 InviteSession::Event
1552 InviteSession::toEvent(const SipMessage& msg, const SdpContents* sdp)
1553 {
1554 MethodTypes method = msg.header(h_CSeq).method();
1555 int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
1556 bool reliable = isReliable(msg);
1557 bool sentOffer = mProposedLocalSdp.get();
1558
1559 if (code == 481 || code == 408)
1560 {
1561 return OnGeneralFailure;
1562 }
1563 else if (code >= 300 && code <= 399)
1564 {
1565 return OnRedirect;
1566 }
1567 else if (method == INVITE && code == 0)
1568 {
1569 if (sdp)
1570 {
1571 if (reliable)
1572 {
1573 return OnInviteReliableOffer;
1574 }
1575 else
1576 {
1577 return OnInviteOffer;
1578 }
1579 }
1580 else
1581 {
1582 if (reliable)
1583 {
1584 return OnInviteReliable;
1585 }
1586 else
1587 {
1588 return OnInvite;
1589 }
1590 }
1591 }
1592 else if (method == INVITE && code > 100 && code < 200) // !kh! 100 is handled by transaction layer.
1593 {
1594 if (reliable)
1595 {
1596 if (sdp)
1597 {
1598 if (sentOffer)
1599 {
1600 return On1xxAnswer;
1601 }
1602 else
1603 {
1604 return On1xxOffer;
1605 }
1606 }
1607 else
1608 {
1609 return On1xx;
1610 }
1611 }
1612 else
1613 {
1614 if (sdp)
1615 {
1616 return On1xxEarly;
1617 }
1618 else
1619 {
1620 return On1xx;
1621 }
1622 }
1623 }
1624 else if (method == INVITE && code >= 200 && code < 300)
1625 {
1626 if (sdp)
1627 {
1628 if (sentOffer)
1629 {
1630 return On2xxAnswer;
1631 }
1632 else
1633 {
1634 return On2xxOffer;
1635 }
1636 }
1637 else
1638 {
1639 return On2xx;
1640 }
1641 }
1642 else if (method == INVITE && code == 422)
1643 {
1644 return On422Invite;
1645 }
1646 else if (method == INVITE && code == 487)
1647 {
1648 return On487Invite;
1649 }
1650 else if (method == INVITE && code == 489)
1651 {
1652 return On489Invite;
1653 }
1654 else if (method == INVITE && code == 491)
1655 {
1656 return On491Invite;
1657 }
1658 else if (method == INVITE && code >= 400)
1659 {
1660 return OnInviteFailure;
1661 }
1662 else if (method == ACK)
1663 {
1664 if (sdp)
1665 {
1666 return OnAckAnswer;
1667 }
1668 else
1669 {
1670 return OnAck;
1671 }
1672 }
1673 else if (method == CANCEL && code == 0)
1674 {
1675 return OnCancel;
1676 }
1677 else if (method == CANCEL && code / 200 == 1)
1678 {
1679 return On200Cancel;
1680 }
1681 else if (method == CANCEL && code >= 400)
1682 {
1683 return OnCancelFailure;
1684 }
1685 else if (method == BYE && code == 0)
1686 {
1687 return OnBye;
1688 }
1689 else if (method == BYE && code / 200 == 1)
1690 {
1691 return On200Bye;
1692 }
1693 else if (method == PRACK && code == 0)
1694 {
1695 return OnPrack;
1696 }
1697 else if (method == PRACK && code / 200 == 1)
1698 {
1699 return On200Prack;
1700 }
1701 else if (method == UPDATE && code == 0)
1702 {
1703 if (sdp)
1704 {
1705 return OnUpdateOffer;
1706 }
1707 else
1708 {
1709 return OnUpdate;
1710 }
1711 }
1712 else if (method == UPDATE && code / 200 == 1)
1713 {
1714 return On200Update;
1715 }
1716 else if (method == UPDATE && code == 422)
1717 {
1718 return On422Update;
1719 }
1720 else if (method == UPDATE && code == 489)
1721 {
1722 return On489Update;
1723 }
1724 else if (method == UPDATE && code == 491)
1725 {
1726 return On491Update;
1727 }
1728 else if (method == UPDATE && code >= 400)
1729 {
1730 return OnUpdateRejected;
1731 }
1732 else
1733 {
1734 //assert(0); // dispatchOthers will throw if the message type is really unknown
1735 return Unknown;
1736 }
1737 }
1738
1739 void InviteSession::sendAck(const SdpContents *sdp)
1740 {
1741 SipMessage ack;
1742 mDialog.makeRequest(ack, ACK);
1743 if(sdp != 0)
1744 {
1745 setSdp(ack, *sdp);
1746 }
1747 InfoLog (<< "Sending " << ack.brief());
1748 mDialog.send(ack);
1749 }
1750
1751 void InviteSession::sendBye()
1752 {
1753 SipMessage bye;
1754 mDialog.makeRequest(bye, BYE);
1755 InfoLog (<< "Sending " << bye.brief());
1756 mDialog.send(bye);
1757 }
1758
1759 DialogUsageManager::EncryptionLevel InviteSession::getEncryptionLevel(const SipMessage& msg)
1760 {
1761 DialogUsageManager::EncryptionLevel level = DialogUsageManager::None;
1762 const SecurityAttributes* secAttr = msg.getSecurityAttributes();
1763 if (secAttr)
1764 {
1765 SignatureStatus sig = secAttr->getSignatureStatus();
1766 bool sign = (SignatureTrusted == sig || SignatureCATrusted == sig || SignatureSelfSigned == sig);
1767 bool encrypted = secAttr->isEncrypted();
1768 if (encrypted && sign ) level = DialogUsageManager::SignAndEncrypt;
1769 else if (encrypted) level = DialogUsageManager::Encrypt;
1770 else if (sign) level = DialogUsageManager::Sign;
1771 }
1772 return level;
1773 }
1774
1775 void InviteSession::setCurrentLocalSdp(const SipMessage& msg)
1776 {
1777 assert(mProposedLocalSdp.get());
1778 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
1779 {
1780 if (DialogUsageManager::Encrypt == getEncryptionLevel(msg) || DialogUsageManager::SignAndEncrypt == getEncryptionLevel(msg))
1781 {
1782 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back()->clone()));
1783 }
1784 else
1785 {
1786 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()->clone()));
1787 }
1788 }
1789 else
1790 {
1791 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>(mProposedLocalSdp.get()->clone()));
1792 }
1793 mProposedLocalSdp.release();
1794 }
1795
1796
1797 /* ====================================================================
1798 * The Vovida Software License, Version 1.0
1799 *
1800 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1801 *
1802 * Redistribution and use in source and binary forms, with or without
1803 * modification, are permitted provided that the following conditions
1804 * are met:
1805 *
1806 * 1. Redistributions of source code must retain the above copyright
1807 * notice, this list of conditions and the following disclaimer.
1808 *
1809 * 2. Redistributions in binary form must reproduce the above copyright
1810 * notice, this list of conditions and the following disclaimer in
1811 * the documentation and/or other materials provided with the
1812
1813 * distribution.
1814 *
1815 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1816 * and "Vovida Open Communication Application Library (VOCAL)" must
1817 * not be used to endorse or promote products derived from this
1818 * software without prior written permission. For written
1819 * permission, please contact vocal@vovida.org.
1820 *
1821 * 4. Products derived from this software may not be called "VOCAL", nor
1822 * may "VOCAL" appear in their name, without prior written
1823 * permission of Vovida Networks, Inc.
1824 *
1825 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1826 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1827 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1828 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1829 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1830 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1831 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1832 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1833 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1834 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1835 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1836 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1837 * DAMAGE.
1838 *
1839 * ====================================================================
1840 *
1841 * This software consists of voluntary contributions made by Vovida
1842 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1843 * Inc. For more information on Vovida Networks, Inc., please see
1844 * <http://www.vovida.org/>.
1845 *
1846 */

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27