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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4599 - (hide annotations) (download)
Wed May 11 23:10:19 2005 UTC (14 years, 7 months ago) by derek
Original Path: main/sip/resiprocate/dum/InviteSession.cxx
File size: 49805 byte(s)
set svn:eol-style to LF
1 jason 4010 #include "resiprocate/MultipartMixedContents.hxx"
2 derek 3138 #include "resiprocate/SdpContents.hxx"
3 jason 2725 #include "resiprocate/SipMessage.hxx"
4 jason 4010 #include "resiprocate/Helper.hxx"
5 jason 2725 #include "resiprocate/dum/Dialog.hxx"
6     #include "resiprocate/dum/DialogUsageManager.hxx"
7     #include "resiprocate/dum/InviteSession.hxx"
8 jason 4010 #include "resiprocate/dum/ServerInviteSession.hxx"
9     #include "resiprocate/dum/ClientSubscription.hxx"
10     #include "resiprocate/dum/ServerSubscription.hxx"
11 sgodin 3392 #include "resiprocate/dum/ClientInviteSession.hxx"
12 jason 2846 #include "resiprocate/dum/InviteSessionHandler.hxx"
13 jason 4010 #include "resiprocate/dum/MasterProfile.hxx"
14 derek 2961 #include "resiprocate/dum/UsageUseException.hxx"
15 jason 4010 #include "resiprocate/os/Inserter.hxx"
16 jason 2856 #include "resiprocate/os/Logger.hxx"
17 derek 3255 #include "resiprocate/os/Timer.hxx"
18 jason 4010 #include "resiprocate/os/Random.hxx"
19     #include "resiprocate/os/compat.hxx"
20     #include "resiprocate/os/WinLeakCheck.hxx"
21 jason 2555
22 sgodin 3314 // Remove warning about 'this' use in initiator list - pointer is only stored
23     #if defined(WIN32)
24 jason 4010 #pragma warning( disable : 4355 ) // using this in base member initializer list
25     #pragma warning( disable : 4800 ) // forcing value to bool (performance warning)
26 sgodin 3314 #endif
27 derek 3092
28 jason 2856 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
29 jason 4010 #define THROW(msg) throw DialogUsage::Exception(msg, __FILE__,__LINE__);
30 jason 2846
31 davidb 2603 using namespace resip;
32 derek 3255 using namespace std;
33 davidb 2603
34 jason 4010 InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog)
35 derek 3089 : DialogUsage(dum, dialog),
36 jason 4010 mState(Undefined),
37 derek 3255 mNitState(NitComplete),
38 jason 4010 mCurrentRetransmit200(0),
39 sgodin 3392 mSessionInterval(0),
40     mSessionRefresherUAS(false),
41     mSessionTimerSeq(0),
42 jason 4010 mSentRefer(false)
43 jason 2555 {
44 jason 4010 DebugLog ( << "^^^ InviteSession::InviteSession " << this);
45 jason 2846 assert(mDum.mInviteSessionHandler);
46 jason 2555 }
47    
48 derek 2858 InviteSession::~InviteSession()
49     {
50 jason 4010 DebugLog ( << "^^^ InviteSession::~InviteSession " << this);
51 derek 2858 mDialog.mInviteSession = 0;
52     }
53 jason 2846
54 jason 4010 void
55     InviteSession::dialogDestroyed(const SipMessage& msg)
56 derek 3064 {
57 jason 4010 assert(0);
58    
59     // !jf! Is this correct? Merged from main...
60     // !jf! what reason - guessed for now?
61     //mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, msg);
62     //delete this;
63     }
64    
65     const SdpContents&
66     InviteSession::getLocalSdp() const
67     {
68     return *mCurrentLocalSdp;
69     }
70    
71     const SdpContents&
72     InviteSession::getRemoteSdp() const
73     {
74     return *mCurrentRemoteSdp;
75     }
76    
77 cktam 4408 const Data&
78     InviteSession::getDialogId() const
79     {
80     return mDialog.getId().getCallId();
81     }
82    
83 jason 4010 InviteSessionHandle
84     InviteSession::getSessionHandle()
85     {
86     return InviteSessionHandle(mDum, getBaseHandle().getId());
87     }
88    
89     void InviteSession::storePeerCapabilities(const SipMessage& msg)
90     {
91     // !slg! ToDo - add methods to get this data, App may be interested
92     if (msg.exists(h_Allows))
93 derek 3064 {
94 jason 4010 mPeerSupportedMethods = msg.header(h_Allows);
95 derek 3064 }
96 jason 4010 if (msg.exists(h_Supporteds))
97     {
98     mPeerSupportedOptionTags = msg.header(h_Supporteds);
99     }
100     if (msg.exists(h_AcceptEncodings))
101     {
102     mPeerSupportedEncodings = msg.header(h_AcceptEncodings);
103     }
104     if (msg.exists(h_AcceptLanguages))
105     {
106     mPeerSupportedLanguages = msg.header(h_AcceptLanguages);
107     }
108     if (msg.exists(h_Accepts))
109     {
110     mPeerSupportedMimeTypes = msg.header(h_Accepts);
111     }
112 derek 3064 }
113    
114 jason 4010 bool
115     InviteSession::updateMethodSupported() const
116 derek 3255 {
117 jason 4010 // Check if Update is supported locally
118     if(mDum.getMasterProfile()->isMethodSupported(UPDATE))
119     {
120     // Check if peer supports UPDATE
121     return mPeerSupportedMethods.find(Token("UPDATE"));
122     }
123     return false;
124     }
125 sgodin 3392
126 jason 4010 const NameAddr&
127     InviteSession::myAddr() const
128     {
129     return mDialog.mLocalNameAddr;
130     }
131 sgodin 3392
132 jason 4010 const NameAddr&
133     InviteSession::peerAddr() const
134     {
135     return mDialog.mRemoteNameAddr;
136     }
137 sgodin 3392
138 jason 4010 bool
139     InviteSession::isConnected() const
140     {
141     switch (mState)
142     {
143     case Connected:
144     case SentUpdate:
145     case SentUpdateGlare:
146     case SentReinvite:
147     case SentReinviteGlare:
148     case ReceivedUpdate:
149     case ReceivedReinvite:
150     case ReceivedReinviteNoOffer:
151     case Answered:
152     case WaitingToOffer:
153     return true;
154    
155     default:
156     return false;
157     }
158 derek 3255 }
159 derek 3064
160 jason 4010 bool
161     InviteSession::isEarly() const
162 derek 3064 {
163 jason 4010 switch (mState)
164 derek 3064 {
165 jason 4010 case UAC_Start:
166     case UAC_Early:
167     case UAC_EarlyWithOffer:
168     case UAC_EarlyWithAnswer:
169     //case UAC_Answered:
170     //case UAC_Terminated:
171     case UAC_SentUpdateEarly:
172     case UAC_SentUpdateConnected:
173     case UAC_ReceivedUpdateEarly:
174     //case UAC_SentAnswer:
175     case UAC_QueuedUpdate:
176     return true;
177    
178     default:
179     return false;
180 derek 3064 }
181 jason 4010 }
182 derek 3064
183 jason 4010
184     bool
185     InviteSession::isTerminated() const
186     {
187     switch (mState)
188     {
189     case Terminated:
190     case WaitingToTerminate:
191     case UAC_Cancelled:
192     case UAS_WaitingToTerminate:
193     case UAS_WaitingToHangup:
194     return true;
195     default:
196     return false;
197     }
198     }
199    
200     std::ostream&
201     InviteSession::dump(std::ostream& strm) const
202     {
203     strm << "INVITE: " << mId
204     << " " << toData(mState)
205     << " ADDR=" << myAddr()
206     << " PEER=" << peerAddr();
207     return strm;
208     }
209    
210 jason 2866 void
211 jason 4010 InviteSession::provideOffer(const SdpContents& offer)
212 jason 2866 {
213 jason 4010 switch (mState)
214 derek 2965 {
215 jason 4010 case Connected:
216     case WaitingToOffer:
217     case UAS_WaitingToOffer:
218     if (updateMethodSupported())
219     {
220     transition(SentUpdate);
221     mDialog.makeRequest(mLastSessionModification, UPDATE);
222     }
223     else
224     {
225     transition(SentReinvite);
226     mDialog.makeRequest(mLastSessionModification, INVITE);
227     }
228 sgodin 4369 setSessionTimerHeaders(mLastSessionModification);
229 jason 4010
230     InfoLog (<< "Sending " << mLastSessionModification.brief());
231     InviteSession::setSdp(mLastSessionModification, offer);
232     mProposedLocalSdp = InviteSession::makeSdp(offer);
233     mDialog.send(mLastSessionModification);
234     break;
235    
236     case Answered:
237     // queue the offer to be sent after the ACK is received
238     transition(WaitingToOffer);
239     mProposedLocalSdp = InviteSession::makeSdp(offer);
240     break;
241    
242     // !slg! Can we handle all of the states listed in isConnected() ???
243     default:
244     WarningLog (<< "Can't provideOffer when not in Connected state");
245     throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
246 derek 2965 }
247 jason 2866 }
248    
249     void
250 jason 4010 InviteSession::provideAnswer(const SdpContents& answer)
251 jason 2866 {
252 jason 4010 switch (mState)
253 derek 2965 {
254 jason 4010 case ReceivedReinvite:
255     transition(Connected);
256     mDialog.makeResponse(mInvite200, mLastSessionModification, 200);
257     handleSessionTimerRequest(mInvite200, mLastSessionModification);
258     InviteSession::setSdp(mInvite200, answer);
259     mCurrentLocalSdp = InviteSession::makeSdp(answer);
260     mCurrentRemoteSdp = mProposedRemoteSdp;
261     InfoLog (<< "Sending " << mInvite200.brief());
262     mDialog.send(mInvite200);
263     startRetransmit200Timer();
264     break;
265    
266     case ReceivedUpdate: // same as ReceivedReinvite case.
267     {
268     transition(Connected);
269    
270     SipMessage response;
271     mDialog.makeResponse(response, mLastSessionModification, 200);
272     handleSessionTimerRequest(response, mLastSessionModification);
273     InviteSession::setSdp(response, answer);
274     mCurrentLocalSdp = InviteSession::makeSdp(answer);
275     mCurrentRemoteSdp = mProposedRemoteSdp;
276     InfoLog (<< "Sending " << response.brief());
277     mDialog.send(response);
278     break;
279     }
280    
281     default:
282 sgodin 4394 WarningLog (<< "Can't provideAnswer when not in Connected state");
283 jason 4010 throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__);
284 derek 2965 }
285 jason 2866 }
286    
287 jason 4010 void
288     InviteSession::end()
289 jason 2555 {
290 jason 4010 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
291    
292     switch (mState)
293     {
294     case Connected:
295     {
296     // !jf! do we need to store the BYE somewhere?
297     sendBye();
298     transition(Terminated);
299     handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
300     break;
301     }
302    
303     case SentUpdate:
304     sendBye();
305     transition(Terminated);
306     handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
307     break;
308    
309     case SentReinvite:
310     transition(WaitingToTerminate);
311     break;
312    
313     case ReceivedUpdate:
314     case ReceivedReinvite:
315     case ReceivedReinviteNoOffer:
316     {
317     SipMessage response;
318     mDialog.makeResponse(response, mLastSessionModification, 488);
319     InfoLog (<< "Sending " << response.brief());
320     mDialog.send(response);
321    
322     sendBye();
323     transition(Terminated);
324     handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
325     break;
326     }
327    
328     case WaitingToTerminate:
329     {
330     sendBye();
331     transition(Terminated);
332     handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
333     break;
334     }
335    
336     case Terminated:
337     // no-op.
338     break;
339    
340     default:
341     assert(0);
342     break;
343     }
344 jason 2555 }
345    
346 jason 4010 void
347     InviteSession::reject(int statusCode, WarningCategory *warning)
348 jason 2555 {
349 jason 4010 switch (mState)
350     {
351     case ReceivedUpdate:
352     case ReceivedReinvite:
353     case ReceivedReinviteNoOffer:
354     {
355     transition(Connected);
356    
357     SipMessage response;
358     mDialog.makeResponse(response, mLastSessionModification, statusCode);
359     if(warning)
360     {
361     response.header(h_Warnings).push_back(*warning);
362     }
363     InfoLog (<< "Sending " << response.brief());
364     mDialog.send(response);
365     break;
366     }
367    
368     default:
369     assert(0);
370     break;
371     }
372 jason 2555 }
373 davidb 2575
374 jason 4010 void
375     InviteSession::targetRefresh(const NameAddr& localUri)
376 jason 2941 {
377 jason 4010 if (isConnected()) // !slg! likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
378     {
379     // !jf! add interface to Dialog
380     //mDialog.setLocalContact(localUri);
381     provideOffer(*mCurrentLocalSdp);
382     }
383     else
384     {
385     WarningLog (<< "Can't targetRefresh before Connected");
386     assert(0);
387     throw UsageUseException("targetRefresh not allowed in this context", __FILE__, __LINE__);
388     }
389 jason 2941 }
390    
391 jason 2856 void
392 jason 4010 InviteSession::refer(const NameAddr& referTo)
393     {
394     if (mSentRefer)
395     {
396     throw UsageUseException("Attempted to send overlapping refer", __FILE__, __LINE__);
397     }
398    
399     if (isConnected()) // !slg! likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
400     {
401     mSentRefer = true;
402     SipMessage refer;
403     mDialog.makeRequest(refer, REFER);
404     refer.header(h_ReferTo) = referTo;
405     refer.header(h_ReferredBy) = mDialog.mLocalContact; // !slg! is it ok to do this - should it be an option?
406     mDialog.send(refer);
407     }
408     else
409     {
410     WarningLog (<< "Can't refer before Connected");
411     assert(0);
412     throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
413     }
414     }
415    
416     void
417     InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace)
418     {
419     if (!sessionToReplace.isValid())
420     {
421     throw UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__);
422     }
423    
424     if (mSentRefer)
425     {
426     throw UsageUseException("Attempted to send overlapping refer", __FILE__, __LINE__);
427     }
428    
429     if (isConnected()) // !slg! likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
430     {
431     mSentRefer = true;
432     SipMessage refer;
433     mDialog.makeRequest(refer, REFER);
434    
435     refer.header(h_ReferTo) = referTo;
436     refer.header(h_ReferredBy) = mDialog.mLocalContact; // !slg! is it ok to do this - should it be an option?
437     CallId replaces;
438     DialogId id = sessionToReplace->mDialog.getId();
439     replaces.value() = id.getCallId();
440     replaces.param(p_toTag) = id.getRemoteTag();
441     replaces.param(p_fromTag) = id.getLocalTag();
442    
443     refer.header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces;
444     mDialog.send(refer);
445     }
446     else
447     {
448     WarningLog (<< "Can't refer before Connected");
449     assert(0);
450     throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__);
451     }
452     }
453    
454     void
455     InviteSession::info(const Contents& contents)
456     {
457     if (mNitState == NitComplete)
458     {
459     if (isConnected()) // !slg! likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite?
460     {
461     mNitState = NitProceeding;
462     SipMessage info;
463     mDialog.makeRequest(info, INFO);
464     // !jf! handle multipart here
465     info.setContents(&contents);
466     mDialog.send(info);
467     }
468     else
469     {
470     WarningLog (<< "Can't send INFO before Connected");
471     assert(0);
472     throw UsageUseException("Can't send INFO before Connected", __FILE__, __LINE__);
473     }
474     }
475     else
476     {
477     throw UsageUseException("Cannot start a non-invite transaction until the previous one has completed",
478     __FILE__, __LINE__);
479     }
480     }
481    
482     void
483     InviteSession::dispatch(const SipMessage& msg)
484     {
485     // !jf! do we need to handle 3xx here or is it handled elsewhere?
486     switch (mState)
487     {
488     case Connected:
489     dispatchConnected(msg);
490     break;
491     case SentUpdate:
492     dispatchSentUpdate(msg);
493     break;
494     case SentReinvite:
495     dispatchSentReinvite(msg);
496     break;
497     case SentUpdateGlare:
498     case SentReinviteGlare:
499     // The behavior is the same except for timer which is handled in dispatch(Timer)
500     dispatchGlare(msg);
501     break;
502     case ReceivedUpdate:
503     case ReceivedReinvite:
504     case ReceivedReinviteNoOffer:
505     dispatchReceivedUpdateOrReinvite(msg);
506     break;
507     case Answered:
508     dispatchAnswered(msg);
509     break;
510     case WaitingToOffer:
511     dispatchWaitingToOffer(msg);
512     break;
513     case WaitingToTerminate:
514     dispatchWaitingToTerminate(msg);
515     break;
516     case Terminated:
517     dispatchTerminated(msg);
518     break;
519     case Undefined:
520     default:
521     assert(0);
522     break;
523     }
524     }
525    
526     void
527 derek 2990 InviteSession::dispatch(const DumTimeout& timeout)
528     {
529 derek 3255 if (timeout.type() == DumTimeout::Retransmit200)
530 derek 2990 {
531 jason 4010 if (mCurrentRetransmit200)
532 derek 3255 {
533 jason 4010 InfoLog (<< "Retransmitting: " << endl << mInvite200);
534     mDialog.send(mInvite200);
535 derek 3255 mCurrentRetransmit200 *= 2;
536     mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq());
537     }
538 derek 2990 }
539 derek 3255 else if (timeout.type() == DumTimeout::WaitForAck)
540 derek 2990 {
541 jason 4010 if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet
542 derek 3255 {
543 jason 4010 mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
544    
545     // this is so the app can decided to ignore this. default implementation
546     // will call end next
547     mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle());
548    
549     // If we are waiting for an Ack and it times out, then end with a BYE
550     if(mState == UAS_WaitingToHangup)
551 sgodin 3363 {
552 jason 4010 sendBye();
553     transition(Terminated);
554     mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
555 sgodin 3363 }
556 derek 3255 }
557 derek 2990 }
558 jason 4010 else if (timeout.type() == DumTimeout::Glare)
559 derek 3255 {
560 jason 4010 if (mState == SentUpdateGlare)
561     {
562     transition(SentUpdate);
563    
564     InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
565     mDialog.send(mLastSessionModification);
566     }
567     else if (mState == SentReinviteGlare)
568     {
569     transition(SentReinvite);
570    
571     InfoLog (<< "Retransmitting the reINVITE (glare condition timer)");
572     mDialog.send(mLastSessionModification);
573     }
574 derek 3255 }
575 sgodin 3392 else if (timeout.type() == DumTimeout::SessionExpiration)
576     {
577     if(timeout.seq() == mSessionTimerSeq)
578     {
579 jason 4010 // this is so the app can decided to ignore this. default implementation
580     // will call end next
581     mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle());
582 sgodin 3392 }
583     }
584     else if (timeout.type() == DumTimeout::SessionRefresh)
585     {
586 jason 4010 if(timeout.seq() == mSessionTimerSeq)
587 sgodin 3392 {
588 jason 4010 if(mState == Connected) // Note: If not connected then we must be issueing a reinvite/update or receiving one - in either case the session timer stuff will get reset/renegotiated - thus just ignore this referesh
589 sgodin 3392 {
590 sgodin 4369 sessionRefresh();
591 sgodin 3392 }
592     }
593     }
594 derek 2990 }
595    
596 jason 4010
597     void
598     InviteSession::dispatchConnected(const SipMessage& msg)
599 sgodin 3392 {
600 jason 4010 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
601     std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
602    
603     switch (toEvent(msg, sdp.get()))
604 sgodin 3392 {
605 jason 4010 case OnInvite:
606     case OnInviteReliable:
607     mLastSessionModification = msg;
608     transition(ReceivedReinviteNoOffer);
609     //handler->onDialogModified(getSessionHandle(), None, msg);
610     handler->onOfferRequired(getSessionHandle(), msg);
611     break;
612 sgodin 3392
613 jason 4010 case OnInviteOffer:
614     case OnInviteReliableOffer:
615     mLastSessionModification = msg;
616     transition(ReceivedReinvite);
617     //handler->onDialogModified(getSessionHandle(), Offer, msg);
618     handler->onOffer(getSessionHandle(), msg, *sdp);
619     break;
620    
621     case On2xx:
622     case On2xxOffer:
623     case On2xxAnswer:
624     // retransmission of 200I
625     // !jf! Need to include the answer here.
626     sendAck();
627     break;
628    
629 sgodin 4369 case OnUpdateOffer:
630 jason 4010 transition(ReceivedUpdate);
631    
632     // !kh!
633     // Find out if it's an UPDATE requiring state change.
634     // See rfc3311 5.2, 4th paragraph.
635     mLastSessionModification = msg;
636     handler->onOffer(getSessionHandle(), msg, *sdp);
637     break;
638    
639 sgodin 4369 case OnUpdate:
640     {
641     // !slg! no sdp in update - just responsd immediately (likely session timer) - do we need a callback?
642     SipMessage response;
643     mLastSessionModification = msg;
644     mDialog.makeResponse(response, mLastSessionModification, 200);
645     handleSessionTimerRequest(response, mLastSessionModification);
646     send(response);
647     break;
648     }
649    
650 jason 4010 case OnUpdateRejected:
651     case On200Update:
652     WarningLog (<< "DUM delivered an UPDATE response in an incorrect state " << endl << msg);
653     assert(0);
654     break;
655    
656     case OnAck:
657     mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
658     break;
659    
660     default:
661     dispatchOthers(msg);
662     break;
663     }
664     }
665    
666    
667    
668     void
669     InviteSession::dispatchSentUpdate(const SipMessage& msg)
670     {
671     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
672     std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
673    
674     switch (toEvent(msg, sdp.get()))
675     {
676     case OnInvite:
677     case OnInviteReliable:
678     case OnInviteOffer:
679     case OnInviteReliableOffer:
680     case OnUpdate:
681 sgodin 4369 case OnUpdateOffer:
682 sgodin 3392 {
683 jason 4010 // glare
684     SipMessage response;
685     mDialog.makeResponse(response, msg, 491);
686     send(response);
687     break;
688     }
689    
690     case On200Update:
691     transition(Connected);
692     handleSessionTimerResponse(msg);
693     if (sdp.get())
694 sgodin 3392 {
695 jason 4010 mCurrentLocalSdp = mProposedLocalSdp;
696     mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
697     handler->onAnswer(getSessionHandle(), msg, *sdp);
698 sgodin 3392 }
699 sgodin 4369 else if(mProposedLocalSdp.get())
700 sgodin 3392 {
701 sgodin 4369 // If we sent an offer in the Update Request and no answer is received
702 jason 4010 handler->onIllegalNegotiation(getSessionHandle(), msg);
703 sgodin 4369 mProposedLocalSdp.release();
704 jason 4010 }
705     break;
706    
707     case On491Update:
708 sgodin 4369 transition(SentUpdateGlare);
709 jason 4010 start491Timer();
710     break;
711    
712 sgodin 4394 case On422Update:
713     if(msg.exists(h_MinSE))
714     {
715     // Change interval to min from 422 response
716     mSessionInterval = msg.header(h_MinSE).value();
717     sessionRefresh();
718     }
719     else
720     {
721     // Response must contact Min_SE - if not - just ignore
722     // !slg! callback?
723     transition(Connected);
724     mProposedLocalSdp.release();
725     }
726     break;
727    
728 jason 4010 case OnUpdateRejected:
729 sgodin 4369 // !jf! - callback?
730     mProposedLocalSdp.release();
731     transition(Connected);
732 jason 4010 break;
733    
734     case OnGeneralFailure:
735     sendBye();
736     transition(Terminated);
737     handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
738     break;
739    
740     default:
741     dispatchOthers(msg);
742     break;
743     }
744     }
745    
746     void
747     InviteSession::dispatchSentReinvite(const SipMessage& msg)
748     {
749     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
750     std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg);
751    
752     switch (toEvent(msg, sdp.get()))
753     {
754     case OnInvite:
755     case OnInviteReliable:
756     case OnInviteOffer:
757     case OnInviteReliableOffer:
758     case OnUpdate:
759 sgodin 4369 case OnUpdateOffer:
760 jason 4010 {
761     SipMessage response;
762     mDialog.makeResponse(response, msg, 491);
763     send(response);
764     break;
765 sgodin 3392 }
766 jason 4010
767     case On1xx:
768     case On1xxEarly:
769     // !slg! Some UA's send a 100 response to a ReInvite - just ignore it
770     break;
771    
772     case On2xxAnswer:
773     case On2xxOffer:
774 sgodin 3392 {
775 jason 4010 transition(Connected);
776     handleSessionTimerResponse(msg);
777     mCurrentLocalSdp = mProposedLocalSdp;
778     mCurrentRemoteSdp = InviteSession::makeSdp(*sdp);
779     // !jf! I need to potentially include an answer in the ACK here
780     sendAck();
781     handler->onAnswer(getSessionHandle(), msg, *sdp);
782    
783    
784     // !jf! do I need to allow a reINVITE overlapping the retransmission of
785     // the ACK when a 200I is received? If yes, then I need to store all
786     // ACK messages for 64*T1
787     break;
788     }
789     case On2xx:
790     sendAck();
791     transition(Connected);
792     handleSessionTimerResponse(msg);
793     handler->onIllegalNegotiation(getSessionHandle(), msg);
794 sgodin 4369 mProposedLocalSdp.release();
795 jason 4010 break;
796    
797 sgodin 4394 case On422Invite:
798     if(msg.exists(h_MinSE))
799     {
800     // Change interval to min from 422 response
801     mSessionInterval = msg.header(h_MinSE).value();
802     sessionRefresh();
803     }
804     else
805     {
806     // Response must contact Min_SE - if not - just ignore
807     // !slg! callback?
808     transition(Connected);
809     mProposedLocalSdp.release();
810     }
811     break;
812    
813 jason 4010 case On491Invite:
814 sgodin 4369 transition(SentReinviteGlare);
815 jason 4010 start491Timer();
816     break;
817    
818     case OnGeneralFailure:
819     sendBye();
820     transition(Terminated);
821     handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
822     break;
823    
824     case OnInviteFailure:
825     transition(Connected);
826 sgodin 4369 mProposedLocalSdp.release();
827 jason 4010 handler->onOfferRejected(getSessionHandle(), msg);
828     break;
829    
830     default:
831     dispatchOthers(msg);
832     break;
833     }
834     }
835    
836     void
837     InviteSession::dispatchGlare(const SipMessage& msg)
838     {
839     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
840     MethodTypes method = msg.header(h_CSeq).method();
841     if (method == INVITE && msg.isRequest())
842     {
843     // Received inbound reinvite, when waiting to resend outbound reinvite or update
844     transition(ReceivedReinvite);
845     handler->onOfferRejected(getSessionHandle(), msg);
846     }
847     else if (method == UPDATE && msg.isRequest())
848     {
849     // Received inbound update, when waiting to resend outbound reinvite or update
850     transition(ReceivedUpdate);
851     handler->onOfferRejected(getSessionHandle(), msg);
852     }
853     else
854     {
855     dispatchOthers(msg);
856     }
857     }
858    
859     void
860     InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg)
861     {
862     MethodTypes method = msg.header(h_CSeq).method();
863     if (method == INVITE || method == UPDATE)
864     {
865     // Means that the UAC has sent us a second reINVITE or UPDATE before we
866     // responded to the first one. Bastard!
867     SipMessage response;
868     mDialog.makeResponse(response, msg, 500);
869     response.header(h_RetryAfter).value() = Random::getRandom() % 10;
870     mDialog.send(response);
871     }
872     else
873     {
874     dispatchOthers(msg);
875     }
876     }
877    
878    
879     void
880     InviteSession::dispatchAnswered(const SipMessage& msg)
881     {
882     if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
883     {
884     mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
885     transition(Connected);
886     }
887     else
888     {
889     dispatchOthers(msg);
890     }
891     }
892    
893     void
894     InviteSession::dispatchWaitingToOffer(const SipMessage& msg)
895     {
896     if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
897     {
898     mCurrentRetransmit200 = 0; // stop the 200 retransmit timer
899     provideOffer(*mProposedLocalSdp);
900     }
901     else
902     {
903     dispatchOthers(msg);
904     }
905     }
906    
907     void
908     InviteSession::dispatchWaitingToTerminate(const SipMessage& msg)
909     {
910     if (msg.isResponse() &&
911     msg.header(h_CSeq).method() == INVITE)
912     {
913     if(msg.header(h_StatusLine).statusCode() / 200 == 1) // Note: stack ACK's non-2xx final responses only
914     {
915     // !jf! Need to include the answer here.
916     sendAck();
917     }
918     sendBye();
919     transition(Terminated);
920     mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended);
921     }
922     }
923    
924     void
925     InviteSession::dispatchTerminated(const SipMessage& msg)
926     {
927     InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief());
928    
929     if (msg.isRequest())
930     {
931     SipMessage response;
932     mDialog.makeResponse(response, msg, 481);
933     mDialog.send(response);
934    
935     // !jf! means the peer sent BYE while we are waiting for response to BYE
936     //mDum.destroy(this);
937     }
938     else
939     {
940     mDum.destroy(this);
941     }
942     }
943    
944     void
945     InviteSession::dispatchOthers(const SipMessage& msg)
946     {
947     // handle OnGeneralFailure
948     // handle OnRedirect
949    
950     switch (msg.header(h_CSeq).method())
951     {
952     case PRACK:
953     dispatchPrack(msg);
954     break;
955     case CANCEL:
956     dispatchCancel(msg);
957     break;
958     case BYE:
959     dispatchBye(msg);
960     break;
961     case INFO:
962     dispatchInfo(msg);
963     break;
964     case ACK:
965     // Ignore duplicate ACKs from 2xx reTransmissions
966     break;
967     default:
968     // handled in Dialog
969     WarningLog (<< "DUM delivered a "
970     << msg.header(h_CSeq).unknownMethodName()
971     << " to the InviteSession "
972     << endl
973     << msg);
974     assert(0);
975     break;
976     }
977     }
978    
979     void
980     InviteSession::dispatchUnhandledInvite(const SipMessage& msg)
981     {
982     assert(msg.isRequest());
983     assert(msg.header(h_CSeq).method() == INVITE);
984    
985     // If we get an INVITE request from the wire and we are not in
986     // Connected state, reject the request and send a BYE
987     SipMessage response;
988     mDialog.makeResponse(response, msg, 400); // !jf! what code to use?
989     InfoLog (<< "Sending " << response.brief());
990     mDialog.send(response);
991    
992     sendBye();
993     transition(Terminated);
994     mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
995     }
996    
997     void
998     InviteSession::dispatchPrack(const SipMessage& msg)
999     {
1000     assert(msg.header(h_CSeq).method() == PRACK);
1001     if(msg.isRequest())
1002     {
1003     SipMessage rsp;
1004     mDialog.makeResponse(rsp, msg, 481);
1005     mDialog.send(rsp);
1006    
1007     sendBye();
1008     // !jf! should we make some other callback here
1009     transition(Terminated);
1010     mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg);
1011     }
1012     else
1013     {
1014     // ignore. could be PRACK/200
1015     }
1016     }
1017    
1018     void
1019     InviteSession::dispatchCancel(const SipMessage& msg)
1020     {
1021     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1022     assert(msg.header(h_CSeq).method() == CANCEL);
1023     if(msg.isRequest())
1024     {
1025     SipMessage rsp;
1026     mDialog.makeResponse(rsp, msg, 200);
1027     mDialog.send(rsp);
1028    
1029     sendBye();
1030     // !jf! should we make some other callback here
1031     transition(Terminated);
1032     handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1033     }
1034     else
1035     {
1036     WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg);
1037     assert(0);
1038     }
1039     }
1040    
1041     void
1042     InviteSession::dispatchBye(const SipMessage& msg)
1043     {
1044     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1045    
1046     if (msg.isRequest())
1047     {
1048    
1049     SipMessage rsp;
1050     InfoLog (<< "Received " << msg.brief());
1051     mDialog.makeResponse(rsp, msg, 200);
1052     mDialog.send(rsp);
1053    
1054     // !jf! should we make some other callback here
1055     transition(Terminated);
1056     handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg);
1057     mDum.destroy(this);
1058     }
1059     else
1060     {
1061     WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg);
1062     assert(0);
1063     }
1064     }
1065    
1066     void
1067     InviteSession::dispatchInfo(const SipMessage& msg)
1068     {
1069     InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1070     if (msg.isRequest())
1071     {
1072     InfoLog (<< "Received " << msg.brief());
1073     mDialog.makeResponse(mLastNitResponse, msg, 200);
1074     handler->onInfo(getSessionHandle(), msg);
1075     }
1076     else
1077     {
1078     assert(mNitState == NitProceeding);
1079     mNitState = NitComplete;
1080     //!dcm! -- toss away 1xx to an info?
1081     if (msg.header(h_StatusLine).statusCode() >= 300)
1082     {
1083     handler->onInfoFailure(getSessionHandle(), msg);
1084     }
1085     else if (msg.header(h_StatusLine).statusCode() >= 200)
1086     {
1087     handler->onInfoSuccess(getSessionHandle(), msg);
1088     }
1089     }
1090     }
1091    
1092     void
1093     InviteSession::acceptInfo(int statusCode)
1094     {
1095     if (statusCode / 100 != 2)
1096     {
1097     throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__);
1098     }
1099    
1100     mLastNitResponse.header(h_StatusLine).statusCode() = statusCode;
1101     send(mLastNitResponse);
1102     }
1103    
1104     void
1105     InviteSession::rejectInfo(int statusCode)
1106     {
1107     if (statusCode < 400)
1108     {
1109     throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__);
1110     }
1111     mLastNitResponse.header(h_StatusLine).statusCode() = statusCode;
1112     send(mLastNitResponse);
1113     }
1114    
1115     void
1116     InviteSession::startRetransmit200Timer()
1117     {
1118     mCurrentRetransmit200 = Timer::T1;
1119     int seq = mLastSessionModification.header(h_CSeq).sequence();
1120     mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq);
1121     mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq);
1122     }
1123    
1124     void
1125     InviteSession::start491Timer()
1126     {
1127     int seq = mLastSessionModification.header(h_CSeq).sequence();
1128     int timer = Random::getRandom() % 4000;
1129     mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq);
1130     }
1131    
1132 sgodin 4369 void
1133     InviteSession::setSessionTimerHeaders(SipMessage &msg)
1134     {
1135     if(mSessionInterval >= 90) // If mSessionInterval is 0 then SessionTimers are considered disabled
1136     {
1137     msg.header(h_SessionExpires).value() = mSessionInterval;
1138     msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresherUAS ? "uas" : "uac");
1139     }
1140     else
1141     {
1142     msg.remove(h_SessionExpires);
1143     msg.remove(h_MinSE);
1144     }
1145     }
1146    
1147 jason 4010 void
1148 sgodin 4369 InviteSession::sessionRefresh()
1149     {
1150     if (updateMethodSupported())
1151     {
1152     transition(SentUpdate);
1153     mDialog.makeRequest(mLastSessionModification, UPDATE);
1154     mLastSessionModification.releaseContents(); // Don't send SDP
1155     }
1156     else
1157     {
1158     transition(SentReinvite);
1159     mDialog.makeRequest(mLastSessionModification, INVITE);
1160     InviteSession::setSdp(mLastSessionModification, *mCurrentLocalSdp);
1161     mProposedLocalSdp = InviteSession::makeSdp(*mCurrentLocalSdp);
1162     }
1163     setSessionTimerHeaders(mLastSessionModification);
1164    
1165     InfoLog (<< "Sending " << mLastSessionModification.brief());
1166     mDialog.send(mLastSessionModification);
1167     }
1168    
1169     void
1170 jason 4010 InviteSession::handleSessionTimerResponse(const SipMessage& msg)
1171     {
1172     assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE);
1173    
1174     // If session timers are locally supported then handle response
1175     if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1176     {
1177     //Profile::SessionTimerMode mode = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode();
1178     bool fUAS = dynamic_cast<ServerInviteSession*>(this) != NULL;
1179    
1180     // Set Defaults
1181     mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if response didn't request a time
1182     switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
1183     {
1184     case Profile::PreferLocalRefreshes:
1185     mSessionRefresherUAS = fUAS; // Default refresher is Local
1186     break;
1187     case Profile::PreferRemoteRefreshes:
1188     mSessionRefresherUAS = !fUAS; // Default refresher is Remote
1189     break;
1190     case Profile::PreferUACRefreshes:
1191     mSessionRefresherUAS = false; // Default refresher is UAC
1192     break;
1193     case Profile::PreferUASRefreshes:
1194     mSessionRefresherUAS = true; // Default refresher is UAS
1195     break;
1196     }
1197    
1198     if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer))
1199     && !msg.exists(h_SessionExpires))
1200     {
1201     // If no Session Expires in response and Requires header is present then session timer is to be 'turned off'
1202     mSessionInterval = 0;
1203     }
1204     // Process Session Timer headers
1205     else if(msg.exists(h_SessionExpires))
1206     {
1207 sgodin 3392 mSessionInterval = msg.header(h_SessionExpires).value();
1208     if(msg.header(h_SessionExpires).exists(p_refresher))
1209     {
1210 jason 4010 // Remote end specified refresher preference
1211     mSessionRefresherUAS = (msg.header(h_SessionExpires).param(p_refresher) == Data("uas"));
1212 sgodin 3392 }
1213     }
1214 jason 4010 else
1215     {
1216     // Note: If no Requires or Session-Expires, then UAS does not support Session Timers
1217     // - we are free to use our SessionInterval settings (set above as a default)
1218     // If far end doesn't support then refresher must be local
1219     mSessionRefresherUAS = fUAS;
1220     }
1221 sgodin 3392
1222     if(mSessionInterval >= 90) // 90 is the absolute minimum
1223     {
1224     // Check if we are the refresher
1225     if((fUAS && mSessionRefresherUAS) || (!fUAS && !mSessionRefresherUAS))
1226     {
1227     // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by draft-ietf-sip-session-timer-15)
1228     mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
1229     }
1230     else
1231     {
1232 jason 3433 // Start Session-Expiration Timer to mSessionInterval - BYE should be sent a minimum of 32 or SessionInterval/3 seconds before the session expires (recommended by draft-ietf-sip-session-timer-15)
1233 sgodin 3392 mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin(32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
1234     }
1235     }
1236 jason 4010 else
1237     {
1238     ++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled
1239     }
1240 sgodin 3392 }
1241     }
1242    
1243 jason 4010 void
1244     InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request)
1245 sgodin 3392 {
1246 jason 4010 assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE);
1247    
1248 sgodin 3392 // If session timers are locally supported then add necessary headers to response
1249 jason 4010 if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer)))
1250 sgodin 3392 {
1251     bool fUAS = dynamic_cast<ServerInviteSession*>(this) != NULL;
1252    
1253 jason 4010 mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if remote doesn't request a time
1254     switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode())
1255 sgodin 3392 {
1256 jason 4010 case Profile::PreferLocalRefreshes:
1257     mSessionRefresherUAS = fUAS; // Default refresher is Local
1258     break;
1259     case Profile::PreferRemoteRefreshes:
1260     mSessionRefresherUAS = !fUAS; // Default refresher is Remote
1261     break;
1262     case Profile::PreferUACRefreshes:
1263     mSessionRefresherUAS = false; // Default refresher is UAC
1264     break;
1265     case Profile::PreferUASRefreshes:
1266     mSessionRefresherUAS = true; // Default refresher is UAS
1267     break;
1268 sgodin 3392 }
1269    
1270     // Check if far-end supports
1271     bool farEndSupportsTimer = false;
1272     if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer)))
1273     {
1274     farEndSupportsTimer = true;
1275     if(request.exists(h_SessionExpires))
1276     {
1277 jason 4010 // Use Session Interval requested by remote - if none then use local settings
1278 sgodin 3392 mSessionInterval = request.header(h_SessionExpires).value();
1279     if(request.header(h_SessionExpires).exists(p_refresher))
1280     {
1281 jason 4010 mSessionRefresherUAS = (request.header(h_SessionExpires).param(p_refresher) == Data("uas"));
1282 sgodin 3392 }
1283     }
1284     }
1285 jason 4010 else
1286     {
1287     // If far end doesn't support then refresher must be local
1288     mSessionRefresherUAS = fUAS;
1289     }
1290 sgodin 3392
1291 jason 4010 // Add Session-Expires to response if required
1292 sgodin 3392 if(mSessionInterval >= 90)
1293     {
1294 jason 4010 if(farEndSupportsTimer)
1295 sgodin 3392 {
1296 jason 4010 // If far end supports session-timer then require it, if not already present
1297     if(!response.header(h_Requires).find(Token(Symbols::Timer)))
1298     {
1299     response.header(h_Requires).push_back(Token(Symbols::Timer));
1300     }
1301 sgodin 3392 }
1302     response.header(h_SessionExpires).value() = mSessionInterval;
1303     response.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresherUAS ? "uas" : "uac");
1304    
1305     // Check if we are the refresher
1306     if((fUAS && mSessionRefresherUAS) || (!fUAS && !mSessionRefresherUAS))
1307     {
1308     // Start Session-Refresh Timer to mSessionInterval / 2 (recommended by draft-ietf-sip-session-timer-15)
1309     mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq);
1310     }
1311     else
1312     {
1313 jason 3433 // Start Session-Expiration Timer to mSessionInterval - BYE should be sent a minimum of 32 or SessionInterval/3 seconds before the session expires (recommended by draft-ietf-sip-session-timer-15)
1314 sgodin 3392 mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin(32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq);
1315     }
1316     }
1317 jason 4010 else
1318     {
1319     ++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled
1320     }
1321 sgodin 3392 }
1322     }
1323    
1324 jason 4010 Data
1325     InviteSession::toData(State state)
1326 jason 2856 {
1327 jason 4010 switch (state)
1328 derek 3255 {
1329 jason 4010 case Undefined:
1330     return "InviteSession::Undefined";
1331     case Connected:
1332     return "InviteSession::Connected";
1333     case SentUpdate:
1334     return "InviteSession::SentUpdate";
1335     case SentUpdateGlare:
1336     return "InviteSession::SentUpdateGlare";
1337     case SentReinvite:
1338     return "InviteSession::SentReinvite";
1339     case SentReinviteGlare:
1340     return "InviteSession::SentReinviteGlare";
1341     case ReceivedUpdate:
1342     return "InviteSession::ReceivedUpdate";
1343     case ReceivedReinvite:
1344     return "InviteSession::ReceivedReinvite";
1345     case ReceivedReinviteNoOffer:
1346     return "InviteSession::ReceivedReinviteNoOffer";
1347     case Answered:
1348     return "InviteSession::Answered";
1349     case WaitingToOffer:
1350     return "InviteSession::WaitingToOffer";
1351     case WaitingToTerminate:
1352     return "InviteSession::WaitingToTerminate";
1353 derek 2961 case Terminated:
1354 jason 4010 return "InviteSession::Terminated";
1355 jason 2856
1356 jason 4010 case UAC_Start:
1357     return "UAC_Start";
1358     case UAS_Offer:
1359     return "UAS_Offer";
1360     case UAS_OfferProvidedAnswer:
1361     return "UAS_OfferProvidedAnswer";
1362     case UAS_EarlyOffer:
1363     return "UAS_EarlyOffer";
1364     case UAS_EarlyProvidedAnswer:
1365     return "UAS_EarlyProvidedAnswer";
1366     case UAS_NoOffer:
1367     return "UAS_NoOffer";
1368     case UAS_ProvidedOffer:
1369     return "UAS_ProvidedOffer";
1370     case UAS_EarlyNoOffer:
1371     return "UAS_EarlyNoOffer";
1372     case UAS_EarlyProvidedOffer:
1373     return "UAS_EarlyProvidedOffer";
1374     case UAS_Accepted:
1375     return "UAS_Accepted";
1376     case UAS_WaitingToOffer:
1377     return "UAS_WaitingToOffer";
1378     case UAS_AcceptedWaitingAnswer:
1379     return "UAS_AcceptedWaitingAnswer";
1380     case UAC_Early:
1381     return "UAC_Early";
1382     case UAC_EarlyWithOffer:
1383     return "UAC_EarlyWithOffer";
1384     case UAC_EarlyWithAnswer:
1385     return "UAC_EarlyWithAnswer";
1386     case UAC_Answered:
1387     return "UAC_Answered";
1388     case UAC_SentUpdateEarly:
1389     return "UAC_SentUpdateEarly";
1390     case UAC_SentUpdateConnected:
1391     return "UAC_SentUpdateConnected";
1392     case UAC_ReceivedUpdateEarly:
1393     return "UAC_ReceivedUpdateEarly";
1394     case UAC_SentAnswer:
1395     return "UAC_SentAnswer";
1396     case UAC_QueuedUpdate:
1397     return "UAC_QueuedUpdate";
1398     case UAC_Cancelled:
1399     return "UAC_Cancelled";
1400 sgodin 3332
1401 jason 4010 case UAS_Start:
1402     return "UAS_Start";
1403     case UAS_OfferReliable:
1404     return "UAS_OfferReliable";
1405     case UAS_NoOfferReliable:
1406     return "UAS_NoOfferReliable";
1407     case UAS_FirstSentOfferReliable:
1408     return "UAS_FirstSentOfferReliable";
1409     case UAS_FirstEarlyReliable:
1410     return "UAS_FirstEarlyReliable";
1411     case UAS_EarlyReliable:
1412     return "UAS_EarlyReliable";
1413     case UAS_SentUpdate:
1414     return "UAS_SentUpdate";
1415     case UAS_SentUpdateAccepted:
1416     return "UAS_SentUpdateAccepted";
1417     case UAS_ReceivedUpdate:
1418     return "UAS_ReceivedUpdate";
1419     case UAS_ReceivedUpdateWaitingAnswer:
1420     return "UAS_ReceivedUpdateWaitingAnswer";
1421     case UAS_WaitingToTerminate:
1422     return "UAS_WaitingToTerminate";
1423     case UAS_WaitingToHangup:
1424     return "UAS_WaitingToHangup";
1425     }
1426     assert(0);
1427     return "Undefined";
1428     }
1429 sgodin 3392
1430    
1431 jason 4010 void
1432     InviteSession::transition(State target)
1433     {
1434     InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target));
1435     mState = target;
1436     }
1437 sgodin 3392
1438 jason 4010 bool
1439     InviteSession::isReliable(const SipMessage& msg)
1440     {
1441     // Ensure supported both locally and remotely
1442     return msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel)) &&
1443     mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::C100rel));
1444 jason 2856 }
1445    
1446 jason 4010 std::auto_ptr<SdpContents>
1447     InviteSession::getSdp(const SipMessage& msg)
1448 derek 3255 {
1449 jason 4010 // !jf! this code doesn't yet work - definitely if USE_SSL=false
1450     //Helper::ContentsSecAttrs attrs = Helper::extractFromPkcs7(msg, mDum.getSecurity());
1451     //return std::auto_ptr<SdpContents>(dynamic_cast<SdpContents*>(attrs.mContents.get()));
1452     SdpContents* sdp = dynamic_cast<SdpContents*>(msg.getContents());
1453     if (sdp)
1454 derek 3255 {
1455 jason 4010 SdpContents* cloned = static_cast<SdpContents*>(sdp->clone());
1456     return std::auto_ptr<SdpContents>(cloned);
1457 derek 3255 }
1458 jason 4010 else
1459     {
1460     static std::auto_ptr<SdpContents> empty;
1461     return empty;
1462     }
1463 derek 3255 }
1464    
1465 jason 4010 std::auto_ptr<SdpContents>
1466     InviteSession::makeSdp(const SdpContents& sdp)
1467 derek 2955 {
1468 jason 4010 return std::auto_ptr<SdpContents>(static_cast<SdpContents*>(sdp.clone()));
1469 derek 2955 }
1470 jason 2856
1471 jason 4010 void
1472     InviteSession::setSdp(SipMessage& msg, const SdpContents& sdp)
1473 derek 3112 {
1474 jason 4010 // !jf! should deal with multipart here
1475 derek 3112
1476 jason 4010 // This will clone the sdp since the InviteSession also wants to keep its own
1477     // copy of the sdp around for the application to access
1478     msg.setContents(&sdp);
1479 derek 3112 }
1480    
1481 jason 4010 InviteSession::Event
1482     InviteSession::toEvent(const SipMessage& msg, const SdpContents* sdp)
1483 jason 2621 {
1484 jason 4010 MethodTypes method = msg.header(h_CSeq).method();
1485     int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
1486     bool reliable = isReliable(msg);
1487     bool sentOffer = mProposedLocalSdp.get();
1488    
1489     if (code == 481 || code == 408)
1490 derek 2961 {
1491 jason 4010 return OnGeneralFailure;
1492     }
1493     else if (code >= 300 && code <= 399)
1494     {
1495     return OnRedirect;
1496     }
1497     else if (method == INVITE && code == 0)
1498     {
1499     if (sdp)
1500     {
1501     if (reliable)
1502 sgodin 3363 {
1503 jason 4010 return OnInviteReliableOffer;
1504     }
1505     else
1506     {
1507     return OnInviteOffer;
1508     }
1509     }
1510     else
1511     {
1512     if (reliable)
1513     {
1514     return OnInviteReliable;
1515     }
1516     else
1517     {
1518     return OnInvite;
1519     }
1520     }
1521     }
1522     else if (method == INVITE && code > 100 && code < 200) // !kh! 100 is handled by transaction layer.
1523     {
1524     if (reliable)
1525     {
1526     if (sdp)
1527     {
1528     if (sentOffer)
1529 sgodin 3363 {
1530 jason 4010 return On1xxAnswer;
1531 sgodin 3363 }
1532     else
1533     {
1534 jason 4010 return On1xxOffer;
1535 sgodin 3363 }
1536     }
1537     else
1538     {
1539 jason 4010 return On1xx;
1540 sgodin 3363 }
1541 jason 4010 }
1542     else
1543     {
1544     if (sdp)
1545 sgodin 3363 {
1546 jason 4010 return On1xxEarly;
1547 sgodin 3363 }
1548     else
1549     {
1550 jason 4010 return On1xx;
1551 sgodin 3363 }
1552 jason 4010 }
1553 derek 2961 }
1554 jason 4010 else if (method == INVITE && code >= 200 && code < 300)
1555 jason 2809 {
1556 jason 4010 if (sdp)
1557     {
1558     if (sentOffer)
1559 jason 2809 {
1560 jason 4010 return On2xxAnswer;
1561 jason 2809 }
1562     else
1563     {
1564 jason 4010 return On2xxOffer;
1565 jason 2809 }
1566 jason 4010 }
1567     else
1568     {
1569     return On2xx;
1570     }
1571 jason 2809 }
1572 sgodin 4394 else if (method == INVITE && code == 422)
1573     {
1574     return On422Invite;
1575     }
1576 jason 4010 else if (method == INVITE && code == 487)
1577 derek 3293 {
1578 jason 4010 return On487Invite;
1579 derek 3293 }
1580 jason 4010 else if (method == INVITE && code == 489)
1581 derek 3276 {
1582 jason 4010 return On489Invite;
1583 derek 3276 }
1584 jason 4010 else if (method == INVITE && code == 491)
1585 derek 2965 {
1586 jason 4010 return On491Invite;
1587 derek 2965 }
1588 jason 4010 else if (method == INVITE && code >= 400)
1589 derek 2965 {
1590 jason 4010 return OnInviteFailure;
1591     }
1592     else if (method == ACK)
1593     {
1594     if (sdp)
1595 derek 2965 {
1596 jason 4010 return OnAckAnswer;
1597 derek 2965 }
1598 derek 2978 else
1599     {
1600 jason 4010 return OnAck;
1601 derek 2978 }
1602 jason 4010 }
1603     else if (method == CANCEL && code == 0)
1604 jason 2809 {
1605 jason 4010 return OnCancel;
1606 jason 2809 }
1607 jason 4010 else if (method == CANCEL && code / 200 == 1)
1608 sgodin 3338 {
1609 jason 4010 return On200Cancel;
1610 sgodin 3338 }
1611 jason 4010 else if (method == CANCEL && code >= 400)
1612 sgodin 3338 {
1613 jason 4010 return OnCancelFailure;
1614 sgodin 3338 }
1615 jason 4010 else if (method == BYE && code == 0)
1616 jason 2846 {
1617 jason 4010 return OnBye;
1618 jason 2846 }
1619 jason 4010 else if (method == BYE && code / 200 == 1)
1620 derek 3101 {
1621 jason 4010 return On200Bye;
1622 derek 3101 }
1623 jason 4010 else if (method == PRACK && code == 0)
1624     {
1625     return OnPrack;
1626     }
1627     else if (method == PRACK && code / 200 == 1)
1628     {
1629     return On200Prack;
1630     }
1631     else if (method == UPDATE && code == 0)
1632     {
1633 sgodin 4369 if (sdp)
1634     {
1635     return OnUpdateOffer;
1636     }
1637     else
1638     {
1639     return OnUpdate;
1640     }
1641 jason 4010 }
1642     else if (method == UPDATE && code / 200 == 1)
1643     {
1644     return On200Update;
1645     }
1646 sgodin 4394 else if (method == UPDATE && code == 422)
1647     {
1648     return On422Update;
1649     }
1650 jason 4010 else if (method == UPDATE && code == 489)
1651     {
1652     return On489Update;
1653     }
1654     else if (method == UPDATE && code == 491)
1655     {
1656     return On491Update;
1657     }
1658     else if (method == UPDATE && code >= 400)
1659     {
1660     return OnUpdateRejected;
1661     }
1662     else
1663     {
1664     assert(0);
1665     return Unknown;
1666     }
1667 derek 2965 }
1668    
1669 jason 4010 void InviteSession::sendAck(const SdpContents *sdp)
1670 derek 2955 {
1671 jason 4010 SipMessage ack;
1672     mDialog.makeRequest(ack, ACK);
1673     if(sdp != 0)
1674 derek 3255 {
1675 jason 4010 setSdp(ack, *sdp);
1676 derek 3255 }
1677 jason 4010 InfoLog (<< "Sending " << ack.brief());
1678     mDialog.send(ack);
1679 derek 2981 }
1680    
1681 jason 4010 void InviteSession::sendBye()
1682 derek 2849 {
1683 jason 4010 SipMessage bye;
1684     mDialog.makeRequest(bye, BYE);
1685     InfoLog (<< "Sending " << bye.brief());
1686     mDialog.send(bye);
1687     }
1688 derek 2992
1689    
1690 davidb 2575 /* ====================================================================
1691 jason 4010 * The Vovida Software License, Version 1.0
1692     *
1693 davidb 2575 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1694 jason 4010 *
1695 davidb 2575 * Redistribution and use in source and binary forms, with or without
1696     * modification, are permitted provided that the following conditions
1697     * are met:
1698 jason 4010 *
1699 davidb 2575 * 1. Redistributions of source code must retain the above copyright
1700     * notice, this list of conditions and the following disclaimer.
1701 jason 4010 *
1702 davidb 2575 * 2. Redistributions in binary form must reproduce the above copyright
1703     * notice, this list of conditions and the following disclaimer in
1704     * the documentation and/or other materials provided with the
1705    
1706     * distribution.
1707 jason 4010 *
1708 davidb 2575 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1709     * and "Vovida Open Communication Application Library (VOCAL)" must
1710     * not be used to endorse or promote products derived from this
1711     * software without prior written permission. For written
1712     * permission, please contact vocal@vovida.org.
1713     *
1714     * 4. Products derived from this software may not be called "VOCAL", nor
1715     * may "VOCAL" appear in their name, without prior written
1716     * permission of Vovida Networks, Inc.
1717 jason 4010 *
1718 davidb 2575 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1719     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1720     * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1721     * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1722     * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1723     * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1724     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1725     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1726     * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1727     * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1728     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1729     * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1730     * DAMAGE.
1731 jason 4010 *
1732 davidb 2575 * ====================================================================
1733 jason 4010 *
1734 davidb 2575 * This software consists of voluntary contributions made by Vovida
1735     * Networks, Inc. and many individuals on behalf of Vovida Networks,
1736     * Inc. For more information on Vovida Networks, Inc., please see
1737     * <http://www.vovida.org/>.
1738     *
1739     */

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27