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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5586 - (hide annotations) (download)
Fri Oct 28 21:01:13 2005 UTC (14 years, 1 month ago) by sgodin
File size: 69540 byte(s)
- modified ACK handling
  - mAckId is no longer tracked by Dialog.cxx - all logic is in InviteSession.cxx
  - Authorization and Proxy-Authorization headers are copied to acks from the InviteSession.cxx
  - 2xx retransmission is now detected and handled properly - no more incorrect handler callbacks
- DialogSet destruction bug fixed
- onStaleCallTimeout callback no has a default handler to send a BYE - app can override and send a CANCEL if desired
- 

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

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27