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

Contents of /main/resip/dum/ClientInviteSession.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10695 - (show annotations) (download)
Fri Nov 22 23:12:34 2013 UTC (5 years, 11 months ago) by sgodin
File MIME type: text/plain
File size: 51139 byte(s)
-Merged from b-uasprack-20130904
  -added UAS Prack support to DUM!  Original implementation taken from b-uasprack-20091103
  -many changes, fixes and enhancements from original branch
  -MasterProfile setting setUasReliableProvisionalMode is used to enable
  -added mode called SupportedEssential where we will send reliable provisionals only if they
   are a provisional that is carrying an offer or answer  - required for 3GPP IMS flows 
  -added resubmit timer for reliable responses to ensure we send a reliable provisional at least 
   every 2.5 minutes  -new profile setting: set1xxRelResubmitTime to support this
  -updated state diagrams and added new PRACK flow diagrams to dum/doc directory (removed old diagrams)
  -fixed update glare handling for UAC prack 
  -added in support for UAC Prack to be able to send an offer in the first PRACK response 
  (must call provideOffer from onAnswer callback)
  -made a helper method on DialogUsageManager to set advertised capabilities 
  -fixed missing break in ClientInviteSession::dispatchReceivedUpdateEarly 
  

  
  
1
2 #include "resip/stack/Contents.hxx"
3 #include "resip/dum/BaseCreator.hxx"
4 #include "resip/dum/ClientInviteSession.hxx"
5 #include "resip/dum/Dialog.hxx"
6 #include "resip/dum/DialogEventStateManager.hxx"
7 #include "resip/dum/DialogUsageManager.hxx"
8 #include "resip/dum/InviteSessionHandler.hxx"
9 #include "resip/dum/DumTimeout.hxx"
10 #include "resip/dum/MasterProfile.hxx"
11 #include "resip/dum/ServerInviteSession.hxx"
12 #include "resip/dum/ServerSubscription.hxx"
13 #include "resip/dum/UsageUseException.hxx"
14 #include "resip/dum/DumHelper.hxx"
15 #include "resip/stack/SipFrag.hxx"
16 #include "rutil/Logger.hxx"
17 #include "rutil/Random.hxx"
18 #include "rutil/compat.hxx"
19 #include "rutil/WinLeakCheck.hxx"
20
21 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
22
23 using namespace resip;
24 using namespace std;
25
26 ClientInviteSession::ClientInviteSession(DialogUsageManager& dum,
27 Dialog& dialog,
28 SharedPtr<SipMessage> request,
29 const Contents* initialOffer,
30 DialogUsageManager::EncryptionLevel level,
31 ServerSubscriptionHandle serverSub) :
32 InviteSession(dum, dialog),
33 mStaleCallTimerSeq(1),
34 mCancelledTimerSeq(1),
35 mServerSub(serverSub),
36 mAllowOfferInPrack(false)
37 {
38 assert(request->isRequest());
39 if(initialOffer)
40 {
41 mProposedLocalOfferAnswer = auto_ptr<Contents>(initialOffer->clone());
42 mProposedEncryptionLevel = level;
43 }
44 *mLastLocalSessionModification = *request; // Copy message, so that modifications to mLastLocalSessionModification don't effect creator->getLastRequest
45
46 mState=UAC_Start;
47 }
48
49 ClientInviteSessionHandle
50 ClientInviteSession::getHandle()
51 {
52 return ClientInviteSessionHandle(mDum, getBaseHandle().getId());
53 }
54
55 const Contents&
56 ClientInviteSession::getEarlyMedia() const
57 {
58 return *mEarlyMedia;
59 }
60
61 void
62 ClientInviteSession::provideOffer(const Contents& offer, DialogUsageManager::EncryptionLevel level, const Contents* alternative)
63 {
64 InfoLog (<< toData(mState) << ": provideOffer");
65
66 switch(mState)
67 {
68 case UAC_EarlyWithAnswer:
69 if(mAllowOfferInPrack)
70 {
71 // This flag is enabled when we are about to send our first PRACK. We are
72 // allowed to send an offer in our first PRACK request, so don't use UPDATE in
73 // this case.
74 // Remember proposed local offferAnswer.
75 mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer, alternative);
76 mProposedEncryptionLevel = level;
77 }
78 else
79 {
80 transition(UAC_SentUpdateEarly);
81
82 // Creates an UPDATE request with application supplied offer.
83 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);
84 InviteSession::setOfferAnswer(*mLastLocalSessionModification, offer);
85
86 // Remember proposed local offferAnswer.
87 mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer, alternative);
88 mProposedEncryptionLevel = level;
89
90 // Send the req and do state transition.
91 DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mProposedEncryptionLevel);
92 send(mLastLocalSessionModification);
93 }
94 break;
95
96 case UAC_SentAnswer:
97 // just queue it for later
98 transition(UAC_QueuedUpdate);
99 mProposedLocalOfferAnswer = InviteSession::makeOfferAnswer(offer, alternative);
100 mProposedEncryptionLevel = level;
101 break;
102
103 case UAC_Start:
104 case UAC_Early:
105 case UAC_EarlyWithOffer:
106 case UAC_Answered:
107 case UAC_SentUpdateEarly:
108 case UAC_ReceivedUpdateEarly:
109 case UAC_Cancelled:
110 case UAC_QueuedUpdate:
111 case Terminated:
112 assert(0);
113 break;
114
115 default:
116 InviteSession::provideOffer(offer, level, alternative);
117 break;
118 }
119 }
120
121 void
122 ClientInviteSession::provideOffer (const Contents& offer)
123 {
124 this->provideOffer(offer, mCurrentEncryptionLevel, 0);
125 }
126
127 void
128 ClientInviteSession::provideAnswer (const Contents& answer)
129 {
130 InfoLog (<< toData(mState) << ": provideAnswer");
131
132 switch(mState)
133 {
134 case UAC_EarlyWithOffer:
135 {
136 transition(UAC_SentAnswer);
137
138 // Remember proposed local offerAnswer.
139 mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
140 mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
141
142 // Creates a PRACK request with application supplied answer
143 sendPrack(answer, mCurrentEncryptionLevel);
144 break;
145 }
146
147 case UAC_Answered:
148 {
149 transition(Connected);
150 sendAck(&answer);
151
152 mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
153 mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
154 break;
155 }
156 case UAC_ReceivedUpdateEarly:
157 {
158 transition(UAC_EarlyWithAnswer); //.dcm. earlyWithAnwer is a strange
159 //name...maybe earlyEstablished?
160 //this sequence is repeated in many places...due for refactoring.
161 //see ReceivedUpdate handling in InviteSession.
162 //?dcm? are session timers allowed in the early dialog?
163
164 SharedPtr<SipMessage> response(new SipMessage);
165 mDialog.makeResponse(*response, *mLastRemoteSessionModification, 200);
166 InviteSession::setOfferAnswer(*response, answer, 0);
167 mCurrentLocalOfferAnswer = InviteSession::makeOfferAnswer(answer);
168 mCurrentRemoteOfferAnswer = mProposedRemoteOfferAnswer;
169 InfoLog (<< "Sending " << response->brief());
170 DumHelper::setOutgoingEncryptionLevel(*response, mCurrentEncryptionLevel);
171 send(response);
172 break;
173 }
174
175 case UAC_Start:
176 case UAC_Early:
177 case UAC_EarlyWithAnswer:
178 case UAC_SentUpdateEarly:
179 case UAC_SentAnswer:
180 case UAC_Cancelled:
181 case UAC_QueuedUpdate:
182 case Terminated:
183 assert(0);
184 break;
185
186 default:
187 InviteSession::provideAnswer(answer);
188 break;
189 }
190 }
191
192 void
193 ClientInviteSession::end()
194 {
195 end(NotSpecified);
196 }
197
198 void
199 ClientInviteSession::end(const Data& userReason)
200 {
201 mUserEndReason = userReason;
202 end(InviteSession::UserSpecified);
203 }
204
205 void
206 ClientInviteSession::end(EndReason reason)
207 {
208 InfoLog (<< toData(mState) << ": end");
209 if (mEndReason == NotSpecified)
210 {
211 mEndReason = reason;
212 }
213
214 switch(mState)
215 {
216 case UAC_Early:
217 case UAC_EarlyWithOffer:
218 case UAC_EarlyWithAnswer:
219 case UAC_Answered:
220 case UAC_SentUpdateEarly:
221 case UAC_ReceivedUpdateEarly:
222 case UAC_SentAnswer:
223 case UAC_QueuedUpdate:
224 case UAC_Cancelled: // !jf! possibly incorrect to always BYE in UAC_Cancelled
225 {
226 SharedPtr<SipMessage> msg = sendBye();
227 transition(Terminated);
228 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
229 break;
230 }
231
232 case UAC_Start:
233 WarningLog (<< "Try to end when in state=" << toData(mState));
234 assert(0);
235 break;
236
237 case Terminated:
238 // no-op
239 break;
240
241 default:
242 InviteSession::end(reason);
243 break;
244 }
245 }
246
247 void
248 ClientInviteSession::reject (int statusCode, WarningCategory *warning)
249 {
250 InfoLog (<< toData(mState) << ": reject(" << statusCode << ")");
251
252 switch(mState)
253 {
254 case UAC_ReceivedUpdateEarly:
255 {
256 SharedPtr<SipMessage> response(new SipMessage);
257 mDialog.makeResponse(*response, *mLastRemoteSessionModification, statusCode);
258 if(warning)
259 {
260 response->header(h_Warnings).push_back(*warning);
261 }
262
263 // Send the req and do state transition.
264 send(response);
265 transition(UAC_EarlyWithAnswer);
266 break;
267 }
268
269 case UAC_Answered:
270 {
271 // We received an offer in a 2xx response, and we want to reject it
272 // ACK with no body, then send bye
273 sendAck();
274 SharedPtr<SipMessage> msg = sendBye();
275 transition(Terminated);
276 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalBye, msg.get());
277 break;
278 }
279
280 case UAC_Start:
281 case UAC_Early:
282 case UAC_EarlyWithOffer:
283 case UAC_EarlyWithAnswer:
284 case UAC_SentUpdateEarly:
285 case UAC_SentAnswer:
286 case UAC_Cancelled:
287 WarningLog (<< "Try to reject when in state=" << toData(mState));
288 assert(0);
289 break;
290
291 default:
292 InviteSession::reject(statusCode, warning);
293 break;
294 }
295 }
296
297 void
298 ClientInviteSession::cancel()
299 {
300 switch(mState)
301 {
302 case UAC_Early:
303 case UAC_EarlyWithOffer:
304 case UAC_EarlyWithAnswer:
305 case UAC_SentUpdateEarly:
306 case UAC_ReceivedUpdateEarly:
307 case UAC_SentAnswer:
308 InfoLog (<< toData(mState) << ": cancel");
309 startCancelTimer();
310 transition(UAC_Cancelled);
311 break;
312
313 case UAC_Cancelled:
314 case Terminated:
315 // no-op already cancelled or ended
316 break;
317
318 default:
319 assert(0);
320 break;
321 }
322 }
323
324 void
325 ClientInviteSession::onForkAccepted()
326 {
327 switch(mState)
328 {
329 case UAC_Early:
330 case UAC_EarlyWithOffer:
331 case UAC_EarlyWithAnswer:
332 case UAC_SentUpdateEarly:
333 case UAC_ReceivedUpdateEarly:
334 InfoLog (<< toData(mState) << ": onForkAccepted");
335 // !jf! should we avoid creating another timer here? I don't think it
336 // matters. Default timer is for 32secs. This is here to handle the
337 // cleanup on forked INVITEs that have sent a provisional response but
338 // don't ever receive a final response.
339 mDum.addTimerMs(DumTimeout::WaitingForForked2xx, Timer::TH, getBaseHandle(), 1);
340 break;
341 default:
342 // If the dialog is already set up (or cancelled) we disregard.
343 break;
344 }
345 }
346
347 void
348 ClientInviteSession::startCancelTimer()
349 {
350 InfoLog (<< toData(mState) << ": startCancelTimer");
351 mDum.addTimerMs(DumTimeout::Cancelled, Timer::TH, getBaseHandle(), ++mCancelledTimerSeq);
352 }
353
354 void
355 ClientInviteSession::startStaleCallTimer()
356 {
357 InfoLog (<< toData(mState) << ": startStaleCallTimer");
358 unsigned long when = mDialog.mDialogSet.getUserProfile()->getDefaultStaleCallTime();
359
360 mDum.addTimer(DumTimeout::StaleCall,
361 when,
362 getBaseHandle(),
363 ++mStaleCallTimerSeq);
364 }
365
366 void
367 ClientInviteSession::sendSipFrag(const SipMessage& msg)
368 {
369 if (mServerSub.isValid())
370 {
371 if (msg.isResponse() && mState >= UAC_Start && mState <= UAC_Cancelled)
372 {
373 int code = msg.header(h_StatusLine).statusCode();
374 if (code > 100)
375 {
376 SipFrag contents;
377 contents.message().header(h_StatusLine) = msg.header(h_StatusLine);
378 if(mDialog.mDialogSet.getUserProfile()->getExtraHeadersInReferNotifySipFragEnabled())
379 {
380 contents.message().header(h_Vias) = msg.header(h_Vias);
381 contents.message().header(h_From) = msg.header(h_From);
382 contents.message().header(h_To) = msg.header(h_To);
383 contents.message().header(h_CallId) = msg.header(h_CallId);
384 contents.message().header(h_CSeq) = msg.header(h_CSeq);
385 contents.message().header(h_Contacts) = msg.header(h_Contacts);
386 }
387 if (code < 200)
388 {
389 mServerSub->send(mServerSub->update(&contents));
390 }
391 else
392 {
393 mServerSub->end(NoResource, &contents);
394 }
395 }
396 }
397 }
398 }
399
400 void
401 ClientInviteSession::dispatch(const SipMessage& msg)
402 {
403 try
404 {
405 if (msg.isRequest())
406 {
407 if (msg.header(h_RequestLine).method() == INFO)
408 {
409 InviteSession::dispatchInfo(msg);
410 return;
411 }
412 if (msg.header(h_RequestLine).method() == MESSAGE)
413 {
414 InviteSession::dispatchMessage(msg);
415 return;
416 }
417 }
418
419 if (isBadRseq(msg))
420 {
421 return;
422 }
423
424 sendSipFrag(msg);
425 switch(mState)
426 {
427 case UAC_Start:
428 dispatchStart(msg);
429 break;
430 case UAC_Early:
431 dispatchEarly(msg);
432 break;
433 case UAC_EarlyWithOffer:
434 dispatchEarlyWithOffer(msg);
435 break;
436 case UAC_EarlyWithAnswer:
437 dispatchEarlyWithAnswer(msg);
438 break;
439 case UAC_Answered:
440 dispatchAnswered(msg);
441 break;
442 case UAC_SentUpdateEarly:
443 dispatchSentUpdateEarly(msg);
444 break;
445 case UAC_SentUpdateEarlyGlare:
446 dispatchSentUpdateEarlyGlare(msg);
447 break;
448 case UAC_ReceivedUpdateEarly:
449 dispatchReceivedUpdateEarly(msg);
450 break;
451 case UAC_SentAnswer:
452 dispatchSentAnswer(msg);
453 break;
454 case UAC_QueuedUpdate:
455 dispatchQueuedUpdate(msg);
456 break;
457 case UAC_Cancelled:
458 dispatchCancelled(msg);
459 break;
460 default:
461 InviteSession::dispatch(msg);
462 break;
463 }
464 }
465 catch (BaseException& e)
466 {
467 WarningLog (<< "Caught: " << e);
468 onFailureAspect(getHandle(), msg);
469 end(NotSpecified);
470 }
471 }
472
473 void
474 ClientInviteSession::dispatch(const DumTimeout& timer)
475 {
476 if (timer.type() == DumTimeout::Cancelled)
477 {
478 if(timer.seq() == mCancelledTimerSeq)
479 {
480 if (mServerSub.isValid())
481 {
482 SipMessage response;
483 mDialog.makeResponse(response, *mLastLocalSessionModification, 487);
484 sendSipFrag(response);
485 }
486 transition(Terminated);
487 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalCancel);
488 mDum.destroy(this);
489 }
490 }
491 else if (timer.type() == DumTimeout::StaleCall)
492 {
493 if(timer.seq() == mStaleCallTimerSeq)
494 {
495 mDum.mInviteSessionHandler->onStaleCallTimeout(getHandle());
496 mDum.mInviteSessionHandler->terminate(getHandle());
497 }
498 }
499 else if (timer.type() == DumTimeout::WaitingForForked2xx)
500 {
501 transition(Terminated);
502 mDum.mInviteSessionHandler->onForkDestroyed(getHandle());
503 mDum.destroy(this);
504 }
505 else if (timer.type() == DumTimeout::Glare)
506 {
507 if (mState == UAC_SentUpdateEarlyGlare)
508 {
509 transition(UAC_SentUpdateEarly);
510 InfoLog (<< "Retransmitting the UPDATE (glare condition timer)");
511 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE); // increments CSeq
512 send(mLastLocalSessionModification);
513 }
514 else
515 {
516 InviteSession::dispatch(timer);
517 }
518 }
519 else
520 {
521 InviteSession::dispatch(timer);
522 }
523 }
524
525 void
526 ClientInviteSession::handleRedirect (const SipMessage& msg)
527 {
528 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
529 transition(Terminated);
530
531 if (mDum.mDialogEventStateManager)
532 {
533 mDum.mDialogEventStateManager->onTerminated(mDialog, msg, InviteSessionHandler::Rejected);
534 }
535
536 handler->onRedirected(getHandle(), msg);
537 mDum.destroy(this);
538 }
539
540 void
541 ClientInviteSession::handleProvisional(const SipMessage& msg)
542 {
543 assert(msg.isResponse());
544 assert(msg.header(h_StatusLine).statusCode() < 200);
545 assert(msg.header(h_StatusLine).statusCode() > 100);
546
547 //.dcm. Kept the following checks here rather than discardMessage as the
548 // state machine can be affected(termination).
549
550 // !dcm! should we really end the InviteSession or should be discard the 1xx instead?
551 // Check CSeq in 1xx against original INVITE request
552 if (msg.header(h_CSeq).sequence() != mDialog.mDialogSet.getCreator()->getLastRequest()->header(h_CSeq).sequence())
553 {
554 InfoLog (<< "Failure: CSeq doesn't match invite: " << msg.brief());
555 onFailureAspect(getHandle(), msg);
556 end(NotSpecified);
557 return;
558 }
559 else if (isReliable(msg))
560 {
561 if (!msg.exists(h_RSeq))
562 {
563 InfoLog (<< "Failure: No RSeq in 1xx: " << msg.brief());
564 onFailureAspect(getHandle(), msg);
565 end(NotSpecified);
566 return;
567 }
568 }
569
570 startStaleCallTimer();
571 onProvisionalAspect(getHandle(), msg);
572 }
573
574 void
575 ClientInviteSession::handleFinalResponse(const SipMessage& msg)
576 {
577 assert(msg.isResponse());
578 assert(msg.header(h_StatusLine).statusCode() >= 200);
579 assert(msg.header(h_StatusLine).statusCode() < 300);
580
581 handleSessionTimerResponse(msg);
582 storePeerCapabilities(msg);
583 ++mStaleCallTimerSeq; // disable stale call timer
584 }
585
586 void
587 ClientInviteSession::handle1xxOffer(const SipMessage& msg, const Contents& offer)
588 {
589 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
590
591 handleProvisional(msg);
592 mProposedRemoteOfferAnswer = InviteSession::makeOfferAnswer(offer);
593 mCurrentEncryptionLevel = getEncryptionLevel(msg);
594 handler->onOffer(getSessionHandle(), msg, offer);
595 }
596
597 void
598 ClientInviteSession::handle1xxAnswer(const SipMessage& msg, const Contents& answer)
599 {
600 setCurrentLocalOfferAnswer(msg);
601 mCurrentEncryptionLevel = getEncryptionLevel(msg);
602 mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(answer);
603
604 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
605 handleProvisional(msg);
606
607 // flag to let handle1xxAnswer know that it is OK to send an offer in the
608 // first PRACK (for a provisional with SDP answer) and to let providerOffer know
609 // that the offer will be going in an PRACK and not in an update. Flag is not
610 // needed after handle1xxAnswer is called so it is reset.
611 mAllowOfferInPrack = true;
612
613 handler->onAnswer(getSessionHandle(), msg, answer);
614
615 // Reset flag - no longer needed
616 mAllowOfferInPrack = false;
617
618 // If offer is provided in onAnswer callback then send offer in PRACK
619 if(mProposedLocalOfferAnswer.get())
620 {
621 sendPrack(*mProposedLocalOfferAnswer.get(), mProposedEncryptionLevel);
622 }
623 else
624 {
625 sendPrackIfNeeded(msg);
626 }
627 }
628
629 // will not include SDP (this is a subsequent 1xx)
630 void
631 ClientInviteSession::sendPrackIfNeeded(const SipMessage& msg)
632 {
633 assert(msg.isResponse());
634 assert(msg.header(h_StatusLine).statusCode() < 200);
635 assert(msg.header(h_StatusLine).statusCode() > 100);
636
637 if (isReliable(msg))
638 {
639 SharedPtr<SipMessage> prack(new SipMessage);
640 mDialog.makeRequest(*prack, PRACK);
641 prack->header(h_RAck) = mRelRespInfo;
642 send(prack);
643 }
644 }
645
646 // This version is used to send an answer to the UAS in PRACK from EarlyWithOffer
647 // state. Assumes that it is the first PRACK. Subsequent PRACK will not have SDP
648 // Also used to send an offer in the first PRACK if the 18x included an
649 // answer.
650 void
651 ClientInviteSession::sendPrack(const Contents& offerAnswer, DialogUsageManager::EncryptionLevel encryptionLevel)
652 {
653 SharedPtr<SipMessage> prack(new SipMessage);
654 mDialog.makeRequest(*prack, PRACK);
655 prack->header(h_RAck)= mRelRespInfo;
656
657 InviteSession::setOfferAnswer(*prack, offerAnswer);
658
659 DumHelper::setOutgoingEncryptionLevel(*prack, encryptionLevel);
660 send(prack);
661 }
662
663 void
664 ClientInviteSession::dispatchStart (const SipMessage& msg)
665 {
666 assert(msg.isResponse());
667 assert(msg.header(h_StatusLine).statusCode() > 100);
668 assert(msg.header(h_CSeq).method() == INVITE);
669
670 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
671 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
672
673 InviteSession::Event event = toEvent(msg, offerAnswer.get());
674
675 switch (event)
676 {
677 case On1xx:
678 transition(UAC_Early);
679 handler->onNewSession(getHandle(), InviteSession::None, msg);
680 if(!isTerminated())
681 {
682 handleProvisional(msg);
683 sendPrackIfNeeded(msg); // may wish to move emprty PRACK handling
684 // outside the state machine
685 }
686 break;
687
688 case On1xxEarly: // only unreliable
689 //!dcm! according to draft-ietf-sipping-offeranswer there can be a non
690 // reliable 1xx followed by a reliable 1xx. Also, the intial 1xx
691 // doesn't have to have an offer. However, DUM will only generate
692 // reliabled 1xx responses when 100rel is available.
693
694 transition(UAC_Early);
695 mEarlyMedia = InviteSession::makeOfferAnswer(*offerAnswer);
696 handler->onNewSession(getHandle(), InviteSession::None, msg);
697 if(!isTerminated())
698 {
699 handleProvisional(msg);
700 if(!isTerminated())
701 {
702 handler->onEarlyMedia(getHandle(), msg, *offerAnswer);
703 }
704 }
705 break;
706
707 case On1xxOffer:
708 transition(UAC_EarlyWithOffer);
709 handler->onNewSession(getHandle(), InviteSession::Offer, msg);
710 if(!isTerminated())
711 {
712 handle1xxOffer(msg, *offerAnswer);
713 }
714 break;
715
716 case On1xxAnswer:
717 transition(UAC_EarlyWithAnswer);
718 handler->onNewSession(getHandle(), InviteSession::Answer, msg);
719 if(!isTerminated())
720 {
721 handle1xxAnswer(msg, *offerAnswer);
722 }
723 break;
724
725 case On2xxOffer:
726 transition(UAC_Answered);
727 handleFinalResponse(msg);
728 mProposedRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
729 handler->onNewSession(getHandle(), InviteSession::Offer, msg);
730 assert(mProposedLocalOfferAnswer.get() == 0);
731 mCurrentEncryptionLevel = getEncryptionLevel(msg);
732 if(!isTerminated())
733 {
734 handler->onOffer(getSessionHandle(), msg, *offerAnswer);
735 if(!isTerminated()) //?jf? can this be terminated here but not above? .slg. yes application can call end()
736 {
737 onConnectedAspect(getHandle(), msg);
738 }
739 }
740 break;
741
742 case On2xxAnswer:
743 transition(Connected);
744 sendAck();
745 handleFinalResponse(msg);
746 setCurrentLocalOfferAnswer(msg);
747 mCurrentEncryptionLevel = getEncryptionLevel(msg);
748 mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
749 handler->onNewSession(getHandle(), InviteSession::Answer, msg);
750 if(!isTerminated()) // onNewSession callback may call end() or reject()
751 {
752 handler->onAnswer(getSessionHandle(), msg, *offerAnswer);
753 if(!isTerminated()) // onAnswer callback may call end() or reject()
754 {
755 onConnectedAspect(getHandle(), msg);
756 }
757 }
758 break;
759
760 case On2xx:
761 {
762 sendAck();
763 sendBye();
764 InfoLog (<< "Failure: 2xx with no answer: " << msg.brief());
765 transition(Terminated);
766 onFailureAspect(getHandle(), msg);
767 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
768 break;
769 }
770
771 case OnRedirect: // Redirects are handled by the DialogSet - if a 3xx gets here then it's because the redirect was intentionaly not handled and should be treated as an INVITE failure
772 case OnInviteFailure:
773 case OnGeneralFailure:
774 case On422Invite:
775 case On487Invite:
776 case On491Invite:
777 InfoLog (<< "Failure: error response: " << msg.brief());
778 transition(Terminated);
779 onFailureAspect(getHandle(), msg);
780 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
781 mDum.destroy(this);
782 break;
783
784 case OnBye:
785 dispatchBye(msg);
786 break;
787
788 default:
789 // !kh!
790 // should not assert here for peer sent us garbage.
791 WarningLog (<< "Don't know what this is : " << msg);
792 break;
793 }
794 }
795
796 void
797 ClientInviteSession::dispatchEarly (const SipMessage& msg)
798 {
799 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
800 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
801
802 switch (toEvent(msg, offerAnswer.get()))
803 {
804 case On1xx:
805 transition(UAC_Early);
806 handleProvisional(msg);
807 sendPrackIfNeeded(msg);
808 break;
809
810 case On1xxEarly: // only unreliable
811 transition(UAC_Early);
812 handleProvisional(msg);
813 if(!isTerminated())
814 {
815 mEarlyMedia = InviteSession::makeOfferAnswer(*offerAnswer);
816 handler->onEarlyMedia(getHandle(), msg, *offerAnswer);
817 }
818 break;
819
820 case On1xxOffer:
821 transition(UAC_EarlyWithOffer);
822 handle1xxOffer(msg, *offerAnswer);
823 break;
824
825 case On1xxAnswer:
826 transition(UAC_EarlyWithAnswer);
827 handle1xxAnswer(msg, *offerAnswer);
828 break;
829
830 case On2xxOffer:
831 transition(UAC_Answered);
832 handleFinalResponse(msg);
833
834 assert(mProposedLocalOfferAnswer.get() == 0);
835 mCurrentEncryptionLevel = getEncryptionLevel(msg);
836 mProposedRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
837
838 handler->onOffer(getSessionHandle(), msg, *offerAnswer);
839 if(!isTerminated())
840 {
841 onConnectedAspect(getHandle(), msg);
842 }
843 break;
844
845 case On2xxAnswer:
846 transition(Connected);
847 sendAck();
848 handleFinalResponse(msg);
849 setCurrentLocalOfferAnswer(msg);
850 mCurrentEncryptionLevel = getEncryptionLevel(msg);
851 mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
852 handler->onAnswer(getSessionHandle(), msg, *offerAnswer);
853 if(!isTerminated()) // onNewSession callback may call end() or reject()
854 {
855 onConnectedAspect(getHandle(), msg);
856 }
857 break;
858
859 case On2xx:
860 {
861 sendAck();
862 sendBye();
863 InfoLog (<< "Failure: 2xx with no answer: " << msg.brief());
864 transition(Terminated);
865 onFailureAspect(getHandle(), msg);
866 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
867 break;
868 }
869
870 case OnRedirect: // Redirects are handled by the DialogSet - if a 3xx gets here then it's because the redirect was intentionaly not handled and should be treated as an INVITE failure
871 case OnInviteFailure:
872 case OnGeneralFailure:
873 case On422Invite:
874 case On487Invite:
875 InfoLog (<< "Failure: error response: " << msg.brief());
876 transition(Terminated);
877 onFailureAspect(getHandle(), msg);
878 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
879 mDum.destroy(this);
880 break;
881
882 case OnBye:
883 dispatchBye(msg);
884 break;
885
886 case OnUpdateOffer:
887 if(mProposedLocalOfferAnswer.get())
888 {
889 WarningLog (<< "Invalid UPDATE with offer received in early state with pending offer: " << msg.brief());
890 SharedPtr<SipMessage> response(new SipMessage);
891 mDialog.makeResponse(*response, msg, 500); // RFC3311 - section 5.2
892 InfoLog (<< "Sending " << response->brief());
893 send(response);
894 }
895 else
896 {
897 *mLastRemoteSessionModification = msg;
898 transition(UAC_ReceivedUpdateEarly);
899 mCurrentEncryptionLevel = getEncryptionLevel(msg);
900 mProposedRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
901 handler->onOffer(getSessionHandle(), msg, *offerAnswer);
902 }
903 break;
904
905 case OnUpdate:
906 {
907 // ?slg? no offerAnswer in update - just respond immediately - do we need a callback?
908 SharedPtr<SipMessage> response(new SipMessage);
909 *mLastRemoteSessionModification = msg;
910 mDialog.makeResponse(*response, msg, 200);
911 send(response);
912 break;
913 }
914
915 case On200Prack:
916 break;
917
918 default:
919 // !kh!
920 // should not assert here for peer sent us garbage.
921 WarningLog (<< "Don't know what this is : " << msg);
922 break;
923 }
924 }
925
926 void
927 ClientInviteSession::dispatchAnswered (const SipMessage& msg)
928 {
929 //InviteSessionHandler* handler = mDum.mInviteSessionHandler;
930 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
931
932 switch (toEvent(msg, offerAnswer.get()))
933 {
934 case On1xx:
935 case On1xxEarly:
936 case On1xxOffer:
937 // late, so ignore
938 break;
939
940 case On2xxOffer:
941 case On2xx:
942 case On2xxAnswer:
943 // retransmission
944 break;
945
946 case OnRedirect:
947 // too late
948 break;
949
950 // .slg. This doesn't really make sense (after a 2xx)
951 case OnGeneralFailure:
952 case On422Invite:
953 break;
954 #if 0 // !jf! don't think this is right
955 {
956 sendBye();
957 InfoLog (<< "Failure: error response: " << msg.brief());
958 transition(Terminated);
959 onFailureAspect(getHandle(), msg);
960 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
961 mDum.destroy(this);
962 break;
963 }
964 #endif
965 case OnBye:
966 dispatchBye(msg);
967 break;
968
969 default:
970 // !kh!
971 // should not assert here for peer sent us garbage.
972 WarningLog (<< "Don't know what this is : " << msg);
973 break;
974 }
975
976 }
977
978 void
979 ClientInviteSession::dispatchEarlyWithOffer (const SipMessage& msg)
980 {
981 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
982 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
983
984 switch (toEvent(msg, offerAnswer.get()))
985 {
986 case On1xx: // must be reliable
987 handleProvisional(msg);
988 sendPrackIfNeeded(msg);
989 break;
990
991 case On2xx:
992 case On2xxAnswer:
993 sendAck();
994 sendBye();
995 InfoLog (<< "Failure: no answer sent: " << msg.brief());
996 transition(Terminated);
997 onFailureAspect(getHandle(), msg);
998 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
999 break;
1000
1001 case OnRedirect: // Redirects are handled by the DialogSet - if a 3xx gets here then it's because the redirect was intentionaly not handled and should be treated as an INVITE failure
1002 case OnInviteFailure:
1003 case OnGeneralFailure:
1004 case On422Invite:
1005 case On487Invite:
1006 case On491Invite:
1007 InfoLog (<< "Failure: error response: " << msg.brief());
1008 transition(Terminated);
1009 onFailureAspect(getHandle(), msg);
1010 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1011 mDum.destroy(this);
1012 break;
1013
1014 case OnBye:
1015 dispatchBye(msg);
1016 break;
1017
1018 case OnUpdateOffer:
1019 {
1020 WarningLog (<< "Invalid UPDATE with offer received in early state with pending offer: " << msg.brief());
1021 SharedPtr<SipMessage> response(new SipMessage);
1022 mDialog.makeResponse(*response, msg, 500); // RFC3311 - section 5.2
1023 InfoLog (<< "Sending " << response->brief());
1024 send(response);
1025 break;
1026 }
1027
1028 case OnUpdate:
1029 {
1030 // ?slg? no offerAnswer in update - just respond immediately - do we need a callback?
1031 SharedPtr<SipMessage> response(new SipMessage);
1032 *mLastRemoteSessionModification = msg;
1033 mDialog.makeResponse(*response, msg, 200);
1034 send(response);
1035 break;
1036 }
1037
1038 default:
1039 // !kh!
1040 // should not assert here for peer sent us garbage.
1041 WarningLog (<< "Don't know what this is : " << msg);
1042 break;
1043 }
1044 }
1045
1046 void
1047 ClientInviteSession::dispatchSentAnswer (const SipMessage& msg)
1048 {
1049 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1050 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1051
1052 switch (toEvent(msg, offerAnswer.get()))
1053 {
1054 case On200Prack:
1055 transition(UAC_EarlyWithAnswer);
1056 break;
1057
1058 case On2xx:
1059 transition(Connected);
1060 sendAck();
1061 handleFinalResponse(msg);
1062 onConnectedAspect(getHandle(), msg);
1063 break;
1064
1065 case On2xxOffer:
1066 {
1067 if (*offerAnswer == *mCurrentRemoteOfferAnswer)
1068 {
1069 InfoLog (<< "Ignoring illegal offer identical with current remote offer/answer");
1070 transition(Connected);
1071 sendAck();
1072 handleFinalResponse(msg);
1073 onConnectedAspect(getHandle(), msg);
1074 break;
1075 }
1076 }
1077 // fall through to next label
1078 case On2xxAnswer:
1079 case On1xxAnswer:
1080 case On1xxOffer:
1081 sendAck();
1082 sendBye();
1083 InfoLog (<< "Failure: illegal offer/answer: " << msg.brief());
1084 transition(Terminated);
1085 onFailureAspect(getHandle(), msg);
1086 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1087 break;
1088
1089 case On1xx:
1090 handleProvisional(msg);
1091 sendPrackIfNeeded(msg);
1092 break;
1093
1094 case OnRedirect: // Redirects are handled by the DialogSet - if a 3xx gets here then it's because the redirect was intentionaly not handled and should be treated as an INVITE failure
1095 case OnInviteFailure:
1096 case OnGeneralFailure:
1097 case On422Invite:
1098 case On487Invite:
1099 case On491Invite:
1100 InfoLog (<< "Failure: error response: " << msg.brief());
1101 transition(Terminated);
1102 onFailureAspect(getHandle(), msg);
1103 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1104 mDum.destroy(this);
1105 break;
1106
1107 case OnBye:
1108 dispatchBye(msg);
1109 break;
1110
1111 default:
1112 // !kh!
1113 // should not assert here for peer sent us garbage.
1114 WarningLog (<< "Don't know what this is : " << msg);
1115 break;
1116 }
1117 }
1118
1119 void
1120 ClientInviteSession::dispatchQueuedUpdate (const SipMessage& msg)
1121 {
1122 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1123 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1124
1125 switch (toEvent(msg, offerAnswer.get()))
1126 {
1127 case On200Prack:
1128 transition(UAC_SentUpdateEarly);
1129 {
1130 mDialog.makeRequest(*mLastLocalSessionModification, UPDATE);
1131 InviteSession::setOfferAnswer(*mLastLocalSessionModification, mProposedLocalOfferAnswer.get());
1132
1133 DumHelper::setOutgoingEncryptionLevel(*mLastLocalSessionModification, mProposedEncryptionLevel);
1134 send(mLastLocalSessionModification);
1135 }
1136 break;
1137
1138 case On2xx:
1139 transition(SentUpdate);
1140 {
1141 sendAck();
1142
1143 SharedPtr<SipMessage> update(new SipMessage);
1144 mDialog.makeRequest(*update, UPDATE);
1145 InviteSession::setOfferAnswer(*update, mProposedLocalOfferAnswer.get());
1146 DumHelper::setOutgoingEncryptionLevel(*update, mProposedEncryptionLevel);
1147 send(update);
1148 }
1149 handleFinalResponse(msg);
1150 onConnectedAspect(getHandle(), msg);
1151 break;
1152
1153 case On2xxOffer:
1154 {
1155 if (*offerAnswer == *mCurrentRemoteOfferAnswer)
1156 {
1157 InfoLog (<< "Ignoring illegal offer identical with current remote offer/answer");
1158 transition(Connected);
1159 sendAck();
1160 handleFinalResponse(msg);
1161 onConnectedAspect(getHandle(), msg);
1162 break;
1163 }
1164 }
1165 // fall through to next label
1166 case On2xxAnswer:
1167 case On1xxAnswer:
1168 case On1xxOffer:
1169 sendAck();
1170 sendBye();
1171 InfoLog (<< "Failure: illegal offer/answer: " << msg.brief());
1172 transition(Terminated);
1173 onFailureAspect(getHandle(), msg);
1174 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1175 break;
1176
1177 case On1xx:
1178 handleProvisional(msg);
1179 sendPrackIfNeeded(msg);
1180 break;
1181
1182 case OnRedirect: // Redirects are handled by the DialogSet - if a 3xx gets here then it's because the redirect was intentionaly not handled and should be treated as an INVITE failure
1183 case OnInviteFailure:
1184 case OnGeneralFailure:
1185 case On422Invite:
1186 case On487Invite:
1187 case On491Invite:
1188 InfoLog (<< "Failure: error response: " << msg.brief());
1189 transition(Terminated);
1190 onFailureAspect(getHandle(), msg);
1191 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1192 mDum.destroy(this);
1193 break;
1194
1195 case OnBye:
1196 dispatchBye(msg);
1197 break;
1198
1199 default:
1200 // !kh!
1201 // should not assert here for peer sent us garbage.
1202 WarningLog (<< "Don't know what this is : " << msg);
1203 break;
1204 }
1205 }
1206
1207
1208
1209 void
1210 ClientInviteSession::dispatchEarlyWithAnswer (const SipMessage& msg)
1211 {
1212 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1213 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1214
1215 switch (toEvent(msg, offerAnswer.get()))
1216 {
1217 case On1xx:
1218 handleProvisional(msg);
1219 sendPrackIfNeeded(msg);
1220 break;
1221
1222 case On1xxOffer:
1223 if(!isTerminated())
1224 {
1225 transition(UAC_EarlyWithOffer);
1226 handle1xxOffer(msg, *offerAnswer);
1227 }
1228 break;
1229
1230 case On2xx:
1231 transition(Connected);
1232 sendAck();
1233 handleFinalResponse(msg);
1234 onConnectedAspect(getHandle(), msg);
1235 break;
1236
1237 case On2xxOffer:
1238 {
1239 if (*offerAnswer == *mCurrentRemoteOfferAnswer)
1240 {
1241 InfoLog (<< "Ignoring illegal offer identical with current remote offer/answer");
1242 transition(Connected);
1243 sendAck();
1244 handleFinalResponse(msg);
1245 onConnectedAspect(getHandle(), msg);
1246 break;
1247 }
1248 }
1249 // fall through to next label
1250 case On2xxAnswer:
1251 sendAck();
1252 sendBye();
1253 InfoLog (<< "Failure: illegal offer/answer: " << msg.brief());
1254 transition(Terminated);
1255 onFailureAspect(getHandle(), msg);
1256 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1257 break;
1258
1259 case OnUpdateOffer:
1260 *mLastRemoteSessionModification = msg;
1261 transition(UAC_ReceivedUpdateEarly);
1262 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1263 mProposedRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
1264 handler->onOffer(getSessionHandle(), msg, *offerAnswer);
1265 break;
1266
1267 case OnUpdate:
1268 {
1269 // ?slg? no offerAnswer in update - just respond immediately - do we need a callback?
1270 SharedPtr<SipMessage> response(new SipMessage);
1271 *mLastRemoteSessionModification = msg;
1272 mDialog.makeResponse(*response, msg, 200);
1273 send(response);
1274 break;
1275 }
1276
1277 case OnRedirect: // Redirects are handled by the DialogSet - if a 3xx gets here then it's because the redirect was intentionaly not handled and should be treated as an INVITE failure
1278 case OnInviteFailure:
1279 case OnGeneralFailure:
1280 case On422Invite:
1281 case On487Invite:
1282 case On491Invite:
1283 InfoLog (<< "Failure: error response: " << msg.brief());
1284 transition(Terminated);
1285 onFailureAspect(getHandle(), msg);
1286 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1287 mDum.destroy(this);
1288 break;
1289
1290 case OnBye:
1291 dispatchBye(msg);
1292 break;
1293
1294 case On200Prack:
1295 // We may have sent a PRACK with an offer (if provideOffer was called from onAnswer
1296 // from the first reliable provisional) - if so this will have SDP we need to call onAnswer
1297 if(offerAnswer.get() && mProposedLocalOfferAnswer.get())
1298 {
1299 setCurrentLocalOfferAnswer(msg);
1300 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1301 mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
1302 handler->onAnswer(getSessionHandle(), msg, *offerAnswer);
1303 }
1304 break;
1305
1306 default:
1307 // !kh!
1308 // should not assert here for peer sent us garbage.
1309 WarningLog (<< "Don't know what this is : " << msg);
1310 break;
1311 }
1312 }
1313
1314 void
1315 ClientInviteSession::dispatchSentUpdateEarly (const SipMessage& msg)
1316 {
1317 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1318 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1319
1320 switch (toEvent(msg, offerAnswer.get()))
1321 {
1322 case On200Update:
1323 transition(UAC_EarlyWithAnswer);
1324 setCurrentLocalOfferAnswer(msg);
1325 mCurrentEncryptionLevel = getEncryptionLevel(msg);
1326 mCurrentRemoteOfferAnswer = InviteSession::makeOfferAnswer(*offerAnswer);
1327 handler->onAnswer(getSessionHandle(), msg, *offerAnswer);
1328 break;
1329
1330 case OnUpdateOffer:
1331 {
1332 SharedPtr<SipMessage> response(new SipMessage);
1333 mDialog.makeResponse(*response, msg, 491);
1334 send(response);
1335 }
1336 break;
1337
1338 case OnUpdate:
1339 {
1340 // ?slg? no offerAnswer in update - just respond immediately - do we need a callback?
1341 SharedPtr<SipMessage> response(new SipMessage);
1342 *mLastRemoteSessionModification = msg;
1343 mDialog.makeResponse(*response, msg, 200);
1344 send(response);
1345 break;
1346 }
1347
1348 case On491Update:
1349 transition(UAC_SentUpdateEarlyGlare);
1350 start491Timer();
1351 break;
1352
1353 case On2xx:
1354 transition(SentUpdate);
1355 sendAck();
1356 break;
1357
1358 case OnRedirect: // Redirects are handled by the DialogSet - if a 3xx gets
1359 // here then it's because the redirect was intentionaly
1360 // not handled and should be treated as an INVITE failure
1361 case OnInviteFailure:
1362 case OnGeneralFailure:
1363 case On422Invite:
1364 case On487Invite:
1365 InfoLog (<< "Failure: error response: " << msg.brief());
1366 transition(Terminated);
1367 onFailureAspect(getHandle(), msg);
1368 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1369 mDum.destroy(this);
1370 break;
1371
1372 case On200Prack:
1373 break;
1374
1375 default:
1376 WarningLog (<< "Don't know what this is : " << msg);
1377 break;
1378 }
1379 }
1380
1381 void
1382 ClientInviteSession::dispatchSentUpdateEarlyGlare (const SipMessage& msg)
1383 {
1384 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1385 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1386
1387 switch (toEvent(msg, offerAnswer.get()))
1388 {
1389 case OnUpdateOffer:
1390 handler->onOfferRejected(getSessionHandle(), &msg);
1391 //will cause transition to UAC_ReceivedUpdateEarly
1392 dispatchEarlyWithAnswer(msg);
1393 break;
1394
1395 case On2xx:
1396 //transition to connected state machine
1397 transition(SentUpdateGlare);
1398 sendAck();
1399 break;
1400 //!dcm! TODO This block below is repeated many, many times...refactor
1401 //!into a method. Prob. represents the effective ClientInvite superstate.
1402 case OnRedirect: // Redirects are handled by the DialogSet - if a 3xx gets
1403 // here then it's because the redirect was intentionaly
1404 // not handled and should be treated as an INVITE failure
1405 case OnInviteFailure:
1406 case OnGeneralFailure:
1407 case On422Invite:
1408 case On487Invite:
1409 InfoLog (<< "Failure: error response: " << msg.brief());
1410 transition(Terminated);
1411 onFailureAspect(getHandle(), msg);
1412 handler->onTerminated(getSessionHandle(), InviteSessionHandler::Error, &msg);
1413 mDum.destroy(this);
1414 break;
1415
1416 default:
1417 WarningLog (<< "Don't know what this is : " << msg);
1418 break;
1419 }
1420 }
1421
1422 void
1423 ClientInviteSession::dispatchReceivedUpdateEarly(const SipMessage& msg)
1424 {
1425 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1426 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1427
1428 switch (toEvent(msg, offerAnswer.get()))
1429 {
1430 case OnUpdate:
1431 case OnUpdateOffer:
1432 // If we receive an UPDATE before we have generated a final response to a previous UPDATE on the
1433 // same dialog, then we MUST return a 500 response with a Retry-After header (random duration 0-10 seconds)
1434 {
1435 SharedPtr<SipMessage> u500(new SipMessage);
1436 mDialog.makeResponse(*u500, msg, 500);
1437 u500->header(h_RetryAfter).value() = Random::getRandom() % 10;
1438 send(u500);
1439 }
1440 break;
1441
1442 default:
1443 WarningLog (<< "Don't know what this is : " << msg);
1444 break;
1445 }
1446 WarningLog (<< "Ignoring message received in ReceivedUpdateEarly: " << msg);
1447 }
1448
1449 void
1450 ClientInviteSession::dispatchCancelled (const SipMessage& msg)
1451 {
1452 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
1453 std::auto_ptr<Contents> offerAnswer = InviteSession::getOfferAnswer(msg);
1454
1455 switch (toEvent(msg, offerAnswer.get()))
1456 {
1457 case OnGeneralFailure:
1458 case OnCancelFailure:
1459 case On487Invite:
1460 case OnRedirect:
1461 case On422Invite:
1462 case On491Invite:
1463 case OnInviteFailure:
1464 transition(Terminated);
1465 handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalCancel, &msg);
1466 mDum.destroy(this);
1467 break;
1468
1469 case On2xx:
1470 case On2xxOffer:
1471 case On2xxAnswer:
1472 {
1473 // this is the 2xx crossing the CANCEL case
1474 sendAck();
1475 sendBye();
1476 transition(Terminated);
1477 handler->onTerminated(getSessionHandle(), InviteSessionHandler::LocalCancel, &msg);
1478 mCancelledTimerSeq++;
1479 break;
1480 }
1481
1482 case OnBye:
1483 dispatchBye(msg);
1484 break;
1485
1486 default:
1487 break;
1488 }
1489 }
1490
1491 //true if 180rel should be ignored. Saves rseq as a side effect.
1492 bool
1493 ClientInviteSession::isBadRseq(const SipMessage& msg)
1494 {
1495 int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0;
1496 if (msg.method() == INVITE && code > 100 && code < 200)
1497 {
1498 if (msg.exists(h_RSeq))
1499 {
1500 // store state about the provisional if reliable, so we can detect retransmissions
1501 unsigned int rseq = (unsigned int) msg.header(h_RSeq).value();
1502 unsigned int lastRseq = (unsigned int) mRelRespInfo.rSequence();
1503
1504 if (rseq == lastRseq)
1505 {
1506 DebugLog(<< "Discarding reliable 1xx retranmission with rseq " << rseq);
1507 return true;
1508 }
1509 else if (lastRseq != 0 && rseq > lastRseq + 1)
1510 {
1511 DebugLog(<< "Discarding out of order reliable 1xx with rseq " << rseq);
1512 return true;
1513 }
1514 mRelRespInfo.rSequence() = rseq;
1515 mRelRespInfo.cSequence() = msg.header(h_CSeq).sequence();
1516 mRelRespInfo.method() = msg.header(h_CSeq).method();
1517 }
1518 }
1519 return false;
1520 }
1521
1522 void
1523 ClientInviteSession::onConnectedAspect(ClientInviteSessionHandle c, const SipMessage& msg)
1524 {
1525 if (mDum.mDialogEventStateManager)
1526 {
1527 mDum.mDialogEventStateManager->onConfirmed(mDialog, getSessionHandle());
1528 }
1529 mDum.mInviteSessionHandler->onConnected(c, msg);
1530 }
1531
1532 void
1533 ClientInviteSession::onProvisionalAspect(ClientInviteSessionHandle c, const SipMessage& msg)
1534 {
1535 if (mDum.mDialogEventStateManager)
1536 {
1537 mDum.mDialogEventStateManager->onEarly(mDialog, getSessionHandle());
1538 }
1539 mDum.mInviteSessionHandler->onProvisional(c, msg);
1540 }
1541
1542 void
1543 ClientInviteSession::onFailureAspect(ClientInviteSessionHandle c, const SipMessage& msg)
1544 {
1545 if (mDum.mDialogEventStateManager)
1546 {
1547 InviteSessionHandler::TerminatedReason reason = InviteSessionHandler::Rejected;
1548 if (msg.isResponse())
1549 {
1550 if (msg.header(h_StatusLine).responseCode() == 408)
1551 {
1552 reason = InviteSessionHandler::Timeout;
1553 }
1554 else if (msg.header(h_StatusLine).responseCode() / 100 == 5)
1555 {
1556 reason = InviteSessionHandler::Error;
1557 }
1558 }
1559 mDum.mDialogEventStateManager->onTerminated(mDialog, msg, reason);
1560 }
1561 mDum.mInviteSessionHandler->onFailure(c, msg);
1562 }
1563
1564 /* ====================================================================
1565 * The Vovida Software License, Version 1.0
1566 *
1567 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1568 *
1569 * Redistribution and use in source and binary forms, with or without
1570 * modification, are permitted provided that the following conditions
1571 * are met:
1572 *
1573 * 1. Redistributions of source code must retain the above copyright
1574 * notice, this list of conditions and the following disclaimer.
1575 *
1576 * 2. Redistributions in binary form must reproduce the above copyright
1577 * notice, this list of conditions and the following disclaimer in
1578 * the documentation and/or other materials provided with the
1579
1580 * distribution.
1581 *
1582 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1583 * and "Vovida Open Communication Application Library (VOCAL)" must
1584 * not be used to endorse or promote products derived from this
1585 * software without prior written permission. For written
1586 * permission, please contact vocal@vovida.org.
1587 *
1588 * 4. Products derived from this software may not be called "VOCAL", nor
1589 * may "VOCAL" appear in their name, without prior written
1590 * permission of Vovida Networks, Inc.
1591 *
1592 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1593 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1594 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1595 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1596 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1597 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1598 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1599 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1600 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1601 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1602 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1603 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1604 * DAMAGE.
1605 *
1606 * ====================================================================
1607 *
1608 * This software consists of voluntary contributions made by Vovida
1609 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1610 * Inc. For more information on Vovida Networks, Inc., please see
1611 * <http://www.vovida.org/>.
1612 *
1613 */

Properties

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

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27