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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27