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

Contents of /main/sip/resiprocate/dum/ClientInviteSession.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2997 - (show annotations) (download)
Wed Jun 16 01:08:25 2004 UTC (15 years, 7 months ago) by derek
File size: 15530 byte(s)
Basic call works w/out crash on exit now.  Added BYE logic to Dialog.
Dialog still needs work.
1 #include "resiprocate/SdpContents.hxx"
2 #include "resiprocate/dum/ClientInviteSession.hxx"
3 #include "resiprocate/dum/Dialog.hxx"
4 #include "resiprocate/dum/DialogUsageManager.hxx"
5 #include "resiprocate/dum/InviteSessionHandler.hxx"
6 #include "resiprocate/dum/DumTimeout.hxx"
7 #include "resiprocate/dum/UsageUseException.hxx"
8 #include "resiprocate/os/Logger.hxx"
9
10 using namespace resip;
11
12 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
13
14 ClientInviteSession::ClientInviteSession(DialogUsageManager& dum,
15 Dialog& dialog,
16 const SipMessage& request,
17 const SdpContents* initialOffer)
18 : InviteSession(dum, dialog, Initial),
19 lastReceivedRSeq(0),
20 lastExpectedRSeq(0),
21 mStaleCallTimerSeq(1)
22 {
23 assert(request.isRequest());
24 if (initialOffer)
25 {
26 sendSdp(static_cast<SdpContents*>(initialOffer->clone()));
27 }
28 mLastRequest = request;
29 mLastRequest.releaseContents();
30 }
31
32 ClientInviteSessionHandle
33 ClientInviteSession::getHandle()
34 {
35 return ClientInviteSessionHandle(mDum, getBaseHandle().getId());
36 }
37
38 void
39 ClientInviteSession::dispatch(const SipMessage& msg)
40 {
41 std::pair<OfferAnswerType, const SdpContents*> offans;
42 offans = InviteSession::getOfferOrAnswer(msg);
43
44 // !jf! consider UPDATE method
45
46 switch(mState)
47 {
48 case Initial:
49 {
50 //!dcm! -- really can't do this assert, prob. kill dialog(erroneous
51 //request) and send a 4xx, but which 4xx?
52 assert(msg.isResponse());
53 int code = msg.header(h_StatusLine).statusCode();
54 if (code == 100)
55 {
56 mDum.addTimer(DumTimeout::StaleCall, DumTimeout::StaleCallTimeout, getBaseHandle(), ++mStaleCallTimerSeq);
57 mState = Proceeding;
58 mDum.mInviteSessionHandler->onNewSession(getHandle(), None, msg);
59 }
60 else if (code < 200)
61 {
62 mDum.addTimer(DumTimeout::StaleCall, DumTimeout::StaleCallTimeout, getBaseHandle(), ++mStaleCallTimerSeq);
63 mState = Early;
64 mDum.mInviteSessionHandler->onNewSession(getHandle(), offans.first, msg);
65 mDum.mInviteSessionHandler->onProvisional(getHandle(), msg);
66
67 if (offans.first != None)
68 {
69 InviteSession::incomingSdp(msg, offans.second);
70 }
71 else if (offans.second)
72 {
73 mDum.mInviteSessionHandler->onEarlyMedia(getHandle(), msg, offans.second);
74 }
75 }
76 else if (code < 300)
77 {
78 //!dcm! -- pretty sure the following timer was bogus
79 // mDum.addTimer(DumTimeout::StaleCall, DumTimeout::StaleCallTimeout, getBaseHandle(), ++mStaleCallTimerSeq);
80 ++mStaleCallTimerSeq; //unifies timer handling logic
81
82 mState = Connected;
83 mDum.mInviteSessionHandler->onNewSession(getHandle(), offans.first, msg);
84 mDum.mInviteSessionHandler->onConnected(getHandle(), msg);
85
86 if (offans.first != None)
87 {
88 InviteSession::incomingSdp(msg, offans.second);
89 }
90 // sendAck(msg); !dcm! -- doesn't allow user to set answer, adorn message
91 }
92 else if (code >= 300)
93 {
94 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg);
95 delete this;
96 }
97 break;
98 }
99
100 case Proceeding:
101 case Early:
102 {
103 if (msg.isResponse())
104 {
105 int code = msg.header(h_StatusLine).statusCode();
106 if (code == 100)
107 {
108 }
109 else if (code < 200)
110 {
111 mDum.addTimer(DumTimeout::StaleCall, DumTimeout::StaleCallTimeout, getBaseHandle(), ++mStaleCallTimerSeq);
112 mState = Early;
113 mDum.mInviteSessionHandler->onProvisional(getHandle(), msg);
114
115 if (offans.first != None)
116 {
117 InviteSession::incomingSdp(msg, offans.second);
118 }
119 else if (offans.second)
120 {
121 mDum.mInviteSessionHandler->onEarlyMedia(getHandle(), msg, offans.second);
122 }
123 }
124 else if (code < 300)
125 {
126 //!dcm! -- pretty sure the following timer was bogus
127 // mDum.addTimer(DumTimeout::StaleCall, DumTimeout::StaleCallTimeout, getBaseHandle(), ++mStaleCallTimerSeq);
128 ++mStaleCallTimerSeq; //unifies timer handling logic
129 mState = Connected;
130 //!dcm! --kill mDum.mInviteSessionHandler->onNewSession(getHandle(), offans.first, msg);
131 mDum.mInviteSessionHandler->onConnected(getHandle(), msg);
132
133 if (offans.first != None)
134 {
135 InviteSession::incomingSdp(msg, offans.second);
136 }
137 // sendAck(msg); !dcm! -- doesn't allow user to set answer, adorn message
138 }
139 else if (code >= 300)
140 {
141 mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg);
142 delete this;
143 }
144 break;
145 }
146 }
147
148 case Cancelled:
149 {
150 if (msg.isResponse())
151 {
152 int code = msg.header(h_StatusLine).statusCode();
153 if (code / 100 == 2 && msg.header(h_CSeq).method() == INVITE)
154 {
155 end();
156 }
157 else if (code >= 300 && msg.header(h_CSeq).method() == INVITE)
158 {
159 delete this;
160 }
161 }
162 break;
163 }
164 case Connected:
165 case Terminated:
166 InviteSession::dispatch(msg);
167 break;
168 default:
169 assert(0); //states should be exhausted
170 }
171 }
172
173 void
174 ClientInviteSession::dispatch(const DumTimeout& timeout)
175 {
176 if (timeout.type() == DumTimeout::StaleCall
177 && timeout.seq() == mStaleCallTimerSeq)
178 {
179 mDum.mInviteSessionHandler->onStaleCallTimeout(getHandle());
180 }
181 else
182 {
183 InviteSession::dispatch(timeout);
184 }
185 }
186
187 void
188 ClientInviteSession::send(SipMessage& msg)
189 {
190 //last ack logic lives in InviteSession(to be re-used for reinvite
191 if (mState == Connected || mState == Terminated)
192 {
193 InviteSession::send(msg);
194 return;
195 }
196
197 //!dcm! -- strawman, no knowledge of prack, so just ack(handled in
198 //InviteSession) and Invite(already done) for now complain bitterly
199 if (mNextOfferOrAnswerSdp)
200 {
201 assert(0);
202 }
203 assert(msg.isRequest()); //!dcm! -- is this correct?
204 mLastRequest = msg;
205 mDum.send(msg);
206 }
207
208 SipMessage&
209 ClientInviteSession::end()
210 {
211 switch (mState)
212 {
213 case Early:
214 // is it legal to cancel a specific fork/dialog.
215 // if so, this is the place to do it
216 case Initial:
217 mDialog.makeCancel(mLastRequest);
218 //!dcm! -- it could be argued that this(and similar) should happen in send so users
219 //can't toast themselves
220 mState = Cancelled;
221 return mLastRequest;
222 break;
223 case Terminated:
224 case Connected:
225 return InviteSession::end();
226 break;
227 case Cancelled: //user error
228 throw new UsageUseException("Cannot end a session that has already been cancelled.", __FILE__, __LINE__);
229 default:
230 assert(0); //states should be exhausted
231 }
232 }
233
234 //!dcm! -- probably kill
235 // void
236 // ClientInviteSession::sendAck(const SipMessage& ok)
237 // {
238 // makeAck(ok);
239 // if (mProposedLocalSdp)
240 // {
241 // // !jf! ?
242 // //mDialog.setContents(mProposedLocalSdp);
243 // }
244 // mDum.send(mAck);
245 // }
246
247 //below here be the prack
248 void
249 ClientInviteSession::sendPrack(const SipMessage& response)
250 {
251 assert(response.isResponse());
252 assert(response.header(h_StatusLine).statusCode() > 100 &&
253 response.header(h_StatusLine).statusCode() < 200);
254
255 SipMessage prack;
256 mDialog.makeRequest(prack, PRACK);
257
258 if (mProposedRemoteSdp)
259 {
260 assert(mProposedLocalSdp);
261 // send an answer
262 prack.setContents(mProposedLocalSdp);
263
264 }
265 else if (mProposedLocalSdp)
266 {
267 // send a counter-offer
268 prack.setContents(mProposedRemoteSdp);
269 }
270 else
271 {
272 // no sdp
273 }
274
275 // much later!!! the deep rathole ....
276 // if there is a pending offer or answer, will include it in the PRACK body
277 assert(0);
278
279
280 }
281
282 void
283 ClientInviteSession::handlePrackResponse(const SipMessage& response)
284 {
285 // more PRACK goodness
286 assert(0);
287 }
288
289 #if 0 //?dcm? --PRACKISH dispatch, or just cruft?
290 void
291 ClientInviteSession::dispatch(const SipMessage& msg)
292 {
293 InviteSessionHandler* handler = mDum.mInviteSessionHandler;
294 assert(handler);
295
296 if (msg.isRequest())
297 {
298 InviteSession::dispatch(msg);
299 return;
300 }
301 else if (msg.isResponse())
302 {
303 switch (msg.header(h_CSeq).method())
304 {
305 case INVITE:
306 break;
307
308 case PRACK:
309 handlePrackResponse(msg);
310 return;
311
312 case CANCEL:
313 if (msg.header(h_StatusLine).statusCode() >= 400)
314 {
315 mState = Terminated;
316 end(); // cleanup the mess
317 }
318 return;
319
320 default:
321 InviteSession::dispatch(msg);
322 return;
323 }
324 }
325
326 int code = msg.header(h_StatusLine).statusCode();
327 if (code < 300 && mState == Initial)
328 {
329 //handler->onNewSession(getHandle(), msg);
330 }
331
332 if (code < 200) // 1XX
333 {
334 if (mState == Initial || mState == Early)
335 {
336 mState = Early;
337 //handler->onEarly(getHandle(), msg);
338
339 SdpContents* sdp = dynamic_cast<SdpContents*>(msg.getContents());
340 bool reliable = msg.header(h_Supporteds).find(Token(Symbols::C100rel));
341 if (sdp)
342 {
343 if (reliable)
344 {
345 if (mProposedLocalSdp)
346 {
347 mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
348 mCurrentLocalSdp = mProposedLocalSdp;
349 mProposedLocalSdp = 0;
350
351 //handler->onAnswer(getHandle(), msg);
352 }
353 else
354 {
355 mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
356 handler->onOffer(getSessionHandle(), msg);
357
358 // handler must provide an answer
359 assert(mProposedLocalSdp);
360 }
361 }
362 else
363 {
364 // do nothing, not an offer/answer
365 }
366 }
367 if (reliable)
368 {
369 sendPrack(msg);
370 }
371 }
372 else
373 {
374 // drop it on the floor. Late 1xx
375 }
376 }
377 else if (code < 300) // 2XX
378 {
379 if (mState == Cancelled)
380 {
381 //sendAck(the200);
382 end();
383 return;
384 }
385 else if (mState != Terminated)
386 {
387 mState = Connected;
388 // !jf!
389 //if (mReceived2xx) // retransmit ACK
390 {
391 mDum.send(mAck);
392 return;
393 }
394
395 //mReceived2xx = true;
396 handler->onConnected(getHandle(), msg);
397
398 SdpContents* sdp = dynamic_cast<SdpContents*>(msg.getContents());
399 if (sdp)
400 {
401 if (mProposedLocalSdp) // got an answer
402 {
403 mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone());
404 mCurrentLocalSdp = mProposedLocalSdp;
405 mProposedLocalSdp = 0;
406
407 //handler->onAnswer(getHandle(), msg);
408 }
409 else // got an offer
410 {
411 mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone());
412 handler->onOffer(getSessionHandle(), msg);
413 }
414 }
415 else
416 {
417 if (mProposedLocalSdp)
418 {
419 // Got a 2xx with no answer (sent an INVITE with an offer,
420 // unreliable provisionals)
421 end();
422 return;
423 }
424 else if (mCurrentLocalSdp == 0 && mProposedRemoteSdp == 0)
425 { Transport::error( e );
426 InfoLog(<< "Unable to route to " << target << " : [" << e << "] " << strerror(e) );
427 throw Transport::Exception("Can't find source address for Via", __FILE__,__LINE__);
428 // Got a 2xx with no offer (sent an INVITE with no offer,
429 // unreliable provisionals)
430 end();
431 return;
432 }
433 else
434 {
435 assert(mCurrentLocalSdp != 0);
436 // do nothing
437 }
438 }
439 sendAck(msg);
440 }
441 }
442 else if (code >= 400)
443 {
444 if (mState != Terminated)
445 {
446 mState = Terminated;
447 handler->onTerminated(getSessionHandle(), msg);
448 delete this;
449 }
450 }
451 else // 3xx
452 {
453 assert(0);
454 }
455 }
456 #endif
457
458
459 /* ====================================================================
460 * The Vovida Software License, Version 1.0
461 *
462 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
463 *
464 * Redistribution and use in source and binary forms, with or without
465 * modification, are permitted provided that the following conditions
466 * are met:
467 *
468 * 1. Redistributions of source code must retain the above copyright
469 * notice, this list of conditions and the following disclaimer.
470 *
471 * 2. Redistributions in binary form must reproduce the above copyright
472 * notice, this list of conditions and the following disclaimer in
473 * the documentation and/or other materials provided with the
474
475 * distribution.
476 *
477 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
478 * and "Vovida Open Communication Application Library (VOCAL)" must
479 * not be used to endorse or promote products derived from this
480 * software without prior written permission. For written
481 * permission, please contact vocal@vovida.org.
482 *
483 * 4. Products derived from this software may not be called "VOCAL", nor
484 * may "VOCAL" appear in their name, without prior written
485 * permission of Vovida Networks, Inc.
486 *
487 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
488 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
489 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
490 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
491 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
492 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
493 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
494 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
495 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
496 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
497 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
498 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
499 * DAMAGE.
500 *
501 * ====================================================================
502 *
503 * This software consists of voluntary contributions made by Vovida
504 * Networks, Inc. and many individuals on behalf of Vovida Networks,
505 * Inc. For more information on Vovida Networks, Inc., please see
506 * <http://www.vovida.org/>.
507 *
508 */

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27