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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5295 - (show annotations) (download)
Mon Aug 22 00:30:05 2005 UTC (14 years, 3 months ago) by jason
File size: 54906 byte(s)
merged 5270:HEAD from b-directory-reorg
1 #include "resip/stack/MultipartMixedContents.hxx"
2 #include "resip/stack/MultipartAlternativeContents.hxx"
3 #include "resip/stack/SdpContents.hxx"
4 #include "resip/stack/SipMessage.hxx"
5 #include "resip/stack/Helper.hxx"
6 #include "resip/dum/Dialog.hxx"
7 #include "resip/dum/DialogUsageManager.hxx"
8 #include "resip/dum/InviteSession.hxx"
9 #include "resip/dum/ServerInviteSession.hxx"
10 #include "resip/dum/ClientSubscription.hxx"
11 #include "resip/dum/ServerSubscription.hxx"
12 #include "resip/dum/ClientInviteSession.hxx"
13 #include "resip/dum/InviteSessionHandler.hxx"
14 #include "resip/dum/MasterProfile.hxx"
15 #include "resip/dum/UsageUseException.hxx"
16 #include "rutil/Inserter.hxx"
17 #include "rutil/Logger.hxx"
18 #include "rutil/Timer.hxx"
19 #include "rutil/Random.hxx"
20 #include "rutil/compat.hxx"
21 #include "rutil/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::message(const Contents& contents)
498 {
499 if (mNitState == NitComplete)
500 {
501 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
502 {
503 mNitState = NitProceeding;
504 SipMessage message;
505 mDialog.makeRequest(message, MESSAGE);
506 // !jf! handle multipart here
507 message.setContents(&contents);
508 mDialog.send(message, mCurrentEncryptionLevel);
509 InfoLog (<< "Trying to send MESSAGE: " << message);
510 }
511 else
512 {
513 WarningLog (<< "Can't send MESSAGE before Connected");
514 assert(0);
515 throw UsageUseException("Can't send MESSAGE before Connected", __FILE__, __LINE__);
516 }
517 }
518 else
519 {
520 throw UsageUseException("Cannot start a non-invite transaction until the previous one has completed",
521 __FILE__, __LINE__);
522 }
523 }
524
525 void
526 InviteSession::dispatch(const SipMessage& msg)
527 {
528 // !jf! do we need to handle 3xx here or is it handled elsewhere?
529 switch (mState)
530 {
531 case Connected:
532 dispatchConnected(msg);
533 break;
534 case SentUpdate:
535 dispatchSentUpdate(msg);
536 break;
537 case SentReinvite:
538 dispatchSentReinvite(msg);
539 break;
540 case SentUpdateGlare:
541 case SentReinviteGlare:
542 // The behavior is the same except for timer which is handled in dispatch(Timer)
543 dispatchGlare(msg);
544 break;
545 case ReceivedUpdate:
546 case ReceivedReinvite:
547 case ReceivedReinviteNoOffer:
548 dispatchReceivedUpdateOrReinvite(msg);
549 break;
550 case Answered:
551 dispatchAnswered(msg);
552 break;
553 case WaitingToOffer:
554 dispatchWaitingToOffer(msg);
555 break;
556 case WaitingToTerminate:
557 dispatchWaitingToTerminate(msg);
558 break;
559 case Terminated:
560 dispatchTerminated(msg);
561 break;
562 case Undefined:
563 default:
564 assert(0);
565 break;
566 }
567 }
568
569 void
570 InviteSession::dispatch(const DumTimeout& timeout)
571 {
572 if (timeout.type() == DumTimeout::Retransmit200)
573 {
574 if (mCurrentRetransmit200)
575 {
576 InfoLog (<< "Retransmitting: " << endl << mInvite200);
577 mDialog.send(mInvite200, mCurrentEncryptionLevel);
578 mCurrentRetransmit200 *= 2;
579 mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq());
580 }
581 }
582 else if (timeout.type() == DumTimeout::WaitForAck)
583 {
584 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet
585 {
586 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
587
588 // this is so the app can decided to ignore this. default implementation
589 // will call end next
590 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
591
592 // If we are waiting for an Ack and it times out, then end with a BYE
593 if(mState == UAS_WaitingToHangup)
594 {
595 sendBye();
596 transition(Terminated);
597 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
598 }
599 }
600 }
601 else if (timeout.type() == DumTimeout::Glare)
602 {
603 if (mState == SentUpdateGlare)
604 {
605 transition(SentUpdate);
606
607 InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
608 mDialog.send(mLastSessionModification, DialogUsageManager::None);
609 }
610 else if (mState == SentReinviteGlare)
611 {
612 transition(SentReinvite);
613
614 InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");
615 mDialog.send(mLastSessionModification, DialogUsageManager::None);
616 }
617 }
618 else if (timeout.type() == DumTimeout::SessionExpiration)
619 {
620 if(timeout.seq() == mSessionTimerSeq)
621 {
622 // this is so the app can decided to ignore this. default implementation
623 // will call end next
624 mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());
625 }
626 }
627 else if (timeout.type() == DumTimeout::SessionRefresh)
628 {
629 if(timeout.seq() == mSessionTimerSeq)
630 {
631 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
632 {
633 sessionRefresh();
634 }
635 }
636 }
637 }
638
639 void
640 InviteSession::dispatchConnected(const SipMessage& msg)
641 {
642 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
643 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
644
645 switch (toEvent(msg, sdp.get()))
646 {
647 case OnInvite:
648 case OnInviteReliable:
649 mLastSessionModification = msg;
650 transition(ReceivedReinviteNoOffer);
651 //handler->onDialogModified(getSessionHandle(), None, msg);
652 handler->onOfferRequired(getSessionHandle(), msg);
653 break;
654
655 case OnInviteOffer:
656 case OnInviteReliableOffer:
657 mLastSessionModification = msg;
658 transition(ReceivedReinvite);
659 mCurrentEncryptionLevel = getEncryptionLevel(msg);
660 //handler->onDialogModified(getSessionHandle(), Offer, msg);
661 handler->onOffer(getSessionHandle(), msg, *sdp);
662 break;
663
664 case On2xx:
665 case On2xxOffer:
666 case On2xxAnswer:
667 // retransmission of 200I
668 // !jf! Need to include the answer here.
669 sendAck();
670 break;
671
672 case OnUpdateOffer:
673 transition(ReceivedUpdate);
674
675 // !kh!
676 // Find out if it's an UPDATE requiring state change.
677 // See rfc3311 5.2, 4th paragraph.
678 mLastSessionModification = msg;
679 mCurrentEncryptionLevel = getEncryptionLevel(msg);
680 handler->onOffer(getSessionHandle(), msg, *sdp);
681 break;
682
683 case OnUpdate:
684 {
685 // ?slg? no sdp in update - just responsd immediately (likely session timer) - do we need a callback?
686 SipMessage response;
687 mLastSessionModification = msg;
688 mDialog.makeResponse(response, mLastSessionModification, 200);
689 handleSessionTimerRequest(response, mLastSessionModification);
690 send(response);
691 break;
692 }
693
694 case OnUpdateRejected:
695 case On200Update:
696 WarningLog (<< "DUM delivered an UPDATE response in an incorrect state " << endl << msg);
697 assert(0);
698 break;
699
700 case OnAck:
701 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
702 break;
703
704 default:
705 dispatchOthers(msg);
706 break;
707 }
708 }
709
710 void
711 InviteSession::dispatchSentUpdate(const SipMessage& msg)
712 {
713 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
714 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
715
716 switch (toEvent(msg, sdp.get()))
717 {
718 case OnInvite:
719 case OnInviteReliable:
720 case OnInviteOffer:
721 case OnInviteReliableOffer:
722 case OnUpdate:
723 case OnUpdateOffer:
724 {
725 // glare
726 SipMessage response;
727 mDialog.makeResponse(response, msg, 491);
728 send(response);
729 break;
730 }
731
732 case On200Update:
733 transition(Connected);
734 handleSessionTimerResponse(msg);
735 if (sdp.get())
736 {
737 mCurrentEncryptionLevel = getEncryptionLevel(msg);
738 setCurrentLocalSdp(msg);
739 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
740 handler->onAnswer(getSessionHandle(), msg, *sdp);
741 }
742 else if(mProposedLocalSdp.get())
743 {
744 // If we sent an offer in the Update Request and no answer is received
745 handler->onIllegalNegotiation(getSessionHandle(), msg);
746 mProposedLocalSdp.release();
747 mProposedEncryptionLevel = DialogUsageManager::None;
748 }
749 break;
750
751 case On491Update:
752 transition(SentUpdateGlare);
753 start491Timer();
754 break;
755
756 case On422Update: // session timer
757 if(msg.exists(h_MinSE))
758 {
759 // Change interval to min from 422 response
760 mSessionInterval = msg.header(h_MinSE).value();
761 mMinSE = mSessionInterval;
762 sessionRefresh();
763 }
764 else
765 {
766 // Response must contact Min_SE - if not - just ignore
767 // ?slg? callback?
768 transition(Connected);
769 mProposedLocalSdp.release();
770 mProposedEncryptionLevel = DialogUsageManager::None;
771 }
772 break;
773
774 case OnUpdateRejected:
775 // !jf! - callback?
776 mProposedLocalSdp.release();
777 mProposedEncryptionLevel = DialogUsageManager::None;
778 transition(Connected);
779 break;
780
781 case OnGeneralFailure:
782 sendBye();
783 transition(Terminated);
784 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
785 break;
786
787 default:
788 dispatchOthers(msg);
789 break;
790 }
791 }
792
793 void
794 InviteSession::dispatchSentReinvite(const SipMessage& msg)
795 {
796 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
797 std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
798
799 switch (toEvent(msg, sdp.get()))
800 {
801 case OnInvite:
802 case OnInviteReliable:
803 case OnInviteOffer:
804 case OnInviteReliableOffer:
805 case OnUpdate:
806 case OnUpdateOffer:
807 {
808 SipMessage response;
809 mDialog.makeResponse(response, msg, 491);
810 send(response);
811 break;
812 }
813
814 case On1xx:
815 case On1xxEarly:
816 // Some UA's send a 100 response to a ReInvite - just ignore it
817 break;
818
819 case On2xxAnswer:
820 case On2xxOffer:
821 {
822 transition(Connected);
823 handleSessionTimerResponse(msg);
824 setCurrentLocalSdp(msg);
825 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
826 mCurrentEncryptionLevel = getEncryptionLevel(msg);
827 // !jf! I need to potentially include an answer in the ACK here
828 sendAck();
829 handler->onAnswer(getSessionHandle(), msg, *sdp);
830
831
832 // !jf! do I need to allow a reINVITE overlapping the retransmission of
833 // the ACK when a 200I is received? If yes, then I need to store all
834 // ACK messages for 64*T1
835 break;
836 }
837 case On2xx:
838 sendAck();
839 transition(Connected);
840 handleSessionTimerResponse(msg);
841 handler->onIllegalNegotiation(getSessionHandle(), msg);
842 mProposedLocalSdp.release();
843 mProposedEncryptionLevel = DialogUsageManager::None;
844 break;
845
846 case On422Invite:
847 if(msg.exists(h_MinSE))
848 {
849 // Change interval to min from 422 response
850 mSessionInterval = msg.header(h_MinSE).value();
851 mMinSE = mSessionInterval;
852 sessionRefresh();
853 }
854 else
855 {
856 // Response must contact Min_SE - if not - just ignore
857 // ?slg? callback?
858 transition(Connected);
859 mProposedLocalSdp.release();
860 mProposedEncryptionLevel = DialogUsageManager::None;
861 }
862 break;
863
864 case On491Invite:
865 transition(SentReinviteGlare);
866 start491Timer();
867 break;
868
869 case OnGeneralFailure:
870 sendBye();
871 transition(Terminated);
872 handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
873 break;
874
875 case OnInviteFailure:
876 case On487Invite:
877 case On489Invite:
878 transition(Connected);
879 mProposedLocalSdp.release();
880 handler->onOfferRejected(getSessionHandle(), msg);
881 break;
882
883 default:
884 dispatchOthers(msg);
885 break;
886 }
887 }
888
889 void
890 InviteSession::dispatchGlare(const SipMessage& msg)
891 {
892 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
893 MethodTypes method = msg.header(h_CSeq).method();
894 if (method == INVITE && msg.isRequest())
895 {
896 // Received inbound reinvite, when waiting to resend outbound reinvite or update
897 transition(ReceivedReinvite);
898 handler->onOfferRejected(getSessionHandle(), msg);
899 }
900 else if (method == UPDATE && msg.isRequest())
901 {
902 // Received inbound update, when waiting to resend outbound reinvite or update
903 transition(ReceivedUpdate);
904 handler->onOfferRejected(getSessionHandle(), msg);
905 }
906 else
907 {
908 dispatchOthers(msg);
909 }
910 }
911
912 void
913 InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
914 {
915 MethodTypes method = msg.header(h_CSeq).method();
916 if (method == INVITE || method == UPDATE)
917 {
918 // Means that the UAC has sent us a second reINVITE or UPDATE before we
919 // responded to the first one. Bastard!
920 SipMessage response;
921 mDialog.makeResponse(response, msg, 500);
922 response.header(h_RetryAfter).value() = Random::getRandom() % 10;
923 mDialog.send(response);
924 }
925 else
926 {
927 dispatchOthers(msg);
928 }
929 }
930
931
932 void
933 InviteSession::dispatchAnswered(const SipMessage& msg)
934 {
935 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
936 {
937 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
938 transition(Connected);
939 }
940 else
941 {
942 dispatchOthers(msg);
943 }
944 }
945
946 void
947 InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
948 {
949 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
950 {
951
952 assert(mProposedLocalSdp.get());
953 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
954 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
955 {
956 provideOffer( *(dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back())),
957 mProposedEncryptionLevel,
958 dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()));
959 }
960 else
961 {
962 provideOffer(*(dynamic_cast<SdpContents*>(mProposedLocalSdp.get())), mProposedEncryptionLevel, 0);
963 }
964 }
965 else
966 {
967 dispatchOthers(msg);
968 }
969 }
970
971 void
972 InviteSession::dispatchWaitingToTerminate(const SipMessage& msg)
973 {
974 if (msg.isResponse() &&
975 msg.header(h_CSeq).method() == INVITE)
976 {
977 if(msg.header(h_StatusLine).statusCode() / 200 == 1) // Note: stack ACK's non-2xx final responses only
978 {
979 // !jf! Need to include the answer here.
980 sendAck();
981 }
982 sendBye();
983 transition(Terminated);
984 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
985 }
986 }
987
988 void
989 InviteSession::dispatchTerminated(const SipMessage& msg)
990 {
991 InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief());
992
993 if (msg.isRequest())
994 {
995 SipMessage response;
996 mDialog.makeResponse(response, msg, 481);
997 mDialog.send(response);
998
999 // !jf! means the peer sent BYE while we are waiting for response to BYE
1000 //mDum.destroy(this);
1001 }
1002 else
1003 {
1004 mDum.destroy(this);
1005 }
1006 }
1007
1008 void
1009 InviteSession::dispatchOthers(const SipMessage& msg)
1010 {
1011 // handle OnGeneralFailure
1012 // handle OnRedirect
1013
1014 switch (msg.header(h_CSeq).method())
1015 {
1016 case PRACK:
1017 dispatchPrack(msg);
1018 break;
1019 case CANCEL:
1020 dispatchCancel(msg);
1021 break;
1022 case BYE:
1023 dispatchBye(msg);
1024 break;
1025 case INFO:
1026 dispatchInfo(msg);
1027 break;
1028 case MESSAGE:
1029 dispatchMessage(msg);
1030 break;
1031 case ACK:
1032 // Ignore duplicate ACKs from 2xx reTransmissions
1033 break;
1034 default:
1035 // handled in Dialog
1036 WarningLog (<< "DUM delivered a "
1037 << msg.header(h_CSeq).unknownMethodName()
1038 << " to the InviteSession "
1039 << endl
1040 << msg);
1041 assert(0);
1042 break;
1043 }
1044 }
1045
1046 void
1047 InviteSession::dispatchUnhandledInvite(const SipMessage& msg)
1048 {
1049 assert(msg.isRequest());
1050 assert(msg.header(h_CSeq).method() == INVITE);
1051
1052 // If we get an INVITE request from the wire and we are not in
1053 // Connected state, reject the request and send a BYE
1054 SipMessage response;
1055 mDialog.makeResponse(response, msg, 400); // !jf! what code to use?
1056 InfoLog (<< "Sending " << response.brief());
1057 mDialog.send(response);
1058
1059 sendBye();
1060 transition(Terminated);
1061 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1062 }
1063
1064 void
1065 InviteSession::dispatchPrack(const SipMessage& msg)
1066 {
1067 assert(msg.header(h_CSeq).method() == PRACK);
1068 if(msg.isRequest())
1069 {
1070 SipMessage rsp;
1071 mDialog.makeResponse(rsp, msg, 481);
1072 mDialog.send(rsp);
1073
1074 sendBye();
1075 // !jf! should we make some other callback here
1076 transition(Terminated);
1077 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1078 }
1079 else
1080 {
1081 // ignore. could be PRACK/200
1082 }
1083 }
1084
1085 void
1086 InviteSession::dispatchCancel(const SipMessage& msg)
1087 {
1088 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1089 assert(msg.header(h_CSeq).method() == CANCEL);
1090 if(msg.isRequest())
1091 {
1092 SipMessage rsp;
1093 mDialog.makeResponse(rsp, msg, 200);
1094 mDialog.send(rsp);
1095
1096 sendBye();
1097 // !jf! should we make some other callback here
1098 transition(Terminated);
1099 handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1100 }
1101 else
1102 {
1103 WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg);
1104 assert(0);
1105 }
1106 }
1107
1108 void
1109 InviteSession::dispatchBye(const SipMessage& msg)
1110 {
1111 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1112
1113 if (msg.isRequest())
1114 {
1115
1116 SipMessage rsp;
1117 InfoLog (<< "Received " << msg.brief());
1118 mDialog.makeResponse(rsp, msg, 200);
1119 mDialog.send(rsp);
1120
1121 // !jf! should we make some other callback here
1122 transition(Terminated);
1123 handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1124 mDum.destroy(this);
1125 }
1126 else
1127 {
1128 WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg);
1129 assert(0);
1130 }
1131 }
1132
1133 void
1134 InviteSession::dispatchInfo(const SipMessage& msg)
1135 {
1136 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1137 if (msg.isRequest())
1138 {
1139 InfoLog (<< "Received " << msg.brief());
1140 mDialog.makeResponse(mLastNitResponse, msg, 200);
1141 handler->onInfo(getSessionHandle(), msg);
1142 }
1143 else
1144 {
1145 assert(mNitState == NitProceeding);
1146 mNitState = NitComplete;
1147 //!dcm! -- toss away 1xx to an info?
1148 if (msg.header(h_StatusLine).statusCode() >= 300)
1149 {
1150 handler->onInfoFailure(getSessionHandle(), msg);
1151 }
1152 else if (msg.header(h_StatusLine).statusCode() >= 200)
1153 {
1154 handler->onInfoSuccess(getSessionHandle(), msg);
1155 }
1156 }
1157 }
1158
1159 void
1160 InviteSession::acceptNIT(int statusCode)
1161 {
1162 if (statusCode / 100 != 2)
1163 {
1164 throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
1165 }
1166
1167 mLastNitResponse.header(h_StatusLine).statusCode() = statusCode;
1168 send(mLastNitResponse);
1169 }
1170
1171 void
1172 InviteSession::rejectNIT(int statusCode)
1173 {
1174 if (statusCode < 400)
1175 {
1176 throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
1177 }
1178 mLastNitResponse.header(h_StatusLine).statusCode() = statusCode;
1179 send(mLastNitResponse);
1180 }
1181
1182 void
1183 InviteSession::dispatchMessage(const SipMessage& msg)
1184 {
1185 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1186 if (msg.isRequest())
1187 {
1188 InfoLog (<< "Received " << msg.brief());
1189 mDialog.makeResponse(mLastNitResponse, msg, 200);
1190 handler->onMessage(getSessionHandle(), msg);
1191 }
1192 else
1193 {
1194 assert(mNitState == NitProceeding);
1195 mNitState = NitComplete;
1196 //!dcm! -- toss away 1xx to an message?
1197 if (msg.header(h_StatusLine).statusCode() >= 300)
1198 {
1199 handler->onMessageFailure(getSessionHandle(), msg);
1200 }
1201 else if (msg.header(h_StatusLine).statusCode() >= 200)
1202 {
1203 handler->onMessageSuccess(getSessionHandle(), msg);
1204 }
1205 }
1206 }
1207
1208 void
1209 InviteSession::startRetransmit200Timer()
1210 {
1211 mCurrentRetransmit200 = Timer::T1;
1212 int seq = mLastSessionModification.header(h_CSeq).sequence();
1213 mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
1214 mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
1215 }
1216
1217 void
1218 InviteSession::start491Timer()
1219 {
1220 int seq = mLastSessionModification.header(h_CSeq).sequence();
1221 int timer = Random::getRandom() % 4000;
1222 mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
1223 }
1224
1225 void
1226 InviteSession::setSessionTimerHeaders(SipMessage &msg)
1227 {
1228 if(mSessionInterval >= 90) // If mSessionInterval is 0 then SessionTimers are considered disabled
1229 {
1230 msg.header(h_SessionExpires).value() = mSessionInterval;
1231 if(msg.isRequest())
1232 {
1233 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uac" : "uas");
1234 }
1235 else
1236 {
1237 msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uas" : "uac");
1238 }
1239 msg.header(h_MinSE).value() = mMinSE;
1240 }
1241 else
1242 {
1243 msg.remove(h_SessionExpires);
1244 msg.remove(h_MinSE);
1245 }
1246 }
1247
1248 void
1249 InviteSession::sessionRefresh()
1250 {
1251 if (updateMethodSupported())
1252 {
1253 transition(SentUpdate);
1254 mDialog.makeRequest(mLastSessionModification, UPDATE);
1255 mLastSessionModification.releaseContents(); // Don't send SDP
1256 }
1257 else
1258 {
1259 transition(SentReinvite);
1260 mDialog.makeRequest(mLastSessionModification, INVITE);
1261 InviteSession::setSdp(mLastSessionModification, mCurrentLocalSdp.get());
1262 mProposedLocalSdp = InviteSession::makeSdp(*mCurrentLocalSdp.get(), 0);
1263 }
1264 setSessionTimerHeaders(mLastSessionModification);
1265
1266 InfoLog (<< "sessionRefresh: Sending " << mLastSessionModification.brief());
1267 mDialog.send(mLastSessionModification, mCurrentEncryptionLevel);
1268 }
1269
1270 void
1271 InviteSession::setSessionTimerPreferences()
1272 {
1273 mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if remote doesn't request a time
1274 if(mSessionInterval != 0)
1275 {
1276 // If session timers are no disabled then ensure interval is greater than or equal to MinSE
1277 mSessionInterval = resipMax(mMinSE, mSessionInterval);
1278 }
1279 switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
1280 {
1281 case Profile::PreferLocalRefreshes:
1282 mSessionRefresher = true; // Default refresher is Local
1283 break;
1284 case Profile::PreferRemoteRefreshes:
1285 mSessionRefresher = false; // Default refresher is Remote
1286 break;
1287 case Profile::PreferUASRefreshes:
1288 mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is UAS (for the session) - callee
1289 break;
1290 case Profile::PreferUACRefreshes:
1291 mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is UAC (for the session) - caller
1292 break;
1293 }
1294 }
1295
1296 void
1297 InviteSession::startSessionTimer()
1298 {
1299 if(mSessionInterval >= 90) // 90 is the absolute minimum - RFC4028
1300 {
1301 // Check if we are the refresher
1302 if(mSessionRefresher)
1303 {
1304 // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by RFC4028)
1305 mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
1306 }
1307 else
1308 {
1309 // 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)
1310 mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin(32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
1311 }
1312 }
1313 else // Session Interval less than 90 - consider timers disabled
1314 {
1315 ++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled
1316 }
1317 }
1318
1319 void
1320 InviteSession::handleSessionTimerResponse(const SipMessage& msg)
1321 {
1322 assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
1323
1324 // If session timers are locally supported then handle response
1325 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1326 {
1327 setSessionTimerPreferences();
1328
1329 if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer))
1330 && !msg.exists(h_SessionExpires))
1331 {
1332 // If no Session Expires in response and Requires header is present then session timer is to be 'turned off'
1333 mSessionInterval = 0;
1334 }
1335 // Process Session Timer headers
1336 else if(msg.exists(h_SessionExpires))
1337 {
1338 mSessionInterval = msg.header(h_SessionExpires).value();
1339 if(msg.header(h_SessionExpires).exists(p_refresher))
1340 {
1341 // Remote end specified refresher preference
1342 mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac"));
1343 }
1344 }
1345 else
1346 {
1347 // Note: If no Requires or Session-Expires, then UAS does not support Session Timers
1348 // - we are free to use our SessionInterval settings (set above as a default)
1349 // If far end doesn't support then refresher must be local
1350 mSessionRefresher = true;
1351 }
1352
1353 // Update MinSE if specified and longer than current value
1354 if(msg.exists(h_MinSE))
1355 {
1356 mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value());
1357 }
1358
1359 startSessionTimer();
1360 }
1361 }
1362
1363 void
1364 InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
1365 {
1366 assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
1367
1368 // If session timers are locally supported then add necessary headers to response
1369 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1370 {
1371 setSessionTimerPreferences();
1372
1373 // Check if far-end supports
1374 bool farEndSupportsTimer = false;
1375 if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer)))
1376 {
1377 farEndSupportsTimer = true;
1378 if(request.exists(h_SessionExpires))
1379 {
1380 // Use Session Interval requested by remote - if none then use local settings
1381 mSessionInterval = request.header(h_SessionExpires).value();
1382 if(request.header(h_SessionExpires).exists(p_refresher))
1383 {
1384 mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
1385 }
1386 }
1387
1388 // Update MinSE if specified and longer than current value
1389 if(request.exists(h_MinSE))
1390 {
1391 mMinSE = resipMax(mMinSE, request.header(h_MinSE).value());
1392 }
1393 }
1394 else
1395 {
1396 // If far end doesn't support then refresher must be local
1397 mSessionRefresher = true;
1398 }
1399
1400 // Add Session-Expires to response if required
1401 if(mSessionInterval >= 90)
1402 {
1403 if(farEndSupportsTimer)
1404 {
1405 // If far end supports session-timer then require it, if not already present
1406 if(!response.header(h_Requires).find(Token(Symbols::Timer)))
1407 {
1408 response.header(h_Requires).push_back(Token(Symbols::Timer));
1409 }
1410 }
1411 setSessionTimerHeaders(response);
1412 }
1413
1414 startSessionTimer();
1415 }
1416 }
1417
1418 Data
1419 InviteSession::toData(State state)
1420 {
1421 switch (state)
1422 {
1423 case Undefined:
1424 return "InviteSession::Undefined";
1425 case Connected:
1426 return "InviteSession::Connected";
1427 case SentUpdate:
1428 return "InviteSession::SentUpdate";
1429 case SentUpdateGlare:
1430 return "InviteSession::SentUpdateGlare";
1431 case SentReinvite:
1432 return "InviteSession::SentReinvite";
1433 case SentReinviteGlare:
1434 return "InviteSession::SentReinviteGlare";
1435 case ReceivedUpdate:
1436 return "InviteSession::ReceivedUpdate";
1437 case ReceivedReinvite:
1438 return "InviteSession::ReceivedReinvite";
1439 case ReceivedReinviteNoOffer:
1440 return "InviteSession::ReceivedReinviteNoOffer";
1441 case Answered:
1442 return "InviteSession::Answered";
1443 case WaitingToOffer:
1444 return "InviteSession::WaitingToOffer";
1445 case WaitingToTerminate:
1446 return "InviteSession::WaitingToTerminate";
1447 case Terminated:
1448 return "InviteSession::Terminated";
1449
1450 case UAC_Start:
1451 return "UAC_Start";
1452 case UAS_Offer:
1453 return "UAS_Offer";
1454 case UAS_OfferProvidedAnswer:
1455 return "UAS_OfferProvidedAnswer";
1456 case UAS_EarlyOffer:
1457 return "UAS_EarlyOffer";
1458 case UAS_EarlyProvidedAnswer:
1459 return "UAS_EarlyProvidedAnswer";
1460 case UAS_NoOffer:
1461 return "UAS_NoOffer";
1462 case UAS_ProvidedOffer:
1463 return "UAS_ProvidedOffer";
1464 case UAS_EarlyNoOffer:
1465 return "UAS_EarlyNoOffer";
1466 case UAS_EarlyProvidedOffer:
1467 return "UAS_EarlyProvidedOffer";
1468 case UAS_Accepted:
1469 return "UAS_Accepted";
1470 case UAS_WaitingToOffer:
1471 return "UAS_WaitingToOffer";
1472 case UAS_AcceptedWaitingAnswer:
1473 return "UAS_AcceptedWaitingAnswer";
1474 case UAC_Early:
1475 return "UAC_Early";
1476 case UAC_EarlyWithOffer:
1477 return "UAC_EarlyWithOffer";
1478 case UAC_EarlyWithAnswer:
1479 return "UAC_EarlyWithAnswer";
1480 case UAC_Answered:
1481 return "UAC_Answered";
1482 case UAC_SentUpdateEarly:
1483 return "UAC_SentUpdateEarly";
1484 case UAC_SentUpdateConnected:
1485 return "UAC_SentUpdateConnected";
1486 case UAC_ReceivedUpdateEarly:
1487 return "UAC_ReceivedUpdateEarly";
1488 case UAC_SentAnswer:
1489 return "UAC_SentAnswer";
1490 case UAC_QueuedUpdate:
1491 return "UAC_QueuedUpdate";
1492 case UAC_Cancelled:
1493 return "UAC_Cancelled";
1494
1495 case UAS_Start:
1496 return "UAS_Start";
1497 case UAS_OfferReliable:
1498 return "UAS_OfferReliable";
1499 case UAS_NoOfferReliable:
1500 return "UAS_NoOfferReliable";
1501 case UAS_FirstSentOfferReliable:
1502 return "UAS_FirstSentOfferReliable";
1503 case UAS_FirstEarlyReliable:
1504 return "UAS_FirstEarlyReliable";
1505 case UAS_EarlyReliable:
1506 return "UAS_EarlyReliable";
1507 case UAS_SentUpdate:
1508 return "UAS_SentUpdate";
1509 case UAS_SentUpdateAccepted:
1510 return "UAS_SentUpdateAccepted";
1511 case UAS_ReceivedUpdate:
1512 return "UAS_ReceivedUpdate";
1513 case UAS_ReceivedUpdateWaitingAnswer:
1514 return "UAS_ReceivedUpdateWaitingAnswer";
1515 case UAS_WaitingToTerminate:
1516 return "UAS_WaitingToTerminate";
1517 case UAS_WaitingToHangup:
1518 return "UAS_WaitingToHangup";
1519 }
1520 assert(0);
1521 return "Undefined";
1522 }
1523
1524
1525 void
1526 InviteSession::transition(State target)
1527 {
1528 InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
1529 mState = target;
1530 }
1531
1532 bool
1533 InviteSession::isReliable(const SipMessage& msg)
1534 {
1535 // Ensure supported both locally and remotely
1536 return msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel)) &&
1537 mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::C100rel));
1538 }
1539
1540 std::auto_ptr<SdpContents>
1541 InviteSession::getSdp(const SipMessage& msg)
1542 {
1543 // !jf! this code doesn't yet work - definitely if USE_SSL=false
1544 //Helper::ContentsSecAttrs attrs = Helper::extractFromPkcs7(msg, mDum.getSecurity());
1545 //return std::auto_ptr<SdpContents>(dynamic_cast<SdpContents*>(attrs.mContents.get()));
1546 SdpContents* sdp = dynamic_cast<SdpContents*>(msg.getContents());
1547 if (sdp)
1548 {
1549 SdpContents* cloned = static_cast<SdpContents*>(sdp->clone());
1550 return std::auto_ptr<SdpContents>(cloned);
1551 }
1552 else
1553 {
1554 static std::auto_ptr<SdpContents> empty;
1555 return empty;
1556 }
1557 }
1558
1559 std::auto_ptr<SdpContents>
1560 InviteSession::makeSdp(const SdpContents& sdp)
1561 {
1562 return std::auto_ptr<SdpContents>(static_cast<SdpContents*>(sdp.clone()));
1563 }
1564
1565 auto_ptr<Contents>
1566 InviteSession::makeSdp(const SdpContents& sdp,
1567 const SdpContents* alternative)
1568 {
1569 if (alternative)
1570 {
1571 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
1572 mac->parts().push_back(alternative->clone());
1573 mac->parts().push_back(sdp.clone());
1574 return auto_ptr<Contents>(mac);
1575 }
1576 else
1577 {
1578 return auto_ptr<Contents>(sdp.clone());
1579 }
1580 }
1581
1582 void
1583 InviteSession::setSdp(SipMessage& msg, const SdpContents& sdp, const SdpContents* alternative)
1584 {
1585 // !jf! should deal with multipart here
1586
1587 // This will clone the sdp since the InviteSession also wants to keep its own
1588 // copy of the sdp around for the application to access
1589 if (alternative)
1590 {
1591 MultipartAlternativeContents* mac = new MultipartAlternativeContents;
1592 mac->parts().push_back(alternative->clone());
1593 mac->parts().push_back(sdp.clone());
1594 msg.setContents(auto_ptr<Contents>(mac));
1595 }
1596 else
1597 {
1598 msg.setContents(&sdp);
1599 }
1600 }
1601
1602 void
1603 InviteSession::setSdp(SipMessage& msg, const Contents* sdp)
1604 {
1605 assert(sdp);
1606 msg.setContents(sdp);
1607 }
1608
1609 InviteSession::Event
1610 InviteSession::toEvent(const SipMessage& msg, const SdpContents* sdp)
1611 {
1612 MethodTypes method = msg.header(h_CSeq).method();
1613 int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
1614 bool reliable = isReliable(msg);
1615 bool sentOffer = mProposedLocalSdp.get();
1616
1617 if (code == 481 || code == 408)
1618 {
1619 return OnGeneralFailure;
1620 }
1621 else if (code >= 300 && code <= 399)
1622 {
1623 return OnRedirect;
1624 }
1625 else if (method == INVITE && code == 0)
1626 {
1627 if (sdp)
1628 {
1629 if (reliable)
1630 {
1631 return OnInviteReliableOffer;
1632 }
1633 else
1634 {
1635 return OnInviteOffer;
1636 }
1637 }
1638 else
1639 {
1640 if (reliable)
1641 {
1642 return OnInviteReliable;
1643 }
1644 else
1645 {
1646 return OnInvite;
1647 }
1648 }
1649 }
1650 else if (method == INVITE && code > 100 && code < 200) // !kh! 100 is handled by transaction layer.
1651 {
1652 if (reliable)
1653 {
1654 if (sdp)
1655 {
1656 if (sentOffer)
1657 {
1658 return On1xxAnswer;
1659 }
1660 else
1661 {
1662 return On1xxOffer;
1663 }
1664 }
1665 else
1666 {
1667 return On1xx;
1668 }
1669 }
1670 else
1671 {
1672 if (sdp)
1673 {
1674 return On1xxEarly;
1675 }
1676 else
1677 {
1678 return On1xx;
1679 }
1680 }
1681 }
1682 else if (method == INVITE && code >= 200 && code < 300)
1683 {
1684 if (sdp)
1685 {
1686 if (sentOffer)
1687 {
1688 return On2xxAnswer;
1689 }
1690 else
1691 {
1692 return On2xxOffer;
1693 }
1694 }
1695 else
1696 {
1697 return On2xx;
1698 }
1699 }
1700 else if (method == INVITE && code == 422)
1701 {
1702 return On422Invite;
1703 }
1704 else if (method == INVITE && code == 487)
1705 {
1706 return On487Invite;
1707 }
1708 else if (method == INVITE && code == 489)
1709 {
1710 return On489Invite;
1711 }
1712 else if (method == INVITE && code == 491)
1713 {
1714 return On491Invite;
1715 }
1716 else if (method == INVITE && code >= 400)
1717 {
1718 return OnInviteFailure;
1719 }
1720 else if (method == ACK)
1721 {
1722 if (sdp)
1723 {
1724 return OnAckAnswer;
1725 }
1726 else
1727 {
1728 return OnAck;
1729 }
1730 }
1731 else if (method == CANCEL && code == 0)
1732 {
1733 return OnCancel;
1734 }
1735 else if (method == CANCEL && code / 200 == 1)
1736 {
1737 return On200Cancel;
1738 }
1739 else if (method == CANCEL && code >= 400)
1740 {
1741 return OnCancelFailure;
1742 }
1743 else if (method == BYE && code == 0)
1744 {
1745 return OnBye;
1746 }
1747 else if (method == BYE && code / 200 == 1)
1748 {
1749 return On200Bye;
1750 }
1751 else if (method == PRACK && code == 0)
1752 {
1753 return OnPrack;
1754 }
1755 else if (method == PRACK && code / 200 == 1)
1756 {
1757 return On200Prack;
1758 }
1759 else if (method == UPDATE && code == 0)
1760 {
1761 if (sdp)
1762 {
1763 return OnUpdateOffer;
1764 }
1765 else
1766 {
1767 return OnUpdate;
1768 }
1769 }
1770 else if (method == UPDATE && code / 200 == 1)
1771 {
1772 return On200Update;
1773 }
1774 else if (method == UPDATE && code == 422)
1775 {
1776 return On422Update;
1777 }
1778 else if (method == UPDATE && code == 489)
1779 {
1780 return On489Update;
1781 }
1782 else if (method == UPDATE && code == 491)
1783 {
1784 return On491Update;
1785 }
1786 else if (method == UPDATE && code >= 400)
1787 {
1788 return OnUpdateRejected;
1789 }
1790 else
1791 {
1792 //assert(0); // dispatchOthers will throw if the message type is really unknown
1793 return Unknown;
1794 }
1795 }
1796
1797 void InviteSession::sendAck(const SdpContents *sdp)
1798 {
1799 SipMessage ack;
1800 mDialog.makeRequest(ack, ACK);
1801 if(sdp != 0)
1802 {
1803 setSdp(ack, *sdp);
1804 }
1805 InfoLog (<< "Sending " << ack.brief());
1806 mDialog.send(ack);
1807 }
1808
1809 void InviteSession::sendBye()
1810 {
1811 SipMessage bye;
1812 mDialog.makeRequest(bye, BYE);
1813 InfoLog (<< "Sending " << bye.brief());
1814 mDialog.send(bye);
1815 }
1816
1817 DialogUsageManager::EncryptionLevel InviteSession::getEncryptionLevel(const SipMessage& msg)
1818 {
1819 DialogUsageManager::EncryptionLevel level = DialogUsageManager::None;
1820 const SecurityAttributes* secAttr = msg.getSecurityAttributes();
1821 if (secAttr)
1822 {
1823 SignatureStatus sig = secAttr->getSignatureStatus();
1824 bool sign = (SignatureTrusted == sig || SignatureCATrusted == sig || SignatureSelfSigned == sig);
1825 bool encrypted = secAttr->isEncrypted();
1826 if (encrypted && sign ) level = DialogUsageManager::SignAndEncrypt;
1827 else if (encrypted) level = DialogUsageManager::Encrypt;
1828 else if (sign) level = DialogUsageManager::Sign;
1829 }
1830 return level;
1831 }
1832
1833 void InviteSession::setCurrentLocalSdp(const SipMessage& msg)
1834 {
1835 assert(mProposedLocalSdp.get());
1836 if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))
1837 {
1838 if (DialogUsageManager::Encrypt == getEncryptionLevel(msg) || DialogUsageManager::SignAndEncrypt == getEncryptionLevel(msg))
1839 {
1840 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back()->clone()));
1841 }
1842 else
1843 {
1844 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()->clone()));
1845 }
1846 }
1847 else
1848 {
1849 mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>(mProposedLocalSdp.get()->clone()));
1850 }
1851 mProposedLocalSdp.release();
1852 }
1853
1854
1855 /* ====================================================================
1856 * The Vovida Software License, Version 1.0
1857 *
1858 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1859 *
1860 * Redistribution and use in source and binary forms, with or without
1861 * modification, are permitted provided that the following conditions
1862 * are met:
1863 *
1864 * 1. Redistributions of source code must retain the above copyright
1865 * notice, this list of conditions and the following disclaimer.
1866 *
1867 * 2. Redistributions in binary form must reproduce the above copyright
1868 * notice, this list of conditions and the following disclaimer in
1869 * the documentation and/or other materials provided with the
1870
1871 * distribution.
1872 *
1873 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1874 * and "Vovida Open Communication Application Library (VOCAL)" must
1875 * not be used to endorse or promote products derived from this
1876 * software without prior written permission. For written
1877 * permission, please contact vocal@vovida.org.
1878 *
1879 * 4. Products derived from this software may not be called "VOCAL", nor
1880 * may "VOCAL" appear in their name, without prior written
1881 * permission of Vovida Networks, Inc.
1882 *
1883 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1884 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1885 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1886 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1887 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1888 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1889 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1890 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1891 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1892 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1893 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1894 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1895 * DAMAGE.
1896 *
1897 * ====================================================================
1898 *
1899 * This software consists of voluntary contributions made by Vovida
1900 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1901 * Inc. For more information on Vovida Networks, Inc., please see
1902 * <http://www.vovida.org/>.
1903 *
1904 */

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27