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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27