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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5276 - (hide annotations) (download)
Fri Aug 19 00:23:17 2005 UTC (14 years, 3 months ago) by jason
Original Path: branches/b-directory-reorg/resip/dum/InviteSession.cxx
File size: 54896 byte(s)
compiles now
1 jason 5276 #include "resip/sip/MultipartMixedContents.hxx"
2     #include "resip/sip/MultipartAlternativeContents.hxx"
3     #include "resip/sip/SdpContents.hxx"
4     #include "resip/sip/SipMessage.hxx"
5     #include "resip/sip/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 jason 2555
23 sgodin 3314 // Remove warning about 'this' use in initiator list - pointer is only stored
24     #if defined(WIN32)
25 jason 4010 #pragma warning( disable : 4355 ) // using this in base member initializer list
26     #pragma warning( disable : 4800 ) // forcing value to bool (performance warning)
27 sgodin 3314 #endif
28 derek 3092
29 jason 2856 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
30 jason 4010 #define THROW(msg) throw DialogUsage::Exception(msg, __FILE__,__LINE__);
31 jason 2846
32 davidb 2603 using namespace resip;
33 derek 3255 using namespace std;
34 davidb 2603
35 jason 4010 InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog)
36 derek 3089 : DialogUsage(dum, dialog),
37 jason 4010 mState(Undefined),
38 derek 3255 mNitState(NitComplete),
39 jason 4010 mCurrentRetransmit200(0),
40 sgodin 3392 mSessionInterval(0),
41 sgodin 4691 mMinSE(90),
42     mSessionRefresher(false),
43 sgodin 3392 mSessionTimerSeq(0),
44 daniel 5068 mSentRefer(false),
45     mCurrentEncryptionLevel(DialogUsageManager::None),
46     mProposedEncryptionLevel(DialogUsageManager::None)
47 jason 2555 {
48 jason 4010 DebugLog ( << "^^^ InviteSession::InviteSession " << this);
49 jason 2846 assert(mDum.mInviteSessionHandler);
50 jason 2555 }
51    
52 derek 2858 InviteSession::~InviteSession()
53     {
54 jason 4010 DebugLog ( << "^^^ InviteSession::~InviteSession " << this);
55 derek 2858 mDialog.mInviteSession = 0;
56     }
57 jason 2846
58 jason 4010 void
59     InviteSession::dialogDestroyed(const SipMessage& msg)
60 derek 3064 {
61 jason 4010 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 cktam 4408 const Data&
82     InviteSession::getDialogId() const
83     {
84     return mDialog.getId().getCallId();
85     }
86    
87 jason 4010 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 derek 3064 {
98 jason 4010 mPeerSupportedMethods = msg.header(h_Allows);
99 derek 3064 }
100 jason 4010 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 derek 3064 }
117    
118 jason 4010 bool
119     InviteSession::updateMethodSupported() const
120 derek 3255 {
121 jason 4010 // 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 sgodin 3392
130 jason 4010 const NameAddr&
131     InviteSession::myAddr() const
132     {
133     return mDialog.mLocalNameAddr;
134     }
135 sgodin 3392
136 jason 4010 const NameAddr&
137     InviteSession::peerAddr() const
138     {
139     return mDialog.mRemoteNameAddr;
140     }
141 sgodin 3392
142 jason 4010 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 derek 3255 }
163 derek 3064
164 jason 4010 bool
165     InviteSession::isEarly() const
166 derek 3064 {
167 jason 4010 switch (mState)
168 derek 3064 {
169 jason 4010 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 derek 3064 }
185 jason 4010 }
186 derek 3064
187 jason 4010
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 jason 2866 void
215 daniel 5068 InviteSession::provideOffer(const SdpContents& offer,
216     DialogUsageManager::EncryptionLevel level,
217     const SdpContents* alternative)
218 jason 2866 {
219 jason 4010 switch (mState)
220 derek 2965 {
221 jason 4010 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 sgodin 4369 setSessionTimerHeaders(mLastSessionModification);
235 jason 4010
236     InfoLog (<< "Sending " << mLastSessionModification.brief());
237 daniel 5068 InviteSession::setSdp(mLastSessionModification, offer, alternative);
238     mProposedLocalSdp = InviteSession::makeSdp(offer, alternative);
239     mProposedEncryptionLevel = level;
240     mDialog.send(mLastSessionModification, mProposedEncryptionLevel);
241 jason 4010 break;
242    
243     case Answered:
244     // queue the offer to be sent after the ACK is received
245     transition(WaitingToOffer);
246 daniel 5068 mProposedEncryptionLevel = level;
247     mProposedLocalSdp = InviteSession::makeSdp(offer, alternative);
248 jason 4010 break;
249    
250 sgodin 5001 // ?slg? Can we handle all of the states listed in isConnected() ???
251 jason 4010 default:
252     WarningLog (<< "Can't provideOffer when not in Connected state");
253     throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
254 derek 2965 }
255 jason 2866 }
256    
257     void
258 daniel 5068 InviteSession::provideOffer(const SdpContents& offer)
259     {
260     return provideOffer(offer, mCurrentEncryptionLevel, 0);
261     }
262    
263     void
264 jason 4010 InviteSession::provideAnswer(const SdpContents& answer)
265 jason 2866 {
266 jason 4010 switch (mState)
267 derek 2965 {
268 jason 4010 case ReceivedReinvite:
269     transition(Connected);
270     mDialog.makeResponse(mInvite200, mLastSessionModification, 200);
271     handleSessionTimerRequest(mInvite200, mLastSessionModification);
272 daniel 5068 InviteSession::setSdp(mInvite200, answer, 0);
273 jason 4010 mCurrentLocalSdp = InviteSession::makeSdp(answer);
274     mCurrentRemoteSdp = mProposedRemoteSdp;
275     InfoLog (<< "Sending " << mInvite200.brief());
276 daniel 5068 mDialog.send(mInvite200, mCurrentEncryptionLevel);
277 jason 4010 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 daniel 5068 InviteSession::setSdp(response, answer, 0);
288 jason 4010 mCurrentLocalSdp = InviteSession::makeSdp(answer);
289     mCurrentRemoteSdp = mProposedRemoteSdp;
290     InfoLog (<< "Sending " << response.brief());
291 daniel 5068 mDialog.send(response, mCurrentEncryptionLevel);
292 jason 4010 break;
293     }
294    
295     default:
296 sgodin 4394 WarningLog (<< "Can't provideAnswer when not in Connected state");
297 jason 4010 throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
298 derek 2965 }
299 jason 2866 }
300    
301 jason 4010 void
302     InviteSession::end()
303 jason 2555 {
304 jason 4010 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 jason 2555 }
359    
360 jason 4010 void
361     InviteSession::reject(int statusCode, WarningCategory *warning)
362 jason 2555 {
363 jason 4010 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 jason 2555 }
387 davidb 2575
388 jason 4010 void
389     InviteSession::targetRefresh(const NameAddr& localUri)
390 jason 2941 {
391 sgodin 5001 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
392 jason 4010 {
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 jason 2941 }
404    
405 jason 2856 void
406 jason 4010 InviteSession::refer(const NameAddr& referTo)
407     {
408     if (mSentRefer)
409     {
410     throw UsageUseException("Attempted to send overlapping refer", __FILE__, __LINE__);
411     }
412    
413 sgodin 5001 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
414 jason 4010 {
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 sgodin 5001 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
444 jason 4010 {
445     mSentRefer = true;
446     SipMessage refer;
447     mDialog.makeRequest(refer, REFER);
448    
449     refer.header(h_ReferTo) = referTo;
450 sgodin 5001 refer.header(h_ReferredBy) = mDialog.mLocalContact; // ?slg? is it ok to do this - should it be an option?
451 jason 4010 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 sgodin 5001 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
474 jason 4010 {
475     mNitState = NitProceeding;
476     SipMessage info;
477     mDialog.makeRequest(info, INFO);
478     // !jf! handle multipart here
479     info.setContents(&contents);
480 daniel 5068 mDialog.send(info, mCurrentEncryptionLevel);
481 jason 4010 }
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 sgodin 5265 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 jason 4010 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 derek 2990 InviteSession::dispatch(const DumTimeout& timeout)
571     {
572 derek 3255 if (timeout.type() == DumTimeout::Retransmit200)
573 derek 2990 {
574 jason 4010 if (mCurrentRetransmit200)
575 derek 3255 {
576 jason 4010 InfoLog (<< "Retransmitting: " << endl << mInvite200);
577 daniel 5214 mDialog.send(mInvite200, mCurrentEncryptionLevel);
578 derek 3255 mCurrentRetransmit200 *= 2;
579     mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq());
580     }
581 derek 2990 }
582 derek 3255 else if (timeout.type() == DumTimeout::WaitForAck)
583 derek 2990 {
584 jason 4010 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet
585 derek 3255 {
586 jason 4010 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 sgodin 3363 {
595 jason 4010 sendBye();
596     transition(Terminated);
597     mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
598 sgodin 3363 }
599 derek 3255 }
600 derek 2990 }
601 jason 4010 else if (timeout.type() == DumTimeout::Glare)
602 derek 3255 {
603 jason 4010 if (mState == SentUpdateGlare)
604     {
605     transition(SentUpdate);
606    
607     InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
608 daniel 5068 mDialog.send(mLastSessionModification, DialogUsageManager::None);
609 jason 4010 }
610     else if (mState == SentReinviteGlare)
611     {
612     transition(SentReinvite);
613    
614     InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");
615 daniel 5068 mDialog.send(mLastSessionModification, DialogUsageManager::None);
616 jason 4010 }
617 derek 3255 }
618 sgodin 3392 else if (timeout.type() == DumTimeout::SessionExpiration)
619     {
620     if(timeout.seq() == mSessionTimerSeq)
621     {
622 jason 4010 // this is so the app can decided to ignore this. default implementation
623     // will call end next
624     mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());
625 sgodin 3392 }
626     }
627     else if (timeout.type() == DumTimeout::SessionRefresh)
628     {
629 jason 4010 if(timeout.seq() == mSessionTimerSeq)
630 sgodin 3392 {
631 jason 4010 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 sgodin 3392 {
633 sgodin 4369 sessionRefresh();
634 sgodin 3392 }
635     }
636     }
637 derek 2990 }
638    
639 jason 4010 void
640     InviteSession::dispatchConnected(const SipMessage& msg)
641 sgodin 3392 {
642 jason 4010 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
643     std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
644    
645     switch (toEvent(msg, sdp.get()))
646 sgodin 3392 {
647 jason 4010 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 sgodin 3392
655 jason 4010 case OnInviteOffer:
656     case OnInviteReliableOffer:
657     mLastSessionModification = msg;
658     transition(ReceivedReinvite);
659 daniel 5068 mCurrentEncryptionLevel = getEncryptionLevel(msg);
660 jason 4010 //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 sgodin 4369 case OnUpdateOffer:
673 jason 4010 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 daniel 5068 mCurrentEncryptionLevel = getEncryptionLevel(msg);
680 jason 4010 handler->onOffer(getSessionHandle(), msg, *sdp);
681     break;
682    
683 sgodin 4369 case OnUpdate:
684     {
685 sgodin 5001 // ?slg? no sdp in update - just responsd immediately (likely session timer) - do we need a callback?
686 sgodin 4369 SipMessage response;
687     mLastSessionModification = msg;
688     mDialog.makeResponse(response, mLastSessionModification, 200);
689     handleSessionTimerRequest(response, mLastSessionModification);
690     send(response);
691     break;
692     }
693    
694 jason 4010 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 sgodin 4369 case OnUpdateOffer:
724 sgodin 3392 {
725 jason 4010 // 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 sgodin 3392 {
737 daniel 5068 mCurrentEncryptionLevel = getEncryptionLevel(msg);
738     setCurrentLocalSdp(msg);
739 jason 4010 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
740     handler->onAnswer(getSessionHandle(), msg, *sdp);
741 sgodin 3392 }
742 sgodin 4369 else if(mProposedLocalSdp.get())
743 sgodin 3392 {
744 sgodin 4369 // If we sent an offer in the Update Request and no answer is received
745 jason 4010 handler->onIllegalNegotiation(getSessionHandle(), msg);
746 sgodin 4369 mProposedLocalSdp.release();
747 daniel 5068 mProposedEncryptionLevel = DialogUsageManager::None;
748 jason 4010 }
749     break;
750    
751     case On491Update:
752 sgodin 4369 transition(SentUpdateGlare);
753 jason 4010 start491Timer();
754     break;
755    
756 daniel 5068 case On422Update: // session timer
757 sgodin 4394 if(msg.exists(h_MinSE))
758     {
759     // Change interval to min from 422 response
760     mSessionInterval = msg.header(h_MinSE).value();
761 sgodin 4691 mMinSE = mSessionInterval;
762 sgodin 4394 sessionRefresh();
763     }
764     else
765     {
766     // Response must contact Min_SE - if not - just ignore
767 sgodin 5001 // ?slg? callback?
768 sgodin 4394 transition(Connected);
769     mProposedLocalSdp.release();
770 daniel 5068 mProposedEncryptionLevel = DialogUsageManager::None;
771 sgodin 4394 }
772     break;
773    
774 jason 4010 case OnUpdateRejected:
775 sgodin 4369 // !jf! - callback?
776     mProposedLocalSdp.release();
777 daniel 5068 mProposedEncryptionLevel = DialogUsageManager::None;
778 sgodin 4369 transition(Connected);
779 jason 4010 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 sgodin 4369 case OnUpdateOffer:
807 jason 4010 {
808     SipMessage response;
809     mDialog.makeResponse(response, msg, 491);
810     send(response);
811     break;
812 sgodin 3392 }
813 jason 4010
814     case On1xx:
815     case On1xxEarly:
816 sgodin 5001 // Some UA's send a 100 response to a ReInvite - just ignore it
817 jason 4010 break;
818    
819     case On2xxAnswer:
820     case On2xxOffer:
821 sgodin 3392 {
822 jason 4010 transition(Connected);
823     handleSessionTimerResponse(msg);
824 daniel 5068 setCurrentLocalSdp(msg);
825 jason 4010 mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
826 daniel 5068 mCurrentEncryptionLevel = getEncryptionLevel(msg);
827 jason 4010 // !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 sgodin 4369 mProposedLocalSdp.release();
843 daniel 5068 mProposedEncryptionLevel = DialogUsageManager::None;
844 jason 4010 break;
845    
846 sgodin 4394 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 sgodin 4691 mMinSE = mSessionInterval;
852 sgodin 4394 sessionRefresh();
853     }
854     else
855     {
856     // Response must contact Min_SE - if not - just ignore
857 sgodin 5001 // ?slg? callback?
858 sgodin 4394 transition(Connected);
859     mProposedLocalSdp.release();
860 daniel 5068 mProposedEncryptionLevel = DialogUsageManager::None;
861 sgodin 4394 }
862     break;
863    
864 jason 4010 case On491Invite:
865 sgodin 4369 transition(SentReinviteGlare);
866 jason 4010 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 sgodin 5130 case On487Invite:
877     case On489Invite:
878 jason 4010 transition(Connected);
879 sgodin 4369 mProposedLocalSdp.release();
880 jason 4010 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 daniel 5068
952     assert(mProposedLocalSdp.get());
953 jason 4010 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
954 daniel 5068 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 jason 4010 }
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 sgodin 5265 case MESSAGE:
1029     dispatchMessage(msg);
1030     break;
1031 jason 4010 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 sgodin 5265 InviteSession::acceptNIT(int statusCode)
1161 jason 4010 {
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 sgodin 5265 InviteSession::rejectNIT(int statusCode)
1173 jason 4010 {
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 sgodin 5265 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 jason 4010 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 sgodin 4369 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 sgodin 4691 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 sgodin 4369 }
1241     else
1242     {
1243     msg.remove(h_SessionExpires);
1244     msg.remove(h_MinSE);
1245     }
1246     }
1247    
1248 jason 4010 void
1249 sgodin 4369 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 daniel 5068 InviteSession::setSdp(mLastSessionModification, mCurrentLocalSdp.get());
1262     mProposedLocalSdp = InviteSession::makeSdp(*mCurrentLocalSdp.get(), 0);
1263 sgodin 4369 }
1264     setSessionTimerHeaders(mLastSessionModification);
1265    
1266 sgodin 4691 InfoLog (<< "sessionRefresh: Sending " << mLastSessionModification.brief());
1267 daniel 5068 mDialog.send(mLastSessionModification, mCurrentEncryptionLevel);
1268 sgodin 4369 }
1269    
1270     void
1271 sgodin 4691 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 jason 4010 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 sgodin 4691 setSessionTimerPreferences();
1328 jason 4010
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 sgodin 3392 mSessionInterval = msg.header(h_SessionExpires).value();
1339     if(msg.header(h_SessionExpires).exists(p_refresher))
1340     {
1341 jason 4010 // Remote end specified refresher preference
1342 sgodin 4691 mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac"));
1343 sgodin 3392 }
1344     }
1345 jason 4010 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 sgodin 4691 mSessionRefresher = true;
1351 jason 4010 }
1352 sgodin 3392
1353 sgodin 4691 // Update MinSE if specified and longer than current value
1354     if(msg.exists(h_MinSE))
1355 sgodin 3392 {
1356 sgodin 4691 mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value());
1357 sgodin 3392 }
1358 sgodin 4691
1359     startSessionTimer();
1360 sgodin 3392 }
1361     }
1362    
1363 jason 4010 void
1364     InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
1365 sgodin 3392 {
1366 jason 4010 assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
1367    
1368 sgodin 3392 // If session timers are locally supported then add necessary headers to response
1369 jason 4010 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1370 sgodin 3392 {
1371 sgodin 4691 setSessionTimerPreferences();
1372 sgodin 3392
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 jason 4010 // Use Session Interval requested by remote - if none then use local settings
1381 sgodin 3392 mSessionInterval = request.header(h_SessionExpires).value();
1382     if(request.header(h_SessionExpires).exists(p_refresher))
1383     {
1384 sgodin 4691 mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
1385 sgodin 3392 }
1386     }
1387 sgodin 4691
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 sgodin 3392 }
1394 jason 4010 else
1395     {
1396     // If far end doesn't support then refresher must be local
1397 sgodin 4691 mSessionRefresher = true;
1398 jason 4010 }
1399 sgodin 3392
1400 jason 4010 // Add Session-Expires to response if required
1401 sgodin 3392 if(mSessionInterval >= 90)
1402     {
1403 jason 4010 if(farEndSupportsTimer)
1404 sgodin 3392 {
1405 jason 4010 // 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 sgodin 3392 }
1411 sgodin 4691 setSessionTimerHeaders(response);
1412     }
1413 sgodin 3392
1414 sgodin 4691 startSessionTimer();
1415 sgodin 3392 }
1416     }
1417    
1418 jason 4010 Data
1419     InviteSession::toData(State state)
1420 jason 2856 {
1421 jason 4010 switch (state)
1422 derek 3255 {
1423 jason 4010 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 derek 2961 case Terminated:
1448 jason 4010 return "InviteSession::Terminated";
1449 jason 2856
1450 jason 4010 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 sgodin 3332
1495 jason 4010 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 sgodin 3392
1524    
1525 jason 4010 void
1526     InviteSession::transition(State target)
1527     {
1528     InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
1529     mState = target;
1530     }
1531 sgodin 3392
1532 jason 4010 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 jason 2856 }
1539    
1540 jason 4010 std::auto_ptr<SdpContents>
1541     InviteSession::getSdp(const SipMessage& msg)
1542 derek 3255 {
1543 jason 4010 // !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 derek 3255 {
1549 jason 4010 SdpContents* cloned = static_cast<SdpContents*>(sdp->clone());
1550     return std::auto_ptr<SdpContents>(cloned);
1551 derek 3255 }
1552 jason 4010 else
1553     {
1554     static std::auto_ptr<SdpContents> empty;
1555     return empty;
1556     }
1557 derek 3255 }
1558    
1559 jason 4010 std::auto_ptr<SdpContents>
1560     InviteSession::makeSdp(const SdpContents& sdp)
1561 derek 2955 {
1562 jason 4010 return std::auto_ptr<SdpContents>(static_cast<SdpContents*>(sdp.clone()));
1563 derek 2955 }
1564 jason 2856
1565 daniel 5068 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 jason 4010 void
1583 daniel 5068 InviteSession::setSdp(SipMessage& msg, const SdpContents& sdp, const SdpContents* alternative)
1584 derek 3112 {
1585 jason 4010 // !jf! should deal with multipart here
1586 derek 3112
1587 jason 4010 // 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 daniel 5068 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 derek 3112 }
1601    
1602 daniel 5068 void
1603     InviteSession::setSdp(SipMessage& msg, const Contents* sdp)
1604     {
1605     assert(sdp);
1606     msg.setContents(sdp);
1607     }
1608    
1609 jason 4010 InviteSession::Event
1610     InviteSession::toEvent(const SipMessage& msg, const SdpContents* sdp)
1611 jason 2621 {
1612 jason 4010 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 derek 2961 {
1619 jason 4010 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 sgodin 3363 {
1631 jason 4010 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 sgodin 3363 {
1658 jason 4010 return On1xxAnswer;
1659 sgodin 3363 }
1660     else
1661     {
1662 jason 4010 return On1xxOffer;
1663 sgodin 3363 }
1664     }
1665     else
1666     {
1667 jason 4010 return On1xx;
1668 sgodin 3363 }
1669 jason 4010 }
1670     else
1671     {
1672     if (sdp)
1673 sgodin 3363 {
1674 jason 4010 return On1xxEarly;
1675 sgodin 3363 }
1676     else
1677     {
1678 jason 4010 return On1xx;
1679 sgodin 3363 }
1680 jason 4010 }
1681 derek 2961 }
1682 jason 4010 else if (method == INVITE && code >= 200 && code < 300)
1683 jason 2809 {
1684 jason 4010 if (sdp)
1685     {
1686     if (sentOffer)
1687 jason 2809 {
1688 jason 4010 return On2xxAnswer;
1689 jason 2809 }
1690     else
1691     {
1692 jason 4010 return On2xxOffer;
1693 jason 2809 }
1694 jason 4010 }
1695     else
1696     {
1697     return On2xx;
1698     }
1699 jason 2809 }
1700 sgodin 4394 else if (method == INVITE && code == 422)
1701     {
1702     return On422Invite;
1703     }
1704 jason 4010 else if (method == INVITE && code == 487)
1705 derek 3293 {
1706 jason 4010 return On487Invite;
1707 derek 3293 }
1708 jason 4010 else if (method == INVITE && code == 489)
1709 derek 3276 {
1710 jason 4010 return On489Invite;
1711 derek 3276 }
1712 jason 4010 else if (method == INVITE && code == 491)
1713 derek 2965 {
1714 jason 4010 return On491Invite;
1715 derek 2965 }
1716 jason 4010 else if (method == INVITE && code >= 400)
1717 derek 2965 {
1718 jason 4010 return OnInviteFailure;
1719     }
1720     else if (method == ACK)
1721     {
1722     if (sdp)
1723 derek 2965 {
1724 jason 4010 return OnAckAnswer;
1725 derek 2965 }
1726 derek 2978 else
1727     {
1728 jason 4010 return OnAck;
1729 derek 2978 }
1730 jason 4010 }
1731     else if (method == CANCEL && code == 0)
1732 jason 2809 {
1733 jason 4010 return OnCancel;
1734 jason 2809 }
1735 jason 4010 else if (method == CANCEL && code / 200 == 1)
1736 sgodin 3338 {
1737 jason 4010 return On200Cancel;
1738 sgodin 3338 }
1739 jason 4010 else if (method == CANCEL && code >= 400)
1740 sgodin 3338 {
1741 jason 4010 return OnCancelFailure;
1742 sgodin 3338 }
1743 jason 4010 else if (method == BYE && code == 0)
1744 jason 2846 {
1745 jason 4010 return OnBye;
1746 jason 2846 }
1747 jason 4010 else if (method == BYE && code / 200 == 1)
1748 derek 3101 {
1749 jason 4010 return On200Bye;
1750 derek 3101 }
1751 jason 4010 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 sgodin 4369 if (sdp)
1762     {
1763     return OnUpdateOffer;
1764     }
1765     else
1766     {
1767     return OnUpdate;
1768     }
1769 jason 4010 }
1770     else if (method == UPDATE && code / 200 == 1)
1771     {
1772     return On200Update;
1773     }
1774 sgodin 4394 else if (method == UPDATE && code == 422)
1775     {
1776     return On422Update;
1777     }
1778 jason 4010 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 sgodin 5012 //assert(0); // dispatchOthers will throw if the message type is really unknown
1793 jason 4010 return Unknown;
1794     }
1795 derek 2965 }
1796    
1797 jason 4010 void InviteSession::sendAck(const SdpContents *sdp)
1798 derek 2955 {
1799 jason 4010 SipMessage ack;
1800     mDialog.makeRequest(ack, ACK);
1801     if(sdp != 0)
1802 derek 3255 {
1803 jason 4010 setSdp(ack, *sdp);
1804 derek 3255 }
1805 jason 4010 InfoLog (<< "Sending " << ack.brief());
1806     mDialog.send(ack);
1807 derek 2981 }
1808    
1809 jason 4010 void InviteSession::sendBye()
1810 derek 2849 {
1811 jason 4010 SipMessage bye;
1812     mDialog.makeRequest(bye, BYE);
1813     InfoLog (<< "Sending " << bye.brief());
1814     mDialog.send(bye);
1815     }
1816 derek 2992
1817 daniel 5068 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 derek 2992
1833 daniel 5068 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 davidb 2575 /* ====================================================================
1856 jason 4010 * The Vovida Software License, Version 1.0
1857     *
1858 davidb 2575 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1859 jason 4010 *
1860 davidb 2575 * Redistribution and use in source and binary forms, with or without
1861     * modification, are permitted provided that the following conditions
1862     * are met:
1863 jason 4010 *
1864 davidb 2575 * 1. Redistributions of source code must retain the above copyright
1865     * notice, this list of conditions and the following disclaimer.
1866 jason 4010 *
1867 davidb 2575 * 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 jason 4010 *
1873 davidb 2575 * 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 jason 4010 *
1883 davidb 2575 * 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 jason 4010 *
1897 davidb 2575 * ====================================================================
1898 jason 4010 *
1899 davidb 2575 * 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