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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11056 - (hide annotations) (download)
Sun Mar 23 19:31:17 2014 UTC (5 years, 8 months ago) by dpocock
File MIME type: text/plain
File size: 96413 byte(s)
resip/dum: add some comments and a warning about acceptNIT and rejectNIT for SIP INFO
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 derek 7144 #include "resip/dum/BaseCreator.hxx"
7 jason 5276 #include "resip/dum/Dialog.hxx"
8 bcampen 8200 #include "resip/dum/DialogEventStateManager.hxx"
9 jason 5276 #include "resip/dum/DialogUsageManager.hxx"
10     #include "resip/dum/InviteSession.hxx"
11     #include "resip/dum/ServerInviteSession.hxx"
12     #include "resip/dum/ClientSubscription.hxx"
13     #include "resip/dum/ServerSubscription.hxx"
14     #include "resip/dum/ClientInviteSession.hxx"
15     #include "resip/dum/InviteSessionHandler.hxx"
16     #include "resip/dum/MasterProfile.hxx"
17     #include "resip/dum/UsageUseException.hxx"
18 daniel 5383 #include "resip/dum/DumHelper.hxx"
19 jason 5276 #include "rutil/Inserter.hxx"
20     #include "rutil/Logger.hxx"
21     #include "rutil/Timer.hxx"
22     #include "rutil/Random.hxx"
23     #include "rutil/compat.hxx"
24     #include "rutil/WinLeakCheck.hxx"
25 jason 2555
26 sgodin 3314 // Remove warning about 'this' use in initiator list - pointer is only stored
27 adam 6568 #if defined(WIN32) && !defined(__GNUC__)
28 jason 4010 #pragma warning( disable : 4355 ) // using this in base member initializer list
29     #pragma warning( disable : 4800 ) // forcing value to bool (performance warning)
30 sgodin 3314 #endif
31 derek 3092
32 jason 2856 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
33 jason 4010 #define THROW(msg) throw DialogUsage::Exception(msg, __FILE__,__LINE__);
34 jason 2846
35 davidb 2603 using namespace resip;
36 derek 3255 using namespace std;
37 davidb 2603
38 derek 5531 Data EndReasons[] =
39     {
40     "Not Specified",
41     "User Hung Up",
42     "Application Rejected Sdp(usually no common codec)",
43     "Illegal Sdp Negotiation",
44     "ACK not received",
45 sgodin 8203 "Session Timer Expired",
46     "Stale re-Invite"
47 derek 5531 };
48    
49 fjoanis 9053 const Data& InviteSession::getEndReasonString(InviteSession::EndReason reason)
50 derek 5531 {
51 fjoanis 9053 if(reason != InviteSession::UserSpecified)
52     {
53     assert(reason >= InviteSession::NotSpecified && reason < InviteSession::ENDREASON_MAX); //!dcm! -- necessary?
54     return EndReasons[reason];
55     }
56     else
57     {
58     return mUserEndReason;
59     }
60 derek 5531 }
61    
62 jason 4010 InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog)
63 derek 3089 : DialogUsage(dum, dialog),
64 jason 4010 mState(Undefined),
65 derek 3255 mNitState(NitComplete),
66 sgodin 8476 mServerNitState(NitComplete),
67 daniel 5757 mLastLocalSessionModification(new SipMessage),
68     mLastRemoteSessionModification(new SipMessage),
69     mInvite200(new SipMessage),
70     mLastNitResponse(new SipMessage),
71 jason 4010 mCurrentRetransmit200(0),
72 sgodin 7292 mStaleReInviteTimerSeq(1),
73 sgodin 3392 mSessionInterval(0),
74 sgodin 4691 mMinSE(90),
75     mSessionRefresher(false),
76 sgodin 3392 mSessionTimerSeq(0),
77 jason 5544 mSessionRefreshReInvite(false),
78 daniel 5830 mReferSub(true),
79 daniel 5068 mCurrentEncryptionLevel(DialogUsageManager::None),
80 derek 5531 mProposedEncryptionLevel(DialogUsageManager::None),
81     mEndReason(NotSpecified)
82 jason 2555 {
83 jason 4010 DebugLog ( << "^^^ InviteSession::InviteSession " << this);
84 jason 2846 assert(mDum.mInviteSessionHandler);
85 jason 2555 }
86    
87 derek 2858 InviteSession::~InviteSession()
88     {
89 jason 4010 DebugLog ( << "^^^ InviteSession::~InviteSession " << this);
90 derek 2858 mDialog.mInviteSession = 0;
91 sgodin 7565 while(!mNITQueue.empty())
92     {
93     delete mNITQueue.front();
94     mNITQueue.pop();
95     }
96 derek 2858 }
97 jason 2846
98 jason 4010 void
99     InviteSession::dialogDestroyed(const SipMessage& msg)
100 derek 3064 {
101 jason 4010 assert(0);
102    
103     // !jf! Is this correct? Merged from main...
104     // !jf! what reason - guessed for now?
105     //mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, msg);
106     //delete this;
107     }
108    
109 bcampen 8200 bool
110 sgodin 8726 InviteSession::hasLocalOfferAnswer() const
111     {
112     return (mCurrentLocalOfferAnswer.get());
113     }
114    
115     const Contents&
116     InviteSession::getLocalOfferAnswer() const
117     {
118     if(mCurrentLocalOfferAnswer.get())
119     {
120     return *mCurrentLocalOfferAnswer;
121     }
122     else
123     {
124     return SdpContents::Empty;
125     }
126     }
127    
128     bool
129     InviteSession::hasRemoteOfferAnswer() const
130     {
131     return (mCurrentRemoteOfferAnswer.get());
132     }
133    
134     const Contents&
135     InviteSession::getRemoteOfferAnswer() const
136     {
137     if(mCurrentRemoteOfferAnswer.get())
138     {
139     return *mCurrentRemoteOfferAnswer;
140     }
141     else
142     {
143     return SdpContents::Empty;
144     }
145     }
146    
147     bool
148     InviteSession::hasProposedRemoteOfferAnswer() const
149     {
150     return (mProposedRemoteOfferAnswer.get());
151     }
152    
153     const Contents&
154     InviteSession::getProposedRemoteOfferAnswer() const
155     {
156     if(mProposedRemoteOfferAnswer.get())
157     {
158     return *mProposedRemoteOfferAnswer;
159     }
160     else
161     {
162     return SdpContents::Empty;
163     }
164     }
165    
166     bool
167 bcampen 8200 InviteSession::hasLocalSdp() const
168     {
169 sgodin 8726 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
170     return (mCurrentLocalOfferAnswer.get());
171 bcampen 8200 }
172    
173 jason 4010 const SdpContents&
174     InviteSession::getLocalSdp() const
175     {
176 sgodin 8726 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
177     if(mCurrentLocalOfferAnswer.get())
178 sgodin 5568 {
179 sgodin 8726 const SdpContents* sdp = dynamic_cast<const SdpContents*>(mCurrentLocalOfferAnswer.get());
180     assert(sdp);
181     return *sdp;
182 sgodin 5568 }
183     else
184     {
185     return SdpContents::Empty;
186     }
187 jason 4010 }
188    
189 bcampen 8200 bool
190     InviteSession::hasRemoteSdp() const
191     {
192 sgodin 8726 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
193     return (mCurrentRemoteOfferAnswer.get());
194 bcampen 8200 }
195    
196 jason 4010 const SdpContents&
197     InviteSession::getRemoteSdp() const
198     {
199 sgodin 8726 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
200     if(mCurrentRemoteOfferAnswer.get())
201 sgodin 5568 {
202 sgodin 8726 const SdpContents* sdp = dynamic_cast<const SdpContents*>(mCurrentRemoteOfferAnswer.get());
203     assert(sdp);
204     return *sdp;
205 sgodin 5568 }
206     else
207     {
208     return SdpContents::Empty;
209     }
210 jason 4010 }
211    
212 bcampen 8200 bool
213     InviteSession::hasProposedRemoteSdp() const
214     {
215 sgodin 8726 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
216     return (mProposedRemoteOfferAnswer.get());
217 bcampen 8200 }
218    
219 nash 7084 const SdpContents&
220     InviteSession::getProposedRemoteSdp() const
221     {
222 sgodin 8726 assert(!mDum.mInviteSessionHandler->isGenericOfferAnswer());
223     if(mProposedRemoteOfferAnswer.get())
224 nash 7084 {
225 sgodin 8726 const SdpContents* sdp = dynamic_cast<const SdpContents*>(mProposedRemoteOfferAnswer.get());
226     assert(sdp);
227     return *sdp;
228 nash 7084 }
229     else
230     {
231     return SdpContents::Empty;
232     }
233     }
234    
235 jason 4010 InviteSessionHandle
236     InviteSession::getSessionHandle()
237     {
238     return InviteSessionHandle(mDum, getBaseHandle().getId());
239     }
240    
241     void InviteSession::storePeerCapabilities(const SipMessage& msg)
242     {
243     if (msg.exists(h_Allows))
244 derek 3064 {
245 jason 4010 mPeerSupportedMethods = msg.header(h_Allows);
246 derek 3064 }
247 jason 4010 if (msg.exists(h_Supporteds))
248     {
249     mPeerSupportedOptionTags = msg.header(h_Supporteds);
250     }
251     if (msg.exists(h_AcceptEncodings))
252     {
253     mPeerSupportedEncodings = msg.header(h_AcceptEncodings);
254     }
255     if (msg.exists(h_AcceptLanguages))
256     {
257     mPeerSupportedLanguages = msg.header(h_AcceptLanguages);
258     }
259 jason 5459 if (msg.exists(h_AllowEvents))
260     {
261     mPeerAllowedEvents = msg.header(h_AllowEvents);
262     }
263 jason 4010 if (msg.exists(h_Accepts))
264     {
265     mPeerSupportedMimeTypes = msg.header(h_Accepts);
266     }
267 sgodin 6259 if (msg.exists(h_UserAgent))
268     {
269     mPeerUserAgent = msg.header(h_UserAgent).value();
270     }
271 derek 3064 }
272    
273 jason 4010 bool
274     InviteSession::updateMethodSupported() const
275 derek 3255 {
276 jason 4010 // Check if Update is supported locally
277     if(mDum.getMasterProfile()->isMethodSupported(UPDATE))
278     {
279     // Check if peer supports UPDATE
280     return mPeerSupportedMethods.find(Token("UPDATE"));
281     }
282     return false;
283     }
284 sgodin 3392
285 jason 4010 bool
286     InviteSession::isConnected() const
287     {
288     switch (mState)
289     {
290     case Connected:
291     case SentUpdate:
292     case SentUpdateGlare:
293     case SentReinvite:
294     case SentReinviteGlare:
295 sgodin 5555 case SentReinviteNoOffer:
296     case SentReinviteAnswered:
297     case SentReinviteNoOfferGlare:
298 jason 4010 case ReceivedUpdate:
299     case ReceivedReinvite:
300     case ReceivedReinviteNoOffer:
301 dragos 6559 case ReceivedReinviteSentOffer:
302 jason 4010 case Answered:
303     case WaitingToOffer:
304 sgodin 6121 case WaitingToRequestOffer:
305 jason 4010 return true;
306    
307     default:
308     return false;
309     }
310 derek 3255 }
311 derek 3064
312 jason 4010 bool
313     InviteSession::isEarly() const
314 derek 3064 {
315 jason 4010 switch (mState)
316 derek 3064 {
317 jason 4010 case UAC_Early:
318     case UAC_EarlyWithOffer:
319     case UAC_EarlyWithAnswer:
320     case UAC_SentUpdateEarly:
321     case UAC_ReceivedUpdateEarly:
322 sgodin 5555 case UAC_SentAnswer:
323 jason 4010 case UAC_QueuedUpdate:
324 sgodin 5555 return true;
325     default:
326     return false;
327     }
328     }
329 jason 5466
330 sgodin 5555 bool
331     InviteSession::isAccepted() const
332     {
333     switch (mState)
334     {
335 jason 5466 case UAS_Start:
336     case UAS_Offer:
337     case UAS_OfferProvidedAnswer:
338     case UAS_EarlyOffer:
339     case UAS_EarlyProvidedAnswer:
340 sgodin 10695
341     case UAS_NoOffer:
342     case UAS_ProvidedOffer:
343 jason 5466 case UAS_EarlyNoOffer:
344 sgodin 10695 case UAS_EarlyProvidedOffer:
345     //case UAS_Accepted: // Obvious
346     //case UAS_WaitingToOffer: // We have accepted here and are waiting for ACK to Offer
347     //case UAS_WaitingToRequestOffer: // We have accepted here and are waiting for ACK to request an offer
348    
349     //case UAS_AcceptedWaitingAnswer: // Obvious
350     case UAS_OfferReliable:
351     case UAS_OfferReliableProvidedAnswer:
352     case UAS_NoOfferReliable:
353     case UAS_ProvidedOfferReliable:
354     case UAS_FirstSentOfferReliable:
355 derek 7144 case UAS_FirstSentAnswerReliable:
356 sgodin 10695 case UAS_NoAnswerReliableWaitingPrack:
357 derek 7144 case UAS_NegotiatedReliable:
358 sgodin 10695 case UAS_NoAnswerReliable:
359     case UAS_SentUpdate:
360     //case UAS_SentUpdateAccepted: // we have accepted here
361     case UAS_SentUpdateGlare:
362     case UAS_ReceivedUpdate:
363     //case UAS_ReceivedUpdateWaitingAnswer: // happens only after accept is called
364     //case UAS_WaitingToHangup: // always from an accepted state
365 sgodin 5602 return false;
366 sgodin 10695
367 sgodin 5602 default:
368 jason 4010 return true;
369 derek 3064 }
370 jason 4010 }
371 derek 3064
372 jason 4010 bool
373     InviteSession::isTerminated() const
374     {
375     switch (mState)
376     {
377     case Terminated:
378     case WaitingToTerminate:
379 sgodin 5377 case WaitingToHangup:
380 jason 4010 case UAC_Cancelled:
381     case UAS_WaitingToHangup:
382     return true;
383     default:
384     return false;
385     }
386     }
387    
388 jmatthewsr 8161 EncodeStream&
389     InviteSession::dump(EncodeStream& strm) const
390 jason 4010 {
391     strm << "INVITE: " << mId
392     << " " << toData(mState)
393     << " ADDR=" << myAddr()
394     << " PEER=" << peerAddr();
395     return strm;
396     }
397    
398 jason 2866 void
399 sgodin 5555 InviteSession::requestOffer()
400     {
401     switch (mState)
402     {
403     case Connected:
404     case WaitingToRequestOffer:
405 sgodin 6121 case UAS_WaitingToRequestOffer:
406 sgodin 5555 transition(SentReinviteNoOffer);
407 daniel 5757 mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
408 sgodin 7292 startStaleReInviteTimer();
409 sgodin 8727 mLastLocalSessionModification->setContents(0); // Clear the contents from the INVITE
410 daniel 5757 setSessionTimerHeaders(*mLastLocalSessionModification);
411 sgodin 5555
412 daniel 5757 InfoLog (<< "Sending " << mLastLocalSessionModification->brief());
413    
414 sgodin 5555 // call send to give app an chance to adorn the message.
415 sgodin 5747 send(mLastLocalSessionModification);
416 sgodin 5555 break;
417    
418     case Answered:
419     // queue the offer to be sent after the ACK is received
420     transition(WaitingToRequestOffer);
421     break;
422    
423     // ?slg? Can we handle all of the states listed in isConnected() ???
424     default:
425     WarningLog (<< "Can't requestOffer when not in Connected state");
426     throw DialogUsage::Exception("Can't request an offer", __FILE__,__LINE__);
427     }
428     }
429    
430     void
431 sgodin 8726 InviteSession::provideOffer(const Contents& offer,
432 daniel 5068 DialogUsageManager::EncryptionLevel level,
433 sgodin 8726 const Contents* alternative)
434 jason 2866 {
435 jason 4010 switch (mState)
436 derek 2965 {
437 jason 4010 case Connected:
438     case WaitingToOffer:
439     case UAS_WaitingToOffer:
440 sgodin 8690 transition(SentReinvite);
441     mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
442     startStaleReInviteTimer();
443    
444 sgodin 9884 setSessionTimerHeaders(*mLastLocalSessionModification);
445 jason 4010
446 daniel 5757 InfoLog (<< "Sending " << mLastLocalSessionModification->brief());
447 sgodin 8726 InviteSession::setOfferAnswer(*mLastLocalSessionModification, offer, alternative);
448     mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer, alternative);
449 daniel 5068 mProposedEncryptionLevel = level;
450 daniel 5757 DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mProposedEncryptionLevel);
451    
452 daniel 5505 // call send to give app an chance to adorn the message.
453 sgodin 5747 send(mLastLocalSessionModification);
454 jason 4010 break;
455    
456     case Answered:
457     // queue the offer to be sent after the ACK is received
458     transition(WaitingToOffer);
459 daniel 5068 mProposedEncryptionLevel = level;
460 sgodin 8726 mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer, alternative);
461 jason 4010 break;
462    
463 derek 5355 case ReceivedReinviteNoOffer:
464 sgodin 8726 assert(!mProposedRemoteOfferAnswer.get());
465 derek 5355 transition(ReceivedReinviteSentOffer);
466 daniel 5757 mDialog.makeResponse(*mInvite200, *mLastRemoteSessionModification, 200);
467     handleSessionTimerRequest(*mInvite200, *mLastRemoteSessionModification);
468 sgodin 8726 InviteSession::setOfferAnswer(*mInvite200, offer, 0);
469     mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer);
470 derek 5355
471 daniel 5757 InfoLog (<< "Sending " << mInvite200->brief());
472     DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
473 daniel 5505 send(mInvite200);
474 derek 5355 startRetransmit200Timer();
475     break;
476 sgodin 6836
477 jason 4010 default:
478 sgodin 6836 WarningLog (<< "Incorrect state to provideOffer: " << toData(mState));
479 jason 4010 throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
480 derek 2965 }
481 jason 2866 }
482    
483 sgodin 7044 class InviteSessionProvideOfferExCommand : public DumCommandAdapter
484 nash 7042 {
485 sgodin 7044 public:
486 fjoanis 9956 InviteSessionProvideOfferExCommand(const InviteSessionHandle& inviteSessionHandle,
487 sgodin 8726 const Contents& offer,
488 sgodin 7044 DialogUsageManager::EncryptionLevel level,
489 sgodin 8726 const Contents* alternative)
490 fjoanis 9956 : mInviteSessionHandle(inviteSessionHandle),
491 sgodin 8726 mOffer(offer.clone()),
492     mLevel(level),
493     mAlternative(alternative ? alternative->clone() : 0)
494 nash 7042 {
495 sgodin 7044 }
496 nash 7042
497 sgodin 7044 virtual void executeCommand()
498     {
499 fjoanis 9956 if(mInviteSessionHandle.isValid())
500     {
501     mInviteSessionHandle->provideOffer(*mOffer, mLevel, mAlternative.get());
502     }
503 sgodin 7044 }
504 nash 7042
505 jmatthewsr 8161 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
506 sgodin 7044 {
507     return strm << "InviteSessionProvideOfferExCommand";
508     }
509     private:
510 fjoanis 9956 InviteSessionHandle mInviteSessionHandle;
511 sgodin 8726 std::auto_ptr<const Contents> mOffer;
512 sgodin 7044 DialogUsageManager::EncryptionLevel mLevel;
513 sgodin 8726 std::auto_ptr<const Contents> mAlternative;
514 sgodin 7044 };
515 nash 7042
516 sgodin 7044 void
517 sgodin 8726 InviteSession::provideOfferCommand(const Contents& offer, DialogUsageManager::EncryptionLevel level, const Contents* alternative)
518 sgodin 7044 {
519 fjoanis 9956 mDum.post(new InviteSessionProvideOfferExCommand(getSessionHandle(), offer, level, alternative));
520 nash 7042 }
521    
522     void
523 sgodin 8726 InviteSession::provideOffer(const Contents& offer)
524 daniel 5068 {
525     return provideOffer(offer, mCurrentEncryptionLevel, 0);
526     }
527    
528 sgodin 7044 class InviteSessionProvideOfferCommand : public DumCommandAdapter
529 nash 7042 {
530 sgodin 7044 public:
531 fjoanis 9956 InviteSessionProvideOfferCommand(const InviteSessionHandle& inviteSessionHandle, const Contents& offer)
532     : mInviteSessionHandle(inviteSessionHandle),
533 sgodin 8726 mOffer(offer.clone())
534 nash 7042 {
535 sgodin 7044 }
536 nash 7042
537 sgodin 7044 virtual void executeCommand()
538     {
539 fjoanis 9956 if(mInviteSessionHandle.isValid())
540     {
541     mInviteSessionHandle->provideOffer(*mOffer);
542     }
543 sgodin 7044 }
544 nash 7042
545 jmatthewsr 8161 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
546 sgodin 7044 {
547     return strm << "InviteSessionProvideOfferCommand";
548     }
549     private:
550 fjoanis 9956 InviteSessionHandle mInviteSessionHandle;
551 sgodin 8726 std::auto_ptr<const Contents> mOffer;
552 sgodin 7044 };
553 nash 7042
554 sgodin 7044 void
555 sgodin 8726 InviteSession::provideOfferCommand(const Contents& offer)
556 sgodin 7044 {
557 fjoanis 9956 mDum.post(new InviteSessionProvideOfferCommand(getSessionHandle(), offer));
558 nash 7042 }
559    
560     void
561 sgodin 8726 InviteSession::provideAnswer(const Contents& answer)
562 jason 2866 {
563 jason 4010 switch (mState)
564 derek 2965 {
565 jason 4010 case ReceivedReinvite:
566     transition(Connected);
567 daniel 5757 mDialog.makeResponse(*mInvite200, *mLastRemoteSessionModification, 200);
568     handleSessionTimerRequest(*mInvite200, *mLastRemoteSessionModification);
569 sgodin 8726 InviteSession::setOfferAnswer(*mInvite200, answer, 0);
570     mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
571     mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
572 daniel 5757 InfoLog (<< "Sending " << mInvite200->brief());
573     DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
574 daniel 5505 send(mInvite200);
575 jason 4010 startRetransmit200Timer();
576     break;
577    
578     case ReceivedUpdate: // same as ReceivedReinvite case.
579     {
580     transition(Connected);
581    
582 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
583     mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
584     handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
585 sgodin 8726 InviteSession::setOfferAnswer(*response, answer, 0);
586     mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
587     mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
588 daniel 5757 InfoLog (<< "Sending " << response->brief());
589     DumHelper::setOutgoingEncryptionLevel(*response, mCurrentEncryptionLevel);
590 daniel 5505 send(response);
591 jason 4010 break;
592     }
593    
594 sgodin 5555 case SentReinviteAnswered:
595     transition(Connected);
596 sgodin 5747 sendAck(&answer);
597 sgodin 5555
598 sgodin 8726 mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
599     mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
600 sgodin 5555 break;
601    
602 jason 4010 default:
603 sgodin 6836 WarningLog (<< "Incorrect state to provideAnswer: " << toData(mState));
604     throw DialogUsage::Exception("Can't provide an answer", __FILE__,__LINE__);
605 derek 2965 }
606 jason 2866 }
607    
608 nash 7042 class InviteSessionProvideAnswerCommand : public DumCommandAdapter
609     {
610     public:
611 fjoanis 9956 InviteSessionProvideAnswerCommand(const InviteSessionHandle& inviteSessionHandle, const Contents& answer)
612     : mInviteSessionHandle(inviteSessionHandle),
613 sgodin 8726 mAnswer(answer.clone())
614 nash 7042 {
615     }
616    
617     virtual void executeCommand()
618     {
619 fjoanis 9956 if(mInviteSessionHandle.isValid())
620     {
621     mInviteSessionHandle->provideAnswer(*mAnswer);
622     }
623 nash 7042 }
624    
625 jmatthewsr 8161 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
626 nash 7042 {
627     return strm << "InviteSessionProvideAnswerCommand";
628     }
629     private:
630 fjoanis 9956 InviteSessionHandle mInviteSessionHandle;
631 sgodin 8726 std::auto_ptr<const Contents> mAnswer;
632 nash 7042 };
633    
634 jason 4010 void
635 sgodin 8726 InviteSession::provideAnswerCommand(const Contents& answer)
636 nash 7042 {
637 fjoanis 9956 mDum.post(new InviteSessionProvideAnswerCommand(getSessionHandle(), answer));
638 nash 7042 }
639    
640     void
641 jason 4010 InviteSession::end()
642 jason 2555 {
643 nash 7085 end(NotSpecified);
644 derek 5531 }
645    
646     void
647 fjoanis 9053 InviteSession::end(const Data& userReason)
648     {
649     mUserEndReason = userReason;
650     end(UserSpecified);
651     }
652    
653     void
654 derek 5531 InviteSession::end(EndReason reason)
655     {
656 derek 5645 if (mEndReason == NotSpecified)
657 derek 5531 {
658     mEndReason = reason;
659     }
660    
661 jason 4010 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
662    
663     switch (mState)
664     {
665     case Connected:
666 sgodin 5377 case SentUpdate:
667     case SentUpdateGlare:
668     case SentReinviteGlare:
669 sgodin 5555 case SentReinviteNoOfferGlare:
670     case SentReinviteAnswered:
671 jason 4010 {
672     // !jf! do we need to store the BYE somewhere?
673 Danweber 9098 // .dw. BYE message handled
674     SharedPtr<SipMessage> msg = sendBye();
675 jason 4010 transition(Terminated);
676 Danweber 9098 handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
677 jason 4010 break;
678     }
679    
680     case SentReinvite:
681 sgodin 5555 case SentReinviteNoOffer:
682 jason 4010 transition(WaitingToTerminate);
683     break;
684    
685 sgodin 5377 case Answered:
686     case WaitingToOffer:
687 sgodin 6121 case WaitingToRequestOffer:
688 sgodin 5377 case ReceivedReinviteSentOffer:
689 sgodin 6121 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet - wait for it
690     {
691     transition(WaitingToHangup);
692     }
693     else
694     {
695     // ACK has likely timedout - hangup immediately
696 Danweber 9098 SharedPtr<SipMessage> msg = sendBye();
697 sgodin 6121 transition(Terminated);
698 Danweber 9098 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
699 sgodin 6121 }
700 sgodin 5377 break;
701    
702 jason 4010 case ReceivedUpdate:
703     case ReceivedReinvite:
704     case ReceivedReinviteNoOffer:
705     {
706 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
707     mDialog.makeResponse(*response, *mLastRemoteSessionModification, 488);
708     InfoLog (<< "Sending " << response->brief());
709 daniel 5505 send(response);
710 jason 4010
711 Danweber 9098 SharedPtr<SipMessage> msg = sendBye();
712 jason 4010 transition(Terminated);
713 Danweber 9098 handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
714 jason 4010 break;
715     }
716    
717 sgodin 5377 case WaitingToTerminate: // ?slg? Why is this here?
718 jason 4010 {
719 Danweber 9098 SharedPtr<SipMessage> msg = sendBye();
720 jason 4010 transition(Terminated);
721 Danweber 9098 handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
722 jason 4010 break;
723     }
724    
725     case Terminated:
726     // no-op.
727     break;
728    
729     default:
730     assert(0);
731     break;
732     }
733 jason 2555 }
734    
735 nash 7042 class InviteSessionEndCommand : public DumCommandAdapter
736     {
737     public:
738 fjoanis 9956 InviteSessionEndCommand(const InviteSessionHandle& inviteSessionHandle, InviteSession::EndReason reason)
739     : mInviteSessionHandle(inviteSessionHandle),
740 nash 7042 mReason(reason)
741     {
742     }
743    
744     virtual void executeCommand()
745     {
746 fjoanis 9956 if(mInviteSessionHandle.isValid())
747     {
748     mInviteSessionHandle->end(mReason);
749     }
750 nash 7042 }
751    
752 jmatthewsr 8161 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
753 nash 7042 {
754     return strm << "InviteSessionEndCommand";
755     }
756     private:
757 fjoanis 9956 InviteSessionHandle mInviteSessionHandle;
758 nash 7042 InviteSession::EndReason mReason;
759     };
760    
761 jason 4010 void
762 nash 7042 InviteSession::endCommand(EndReason reason)
763     {
764 fjoanis 9956 mDum.post(new InviteSessionEndCommand(getSessionHandle(), reason));
765 nash 7042 }
766    
767     void
768 jason 4010 InviteSession::reject(int statusCode, WarningCategory *warning)
769 jason 2555 {
770 jason 4010 switch (mState)
771     {
772     case ReceivedUpdate:
773     case ReceivedReinvite:
774     case ReceivedReinviteNoOffer:
775     {
776     transition(Connected);
777    
778 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
779     mDialog.makeResponse(*response, *mLastRemoteSessionModification, statusCode);
780 jason 4010 if(warning)
781     {
782 daniel 5757 response->header(h_Warnings).push_back(*warning);
783 jason 4010 }
784 daniel 5757 InfoLog (<< "Sending " << response->brief());
785 daniel 5505 send(response);
786 jason 4010 break;
787     }
788 fjoanis 9267 // Sent a reINVITE no offer and received a 200-offer.
789     // Simply send an ACK without an answer and stay in Connected.
790     case SentReinviteAnswered:
791     {
792     InfoLog (<< "Not sending " << statusCode << " error since transaction"
793     "already completed, sending answer-less ACK");
794     transition(Connected);
795     sendAck();
796     break;
797     }
798 jason 4010 default:
799     assert(0);
800     break;
801     }
802 jason 2555 }
803 davidb 2575
804 nash 7042 class InviteSessionRejectCommand : public DumCommandAdapter
805     {
806     public:
807 fjoanis 9956 InviteSessionRejectCommand(const InviteSessionHandle& inviteSessionHandle, int code, WarningCategory* warning)
808     : mInviteSessionHandle(inviteSessionHandle),
809 nash 7042 mCode(code),
810     mWarning(warning?new WarningCategory(*warning):0)
811     {
812     }
813    
814     virtual void executeCommand()
815     {
816 fjoanis 9956 if(mInviteSessionHandle.isValid())
817     {
818     mInviteSessionHandle->reject(mCode, mWarning.get());
819     }
820 nash 7042 }
821    
822 jmatthewsr 8161 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
823 nash 7042 {
824     return strm << "InviteSessionRejectCommand";
825     }
826     private:
827 fjoanis 9956 InviteSessionHandle mInviteSessionHandle;
828 nash 7042 int mCode;
829     std::auto_ptr<WarningCategory> mWarning;
830     };
831    
832 jason 4010 void
833 nash 7042 InviteSession::rejectCommand(int code, WarningCategory *warning)
834     {
835 fjoanis 9956 mDum.post(new InviteSessionRejectCommand(getSessionHandle(), code, warning));
836 nash 7042 }
837    
838     void
839 jason 4010 InviteSession::targetRefresh(const NameAddr& localUri)
840 jason 2941 {
841 sgodin 5001 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
842 jason 4010 {
843 sgodin 6755 mDialog.mLocalContact = localUri;
844     sessionRefresh();
845 jason 4010 }
846     else
847     {
848     WarningLog (<< "Can't targetRefresh before Connected");
849     throw UsageUseException("targetRefresh not allowed in this context", __FILE__, __LINE__);
850     }
851 jason 2941 }
852    
853 jason 2856 void
854 daniel 5830 InviteSession::refer(const NameAddr& referTo, bool referSub)
855 jason 4010 {
856 sgodin 7544 refer(referTo,std::auto_ptr<resip::Contents>(0),referSub);
857     }
858     void
859     InviteSession::refer(const NameAddr& referTo, std::auto_ptr<resip::Contents> contents,bool referSub)
860     {
861 sgodin 5001 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
862 jason 4010 {
863 daniel 5757 SharedPtr<SipMessage> refer(new SipMessage());
864     mDialog.makeRequest(*refer, REFER);
865     refer->header(h_ReferTo) = referTo;
866 sgodin 7200 refer->header(h_ReferredBy) = myAddr();
867 vann 7165 refer->header(h_ReferredBy).remove(p_tag); // tag-param not permitted in rfc3892; not the same as generic-param
868 sgodin 7544 refer->setContents(contents);
869 daniel 5830 if (!referSub)
870     {
871     refer->header(h_ReferSub).value() = "false";
872 sgodin 6617 refer->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
873 daniel 5830 }
874    
875 sgodin 7565 if(mNitState == NitComplete)
876     {
877     mNitState = NitProceeding;
878     mReferSub = referSub;
879 fjoanis 8908 mLastSentNITRequest = refer;
880 sgodin 7565 send(refer);
881     return;
882     }
883     mNITQueue.push(new QueuedNIT(refer,referSub));
884 sgodin 8453 InfoLog(<< "refer - queuing NIT:" << refer->brief());
885 sgodin 7565 return;
886 jason 4010 }
887     else
888     {
889     WarningLog (<< "Can't refer before Connected");
890     assert(0);
891     throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
892     }
893     }
894    
895 fjoanis 8908 const SharedPtr<SipMessage>
896     InviteSession::getLastSentNITRequest() const
897     {
898     return mLastSentNITRequest;
899     }
900    
901 sgodin 7565 void
902     InviteSession::nitComplete()
903     {
904     mNitState = NitComplete;
905     if (mNITQueue.size())
906     {
907     QueuedNIT *qn=mNITQueue.front();
908     mNITQueue.pop();
909     mNitState = NitProceeding;
910     mReferSub = qn->referSubscription();
911 fjoanis 8908 mLastSentNITRequest = qn->getNIT();
912     InfoLog(<< "checkNITQueue - sending queued NIT:" << mLastSentNITRequest->brief());
913     send(mLastSentNITRequest);
914 sgodin 7565 delete qn;
915     }
916     }
917    
918 sgodin 7044 class InviteSessionReferCommand : public DumCommandAdapter
919 nash 7042 {
920 sgodin 7044 public:
921 fjoanis 9956 InviteSessionReferCommand(const InviteSessionHandle& inviteSessionHandle, const NameAddr& referTo, bool referSub)
922     : mInviteSessionHandle(inviteSessionHandle),
923 sgodin 7044 mReferTo(referTo),
924     mReferSub(referSub)
925 nash 7042 {
926    
927 sgodin 7044 }
928 nash 7042
929 sgodin 7044 virtual void executeCommand()
930     {
931 fjoanis 9956 if(mInviteSessionHandle.isValid())
932     {
933     mInviteSessionHandle->refer(mReferTo, mReferSub);
934     }
935 sgodin 7044 }
936 nash 7042
937 jmatthewsr 8161 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
938 sgodin 7044 {
939     return strm << "InviteSessionReferCommand";
940     }
941 nash 7042
942 sgodin 7044 private:
943 fjoanis 9956 InviteSessionHandle mInviteSessionHandle;
944 sgodin 7044 NameAddr mReferTo;
945     bool mReferSub;
946     };
947 nash 7042
948 sgodin 7044 void
949     InviteSession::referCommand(const NameAddr& referTo, bool referSub)
950     {
951 fjoanis 9956 mDum.post(new InviteSessionReferCommand(getSessionHandle(), referTo, referSub));
952 nash 7042 }
953    
954     void
955 daniel 5830 InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
956 jason 4010 {
957 arosenberg 9006 refer(referTo,sessionToReplace,std::auto_ptr<resip::Contents>(0),referSub);
958     }
959    
960     void
961     InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace, std::auto_ptr<resip::Contents> contents, bool referSub)
962     {
963 jason 4010 if (!sessionToReplace.isValid())
964     {
965     throw UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__);
966     }
967    
968 sgodin 8930 CallId replaces;
969     DialogId id = sessionToReplace->mDialog.getId();
970     replaces.value() = id.getCallId();
971     replaces.param(p_toTag) = id.getRemoteTag();
972     replaces.param(p_fromTag) = id.getLocalTag();
973    
974 arosenberg 9006 refer(referTo, replaces, contents, referSub);
975 sgodin 8930 }
976    
977     void
978     InviteSession::refer(const NameAddr& referTo, const CallId& replaces, bool referSub)
979     {
980 arosenberg 9006 refer(referTo,replaces,std::auto_ptr<resip::Contents>(0),referSub);
981     }
982    
983     void
984     InviteSession::refer(const NameAddr& referTo, const CallId& replaces, std::auto_ptr<resip::Contents> contents, bool referSub)
985     {
986 sgodin 5001 if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
987 jason 4010 {
988 daniel 5757 SharedPtr<SipMessage> refer(new SipMessage());
989     mDialog.makeRequest(*refer, REFER);
990 arosenberg 9006 refer->setContents(contents);
991 daniel 5757 refer->header(h_ReferTo) = referTo;
992 jason 7101 refer->header(h_ReferredBy) = myAddr();
993 vann 7165 refer->header(h_ReferredBy).remove(p_tag);
994    
995 daniel 5757 refer->header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces;
996 daniel 5830
997     if (!referSub)
998     {
999     refer->header(h_ReferSub).value() = "false";
1000 sgodin 6617 refer->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
1001 daniel 5830 }
1002    
1003 sgodin 7565 if(mNitState == NitComplete)
1004     {
1005     mNitState = NitProceeding;
1006     mReferSub = referSub;
1007 fjoanis 8908 mLastSentNITRequest = refer;
1008 sgodin 7565 send(refer);
1009     return;
1010     }
1011     mNITQueue.push(new QueuedNIT(refer,referSub));
1012 sgodin 8453 InfoLog(<< "refer/replace - queuing NIT:" << refer->brief());
1013 sgodin 7565 return;
1014 jason 4010 }
1015     else
1016     {
1017     WarningLog (<< "Can't refer before Connected");
1018     assert(0);
1019     throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
1020     }
1021     }
1022    
1023 sgodin 7044 class InviteSessionReferExCommand : public DumCommandAdapter
1024 nash 7042 {
1025 sgodin 7044 public:
1026 fjoanis 9956 InviteSessionReferExCommand(const InviteSessionHandle& inviteSessionHandle, const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
1027     : mInviteSessionHandle(inviteSessionHandle),
1028 sgodin 7100 mSessionToReplace(sessionToReplace),
1029 sgodin 7044 mReferTo(referTo),
1030     mReferSub(referSub)
1031 nash 7042 {
1032 sgodin 7044 }
1033 nash 7042
1034 sgodin 7044 virtual void executeCommand()
1035     {
1036 fjoanis 9956 if(mInviteSessionHandle.isValid())
1037     {
1038     mInviteSessionHandle->refer(mReferTo, mSessionToReplace, mReferSub);
1039     }
1040 sgodin 7044 }
1041 nash 7042
1042 jmatthewsr 8161 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
1043 sgodin 7044 {
1044     return strm << "InviteSessionReferExCommand";
1045     }
1046 nash 7042
1047 sgodin 7044 private:
1048 fjoanis 9956 InviteSessionHandle mInviteSessionHandle;
1049 sgodin 7044 InviteSessionHandle mSessionToReplace;
1050     NameAddr mReferTo;
1051     bool mReferSub;
1052     };
1053 nash 7042
1054 sgodin 7044 void
1055     InviteSession::referCommand(const NameAddr& referTo, InviteSessionHandle sessionToReplace, bool referSub)
1056     {
1057 fjoanis 9956 mDum.post(new InviteSessionReferExCommand(getSessionHandle(), referTo, sessionToReplace, referSub));
1058 nash 7042 }
1059    
1060     void
1061 jason 4010 InviteSession::info(const Contents& contents)
1062     {
1063 sgodin 8842 SharedPtr<SipMessage> info(new SipMessage());
1064     mDialog.makeRequest(*info, INFO);
1065     // !jf! handle multipart here
1066     info->setContents(&contents);
1067     DumHelper::setOutgoingEncryptionLevel(*info, mCurrentEncryptionLevel);
1068     if (mNitState == NitComplete)
1069 jason 4010 {
1070 sgodin 8842 mNitState = NitProceeding;
1071 fjoanis 8908 mLastSentNITRequest = info;
1072 sgodin 8842 send(info);
1073 sgodin 7565 return;
1074 jason 4010 }
1075 sgodin 8842 mNITQueue.push(new QueuedNIT(info));
1076     InfoLog(<< "info - queuing NIT:" << info->brief());
1077     return;
1078 jason 4010 }
1079    
1080 nash 7042 class InviteSessionInfoCommand : public DumCommandAdapter
1081     {
1082     public:
1083 fjoanis 9956 InviteSessionInfoCommand(const InviteSessionHandle& inviteSessionHandle, const Contents& contents)
1084     : mInviteSessionHandle(inviteSessionHandle),
1085 nash 7042 mContents(contents.clone())
1086     {
1087     }
1088    
1089     virtual void executeCommand()
1090     {
1091 fjoanis 9956 if(mInviteSessionHandle.isValid())
1092     {
1093     mInviteSessionHandle->info(*mContents);
1094     }
1095 nash 7042 }
1096    
1097 jmatthewsr 8161 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
1098 nash 7042 {
1099     return strm << "InviteSessionInfoCommand";
1100     }
1101     private:
1102 fjoanis 9956 InviteSessionHandle mInviteSessionHandle;
1103 nash 7042 std::auto_ptr<Contents> mContents;
1104     };
1105    
1106 jason 4010 void
1107 nash 7042 InviteSession::infoCommand(const Contents& contents)
1108     {
1109 fjoanis 9956 mDum.post(new InviteSessionInfoCommand(getSessionHandle(), contents));
1110 nash 7042 }
1111    
1112     void
1113 sgodin 5265 InviteSession::message(const Contents& contents)
1114     {
1115 sgodin 8842 SharedPtr<SipMessage> message(new SipMessage());
1116     mDialog.makeRequest(*message, MESSAGE);
1117     // !jf! handle multipart here
1118     message->setContents(&contents);
1119     DumHelper::setOutgoingEncryptionLevel(*message, mCurrentEncryptionLevel);
1120     InfoLog (<< "Trying to send MESSAGE: " << message);
1121     if (mNitState == NitComplete)
1122 sgodin 5265 {
1123 sgodin 8842 mNitState = NitProceeding;
1124 fjoanis 8908 mLastSentNITRequest = message;
1125 sgodin 8842 send(message);
1126 sgodin 7565 return;
1127 sgodin 5265 }
1128 sgodin 8842 mNITQueue.push(new QueuedNIT(message));
1129     InfoLog(<< "message - queuing NIT:" << message->brief());
1130     return;
1131 sgodin 5265 }
1132    
1133 nash 7042 class InviteSessionMessageCommand : public DumCommandAdapter
1134     {
1135     public:
1136 fjoanis 9956 InviteSessionMessageCommand(const InviteSessionHandle& inviteSessionHandle, const Contents& contents)
1137     : mInviteSessionHandle(inviteSessionHandle),
1138 nash 7042 mContents(contents.clone())
1139     {
1140     }
1141    
1142     virtual void executeCommand()
1143     {
1144 fjoanis 9956 if(mInviteSessionHandle.isValid())
1145     {
1146     mInviteSessionHandle->message(*mContents);
1147     }
1148 nash 7042 }
1149    
1150 jmatthewsr 8161 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
1151 nash 7042 {
1152     return strm << "InviteSessionMessageCommand";
1153     }
1154     private:
1155 fjoanis 9956 InviteSessionHandle mInviteSessionHandle;
1156 nash 7042 std::auto_ptr<Contents> mContents;
1157     };
1158    
1159    
1160 sgodin 5265 void
1161 nash 7042 InviteSession::messageCommand(const Contents& contents)
1162     {
1163 fjoanis 9956 mDum.post(new InviteSessionMessageCommand(getSessionHandle(), contents));
1164 nash 7042 }
1165    
1166     void
1167 jason 4010 InviteSession::dispatch(const SipMessage& msg)
1168     {
1169 sgodin 5586 // Look for 2xx retransmissions - resend ACK and filter out of state machine
1170 bcampen 7206 if(msg.header(h_CSeq).method() == INVITE && msg.isResponse() && msg.header(h_StatusLine).statusCode() / 100 == 2)
1171 sgodin 5586 {
1172 jmatthewsr 7238 AckMap::iterator i = mAcks.find(msg.getTransactionId());
1173 sgodin 5586 if (i != mAcks.end())
1174     {
1175     send(i->second); // resend ACK
1176     return;
1177     }
1178     }
1179    
1180 jason 4010 // !jf! do we need to handle 3xx here or is it handled elsewhere?
1181     switch (mState)
1182     {
1183     case Connected:
1184     dispatchConnected(msg);
1185     break;
1186     case SentUpdate:
1187     dispatchSentUpdate(msg);
1188 daniel 5591 break;
1189 jason 4010 case SentReinvite:
1190     dispatchSentReinvite(msg);
1191     break;
1192 sgodin 5555 case SentReinviteNoOffer:
1193     dispatchSentReinviteNoOffer(msg);
1194     break;
1195     case SentReinviteAnswered:
1196     dispatchSentReinviteAnswered(msg);
1197     break;
1198 jason 4010 case SentUpdateGlare:
1199     case SentReinviteGlare:
1200     // The behavior is the same except for timer which is handled in dispatch(Timer)
1201     dispatchGlare(msg);
1202     break;
1203 sgodin 5555 case SentReinviteNoOfferGlare:
1204     dispatchReinviteNoOfferGlare(msg);
1205     break;
1206 jason 4010 case ReceivedUpdate:
1207     case ReceivedReinvite:
1208     case ReceivedReinviteNoOffer:
1209     dispatchReceivedUpdateOrReinvite(msg);
1210     break;
1211 derek 5355 case ReceivedReinviteSentOffer:
1212     dispatchReceivedReinviteSentOffer(msg);
1213     break;
1214 jason 4010 case Answered:
1215     dispatchAnswered(msg);
1216     break;
1217     case WaitingToOffer:
1218     dispatchWaitingToOffer(msg);
1219     break;
1220 sgodin 5555 case WaitingToRequestOffer:
1221     dispatchWaitingToRequestOffer(msg);
1222     break;
1223 jason 4010 case WaitingToTerminate:
1224     dispatchWaitingToTerminate(msg);
1225     break;
1226 sgodin 5377 case WaitingToHangup:
1227     dispatchWaitingToHangup(msg);
1228     break;
1229 jason 4010 case Terminated:
1230     dispatchTerminated(msg);
1231     break;
1232     case Undefined:
1233     default:
1234     assert(0);
1235     break;
1236     }
1237     }
1238    
1239     void
1240 derek 2990 InviteSession::dispatch(const DumTimeout& timeout)
1241     {
1242 derek 3255 if (timeout.type() == DumTimeout::Retransmit200)
1243 derek 2990 {
1244 jason 4010 if (mCurrentRetransmit200)
1245 derek 3255 {
1246 derek 7144 InfoLog (<< "Retransmitting: " << endl << mInvite200->brief());
1247 daniel 5757 //DumHelper::setOutgoingEncryptionLevel(*mInvite200, mCurrentEncryptionLevel);
1248 daniel 5505 send(mInvite200);
1249 derek 3255 mCurrentRetransmit200 *= 2;
1250     mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq());
1251     }
1252 derek 2990 }
1253 derek 3255 else if (timeout.type() == DumTimeout::WaitForAck)
1254 derek 2990 {
1255 jason 4010 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet
1256 derek 3255 {
1257 daniel 5757 if (timeout.seq() == mLastRemoteSessionModification->header(h_CSeq).sequence())
1258 daniel 5591 {
1259     mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1260 jason 4010
1261 daniel 5591 // If we are waiting for an Ack and it times out, then end with a BYE
1262     if(mState == UAS_WaitingToHangup ||
1263     mState == WaitingToHangup)
1264     {
1265 Danweber 9098 SharedPtr<SipMessage> msg = sendBye();
1266 daniel 5591 transition(Terminated);
1267 Danweber 9098 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
1268 daniel 5591 }
1269     else if(mState == ReceivedReinviteSentOffer)
1270     {
1271     transition(Connected);
1272 sgodin 8726 mProposedLocalOfferAnswer.reset();
1273 daniel 5591 mProposedEncryptionLevel = DialogUsageManager::None;
1274     //!dcm! -- should this be onIllegalNegotiation?
1275     mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), 0);
1276     }
1277 sgodin 6121 else if(mState == WaitingToOffer ||
1278     mState == UAS_WaitingToOffer)
1279 daniel 5591 {
1280 sgodin 8726 assert(mProposedLocalOfferAnswer.get());
1281 sgodin 6121 mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1282     if(!isTerminated())
1283     {
1284     provideProposedOffer();
1285     }
1286 daniel 5591 }
1287 sgodin 6121 else if(mState == WaitingToRequestOffer ||
1288     mState == UAS_WaitingToRequestOffer)
1289     {
1290     mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1291     if(!isTerminated())
1292     {
1293     requestOffer();
1294     }
1295     }
1296 daniel 5591 else
1297     {
1298     // this is so the app can decided to ignore this. default implementation
1299     // will call end next
1300     mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
1301     }
1302 sgodin 3363 }
1303 derek 3255 }
1304 derek 2990 }
1305 sgodin 5586 else if (timeout.type() == DumTimeout::CanDiscardAck)
1306     {
1307 jmatthewsr 7238 AckMap::iterator i = mAcks.find(timeout.transactionId());
1308 sgodin 5586 if (i != mAcks.end())
1309     {
1310     mAcks.erase(i);
1311     }
1312     }
1313 jason 4010 else if (timeout.type() == DumTimeout::Glare)
1314 derek 3255 {
1315 jason 4010 if (mState == SentUpdateGlare)
1316     {
1317     transition(SentUpdate);
1318    
1319     InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
1320 sgodin 6186 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE); // increments CSeq
1321 sgodin 5747 send(mLastLocalSessionModification);
1322 jason 4010 }
1323     else if (mState == SentReinviteGlare)
1324     {
1325     transition(SentReinvite);
1326    
1327     InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");
1328 sgodin 6186 mDialog.makeRequest(*mLastLocalSessionModification, INVITE); // increments CSeq
1329 sgodin 7292 startStaleReInviteTimer();
1330 sgodin 5747 send(mLastLocalSessionModification);
1331 jason 4010 }
1332 sgodin 5555 else if (mState == SentReinviteNoOfferGlare)
1333     {
1334     transition(SentReinviteNoOffer);
1335    
1336     InfoLog (<< "Retransmitting the reINVITE-nooffer (glare condition timer)");
1337 sgodin 6186 mDialog.makeRequest(*mLastLocalSessionModification, INVITE); // increments CSeq
1338 sgodin 7292 startStaleReInviteTimer();
1339 sgodin 5747 send(mLastLocalSessionModification);
1340 sgodin 5555 }
1341 derek 3255 }
1342 sgodin 7292 else if (timeout.type() == DumTimeout::StaleReInvite)
1343     {
1344     if(timeout.seq() == mStaleReInviteTimerSeq)
1345     {
1346     if(mState == WaitingToTerminate)
1347     {
1348 Danweber 9098 SharedPtr<SipMessage> msg = sendBye();
1349 sgodin 7292 transition(Terminated);
1350 Danweber 9098 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
1351 sgodin 7292 }
1352     else if(mState == SentReinvite ||
1353     mState == SentReinviteNoOffer)
1354     {
1355     transition(Connected);
1356 sgodin 8726 mProposedLocalOfferAnswer.reset();
1357 sgodin 7292 mProposedEncryptionLevel = DialogUsageManager::None;
1358    
1359     // this is so the app can decide to ignore this. default implementation
1360     // will call end next - which will send a BYE
1361     mDum.mInviteSessionHandler->onStaleReInviteTimeout(getSessionHandle());
1362     }
1363     }
1364     }
1365 sgodin 3392 else if (timeout.type() == DumTimeout::SessionExpiration)
1366     {
1367     if(timeout.seq() == mSessionTimerSeq)
1368     {
1369 sgodin 7292 // this is so the app can decide to ignore this. default implementation
1370 jason 5544 // will call end next - which will send a BYE
1371 jason 4010 mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());
1372 sgodin 3392 }
1373     }
1374     else if (timeout.type() == DumTimeout::SessionRefresh)
1375     {
1376 jason 4010 if(timeout.seq() == mSessionTimerSeq)
1377 jason 5544 {
1378     // Note: If not connected then we must be issueing a reinvite/update or
1379     // receiving one - in either case the session timer stuff will get
1380     // reset/renegotiated - thus just ignore this referesh
1381     if(mState == Connected)
1382     {
1383     sessionRefresh();
1384     }
1385     }
1386 sgodin 3392 }
1387 derek 2990 }
1388    
1389 jason 4010 void
1390     InviteSession::dispatchConnected(const SipMessage& msg)
1391 sgodin 3392 {
1392 jason 4010 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1393 sgodin 8726 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1394 jason 4010
1395 sgodin 8726 switch (toEvent(msg, offerAnswer.get()))
1396 sgodin 3392 {
1397 jason 4010 case OnInvite:
1398     case OnInviteReliable:
1399 daniel 5757 *mLastRemoteSessionModification = msg;
1400 jason 4010 transition(ReceivedReinviteNoOffer);
1401     handler->onOfferRequired(getSessionHandle(), msg);
1402     break;
1403 sgodin 3392
1404 jason 4010 case OnInviteOffer:
1405     case OnInviteReliableOffer:
1406 daniel 5757 *mLastRemoteSessionModification = msg;
1407 jason 4010 transition(ReceivedReinvite);
1408 daniel 5068 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1409 sgodin 8726 mProposedRemoteOfferAnswer = offerAnswer;
1410 sgodin 5555
1411 sgodin 8727 handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
1412 jason 4010 break;
1413    
1414     case On2xx:
1415     case On2xxOffer:
1416     case On2xxAnswer:
1417     // retransmission of 200I
1418     // !jf! Need to include the answer here.
1419 sgodin 5747 sendAck();
1420 jason 4010 break;
1421    
1422 sgodin 4369 case OnUpdateOffer:
1423 jason 4010 transition(ReceivedUpdate);
1424    
1425     // !kh!
1426     // Find out if it's an UPDATE requiring state change.
1427     // See rfc3311 5.2, 4th paragraph.
1428 daniel 5757 *mLastRemoteSessionModification = msg;
1429 daniel 5068 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1430 sgodin 8726 mProposedRemoteOfferAnswer = offerAnswer;
1431     handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
1432 jason 4010 break;
1433    
1434 sgodin 4369 case OnUpdate:
1435     {
1436 sgodin 8726 // ?slg? no offerAnswer in update - just respond immediately (likely session timer) - do we need a callback?
1437 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
1438     *mLastRemoteSessionModification = msg;
1439     mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
1440     handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
1441 sgodin 5747 send(response);
1442 sgodin 4369 break;
1443     }
1444    
1445 jason 4010 case OnUpdateRejected:
1446     case On200Update:
1447 sgodin 6121 WarningLog (<< "DUM delivered an UPDATE response in an incorrect state " << endl << msg);
1448     assert(0);
1449 jason 4010 break;
1450    
1451     case OnAck:
1452 bcampen 7267 case OnAckAnswer: // .bwc. Don't drop ACK with SDP!
1453 jason 4010 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1454 nash 7042 handler->onAckReceived(getSessionHandle(), msg);
1455 jason 4010 break;
1456    
1457     default:
1458     dispatchOthers(msg);
1459     break;
1460     }
1461     }
1462    
1463     void
1464     InviteSession::dispatchSentUpdate(const SipMessage& msg)
1465     {
1466     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1467 sgodin 8726 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1468 jason 4010
1469 sgodin 8726 switch (toEvent(msg, offerAnswer.get()))
1470 jason 4010 {
1471     case OnInvite:
1472     case OnInviteReliable:
1473     case OnInviteOffer:
1474     case OnInviteReliableOffer:
1475     case OnUpdate:
1476 sgodin 4369 case OnUpdateOffer:
1477 sgodin 3392 {
1478 jason 4010 // glare
1479 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
1480     mDialog.makeResponse(*response, msg, 491);
1481 sgodin 5747 send(response);
1482 jason 4010 break;
1483     }
1484    
1485     case On200Update:
1486     transition(Connected);
1487     handleSessionTimerResponse(msg);
1488 sgodin 8726 if (offerAnswer.get() && mProposedLocalOfferAnswer.get())
1489 sgodin 3392 {
1490 daniel 5068 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1491 sgodin 8726 setCurrentLocalOfferAnswer(msg);
1492 jason 7102
1493 sgodin 8726 mCurrentRemoteOfferAnswer = offerAnswer;
1494     handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1495 sgodin 3392 }
1496 sgodin 8726 else if(mProposedLocalOfferAnswer.get())
1497 sgodin 3392 {
1498 sgodin 4369 // If we sent an offer in the Update Request and no answer is received
1499 jason 4010 handler->onIllegalNegotiation(getSessionHandle(), msg);
1500 sgodin 8726 mProposedLocalOfferAnswer.reset();
1501 daniel 5068 mProposedEncryptionLevel = DialogUsageManager::None;
1502 jason 4010 }
1503     break;
1504    
1505     case On491Update:
1506 sgodin 4369 transition(SentUpdateGlare);
1507 jason 4010 start491Timer();
1508     break;
1509    
1510 daniel 5068 case On422Update: // session timer
1511 sgodin 4394 if(msg.exists(h_MinSE))
1512     {
1513     // Change interval to min from 422 response
1514     mSessionInterval = msg.header(h_MinSE).value();
1515 sgodin 4691 mMinSE = mSessionInterval;
1516 sgodin 4394 sessionRefresh();
1517     }
1518     else
1519     {
1520 sgodin 5747 // Response must contain Min_SE - if not - just ignore
1521 sgodin 5001 // ?slg? callback?
1522 sgodin 4394 transition(Connected);
1523 sgodin 8726 mProposedLocalOfferAnswer.reset();
1524 daniel 5068 mProposedEncryptionLevel = DialogUsageManager::None;
1525 sgodin 4394 }
1526     break;
1527    
1528 jason 4010 case OnUpdateRejected:
1529 derek 7144 transition(Connected);
1530 sgodin 8726 mProposedLocalOfferAnswer.reset();
1531 derek 7144 handler->onOfferRejected(getSessionHandle(), &msg);
1532 jason 4010 break;
1533    
1534     case OnGeneralFailure:
1535     sendBye();
1536     transition(Terminated);
1537 bcampen 8200 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1538 jason 4010 break;
1539    
1540     default:
1541     dispatchOthers(msg);
1542     break;
1543     }
1544     }
1545    
1546     void
1547     InviteSession::dispatchSentReinvite(const SipMessage& msg)
1548     {
1549     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1550 sgodin 8726 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1551 jason 4010
1552 sgodin 8726 switch (toEvent(msg, offerAnswer.get()))
1553 jason 4010 {
1554     case OnInvite:
1555     case OnInviteReliable:
1556     case OnInviteOffer:
1557     case OnInviteReliableOffer:
1558     case OnUpdate:
1559 sgodin 4369 case OnUpdateOffer:
1560 jason 4010 {
1561 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
1562     mDialog.makeResponse(*response, msg, 491);
1563 sgodin 5747 send(response);
1564 jason 4010 break;
1565 sgodin 3392 }
1566 jason 4010
1567     case On1xx:
1568     case On1xxEarly:
1569 sgodin 5001 // Some UA's send a 100 response to a ReInvite - just ignore it
1570 jason 4010 break;
1571    
1572     case On2xxAnswer:
1573 sgodin 9884 case On2xxOffer: // .slg. doesn't really make sense - should be in SentReinviteNoOffer to get this
1574 sgodin 3392 {
1575 sgodin 7292 mStaleReInviteTimerSeq++;
1576 jason 4010 transition(Connected);
1577     handleSessionTimerResponse(msg);
1578 sgodin 8726 setCurrentLocalOfferAnswer(msg);
1579 jason 5544
1580 jason 4010 // !jf! I need to potentially include an answer in the ACK here
1581 sgodin 5747 sendAck();
1582 jason 5544 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1583    
1584     if (mSessionRefreshReInvite)
1585     {
1586     mSessionRefreshReInvite = false;
1587    
1588 sgodin 10695 if (*mCurrentRemoteOfferAnswer != *offerAnswer)
1589 jason 5544 {
1590 sgodin 8726 mCurrentRemoteOfferAnswer = offerAnswer;
1591     handler->onRemoteAnswerChanged(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1592 jason 5544 }
1593     }
1594     else
1595     {
1596 sgodin 8726 mCurrentRemoteOfferAnswer = offerAnswer;
1597     handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1598 jason 5544 }
1599    
1600 jason 4010 // !jf! do I need to allow a reINVITE overlapping the retransmission of
1601     // the ACK when a 200I is received? If yes, then I need to store all
1602     // ACK messages for 64*T1
1603     break;
1604     }
1605     case On2xx:
1606 sgodin 7292 mStaleReInviteTimerSeq++;
1607 sgodin 5747 sendAck();
1608 jason 4010 transition(Connected);
1609     handleSessionTimerResponse(msg);
1610     handler->onIllegalNegotiation(getSessionHandle(), msg);
1611 sgodin 8726 mProposedLocalOfferAnswer.reset();
1612 daniel 5068 mProposedEncryptionLevel = DialogUsageManager::None;
1613 jason 4010 break;
1614    
1615 sgodin 4394 case On422Invite:
1616 sgodin 7292 mStaleReInviteTimerSeq++;
1617 sgodin 4394 if(msg.exists(h_MinSE))
1618     {
1619     // Change interval to min from 422 response
1620     mSessionInterval = msg.header(h_MinSE).value();
1621 sgodin 4691 mMinSE = mSessionInterval;
1622 sgodin 4394 sessionRefresh();
1623     }
1624     else
1625     {
1626     // Response must contact Min_SE - if not - just ignore
1627 sgodin 5001 // ?slg? callback?
1628 sgodin 4394 transition(Connected);
1629 sgodin 8726 mProposedLocalOfferAnswer.reset();
1630 daniel 5068 mProposedEncryptionLevel = DialogUsageManager::None;
1631 sgodin 4394 }
1632     break;
1633    
1634 jason 4010 case On491Invite:
1635 sgodin 7292 mStaleReInviteTimerSeq++;
1636 sgodin 4369 transition(SentReinviteGlare);
1637 jason 4010 start491Timer();
1638     break;
1639    
1640     case OnGeneralFailure:
1641 sgodin 7292 mStaleReInviteTimerSeq++;
1642 jason 4010 sendBye();
1643     transition(Terminated);
1644 bcampen 8200 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1645 jason 4010 break;
1646    
1647     case OnInviteFailure:
1648 sgodin 5130 case On487Invite:
1649 sgodin 7292 mStaleReInviteTimerSeq++;
1650 jason 4010 transition(Connected);
1651 sgodin 8726 mProposedLocalOfferAnswer.reset();
1652 derek 5355 handler->onOfferRejected(getSessionHandle(), &msg);
1653 jason 4010 break;
1654    
1655     default:
1656     dispatchOthers(msg);
1657     break;
1658     }
1659     }
1660    
1661 sgodin 5555 void
1662     InviteSession::dispatchSentReinviteNoOffer(const SipMessage& msg)
1663     {
1664     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1665 sgodin 8726 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1666 sgodin 5555
1667 sgodin 8726 switch (toEvent(msg, offerAnswer.get()))
1668 sgodin 5555 {
1669     case OnInvite:
1670     case OnInviteReliable:
1671     case OnInviteOffer:
1672     case OnInviteReliableOffer:
1673     case OnUpdate:
1674     case OnUpdateOffer:
1675     {
1676 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
1677     mDialog.makeResponse(*response, msg, 491);
1678 sgodin 5747 send(response);
1679 sgodin 5555 break;
1680     }
1681    
1682     case On1xx:
1683     case On1xxEarly:
1684     // Some UA's send a 100 response to a ReInvite - just ignore it
1685     break;
1686    
1687 sgodin 9884 case On2xxAnswer: // .slg. doesn't really make sense - should be in SentReinvite to get this
1688 sgodin 5555 case On2xxOffer:
1689     {
1690 sgodin 7292 mStaleReInviteTimerSeq++;
1691 sgodin 5555 transition(SentReinviteAnswered);
1692     handleSessionTimerResponse(msg);
1693     mCurrentEncryptionLevel = getEncryptionLevel(msg);
1694 sgodin 8726 mProposedRemoteOfferAnswer = offerAnswer;
1695     handler->onOffer(getSessionHandle(), msg, *mProposedRemoteOfferAnswer);
1696 sgodin 5555 break;
1697     }
1698    
1699     case On2xx:
1700 sgodin 7292 mStaleReInviteTimerSeq++;
1701 sgodin 5747 sendAck();
1702 sgodin 5555 transition(Connected);
1703     handleSessionTimerResponse(msg);
1704     handler->onIllegalNegotiation(getSessionHandle(), msg);
1705 sgodin 8726 mProposedLocalOfferAnswer.reset();
1706 sgodin 5555 mProposedEncryptionLevel = DialogUsageManager::None;
1707     break;
1708    
1709     case On422Invite:
1710 sgodin 7292 mStaleReInviteTimerSeq++;
1711 sgodin 5555 if(msg.exists(h_MinSE))
1712     {
1713     // Change interval to min from 422 response
1714     mSessionInterval = msg.header(h_MinSE).value();
1715     mMinSE = mSessionInterval;
1716 sgodin 6186 sessionRefresh();
1717 sgodin 5555 }
1718     else
1719     {
1720     // Response must contact Min_SE - if not - just ignore
1721     // ?slg? callback?
1722     transition(Connected);
1723 sgodin 8726 mProposedLocalOfferAnswer.reset();
1724 sgodin 5555 mProposedEncryptionLevel = DialogUsageManager::None;
1725     }
1726     break;
1727    
1728     case On491Invite:
1729 sgodin 7292 mStaleReInviteTimerSeq++;
1730 sgodin 5555 transition(SentReinviteNoOfferGlare);
1731     start491Timer();
1732     break;
1733    
1734     case OnGeneralFailure:
1735 sgodin 7292 mStaleReInviteTimerSeq++;
1736 sgodin 5555 sendBye();
1737     transition(Terminated);
1738 bcampen 8200 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1739 sgodin 5555 break;
1740    
1741     case OnInviteFailure:
1742     case On487Invite:
1743 sgodin 7292 mStaleReInviteTimerSeq++;
1744 sgodin 5555 transition(Connected);
1745 sgodin 8726 mProposedLocalOfferAnswer.reset();
1746 sgodin 5555 handler->onOfferRejected(getSessionHandle(), &msg);
1747     break;
1748    
1749     default:
1750     dispatchOthers(msg);
1751     break;
1752     }
1753     }
1754    
1755 jason 5544 void
1756     InviteSession::dispatchReceivedReinviteSentOffer(const SipMessage& msg)
1757 derek 5355 {
1758     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1759 sgodin 8726 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1760 derek 5355
1761 sgodin 8726 switch (toEvent(msg, offerAnswer.get()))
1762 derek 5355 {
1763     case OnInvite:
1764     case OnInviteReliable:
1765     case OnInviteOffer:
1766     case OnInviteReliableOffer:
1767     case OnUpdate:
1768     case OnUpdateOffer:
1769     {
1770 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
1771     mDialog.makeResponse(*response, msg, 491);
1772 sgodin 5747 send(response);
1773 derek 5355 break;
1774     }
1775     case OnAckAnswer:
1776     transition(Connected);
1777 sgodin 8726 setCurrentLocalOfferAnswer(msg);
1778     mCurrentRemoteOfferAnswer = offerAnswer;
1779 derek 5355 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1780     mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1781 derek 7144
1782 sgodin 8726 handler->onAnswer(getSessionHandle(), msg, *mCurrentRemoteOfferAnswer);
1783 derek 5355 break;
1784     case OnAck:
1785 daniel 6267 if (mLastRemoteSessionModification->header(h_CSeq).sequence() > msg.header(h_CSeq).sequence())
1786 daniel 6266 {
1787     InfoLog(<< "dropped stale ACK");
1788     }
1789     else
1790     {
1791     InfoLog(<< "Got Ack with no answer");
1792     transition(Connected);
1793 sgodin 8726 mProposedLocalOfferAnswer.reset();
1794 daniel 6266 mProposedEncryptionLevel = DialogUsageManager::None;
1795     mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1796     //!dcm! -- should this be onIllegalNegotiation?
1797     handler->onOfferRejected(getSessionHandle(), &msg);
1798     }
1799 derek 5355 break;
1800     default:
1801     dispatchOthers(msg);
1802     break;
1803     }
1804     }
1805    
1806 jason 4010 void
1807     InviteSession::dispatchGlare(const SipMessage& msg)
1808     {
1809     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1810     MethodTypes method = msg.header(h_CSeq).method();
1811 sgodin 5555 if (msg.isRequest() && (method == INVITE || method == UPDATE))
1812 jason 4010 {
1813 daniel 5591 DebugLog(<< "Re-INVITE or UPDATE received when in SentReinviteGlare or SentUpdateGlare" << endl);
1814 sgodin 5555 // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1815 derek 5355 handler->onOfferRejected(getSessionHandle(), &msg);
1816 sgodin 7404 if(!isTerminated()) // make sure application didn't call end()
1817     {
1818     dispatchConnected(msg); // act as if we received message in Connected state
1819     }
1820     else
1821     {
1822     dispatchTerminated(msg);
1823     }
1824 jason 4010 }
1825 sgodin 5555 else
1826 jason 4010 {
1827 sgodin 5555 dispatchOthers(msg);
1828 jason 4010 }
1829 sgodin 5555 }
1830    
1831     void
1832     InviteSession::dispatchReinviteNoOfferGlare(const SipMessage& msg)
1833     {
1834     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1835     MethodTypes method = msg.header(h_CSeq).method();
1836     if (msg.isRequest() && (method == INVITE || method == UPDATE))
1837     {
1838     // Received inbound reinvite or update, when waiting to resend outbound reinvite or update
1839     handler->onOfferRequestRejected(getSessionHandle(), msg);
1840 sgodin 7404 if(!isTerminated()) // make sure application didn't call end()
1841     {
1842     dispatchConnected(msg); // act as if we received message in Connected state
1843     }
1844     else
1845     {
1846     dispatchTerminated(msg);
1847     }
1848 sgodin 5555 }
1849 jason 4010 else
1850     {
1851     dispatchOthers(msg);
1852     }
1853     }
1854    
1855     void
1856     InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
1857     {
1858 kwhite 8925 // InviteSessionHandler* handler = mDum.mInviteSessionHandler; // unused
1859 sgodin 8726 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1860 sgodin 8476
1861 sgodin 8726 switch (toEvent(msg, offerAnswer.get()))
1862 jason 4010 {
1863 sgodin 8476 case OnInvite:
1864     case OnInviteReliable:
1865     case OnInviteOffer:
1866     case OnInviteReliableOffer:
1867     case OnUpdate:
1868     case OnUpdateOffer:
1869     {
1870     // Means that the UAC has sent us a second reINVITE or UPDATE before we
1871     // responded to the first one. Bastard!
1872     SharedPtr<SipMessage> response(new SipMessage);
1873     mDialog.makeResponse(*response, msg, 500);
1874     response->header(h_RetryAfter).value() = Random::getRandom() % 10;
1875     send(response);
1876     break;
1877     }
1878     case OnBye:
1879     {
1880     // BYE received after a reINVITE, terminate the reINVITE transaction.
1881     SharedPtr<SipMessage> response(new SipMessage);
1882     mDialog.makeResponse(*response, *mLastRemoteSessionModification, 487); // Request Terminated
1883     handleSessionTimerRequest(*response, *mLastRemoteSessionModification);
1884     send(response);
1885    
1886     dispatchBye(msg);
1887     break;
1888     }
1889     default:
1890     dispatchOthers(msg);
1891     break;
1892 jason 4010 }
1893     }
1894    
1895    
1896     void
1897     InviteSession::dispatchAnswered(const SipMessage& msg)
1898     {
1899     if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1900     {
1901     mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1902     transition(Connected);
1903     }
1904     else
1905     {
1906     dispatchOthers(msg);
1907     }
1908     }
1909    
1910     void
1911 sgodin 5555 InviteSession::dispatchSentReinviteAnswered(const SipMessage& msg)
1912     {
1913 sgodin 6076 if (msg.isResponse() &&
1914     msg.header(h_CSeq).method() == INVITE &&
1915     msg.header(h_StatusLine).statusCode() / 200 == 1)
1916     {
1917     // Receving a 200 retransmission is possible - but we don't have an ACK response yet - we are still waiting for provideAnswer to be
1918     // called by the app - so just drop the retransmission
1919     return;
1920     }
1921 sgodin 5555 dispatchOthers(msg);
1922     }
1923    
1924     void
1925 jason 4010 InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
1926     {
1927     if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1928     {
1929 sgodin 8726 assert(mProposedLocalOfferAnswer.get());
1930 jason 4010 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1931 sgodin 5555 provideProposedOffer();
1932 jason 4010 }
1933     else
1934     {
1935     dispatchOthers(msg);
1936     }
1937     }
1938    
1939     void
1940 sgodin 5555 InviteSession::dispatchWaitingToRequestOffer(const SipMessage& msg)
1941     {
1942     if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
1943     {
1944     mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1945     requestOffer();
1946     }
1947     else
1948     {
1949     dispatchOthers(msg);
1950     }
1951     }
1952    
1953     void
1954 jason 4010 InviteSession::dispatchWaitingToTerminate(const SipMessage& msg)
1955     {
1956     if (msg.isResponse() &&
1957     msg.header(h_CSeq).method() == INVITE)
1958     {
1959     if(msg.header(h_StatusLine).statusCode() / 200 == 1) // Note: stack ACK's non-2xx final responses only
1960     {
1961     // !jf! Need to include the answer here.
1962 sgodin 5747 sendAck();
1963 jason 4010 }
1964 Danweber 9098 SharedPtr<SipMessage> msg = sendBye();
1965 jason 4010 transition(Terminated);
1966 Danweber 9098 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
1967 jason 4010 }
1968 sgodin 7292 else if(msg.isRequest())
1969     {
1970     if(msg.method() == BYE)
1971     {
1972     dispatchBye(msg);
1973     }
1974     else
1975     {
1976     SharedPtr<SipMessage> response(new SipMessage);
1977     mDialog.makeResponse(*response, msg, 400 /* Bad Request */);
1978     send(response);
1979     }
1980     }
1981 jason 4010 }
1982    
1983     void
1984 sgodin 5377 InviteSession::dispatchWaitingToHangup(const SipMessage& msg)
1985     {
1986 sgodin 8726 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1987 sgodin 5377
1988 sgodin 8726 switch (toEvent(msg, offerAnswer.get()))
1989 sgodin 5377 {
1990     case OnAck:
1991     case OnAckAnswer:
1992     {
1993     mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
1994    
1995 Danweber 9098 SharedPtr<SipMessage> msg = sendBye();
1996 sgodin 5377 transition(Terminated);
1997 Danweber 9098 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
1998 sgodin 5377 break;
1999     }
2000    
2001     default:
2002     break;
2003     }
2004     }
2005    
2006     void
2007 jason 4010 InviteSession::dispatchTerminated(const SipMessage& msg)
2008     {
2009     InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief());
2010    
2011     if (msg.isRequest())
2012     {
2013 daniel 6912 if (BYE == msg.header(h_CSeq).method())
2014     {
2015     SharedPtr<SipMessage> response(new SipMessage);
2016     mDialog.makeResponse(*response, msg, 200);
2017     send(response);
2018     }
2019     else
2020     {
2021     SharedPtr<SipMessage> response(new SipMessage);
2022     mDialog.makeResponse(*response, msg, 481);
2023     send(response);
2024     }
2025 jason 4010
2026     // !jf! means the peer sent BYE while we are waiting for response to BYE
2027     //mDum.destroy(this);
2028     }
2029     else
2030     {
2031     mDum.destroy(this);
2032     }
2033     }
2034    
2035     void
2036     InviteSession::dispatchOthers(const SipMessage& msg)
2037     {
2038     // handle OnGeneralFailure
2039     // handle OnRedirect
2040    
2041     switch (msg.header(h_CSeq).method())
2042     {
2043     case PRACK:
2044     dispatchPrack(msg);
2045     break;
2046     case CANCEL:
2047     dispatchCancel(msg);
2048     break;
2049     case BYE:
2050     dispatchBye(msg);
2051     break;
2052     case INFO:
2053     dispatchInfo(msg);
2054     break;
2055 sgodin 5265 case MESSAGE:
2056     dispatchMessage(msg);
2057     break;
2058 jason 4010 case ACK:
2059     // Ignore duplicate ACKs from 2xx reTransmissions
2060     break;
2061     default:
2062     // handled in Dialog
2063     WarningLog (<< "DUM delivered a "
2064     << msg.header(h_CSeq).unknownMethodName()
2065 derek 7144 << " to the InviteSession in state: " << toData(mState)
2066 jason 4010 << endl
2067     << msg);
2068     assert(0);
2069     break;
2070     }
2071     }
2072    
2073     void
2074     InviteSession::dispatchUnhandledInvite(const SipMessage& msg)
2075     {
2076     assert(msg.isRequest());
2077     assert(msg.header(h_CSeq).method() == INVITE);
2078    
2079     // If we get an INVITE request from the wire and we are not in
2080     // Connected state, reject the request and send a BYE
2081 daniel 5757 SharedPtr<SipMessage> response(new SipMessage);
2082     mDialog.makeResponse(*response, msg, 400); // !jf! what code to use?
2083     InfoLog (<< "Sending " << response->brief());
2084 daniel 5505 send(response);
2085 jason 4010
2086     sendBye();
2087     transition(Terminated);
2088 bcampen 8200 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
2089 jason 4010 }
2090    
2091     void
2092     InviteSession::dispatchPrack(const SipMessage& msg)
2093     {
2094     assert(msg.header(h_CSeq).method() == PRACK);
2095     if(msg.isRequest())
2096     {
2097 daniel 5757 SharedPtr<SipMessage> rsp(new SipMessage);
2098     mDialog.makeResponse(*rsp, msg, 481);
2099 daniel 5505 send(rsp);
2100 jason 4010
2101     sendBye();
2102     // !jf! should we make some other callback here
2103     transition(Terminated);
2104 bcampen 8200 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
2105 jason 4010 }
2106     else
2107     {
2108     // ignore. could be PRACK/200
2109     }
2110     }
2111    
2112     void
2113     InviteSession::dispatchCancel(const SipMessage& msg)
2114     {
2115     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2116     assert(msg.header(h_CSeq).method() == CANCEL);
2117     if(msg.isRequest())
2118     {
2119 daniel 5757 SharedPtr<SipMessage> rsp(new SipMessage);
2120     mDialog.makeResponse(*rsp, msg, 200);
2121 daniel 5505 send(rsp);
2122 jason 4010
2123     sendBye();
2124     // !jf! should we make some other callback here
2125     transition(Terminated);
2126 bcampen 8200
2127     handler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteCancel, &msg);
2128 jason 4010 }
2129     else
2130     {
2131     WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg);
2132     assert(0);
2133     }
2134     }
2135    
2136     void
2137     InviteSession::dispatchBye(const SipMessage& msg)
2138     {
2139     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2140    
2141     if (msg.isRequest())
2142     {
2143 sgodin 8476 // Check for any non-invite server transactions (e.g. INFO)
2144     // that have not been responded yet and terminate them.
2145     if (mServerNitState == NitProceeding)
2146     {
2147     mLastNitResponse->header(h_StatusLine).statusCode() = 487;
2148     mLastNitResponse->setContents(0);
2149     Helper::getResponseCodeReason(487, mLastNitResponse->header(h_StatusLine).reason());
2150     send(mLastNitResponse);
2151     mServerNitState = NitComplete;
2152     }
2153 jason 4010
2154 daniel 5757 SharedPtr<SipMessage> rsp(new SipMessage);
2155 jason 4010 InfoLog (<< "Received " << msg.brief());
2156 daniel 5757 mDialog.makeResponse(*rsp, msg, 200);
2157 daniel 5505 send(rsp);
2158 jason 4010
2159     // !jf! should we make some other callback here
2160     transition(Terminated);
2161 bcampen 8200
2162     if (mDum.mDialogEventStateManager)
2163     {
2164 sgodin 8726 mDum.mDialogEventStateManager->onTerminated(mDialog, msg, InviteSessionHandler::RemoteBye);
2165 bcampen 8200 }
2166    
2167     handler->onTerminated(getSessionHandle(), InviteSessionHandler::RemoteBye, &msg);
2168 jason 4010 mDum.destroy(this);
2169     }
2170     else
2171     {
2172     WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg);
2173     assert(0);
2174     }
2175     }
2176    
2177     void
2178     InviteSession::dispatchInfo(const SipMessage& msg)
2179     {
2180     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2181     if (msg.isRequest())
2182     {
2183 sgodin 8476 if (mServerNitState == NitProceeding)
2184     {
2185     // Means that the UAC has sent us a second INFO before we
2186     // responded to the first one.
2187     SharedPtr<SipMessage> response(new SipMessage);
2188     mDialog.makeResponse(*response, msg, 500);
2189     response->header(h_RetryAfter).value() = Random::getRandom() % 10;
2190     send(response);
2191 dpocock 11056 WarningLog(<<"an INFO message was received before the application called acceptNIT() for the previous INFO message");
2192 sgodin 8476 }
2193     else
2194     {
2195     InfoLog (<< "Received " << msg.brief());
2196     mServerNitState = NitProceeding;
2197     mDialog.makeResponse(*mLastNitResponse, msg, 200);
2198     handler->onInfo(getSessionHandle(), msg);
2199     }
2200 jason 4010 }
2201     else
2202     {
2203     assert(mNitState == NitProceeding);
2204     //!dcm! -- toss away 1xx to an info?
2205     if (msg.header(h_StatusLine).statusCode() >= 300)
2206     {
2207     handler->onInfoFailure(getSessionHandle(), msg);
2208     }
2209     else if (msg.header(h_StatusLine).statusCode() >= 200)
2210     {
2211     handler->onInfoSuccess(getSessionHandle(), msg);
2212     }
2213 sgodin 7565 nitComplete();
2214 jason 4010 }
2215     }
2216    
2217     void
2218 sgodin 5592 InviteSession::acceptNIT(int statusCode, const Contents * contents)
2219 jason 4010 {
2220     if (statusCode / 100 != 2)
2221     {
2222     throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
2223     }
2224    
2225 sgodin 8476 if (mServerNitState != NitProceeding )
2226     {
2227     throw UsageUseException("No transaction to accept", __FILE__, __LINE__);
2228     }
2229    
2230 daniel 5757 mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;
2231     mLastNitResponse->setContents(contents);
2232     Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
2233 sgodin 5747 send(mLastNitResponse);
2234 sgodin 8476 mServerNitState = NitComplete;
2235 jason 4010 }
2236    
2237 nash 7042 class InviteSessionAcceptNITCommand : public DumCommandAdapter
2238     {
2239     public:
2240 fjoanis 9956 InviteSessionAcceptNITCommand(const InviteSessionHandle& inviteSessionHandle, int statusCode, const Contents* contents)
2241     : mInviteSessionHandle(inviteSessionHandle),
2242 nash 7042 mStatusCode(statusCode),
2243     mContents(contents?contents->clone():0)
2244     {
2245    
2246     }
2247    
2248     virtual void executeCommand()
2249     {
2250 fjoanis 9956 if(mInviteSessionHandle.isValid())
2251     {
2252     mInviteSessionHandle->acceptNIT(mStatusCode, mContents.get());
2253     }
2254 nash 7042 }
2255    
2256 jmatthewsr 8161 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
2257 nash 7042 {
2258     return strm << "InviteSessionAcceptNITCommand";
2259     }
2260     private:
2261 fjoanis 9956 InviteSessionHandle mInviteSessionHandle;
2262 nash 7042 int mStatusCode;
2263     std::auto_ptr<Contents> mContents;
2264     };
2265    
2266 jason 4010 void
2267 nash 7042 InviteSession::acceptNITCommand(int statusCode, const Contents* contents)
2268     {
2269 fjoanis 9956 mDum.post(new InviteSessionAcceptNITCommand(getSessionHandle(), statusCode, contents));
2270 nash 7042 }
2271    
2272     void
2273 sgodin 5265 InviteSession::rejectNIT(int statusCode)
2274 jason 4010 {
2275     if (statusCode < 400)
2276     {
2277     throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
2278     }
2279 sgodin 8476
2280     if (mServerNitState != NitProceeding )
2281     {
2282     throw UsageUseException("No transaction to reject", __FILE__, __LINE__);
2283     }
2284    
2285 daniel 5757 mLastNitResponse->header(h_StatusLine).statusCode() = statusCode;
2286 sgodin 8400 mLastNitResponse->setContents(0);
2287 daniel 5757 Helper::getResponseCodeReason(statusCode, mLastNitResponse->header(h_StatusLine).reason());
2288 sgodin 5747 send(mLastNitResponse);
2289 sgodin 8476 mServerNitState = NitComplete;
2290 jason 4010 }
2291    
2292 nash 7042 class InviteSessionRejectNITCommand : public DumCommandAdapter
2293     {
2294     public:
2295 fjoanis 9956 InviteSessionRejectNITCommand(const InviteSessionHandle& inviteSessionHandle, int statusCode)
2296     : mInviteSessionHandle(inviteSessionHandle),
2297 nash 7042 mStatusCode(statusCode)
2298     {
2299     }
2300    
2301     virtual void executeCommand()
2302     {
2303 fjoanis 9956 if(mInviteSessionHandle.isValid())
2304     {
2305     mInviteSessionHandle->rejectNIT(mStatusCode);
2306     }
2307 nash 7042 }
2308    
2309 jmatthewsr 8161 virtual EncodeStream& encodeBrief(EncodeStream& strm) const
2310 nash 7042 {
2311     return strm << "InviteSessionRejectNITCommand";
2312     }
2313     private:
2314 fjoanis 9956 InviteSessionHandle mInviteSessionHandle;
2315 nash 7042 int mStatusCode;
2316     };
2317    
2318 jason 4010 void
2319 nash 7042 InviteSession::rejectNITCommand(int statusCode)
2320     {
2321 fjoanis 9956 mDum.post(new InviteSessionRejectNITCommand(getSessionHandle(), statusCode));
2322 nash 7042 }
2323    
2324     void
2325 sgodin 5265 InviteSession::dispatchMessage(const SipMessage& msg)
2326     {
2327     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
2328     if (msg.isRequest())
2329     {
2330 sgodin 8476 if (mServerNitState == NitProceeding)
2331     {
2332     // Means that the UAC has sent us a second NIT message before we
2333     // responded to the first one.
2334     SharedPtr<SipMessage> response(new SipMessage);
2335     mDialog.makeResponse(*response, msg, 500);
2336     response->header(h_RetryAfter).value() = Random::getRandom() % 10;
2337     send(response);
2338     }
2339     else
2340     {
2341     InfoLog (<< "Received " << msg.brief());
2342     mServerNitState = NitProceeding;
2343     mDialog.makeResponse(*mLastNitResponse, msg, 200);
2344     mLastNitResponse->header(h_Contacts).clear();
2345     handler->onMessage(getSessionHandle(), msg);
2346     }
2347 sgodin 5265 }
2348     else
2349     {
2350     assert(mNitState == NitProceeding);
2351     //!dcm! -- toss away 1xx to an message?
2352     if (msg.header(h_StatusLine).statusCode() >= 300)
2353     {
2354     handler->onMessageFailure(getSessionHandle(), msg);
2355     }
2356     else if (msg.header(h_StatusLine).statusCode() >= 200)
2357     {
2358     handler->onMessageSuccess(getSessionHandle(), msg);
2359     }
2360 sgodin 7565 nitComplete();
2361 sgodin 5265 }
2362     }
2363    
2364     void
2365 jason 4010 InviteSession::startRetransmit200Timer()
2366     {
2367     mCurrentRetransmit200 = Timer::T1;
2368 sgodin 6416 unsigned int seq = mLastRemoteSessionModification->header(h_CSeq).sequence();
2369 jason 4010 mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
2370     mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
2371     }
2372    
2373 daniel 5591 // RFC3261 section 14.1
2374     // If a UAC receives a 491 response to a re-INVITE, it SHOULD start a timer with
2375     // a value T chosen as follows:
2376     // 1. If the UAC is the owner of the Call-ID of the dialog ID, T has a randomly
2377     // chosen value between 2.1 and 4 seconds in units of 10 ms.
2378     // 2. If the UAC is not the owner of the Call-ID of the dialog ID, T has a
2379     // randomly chosen value of between 0 and 2 seconds in units of 10 ms.
2380 jason 4010 void
2381     InviteSession::start491Timer()
2382     {
2383 sgodin 6416 unsigned int seq = mLastLocalSessionModification->header(h_CSeq).sequence();
2384 daniel 5591
2385     if (dynamic_cast<ClientInviteSession*>(this))
2386     {
2387     int timer = Random::getRandom() % (4000 - 2100);
2388     timer += 2100;
2389     timer -= timer % 10;
2390    
2391     DebugLog(<< "491 timer value: " << timer << "ms" << endl);
2392     mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
2393     }
2394     else
2395     {
2396     int timer = Random::getRandom() % 2000;
2397     timer -= timer % 10;
2398     DebugLog(<< "491 timer value: " << timer << "ms" << endl);
2399     mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
2400     }
2401 jason 4010 }
2402    
2403 sgodin 4369 void
2404 sgodin 7292 InviteSession::startStaleReInviteTimer()
2405     {
2406     InfoLog (<< toData(mState) << ": startStaleReInviteTimer");
2407     unsigned long when = mDialog.mDialogSet.getUserProfile()->getDefaultStaleReInviteTime();
2408    
2409     mDum.addTimer(DumTimeout::StaleReInvite,
2410     when,
2411     getBaseHandle(),
2412     ++mStaleReInviteTimerSeq);
2413     }
2414    
2415     void
2416 sgodin 4369 InviteSession::setSessionTimerHeaders(SipMessage &msg)
2417     {
2418     if(mSessionInterval >= 90) // If mSessionInterval is 0 then SessionTimers are considered disabled
2419     {
2420     msg.header(h_SessionExpires).value() = mSessionInterval;
2421 sgodin 4691 if(msg.isRequest())
2422     {
2423     msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uac" : "uas");
2424     }
2425     else
2426     {
2427     msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uas" : "uac");
2428     }
2429     msg.header(h_MinSE).value() = mMinSE;
2430 sgodin 4369 }
2431     else
2432     {
2433     msg.remove(h_SessionExpires);
2434     msg.remove(h_MinSE);
2435     }
2436     }
2437    
2438 jason 4010 void
2439 sgodin 4369 InviteSession::sessionRefresh()
2440     {
2441     if (updateMethodSupported())
2442     {
2443     transition(SentUpdate);
2444 daniel 5757 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);
2445 sgodin 8400 mLastLocalSessionModification->setContents(0); // Don't send SDP
2446 sgodin 4369 }
2447     else
2448     {
2449     transition(SentReinvite);
2450 daniel 5757 mDialog.makeRequest(*mLastLocalSessionModification, INVITE);
2451 sgodin 7292 startStaleReInviteTimer();
2452 sgodin 8726 InviteSession::setOfferAnswer(*mLastLocalSessionModification, mCurrentLocalOfferAnswer.get());
2453     mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(*mCurrentLocalOfferAnswer.get(), 0);
2454 jason 5544 mSessionRefreshReInvite = true;
2455 sgodin 4369 }
2456 daniel 5757 setSessionTimerHeaders(*mLastLocalSessionModification);
2457 sgodin 4369
2458 daniel 5757 InfoLog (<< "sessionRefresh: Sending " << mLastLocalSessionModification->brief());
2459     DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mCurrentEncryptionLevel);
2460 sgodin 5747 send(mLastLocalSessionModification);
2461 sgodin 4369 }
2462    
2463     void
2464 sgodin 4691 InviteSession::setSessionTimerPreferences()
2465     {
2466     mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if remote doesn't request a time
2467     if(mSessionInterval != 0)
2468     {
2469 sgodin 9902 // If session timers are not disabled then ensure interval is greater than or equal to MinSE
2470 sgodin 4691 mSessionInterval = resipMax(mMinSE, mSessionInterval);
2471     }
2472     switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
2473     {
2474     case Profile::PreferLocalRefreshes:
2475     mSessionRefresher = true; // Default refresher is Local
2476     break;
2477     case Profile::PreferRemoteRefreshes:
2478     mSessionRefresher = false; // Default refresher is Remote
2479     break;
2480 sgodin 8516 case Profile::PreferCalleeRefreshes:
2481     mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is callee
2482 sgodin 4691 break;
2483 sgodin 8516 case Profile::PreferCallerRefreshes:
2484     mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is caller
2485 sgodin 4691 break;
2486     }
2487     }
2488    
2489     void
2490     InviteSession::startSessionTimer()
2491     {
2492     if(mSessionInterval >= 90) // 90 is the absolute minimum - RFC4028
2493     {
2494     // Check if we are the refresher
2495     if(mSessionRefresher)
2496     {
2497     // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by RFC4028)
2498     mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
2499     }
2500     else
2501     {
2502     // 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)
2503 sgodin 6507 mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin((UInt32)32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
2504 sgodin 4691 }
2505     }
2506     else // Session Interval less than 90 - consider timers disabled
2507     {
2508     ++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled
2509     }
2510     }
2511    
2512     void
2513 jason 4010 InviteSession::handleSessionTimerResponse(const SipMessage& msg)
2514     {
2515     assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
2516    
2517 sgodin 6755 // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
2518     if (msg.exists(h_PAssertedIdentities))
2519     {
2520     mPeerPAssertedIdentities = msg.header(h_PAssertedIdentities);
2521     }
2522    
2523 jason 4010 // If session timers are locally supported then handle response
2524     if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
2525     {
2526 sgodin 4691 setSessionTimerPreferences();
2527 jason 4010
2528     if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer))
2529     && !msg.exists(h_SessionExpires))
2530     {
2531     // If no Session Expires in response and Requires header is present then session timer is to be 'turned off'
2532     mSessionInterval = 0;
2533     }
2534     // Process Session Timer headers
2535     else if(msg.exists(h_SessionExpires))
2536     {
2537 sgodin 3392 mSessionInterval = msg.header(h_SessionExpires).value();
2538     if(msg.header(h_SessionExpires).exists(p_refresher))
2539     {
2540 jason 4010 // Remote end specified refresher preference
2541 sgodin 4691 mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac"));
2542 sgodin 3392 }
2543     }
2544 jason 4010 else
2545     {
2546     // Note: If no Requires or Session-Expires, then UAS does not support Session Timers
2547     // - we are free to use our SessionInterval settings (set above as a default)
2548     // If far end doesn't support then refresher must be local
2549 sgodin 4691 mSessionRefresher = true;
2550 jason 4010 }
2551 sgodin 3392
2552 sgodin 4691 // Update MinSE if specified and longer than current value
2553     if(msg.exists(h_MinSE))
2554 sgodin 3392 {
2555 sgodin 4691 mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value());
2556 sgodin 3392 }
2557 sgodin 4691
2558     startSessionTimer();
2559 sgodin 3392 }
2560     }
2561    
2562 jason 4010 void
2563     InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
2564 sgodin 3392 {
2565 jason 4010 assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
2566    
2567 sgodin 6755 // Allow Re-Invites and Updates to update the Peer P-Asserted-Identity
2568     if (request.exists(h_PAssertedIdentities))
2569     {
2570     mPeerPAssertedIdentities = request.header(h_PAssertedIdentities);
2571     }
2572    
2573 sgodin 3392 // If session timers are locally supported then add necessary headers to response
2574 jason 4010 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
2575 sgodin 3392 {
2576 sgodin 9902 // Update MinSE if specified and longer than current value
2577     if(request.exists(h_MinSE))
2578     {
2579     mMinSE = resipMax(mMinSE, request.header(h_MinSE).value());
2580     }
2581 sgodin 4691 setSessionTimerPreferences();
2582 sgodin 3392
2583     // Check if far-end supports
2584     bool farEndSupportsTimer = false;
2585     if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer)))
2586     {
2587     farEndSupportsTimer = true;
2588     if(request.exists(h_SessionExpires))
2589     {
2590 jason 4010 // Use Session Interval requested by remote - if none then use local settings
2591 sgodin 3392 mSessionInterval = request.header(h_SessionExpires).value();
2592     if(request.header(h_SessionExpires).exists(p_refresher))
2593     {
2594 sgodin 4691 mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
2595 sgodin 3392 }
2596     }
2597     }
2598 jason 4010 else
2599     {
2600     // If far end doesn't support then refresher must be local
2601 sgodin 4691 mSessionRefresher = true;
2602 jason 4010 }
2603 sgodin 3392
2604 jason 4010 // Add Session-Expires to response if required
2605 sgodin 3392 if(mSessionInterval >= 90)
2606     {
2607 jason 4010 if(farEndSupportsTimer)
2608 sgodin 3392 {
2609 jason 4010 // If far end supports session-timer then require it, if not already present
2610     if(!response.header(h_Requires).find(Token(Symbols::Timer)))
2611     {
2612     response.header(h_Requires).push_back(Token(Symbols::Timer));
2613     }
2614 sgodin 3392 }
2615 sgodin 4691 setSessionTimerHeaders(response);
2616     }
2617 sgodin 3392
2618 sgodin 4691 startSessionTimer();
2619 sgodin 3392 }
2620     }
2621    
2622 jason 4010 Data
2623     InviteSession::toData(State state)
2624 jason 2856 {
2625 jason 4010 switch (state)
2626 derek 3255 {
2627 jason 4010 case Undefined:
2628     return "InviteSession::Undefined";
2629     case Connected:
2630     return "InviteSession::Connected";
2631     case SentUpdate:
2632     return "InviteSession::SentUpdate";
2633     case SentUpdateGlare:
2634     return "InviteSession::SentUpdateGlare";
2635     case SentReinvite:
2636     return "InviteSession::SentReinvite";
2637     case SentReinviteGlare:
2638     return "InviteSession::SentReinviteGlare";
2639 sgodin 5555 case SentReinviteNoOffer:
2640     return "InviteSession::SentReinviteNoOffer";
2641     case SentReinviteAnswered:
2642     return "InviteSession::SentReinviteAnswered";
2643     case SentReinviteNoOfferGlare:
2644     return "InviteSession::SentReinviteNoOfferGlare";
2645 jason 4010 case ReceivedUpdate:
2646     return "InviteSession::ReceivedUpdate";
2647     case ReceivedReinvite:
2648     return "InviteSession::ReceivedReinvite";
2649     case ReceivedReinviteNoOffer:
2650     return "InviteSession::ReceivedReinviteNoOffer";
2651 derek 5355 case ReceivedReinviteSentOffer:
2652     return "InviteSession::ReceivedReinviteSentOffer";
2653 jason 4010 case Answered:
2654     return "InviteSession::Answered";
2655     case WaitingToOffer:
2656     return "InviteSession::WaitingToOffer";
2657 sgodin 5555 case WaitingToRequestOffer:
2658     return "InviteSession::WaitingToRequestOffer";
2659 jason 4010 case WaitingToTerminate:
2660     return "InviteSession::WaitingToTerminate";
2661 sgodin 5377 case WaitingToHangup:
2662     return "InviteSession::WaitingToHangup";
2663 derek 2961 case Terminated:
2664 jason 4010 return "InviteSession::Terminated";
2665 jason 2856
2666 jason 4010 case UAC_Start:
2667     return "UAC_Start";
2668     case UAS_Offer:
2669     return "UAS_Offer";
2670     case UAS_OfferProvidedAnswer:
2671     return "UAS_OfferProvidedAnswer";
2672     case UAS_EarlyOffer:
2673     return "UAS_EarlyOffer";
2674     case UAS_EarlyProvidedAnswer:
2675     return "UAS_EarlyProvidedAnswer";
2676     case UAS_NoOffer:
2677     return "UAS_NoOffer";
2678     case UAS_ProvidedOffer:
2679     return "UAS_ProvidedOffer";
2680     case UAS_EarlyNoOffer:
2681     return "UAS_EarlyNoOffer";
2682     case UAS_EarlyProvidedOffer:
2683     return "UAS_EarlyProvidedOffer";
2684     case UAS_Accepted:
2685     return "UAS_Accepted";
2686     case UAS_WaitingToOffer:
2687     return "UAS_WaitingToOffer";
2688     case UAS_AcceptedWaitingAnswer:
2689     return "UAS_AcceptedWaitingAnswer";
2690     case UAC_Early:
2691     return "UAC_Early";
2692     case UAC_EarlyWithOffer:
2693     return "UAC_EarlyWithOffer";
2694     case UAC_EarlyWithAnswer:
2695     return "UAC_EarlyWithAnswer";
2696     case UAC_Answered:
2697     return "UAC_Answered";
2698     case UAC_SentUpdateEarly:
2699     return "UAC_SentUpdateEarly";
2700 derek 7144 case UAC_SentUpdateEarlyGlare:
2701     return "UAC_SentUpdateEarlyGlare";
2702 jason 4010 case UAC_ReceivedUpdateEarly:
2703     return "UAC_ReceivedUpdateEarly";
2704     case UAC_SentAnswer:
2705     return "UAC_SentAnswer";
2706     case UAC_QueuedUpdate:
2707     return "UAC_QueuedUpdate";
2708     case UAC_Cancelled:
2709     return "UAC_Cancelled";
2710 derek 7144
2711 jason 4010 case UAS_Start:
2712     return "UAS_Start";
2713 sgodin 10695 case UAS_OfferReliable:
2714     return "UAS_OfferReliable";
2715     case UAS_OfferReliableProvidedAnswer:
2716     return "UAS_OfferReliableProvidedAnswer";
2717 jason 4010 case UAS_NoOfferReliable:
2718     return "UAS_NoOfferReliable";
2719 sgodin 10695 case UAS_ProvidedOfferReliable:
2720     return "UAS_ProvidedOfferReliable";
2721 jason 4010 case UAS_FirstSentOfferReliable:
2722     return "UAS_FirstSentOfferReliable";
2723 derek 7144 case UAS_FirstSentAnswerReliable:
2724     return "UAS_FirstSentAnswerReliable";
2725 sgodin 10695 case UAS_NoAnswerReliableWaitingPrack:
2726     return "UAS_NoAnswerReliableWaitingPrack";
2727     case UAS_NoAnswerReliable:
2728     return "UAS_NoAnswerReliable";
2729 derek 7144 case UAS_NegotiatedReliable:
2730     return "UAS_NegotiatedReliable";
2731 jason 4010 case UAS_SentUpdate:
2732     return "UAS_SentUpdate";
2733     case UAS_SentUpdateAccepted:
2734     return "UAS_SentUpdateAccepted";
2735 sgodin 10695 case UAS_SentUpdateGlare:
2736     return "UAS_SentUpdateGlare";
2737 jason 4010 case UAS_ReceivedUpdate:
2738     return "UAS_ReceivedUpdate";
2739     case UAS_ReceivedUpdateWaitingAnswer:
2740     return "UAS_ReceivedUpdateWaitingAnswer";
2741     case UAS_WaitingToHangup:
2742     return "UAS_WaitingToHangup";
2743 sgodin 6139 case UAS_WaitingToRequestOffer:
2744     return "UAS_WaitingToRequestOffer";
2745 jason 4010 }
2746     assert(0);
2747     return "Undefined";
2748     }
2749 sgodin 3392
2750    
2751 jason 4010 void
2752     InviteSession::transition(State target)
2753     {
2754     InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
2755     mState = target;
2756     }
2757 sgodin 3392
2758 jason 4010 bool
2759 sgodin 10695 InviteSession::isReliable(const SipMessage& msg) const
2760 jason 4010 {
2761 derek 7144 if(msg.method() != INVITE)
2762     {
2763     return false;
2764     }
2765     if(msg.isRequest())
2766     {
2767 sgodin 10695 return mDum.getMasterProfile()->getUasReliableProvisionalMode() > MasterProfile::Never &&
2768     ((msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel))) ||
2769     (msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel))));
2770 derek 7144 }
2771     else
2772     {
2773 sgodin 10695 // RFC3262 says reliable provisionals MUST have a Require: 100rel and an RSeq
2774     return mDum.getMasterProfile()->getUacReliableProvisionalMode() > MasterProfile::Never &&
2775     msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::C100rel)) &&
2776     msg.exists(h_RSeq);
2777 derek 7144 }
2778 jason 2856 }
2779    
2780 sgodin 8726 //static std::auto_ptr<SdpContents> emptySdp;
2781     std::auto_ptr<Contents>
2782     InviteSession::getOfferAnswer(const SipMessage& msg)
2783 derek 3255 {
2784 sgodin 8726 if(mDum.mInviteSessionHandler->isGenericOfferAnswer())
2785     {
2786     if(msg.getContents())
2787     {
2788     return std::auto_ptr<Contents>(msg.getContents()->clone());
2789     }
2790     else
2791     {
2792     return std::auto_ptr<Contents>();
2793     }
2794     }
2795     else
2796     {
2797     return std::auto_ptr<Contents>(Helper::getSdp(msg.getContents()));
2798     }
2799 derek 3255 }
2800    
2801 sgodin 8726 std::auto_ptr<Contents>
2802     InviteSession::makeOfferAnswer(const Contents& offerAnswer)
2803 derek 2955 {
2804 sgodin 8726 return std::auto_ptr<Contents>(static_cast<Contents*>(offerAnswer.clone()));
2805 derek 2955 }
2806 jason 2856
2807 daniel 5068 auto_ptr<Contents>
2808 sgodin 8726 InviteSession::makeOfferAnswer(const Contents& offerAnswer,
2809     const Contents* alternative)
2810 daniel 5068 {
2811     if (alternative)
2812     {
2813     MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2814     mac->parts().push_back(alternative->clone());
2815 sgodin 8726 mac->parts().push_back(offerAnswer.clone());
2816 daniel 5068 return auto_ptr<Contents>(mac);
2817     }
2818     else
2819     {
2820 sgodin 8726 return auto_ptr<Contents>(offerAnswer.clone());
2821 daniel 5068 }
2822     }
2823    
2824 jason 4010 void
2825 sgodin 8726 InviteSession::setOfferAnswer(SipMessage& msg, const Contents& offerAnswer, const Contents* alternative)
2826 derek 3112 {
2827 jason 4010 // !jf! should deal with multipart here
2828 derek 3112
2829 sgodin 8726 // This will clone the offerAnswer since the InviteSession also wants to keep its own
2830     // copy of the offerAnswer around for the application to access
2831 daniel 5068 if (alternative)
2832     {
2833     MultipartAlternativeContents* mac = new MultipartAlternativeContents;
2834     mac->parts().push_back(alternative->clone());
2835 sgodin 8726 mac->parts().push_back(offerAnswer.clone());
2836 daniel 5068 msg.setContents(auto_ptr<Contents>(mac));
2837     }
2838     else
2839     {
2840 sgodin 8726 msg.setContents(&offerAnswer);
2841 daniel 5068 }
2842 derek 3112 }
2843    
2844 daniel 5068 void
2845 sgodin 8726 InviteSession::setOfferAnswer(SipMessage& msg, const Contents* offerAnswer)
2846 daniel 5068 {
2847 sgodin 8726 assert(offerAnswer);
2848     msg.setContents(offerAnswer);
2849 daniel 5068 }
2850    
2851 sgodin 5555 void
2852     InviteSession::provideProposedOffer()
2853     {
2854 kwhite 8925 MultipartAlternativeContents* mp_ans =
2855     dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get());
2856     if (mp_ans)
2857 sgodin 5555 {
2858 kwhite 8925 // .kw. can cast below ever be NULL? Need assert/throw?
2859     provideOffer( *(dynamic_cast<Contents*>((mp_ans)->parts().back())),
2860 sgodin 5555 mProposedEncryptionLevel,
2861 kwhite 8925 dynamic_cast<Contents*>((mp_ans)->parts().front()));
2862 sgodin 5555 }
2863     else
2864     {
2865 kwhite 8925 // .kw. can cast below ever be NULL? Need assert/throw?
2866 sgodin 8726 provideOffer(*(dynamic_cast<Contents*>(mProposedLocalOfferAnswer.get())), mProposedEncryptionLevel, 0);
2867 sgodin 5555 }
2868     }
2869    
2870 jason 4010 InviteSession::Event
2871 sgodin 8726 InviteSession::toEvent(const SipMessage& msg, const Contents* offerAnswer)
2872 jason 2621 {
2873 jason 4010 MethodTypes method = msg.header(h_CSeq).method();
2874     int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
2875 derek 7144
2876     //.dcm. Treat an invite as reliable if UAS 100rel support is enabled. For
2877     //responses, reiable provisionals should only be received if the invite was
2878     //sent reliably. Spurious reliable provisional respnoses are dropped outside
2879     //the state machine.
2880 jason 4010 bool reliable = isReliable(msg);
2881 sgodin 8726 bool sentOffer = mProposedLocalOfferAnswer.get();
2882 jason 4010
2883     if (code == 481 || code == 408)
2884 derek 2961 {
2885 jason 4010 return OnGeneralFailure;
2886     }
2887     else if (code >= 300 && code <= 399)
2888     {
2889     return OnRedirect;
2890     }
2891     else if (method == INVITE && code == 0)
2892     {
2893 sgodin 8726 if (offerAnswer)
2894 jason 4010 {
2895     if (reliable)
2896 sgodin 3363 {
2897 jason 4010 return OnInviteReliableOffer;
2898     }
2899     else
2900     {
2901     return OnInviteOffer;
2902     }
2903     }
2904     else
2905     {
2906     if (reliable)
2907     {
2908     return OnInviteReliable;
2909     }
2910     else
2911     {
2912     return OnInvite;
2913     }
2914     }
2915     }
2916 derek 7144 else if (method == INVITE && code > 100 && code < 200)
2917 jason 4010 {
2918     if (reliable)
2919     {
2920 sgodin 8726 if (offerAnswer)
2921 jason 4010 {
2922     if (sentOffer)
2923 sgodin 3363 {
2924 jason 4010 return On1xxAnswer;
2925 sgodin 3363 }
2926     else
2927     {
2928 jason 4010 return On1xxOffer;
2929 sgodin 3363 }
2930     }
2931     else
2932     {
2933 jason 4010 return On1xx;
2934 sgodin 3363 }
2935 jason 4010 }
2936     else
2937     {
2938 sgodin 8726 if (offerAnswer)
2939 sgodin 3363 {
2940 jason 4010 return On1xxEarly;
2941 sgodin 3363 }
2942     else
2943     {
2944 jason 4010 return On1xx;
2945 sgodin 3363 }
2946 jason 4010 }
2947 derek 2961 }
2948 jason 4010 else if (method == INVITE && code >= 200 && code < 300)
2949 jason 2809 {
2950 sgodin 8726 if (offerAnswer)
2951 jason 4010 {
2952     if (sentOffer)
2953 jason 2809 {
2954 jason 4010 return On2xxAnswer;
2955 jason 2809 }
2956     else
2957     {
2958 jason 4010 return On2xxOffer;
2959 jason 2809 }
2960 jason 4010 }
2961     else
2962     {
2963     return On2xx;
2964     }
2965 jason 2809 }
2966 sgodin 4394 else if (method == INVITE && code == 422)
2967     {
2968     return On422Invite;
2969     }
2970 jason 4010 else if (method == INVITE && code == 487)
2971 derek 3293 {
2972 jason 4010 return On487Invite;
2973 derek 3293 }
2974 jason 4010 else if (method == INVITE && code == 491)
2975 derek 2965 {
2976 jason 4010 return On491Invite;
2977 derek 2965 }
2978 jason 4010 else if (method == INVITE && code >= 400)
2979 derek 2965 {
2980 jason 4010 return OnInviteFailure;
2981     }
2982     else if (method == ACK)
2983     {
2984 sgodin 8726 if (offerAnswer)
2985 derek 2965 {
2986 jason 4010 return OnAckAnswer;
2987 derek 2965 }
2988 derek 2978 else
2989     {
2990 jason 4010 return OnAck;
2991 derek 2978 }
2992 jason 4010 }
2993     else if (method == CANCEL && code == 0)
2994 jason 2809 {
2995 jason 4010 return OnCancel;
2996 jason 2809 }
2997 jason 4010 else if (method == CANCEL && code / 200 == 1)
2998 sgodin 3338 {
2999 jason 4010 return On200Cancel;
3000 sgodin 3338 }
3001 jason 4010 else if (method == CANCEL && code >= 400)
3002 sgodin 3338 {
3003 jason 4010 return OnCancelFailure;
3004 sgodin 3338 }
3005 jason 4010 else if (method == BYE && code == 0)
3006 jason 2846 {
3007 jason 4010 return OnBye;
3008 jason 2846 }
3009 jason 4010 else if (method == BYE && code / 200 == 1)
3010 derek 3101 {
3011 jason 4010 return On200Bye;
3012 derek 3101 }
3013 jason 4010 else if (method == PRACK && code == 0)
3014     {
3015     return OnPrack;
3016     }
3017     else if (method == PRACK && code / 200 == 1)
3018     {
3019     return On200Prack;
3020     }
3021     else if (method == UPDATE && code == 0)
3022     {
3023 sgodin 8726 if (offerAnswer)
3024 sgodin 4369 {
3025     return OnUpdateOffer;
3026     }
3027     else
3028     {
3029     return OnUpdate;
3030     }
3031 jason 4010 }
3032     else if (method == UPDATE && code / 200 == 1)
3033     {
3034     return On200Update;
3035     }
3036 sgodin 4394 else if (method == UPDATE && code == 422)
3037     {
3038     return On422Update;
3039     }
3040 jason 4010 else if (method == UPDATE && code == 491)
3041     {
3042     return On491Update;
3043     }
3044     else if (method == UPDATE && code >= 400)
3045     {
3046     return OnUpdateRejected;
3047     }
3048     else
3049     {
3050 sgodin 5012 //assert(0); // dispatchOthers will throw if the message type is really unknown
3051 jason 4010 return Unknown;
3052     }
3053 derek 2965 }
3054    
3055 sgodin 9033 void
3056     InviteSession::sendAck(const Contents *answer)
3057 derek 2955 {
3058 daniel 5757 SharedPtr<SipMessage> ack(new SipMessage);
3059 sgodin 5586
3060 derek 7144 SharedPtr<SipMessage> source;
3061    
3062     if (mLastLocalSessionModification->method() == UPDATE)
3063     {
3064     //.dcm. scary--we could make a special ClientInviteSession variable/sendAck
3065     source = mDialog.mDialogSet.getCreator()->getLastRequest();
3066     }
3067     else
3068     {
3069     source = mLastLocalSessionModification;
3070     }
3071 sgodin 5586
3072 bcampen 8770 assert(mAcks.count(source->getTransactionId()) == 0);
3073    
3074 daniel 5757 mDialog.makeRequest(*ack, ACK);
3075 sgodin 5586
3076 bcampen 8770 // Copy Authorization and Proxy Authorization headers from
3077     // mLastLocalSessionModification; regardless of whether this was the original
3078     // INVITE or not, this is the correct place to go for auth headers.
3079     if(mLastLocalSessionModification->exists(h_Authorizations))
3080 sgodin 5586 {
3081 bcampen 8770 ack->header(h_Authorizations) = mLastLocalSessionModification->header(h_Authorizations);
3082 sgodin 5586 }
3083 bcampen 8770 if(mLastLocalSessionModification->exists(h_ProxyAuthorizations))
3084 sgodin 5586 {
3085 bcampen 8770 ack->header(h_ProxyAuthorizations) = mLastLocalSessionModification->header(h_ProxyAuthorizations);
3086 sgodin 5586 }
3087 bcampen 8770
3088     // Copy CSeq from original INVITE
3089 derek 7144 ack->header(h_CSeq).sequence() = source->header(h_CSeq).sequence();
3090 sgodin 5586
3091 sgodin 8726 if(answer != 0)
3092 derek 3255 {
3093 sgodin 8726 setOfferAnswer(*ack, *answer);
3094 derek 3255 }
3095 sgodin 7424 mAcks[source->getTransactionId()] = ack;
3096     mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), ack->header(h_CSeq).sequence(), 0, source->getTransactionId());
3097 sgodin 5586
3098 daniel 5757 InfoLog (<< "Sending " << ack->brief());
3099 daniel 5505 send(ack);
3100 derek 2981 }
3101    
3102 Danweber 9098 SharedPtr<SipMessage>
3103 sgodin 9033 InviteSession::sendBye()
3104 derek 2849 {
3105 daniel 5757 SharedPtr<SipMessage> bye(new SipMessage());
3106     mDialog.makeRequest(*bye, BYE);
3107 daniel 6047 Data txt;
3108 derek 5531 if (mEndReason != NotSpecified)
3109     {
3110 daniel 6047 Token reason("SIP");
3111     txt = getEndReasonString(mEndReason);
3112 bcampen 9176 reason.param(p_text) = txt;
3113 daniel 6047 bye->header(h_Reasons).push_back(reason);
3114 derek 5531 }
3115 bcampen 8200
3116     if (mDum.mDialogEventStateManager)
3117     {
3118     mDum.mDialogEventStateManager->onTerminated(mDialog, *bye, InviteSessionHandler::LocalBye);
3119     }
3120 derek 5531
3121 daniel 6047 InfoLog (<< myAddr() << " Sending BYE " << txt);
3122 daniel 5505 send(bye);
3123 Danweber 9098 return bye;
3124 jason 4010 }
3125 derek 2992
3126 sgodin 9033 DialogUsageManager::EncryptionLevel
3127     InviteSession::getEncryptionLevel(const SipMessage& msg)
3128 daniel 5068 {
3129     DialogUsageManager::EncryptionLevel level = DialogUsageManager::None;
3130     const SecurityAttributes* secAttr = msg.getSecurityAttributes();
3131     if (secAttr)
3132     {
3133     SignatureStatus sig = secAttr->getSignatureStatus();
3134     bool sign = (SignatureTrusted == sig || SignatureCATrusted == sig || SignatureSelfSigned == sig);
3135     bool encrypted = secAttr->isEncrypted();
3136     if (encrypted && sign ) level = DialogUsageManager::SignAndEncrypt;
3137     else if (encrypted) level = DialogUsageManager::Encrypt;
3138     else if (sign) level = DialogUsageManager::Sign;
3139     }
3140     return level;
3141     }
3142 derek 2992
3143 sgodin 9033 void
3144     InviteSession::setCurrentLocalOfferAnswer(const SipMessage& msg)
3145 daniel 5068 {
3146 sgodin 8726 assert(mProposedLocalOfferAnswer.get());
3147     if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))
3148 daniel 5068 {
3149     if (DialogUsageManager::Encrypt == getEncryptionLevel(msg) || DialogUsageManager::SignAndEncrypt == getEncryptionLevel(msg))
3150     {
3151 sgodin 8726 mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))->parts().back()->clone()));
3152 daniel 5068 }
3153     else
3154     {
3155 sgodin 8726 mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalOfferAnswer.get()))->parts().front()->clone()));
3156 daniel 5068 }
3157     }
3158     else
3159     {
3160 sgodin 8726 mCurrentLocalOfferAnswer = auto_ptr<Contents>(static_cast<Contents*>(mProposedLocalOfferAnswer.get()->clone()));
3161 daniel 5068 }
3162 sgodin 8726 mProposedLocalOfferAnswer.reset();
3163 daniel 5068 }
3164    
3165 sgodin 9033 void
3166     InviteSession::onReadyToSend(SipMessage& msg)
3167 daniel 5505 {
3168     mDum.mInviteSessionHandler->onReadyToSend(getSessionHandle(), msg);
3169     }
3170 daniel 5068
3171 sgodin 9033 void
3172     InviteSession::flowTerminated()
3173 daniel 5830 {
3174 sgodin 9033 // notify handler
3175     mDum.mInviteSessionHandler->onFlowTerminated(getSessionHandle());
3176     }
3177    
3178     void
3179     InviteSession::referNoSub(const SipMessage& msg)
3180     {
3181 daniel 5830 assert(msg.isRequest() && msg.header(h_CSeq).method()==REFER);
3182     mLastReferNoSubRequest = msg;
3183     mDum.mInviteSessionHandler->onReferNoSub(getSessionHandle(), mLastReferNoSubRequest);
3184     }
3185    
3186     void
3187     InviteSession::acceptReferNoSub(int statusCode)
3188     {
3189     if (statusCode / 100 != 2)
3190     {
3191     throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
3192     }
3193    
3194     SharedPtr<SipMessage> response(new SipMessage);
3195     mDialog.makeResponse(*response, mLastReferNoSubRequest, statusCode);
3196     response->header(h_ReferSub).value() = "false";
3197 sgodin 6617 //response->header(h_Supporteds).push_back(Token(Symbols::NoReferSub));
3198 daniel 5830
3199     send(response);
3200     }
3201    
3202     void
3203     InviteSession::rejectReferNoSub(int responseCode)
3204     {
3205     if (responseCode < 400)
3206     {
3207     throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
3208     }
3209    
3210     SharedPtr<SipMessage> response(new SipMessage);
3211     mDialog.makeResponse(*response, mLastReferNoSubRequest, responseCode);
3212     send(response);
3213     }
3214    
3215 davidb 2575 /* ====================================================================
3216 jason 4010 * The Vovida Software License, Version 1.0
3217     *
3218 davidb 2575 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
3219 jason 4010 *
3220 davidb 2575 * Redistribution and use in source and binary forms, with or without
3221     * modification, are permitted provided that the following conditions
3222     * are met:
3223 jason 4010 *
3224 davidb 2575 * 1. Redistributions of source code must retain the above copyright
3225     * notice, this list of conditions and the following disclaimer.
3226 jason 4010 *
3227 davidb 2575 * 2. Redistributions in binary form must reproduce the above copyright
3228     * notice, this list of conditions and the following disclaimer in
3229     * the documentation and/or other materials provided with the
3230    
3231     * distribution.
3232 jason 4010 *
3233 davidb 2575 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
3234     * and "Vovida Open Communication Application Library (VOCAL)" must
3235     * not be used to endorse or promote products derived from this
3236     * software without prior written permission. For written
3237     * permission, please contact vocal@vovida.org.
3238     *
3239     * 4. Products derived from this software may not be called "VOCAL", nor
3240     * may "VOCAL" appear in their name, without prior written
3241     * permission of Vovida Networks, Inc.
3242 jason 4010 *
3243 davidb 2575 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
3244     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3245     * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
3246