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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27