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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27