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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5948 - (hide annotations) (download)
Fri Feb 17 15:30:16 2006 UTC (13 years, 9 months ago) by dworley
File MIME type: text/plain
File size: 72268 byte(s)
Setting more svn: properties, and adding EOLs to the ends of files
that need it.

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