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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2992 - (show annotations) (download)
Tue Jun 15 19:41:56 2004 UTC (15 years, 5 months ago) by derek
Original Path: main/sip/resiprocate/dum/InviteSession.cxx
File size: 15485 byte(s)
more fixes
1 #include "resiprocate/SipMessage.hxx"
2 #include "resiprocate/SdpContents.hxx"
3 #include "resiprocate/dum/Dialog.hxx"
4 #include "resiprocate/dum/DialogUsageManager.hxx"
5 #include "resiprocate/dum/InviteSession.hxx"
6 #include "resiprocate/dum/InviteSessionHandler.hxx"
7 #include "resiprocate/dum/UsageUseException.hxx"
8 #include "resiprocate/os/Logger.hxx"
9
10 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
11
12 using namespace resip;
13
14 unsigned long
15 InviteSession::T1 = 500;
16
17 unsigned long
18 InviteSession::T2 = 8 * T1;
19
20 unsigned long
21 InviteSession::TimerH = 64 * T1;
22
23 InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog, State initialState)
24 : BaseUsage(dum, dialog),
25 mState(initialState),
26 mOfferState(Nothing),
27 mCurrentLocalSdp(0),
28 mCurrentRemoteSdp(0),
29 mProposedLocalSdp(0),
30 mProposedRemoteSdp(0),
31 mNextOfferOrAnswerSdp(0),
32 mCurrentRetransmit200(0)
33
34 {
35 assert(mDum.mInviteSessionHandler);
36 }
37
38 InviteSession::~InviteSession()
39 {
40 delete mCurrentLocalSdp;
41 delete mCurrentRemoteSdp;
42 delete mProposedLocalSdp;
43 delete mProposedRemoteSdp;
44 delete mNextOfferOrAnswerSdp;
45 mDialog.mInviteSession = 0;
46 }
47
48 void
49 InviteSession::setOffer(const SdpContents* sdp)
50 {
51 if (mProposedRemoteSdp)
52 {
53 throw UsageUseException("Cannot set an offer with an oustanding remote offer", __FILE__, __LINE__);
54 }
55 mNextOfferOrAnswerSdp = static_cast<SdpContents*>(sdp->clone());
56 }
57
58 void
59 InviteSession::setAnswer(const SdpContents* sdp)
60 {
61 if (mProposedLocalSdp )
62 {
63 throw UsageUseException("Cannot set an answer with an oustanding offer", __FILE__, __LINE__);
64 }
65 mNextOfferOrAnswerSdp = static_cast<SdpContents*>(sdp->clone());
66 }
67
68 const SdpContents*
69 InviteSession::getLocalSdp()
70 {
71 return mCurrentLocalSdp;
72 }
73
74 const SdpContents*
75 InviteSession::getRemoteSdp()
76 {
77 return mCurrentRemoteSdp;
78 }
79
80 InviteSessionHandle
81 InviteSession::getSessionHandle()
82 {
83 return InviteSessionHandle(mDum, getBaseHandle().getId());
84 }
85
86
87 void
88 InviteSession::dispatch(const DumTimeout& timeout)
89 {
90 if (timeout.type() == DumTimeout::Retransmit200 && mState == Accepting)
91 {
92 mDum.addTimer(DumTimeout::Retransmit200, resipMin(T2, mCurrentRetransmit200*2), getBaseHandle(), 0);
93 }
94 else if (timeout.type() == DumTimeout::WaitForAck && mState != Connected)
95 {
96 mDialog.makeResponse(mLastResponse, mLastRequest, 408);
97 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), mLastResponse);
98 delete this;
99 }
100 }
101
102 void
103 InviteSession::dispatch(const SipMessage& msg)
104 {
105 std::pair<OfferAnswerType, const SdpContents*> offans;
106 offans = InviteSession::getOfferOrAnswer(msg);
107
108 switch(mState)
109 {
110 case Terminated:
111 //!dcm! -- 481 behaviour here, should pretty much die on anything
112 if (msg.isResponse() && msg.header(h_StatusLine).statusCode() == 200 && msg.header(h_CSeq).method() == BYE)
113 {
114 delete this;
115 }
116 break;
117 case Connected:
118 // reINVITE
119 if (msg.isRequest())
120 {
121 switch(msg.header(h_RequestLine).method())
122 {
123 case INVITE:
124 mDialog.update(msg);
125 mDum.mInviteSessionHandler->onDialogModified(getSessionHandle(), msg);
126
127 if (offans.first != None)
128 {
129 incomingSdp(msg, offans.second);
130 }
131 break;
132
133 case BYE:
134 mState = Terminated;
135 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg);
136 mDialog.makeResponse(mLastResponse, msg, 200);
137 send(mLastResponse);
138 break;
139
140 case UPDATE:
141 assert(0);
142 break;
143
144 case INFO:
145 mDum.mInviteSessionHandler->onInfo(getSessionHandle(), msg);
146 break;
147
148 case REFER:
149 assert(0); // !jf!
150 mDum.mInviteSessionHandler->onRefer(getSessionHandle(), msg);
151 break;
152
153 default:
154 InfoLog (<< "Ignoring request in an INVITE dialog: " << msg.brief());
155 break;
156 }
157 }
158 case Accepting:
159 if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK)
160 {
161 //cancel 200 retransmission timer
162 mState = Connected;
163 mDum.mInviteSessionHandler->onConnected(getSessionHandle(), msg);
164 if (offans.first != None)
165 {
166 InviteSession::incomingSdp(msg, offans.second);
167 }
168 }
169 else
170 {
171 assert(0); // !dcm! -- usual nonsence message behaviour question
172 }
173 break;
174 default:
175 assert(0); //all other cases should be handled in base classes
176 }
177 }
178
179 SipMessage&
180 InviteSession::makeRefer(const H_ReferTo::Type& referTo)
181 {
182 assert(0);
183 return mLastRequest;
184 }
185
186 SipMessage&
187 InviteSession::end()
188 {
189 switch (mState)
190 {
191 case Terminated:
192 throw UsageUseException("Cannot end a session that has already been cancelled.", __FILE__, __LINE__);
193 break;
194 case Connected:
195 mDialog.makeRequest(mLastRequest, BYE);
196 //new transaction
197 assert(mLastRequest.header(h_Vias).size() == 1);
198 mLastRequest.header(h_Vias).front().param(p_branch).reset();
199 mState = Terminated;
200 return mLastRequest;
201 break;
202 default:
203 assert(0); // out of states
204 }
205 throw UsageUseException("Programmer error", __FILE__, __LINE__); //make VC++ happy
206 }
207
208 // If sdp==0, it means the last offer failed
209 // !dcm! -- eventually handle confused UA's that send offers/answers at
210 // inappropriate times, probably with a different callback
211 void
212 InviteSession::incomingSdp(const SipMessage& msg, const SdpContents* sdp)
213 {
214 switch (mOfferState)
215 {
216 case Nothing:
217 assert(mCurrentLocalSdp == 0);
218 assert(mCurrentRemoteSdp == 0);
219 mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
220 mOfferState = Offerred;
221 mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp);
222 break;
223
224 case Offerred:
225 mCurrentLocalSdp = mProposedLocalSdp;
226 mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
227 mProposedLocalSdp = 0;
228 mProposedRemoteSdp = 0;
229 mOfferState = Answered;
230 mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp);
231 break;
232
233 case Answered:
234 assert(mProposedLocalSdp == 0);
235 assert(mProposedRemoteSdp == 0);
236 mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
237 mOfferState = CounterOfferred;
238 mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp);
239 break;
240
241 case CounterOfferred:
242 assert(mCurrentLocalSdp);
243 assert(mCurrentRemoteSdp);
244 mOfferState = Answered;
245 if (sdp)
246 {
247 delete mCurrentLocalSdp;
248 delete mCurrentRemoteSdp;
249 mCurrentLocalSdp = mProposedLocalSdp;
250 mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
251 mProposedLocalSdp = 0;
252 mProposedRemoteSdp = 0;
253 mOfferState = Answered;
254 mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp);
255 }
256 else
257 {
258 mProposedLocalSdp = 0;
259 mProposedRemoteSdp = 0;
260 // !jf! is this right?
261 mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), msg);
262 }
263 break;
264 }
265 }
266
267 void
268 InviteSession::send(SipMessage& msg)
269 {
270 if (msg.isRequest())
271 {
272 //unless the message is an ACK(in which case it is mAck)
273 //strip out the SDP after sending
274 if (msg.header(h_RequestLine).getMethod() == ACK)
275 {
276 mDum.send(msg);
277 }
278 else
279 {
280 mDum.send(msg);
281 msg.releaseContents();
282 }
283 }
284 else
285 {
286 int code = msg.header(h_StatusLine).statusCode();
287 //!dcm! -- probably kill this object earlier, handle 200 to bye in
288 //DialogUsageManager...very soon
289 if (msg.header(h_CSeq).method() == BYE && code == 200) //!dcm! -- not 2xx?
290
291 {
292 mState = Terminated;
293 mDum.send(msg);
294 delete this;
295 }
296 else if (code >= 200 && code < 300 && msg.header(h_CSeq).method() == INVITE)
297 {
298 assert(&msg == &mFinalResponse);
299 mCurrentRetransmit200 = T1;
300 mDum.addTimer(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), 0);
301 mDum.addTimer(DumTimeout::WaitForAck, TimerH, getBaseHandle(), 0);
302
303 //!dcm! -- this should be mFinalResponse...maybe assign here in
304 //case the user wants to be very strange
305 if (mNextOfferOrAnswerSdp)
306 {
307 msg.setContents(static_cast<SdpContents*>(mNextOfferOrAnswerSdp->clone()));
308 sendSdp(mNextOfferOrAnswerSdp);
309 }
310 mDum.send(msg);
311 }
312 else
313 {
314 mDum.send(msg);
315 msg.releaseContents();
316 }
317 }
318 }
319
320 void
321 InviteSession::sendSdp(SdpContents* sdp)
322 {
323 switch (mOfferState)
324 {
325 case Nothing:
326 assert(mCurrentLocalSdp == 0);
327 assert(mCurrentRemoteSdp == 0);
328 mProposedLocalSdp = sdp;
329 mOfferState = Offerred;
330 break;
331
332 case Offerred:
333 mCurrentLocalSdp = sdp;
334 mCurrentRemoteSdp = mProposedRemoteSdp;
335 mProposedLocalSdp = 0;
336 mProposedRemoteSdp = 0;
337 mOfferState = Answered;
338 break;
339
340 case Answered:
341 assert(mProposedLocalSdp == 0);
342 assert(mProposedRemoteSdp == 0);
343 mProposedLocalSdp = sdp;
344 mOfferState = CounterOfferred;
345 break;
346
347 case CounterOfferred:
348 assert(mCurrentLocalSdp);
349 assert(mCurrentRemoteSdp);
350 if (sdp)
351 {
352 mCurrentLocalSdp = static_cast<SdpContents*>(sdp->clone());
353 mCurrentRemoteSdp = mProposedRemoteSdp;
354 }
355 else
356 {
357 mProposedLocalSdp = 0;
358 mProposedRemoteSdp = 0;
359 }
360 mOfferState = Answered;
361 break;
362 }
363 }
364
365 std::pair<InviteSession::OfferAnswerType, const SdpContents*>
366 InviteSession::getOfferOrAnswer(const SipMessage& msg) const
367 {
368 std::pair<InviteSession::OfferAnswerType, const SdpContents*> ret;
369 ret.first = None;
370
371 const SdpContents* contents = dynamic_cast<const SdpContents*>(msg.getContents());
372 if (contents)
373 {
374 static Token c100rel(Symbols::C100rel);
375 if (msg.isRequest() || msg.header(h_StatusLine).responseCode() == 200 ||
376 msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(c100rel))
377 {
378 switch (mOfferState)
379 {
380 case None:
381 ret.first = Offer;
382 ret.second = contents;
383 break;
384
385 case Offerred:
386 ret.first = Answer;
387 ret.second = contents;
388 break;
389
390 case Answered:
391 ret.first = Offer;
392 ret.second = contents;
393 break;
394
395 case CounterOfferred:
396 ret.first = Answer;
397 ret.second = contents;
398 break;
399 }
400 }
401 }
402 return ret;
403 }
404
405 void
406 InviteSession::copyAuthorizations(SipMessage& request)
407 {
408 #if 0
409 if (mLastRequest.exists(h_ProxyAuthorizations))
410 {
411 // should make the next auth (change nextNonce)
412 request.header(h_ProxyAuthorizations) = mLastRequest.header(h_ProxyAuthorizations);
413 }
414 if (mLastRequest.exists(h_ProxyAuthorizations))
415 {
416 // should make the next auth (change nextNonce)
417 request.header(h_ProxyAuthorizations) = mLastRequest.header(h_ProxyAuthorizations);
418 }
419 #endif
420 }
421
422 SipMessage&
423 InviteSession::rejectOffer(int statusCode)
424 {
425 mDialog.makeResponse(mLastResponse, mLastRequest, statusCode);
426 return mLastResponse;
427 }
428
429 SipMessage&
430 InviteSession::targetRefresh(const NameAddr& localUri)
431 {
432 assert(0);
433 return mLastRequest;
434 }
435
436 SipMessage&
437 InviteSession::ackConnection()
438 {
439 //if not a reinvite, and a pending offer exists, throw
440 makeAck();
441 //new transaction
442 assert(mAck.header(h_Vias).size() == 1);
443 mAck.header(h_Vias).front().param(p_branch).reset();
444 return mAck;
445 }
446
447 void
448 InviteSession::makeAck()
449 {
450 mAck = mLastRequest;
451
452 InfoLog ( << "InviteSession::makeAck:before: " << mAck );
453
454 mDialog.makeRequest(mAck, ACK);
455 if (mNextOfferOrAnswerSdp)
456 {
457 mAck.setContents(static_cast<SdpContents*>(mNextOfferOrAnswerSdp->clone()));
458 sendSdp(mNextOfferOrAnswerSdp);
459 }
460
461 InfoLog ( << "InviteSession::makeAck:after: " << mAck );
462 }
463
464 SipMessage&
465 InviteSession::reInvite(const SdpContents* offer)
466 {
467 assert(0);
468 return mLastRequest;
469 }
470
471 /* ====================================================================
472 * The Vovida Software License, Version 1.0
473 *
474 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
475 *
476 * Redistribution and use in source and binary forms, with or without
477 * modification, are permitted provided that the following conditions
478 * are met:
479 *
480 * 1. Redistributions of source code must retain the above copyright
481 * notice, this list of conditions and the following disclaimer.
482 *
483 * 2. Redistributions in binary form must reproduce the above copyright
484 * notice, this list of conditions and the following disclaimer in
485 * the documentation and/or other materials provided with the
486
487 * distribution.
488 *
489 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
490 * and "Vovida Open Communication Application Library (VOCAL)" must
491 * not be used to endorse or promote products derived from this
492 * software without prior written permission. For written
493 * permission, please contact vocal@vovida.org.
494 *
495 * 4. Products derived from this software may not be called "VOCAL", nor
496 * may "VOCAL" appear in their name, without prior written
497 * permission of Vovida Networks, Inc.
498 *
499 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
500 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
501 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
502 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
503 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
504 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
505 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
506 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
507 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
508 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
509 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
510 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
511 * DAMAGE.
512 *
513 * ====================================================================
514 *
515 * This software consists of voluntary contributions made by Vovida
516 * Networks, Inc. and many individuals on behalf of Vovida Networks,
517 * Inc. For more information on Vovida Networks, Inc., please see
518 * <http://www.vovida.org/>.
519 *
520 */

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27