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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native
svn:mime-type text/plain

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27