1 |
derek |
3138 |
#include "resiprocate/SdpContents.hxx" |
2 |
sgodin |
3338 |
#include "resiprocate/MultipartMixedContents.hxx" |
3 |
jason |
2725 |
#include "resiprocate/SipMessage.hxx" |
4 |
|
|
#include "resiprocate/dum/Dialog.hxx" |
5 |
|
|
#include "resiprocate/dum/DialogUsageManager.hxx" |
6 |
|
|
#include "resiprocate/dum/InviteSession.hxx" |
7 |
jason |
2846 |
#include "resiprocate/dum/InviteSessionHandler.hxx" |
8 |
derek |
3138 |
#include "resiprocate/dum/Profile.hxx" |
9 |
derek |
2961 |
#include "resiprocate/dum/UsageUseException.hxx" |
10 |
jason |
2856 |
#include "resiprocate/os/Logger.hxx" |
11 |
derek |
3255 |
#include "resiprocate/os/Timer.hxx" |
12 |
derek |
3295 |
#include "resiprocate/os/Inserter.hxx" |
13 |
jason |
2555 |
|
14 |
derek |
3094 |
#if defined(WIN32) && defined(_DEBUG) &&defined(LEAK_CHECK)// Used for tracking down memory leaks in Visual Studio |
15 |
derek |
3092 |
#define _CRTDBG_MAP_ALLOC |
16 |
|
|
#include <stdlib.h> |
17 |
|
|
#include <crtdbg.h> |
18 |
|
|
#define new new( _NORMAL_BLOCK, __FILE__, __LINE__) |
19 |
|
|
#endif // defined(WIN32) && defined(_DEBUG) |
20 |
sgodin |
3091 |
|
21 |
sgodin |
3314 |
// Remove warning about 'this' use in initiator list - pointer is only stored |
22 |
|
|
#if defined(WIN32) |
23 |
|
|
#pragma warning( disable : 4355 ) // using this in base member initializer list |
24 |
|
|
#endif |
25 |
derek |
3092 |
|
26 |
jason |
2856 |
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM |
27 |
jason |
2846 |
|
28 |
davidb |
2603 |
using namespace resip; |
29 |
derek |
3255 |
using namespace std; |
30 |
davidb |
2603 |
|
31 |
derek |
2976 |
InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog, State initialState) |
32 |
derek |
3089 |
: DialogUsage(dum, dialog), |
33 |
derek |
2976 |
mState(initialState), |
34 |
derek |
3255 |
mNitState(NitComplete), |
35 |
jason |
2846 |
mOfferState(Nothing), |
36 |
jason |
2725 |
mCurrentLocalSdp(0), |
37 |
|
|
mCurrentRemoteSdp(0), |
38 |
|
|
mProposedLocalSdp(0), |
39 |
derek |
2965 |
mProposedRemoteSdp(0), |
40 |
derek |
2990 |
mNextOfferOrAnswerSdp(0), |
41 |
jason |
3257 |
mUserConnected(false), |
42 |
jason |
3278 |
mQueuedBye(0), |
43 |
jason |
3147 |
mDestroyer(this), |
44 |
jason |
3278 |
mCurrentRetransmit200(Timer::T1) |
45 |
jason |
2555 |
{ |
46 |
jason |
3156 |
DebugLog ( << "^^^ InviteSession::InviteSession " << this); |
47 |
jason |
2846 |
assert(mDum.mInviteSessionHandler); |
48 |
jason |
2555 |
} |
49 |
|
|
|
50 |
derek |
2858 |
InviteSession::~InviteSession() |
51 |
|
|
{ |
52 |
jason |
3156 |
DebugLog ( << "^^^ InviteSession::~InviteSession " << this); |
53 |
derek |
2965 |
delete mCurrentLocalSdp; |
54 |
|
|
delete mCurrentRemoteSdp; |
55 |
|
|
delete mProposedLocalSdp; |
56 |
|
|
delete mProposedRemoteSdp; |
57 |
|
|
delete mNextOfferOrAnswerSdp; |
58 |
derek |
3276 |
delete mQueuedBye; |
59 |
derek |
2858 |
mDialog.mInviteSession = 0; |
60 |
|
|
} |
61 |
jason |
2846 |
|
62 |
derek |
3064 |
SipMessage& |
63 |
|
|
InviteSession::modifySession() |
64 |
|
|
{ |
65 |
derek |
3308 |
DebugLog( << "InviteSession::modifySession: " << mDialog.getId()); |
66 |
derek |
3291 |
if (mNextOfferOrAnswerSdp == 0 || mState != Connected || mOfferState != Answered) |
67 |
derek |
3064 |
{ |
68 |
|
|
throw new UsageUseException("Must be in the connected state and have propsed an offer to call modifySession", |
69 |
|
|
__FILE__, __LINE__); |
70 |
|
|
} |
71 |
|
|
mState = ReInviting; |
72 |
|
|
mDialog.makeRequest(mLastRequest, INVITE); |
73 |
|
|
return mLastRequest; |
74 |
|
|
} |
75 |
|
|
|
76 |
derek |
3255 |
SipMessage& |
77 |
|
|
InviteSession::makeFinalResponse(int code) |
78 |
|
|
{ |
79 |
derek |
3289 |
int cseq = mLastIncomingRequest.header(h_CSeq).sequence(); |
80 |
derek |
3255 |
SipMessage& finalResponse = mFinalResponseMap[cseq]; |
81 |
derek |
3289 |
mDialog.makeResponse(finalResponse, mLastIncomingRequest, 200); |
82 |
derek |
3255 |
return finalResponse; |
83 |
|
|
} |
84 |
derek |
3064 |
|
85 |
|
|
SipMessage& |
86 |
derek |
3291 |
InviteSession::acceptDialogModification(int statusCode) |
87 |
derek |
3064 |
{ |
88 |
|
|
if (mNextOfferOrAnswerSdp == 0 || mState != ReInviting) |
89 |
|
|
{ |
90 |
|
|
throw new UsageUseException("Must be in the ReInviting state and have propsed an answer to call answerModifySession", |
91 |
|
|
__FILE__, __LINE__); |
92 |
|
|
} |
93 |
derek |
3255 |
mState = Connected; |
94 |
|
|
return makeFinalResponse(statusCode); |
95 |
derek |
3064 |
} |
96 |
|
|
|
97 |
jason |
2866 |
void |
98 |
|
|
InviteSession::setOffer(const SdpContents* sdp) |
99 |
|
|
{ |
100 |
derek |
3308 |
DebugLog( << "InviteSession::setOffer: " << mDialog.getId()); |
101 |
derek |
2965 |
if (mProposedRemoteSdp) |
102 |
|
|
{ |
103 |
|
|
throw UsageUseException("Cannot set an offer with an oustanding remote offer", __FILE__, __LINE__); |
104 |
|
|
} |
105 |
sgodin |
3091 |
assert(mNextOfferOrAnswerSdp == 0); |
106 |
derek |
2965 |
mNextOfferOrAnswerSdp = static_cast<SdpContents*>(sdp->clone()); |
107 |
jason |
2866 |
} |
108 |
|
|
|
109 |
|
|
void |
110 |
|
|
InviteSession::setAnswer(const SdpContents* sdp) |
111 |
|
|
{ |
112 |
derek |
3308 |
DebugLog( << "InviteSession::setAnswer: " << mDialog.getId()); |
113 |
derek |
2965 |
if (mProposedLocalSdp ) |
114 |
|
|
{ |
115 |
|
|
throw UsageUseException("Cannot set an answer with an oustanding offer", __FILE__, __LINE__); |
116 |
|
|
} |
117 |
sgodin |
3091 |
assert(mNextOfferOrAnswerSdp == 0); |
118 |
derek |
2965 |
mNextOfferOrAnswerSdp = static_cast<SdpContents*>(sdp->clone()); |
119 |
jason |
2866 |
} |
120 |
|
|
|
121 |
jason |
2555 |
const SdpContents* |
122 |
|
|
InviteSession::getLocalSdp() |
123 |
|
|
{ |
124 |
jason |
2725 |
return mCurrentLocalSdp; |
125 |
jason |
2555 |
} |
126 |
|
|
|
127 |
|
|
const SdpContents* |
128 |
|
|
InviteSession::getRemoteSdp() |
129 |
|
|
{ |
130 |
jason |
2725 |
return mCurrentRemoteSdp; |
131 |
jason |
2555 |
} |
132 |
davidb |
2575 |
|
133 |
jason |
2941 |
InviteSessionHandle |
134 |
|
|
InviteSession::getSessionHandle() |
135 |
|
|
{ |
136 |
|
|
return InviteSessionHandle(mDum, getBaseHandle().getId()); |
137 |
|
|
} |
138 |
|
|
|
139 |
jason |
2856 |
void |
140 |
derek |
2990 |
InviteSession::dispatch(const DumTimeout& timeout) |
141 |
|
|
{ |
142 |
derek |
3138 |
Destroyer::Guard guard(mDestroyer); |
143 |
derek |
3255 |
if (timeout.type() == DumTimeout::Retransmit200) |
144 |
derek |
2990 |
{ |
145 |
derek |
3255 |
CSeqToMessageMap::iterator it = mFinalResponseMap.find(timeout.seq()); |
146 |
|
|
if (it != mFinalResponseMap.end()) |
147 |
|
|
{ |
148 |
|
|
mDum.send(it->second); |
149 |
|
|
mCurrentRetransmit200 *= 2; |
150 |
|
|
mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq()); |
151 |
|
|
} |
152 |
derek |
2990 |
} |
153 |
derek |
3255 |
else if (timeout.type() == DumTimeout::WaitForAck) |
154 |
derek |
2990 |
{ |
155 |
derek |
3255 |
CSeqToMessageMap::iterator it = mFinalResponseMap.find(timeout.seq()); |
156 |
|
|
if (it != mFinalResponseMap.end()) |
157 |
|
|
{ |
158 |
sgodin |
3363 |
// BYE could be queued if end() is called when we are still waiting for far end ACK to be received |
159 |
|
|
if (mQueuedBye) |
160 |
|
|
{ |
161 |
|
|
mState = Terminated; |
162 |
|
|
mLastRequest = *mQueuedBye; |
163 |
|
|
delete mQueuedBye; |
164 |
|
|
mQueuedBye = 0; |
165 |
|
|
send(mLastRequest); |
166 |
|
|
} |
167 |
|
|
else |
168 |
|
|
{ |
169 |
|
|
mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle(), it->second); |
170 |
|
|
} |
171 |
|
|
|
172 |
derek |
3255 |
mFinalResponseMap.erase(it); |
173 |
|
|
} |
174 |
derek |
2990 |
} |
175 |
derek |
3255 |
else if (timeout.type() == DumTimeout::CanDiscardAck) |
176 |
|
|
{ |
177 |
|
|
assert(mAckMap.find(timeout.seq()) != mFinalResponseMap.end()); |
178 |
|
|
mAckMap.erase(timeout.seq()); |
179 |
|
|
} |
180 |
derek |
2990 |
} |
181 |
|
|
|
182 |
|
|
void |
183 |
jason |
2856 |
InviteSession::dispatch(const SipMessage& msg) |
184 |
|
|
{ |
185 |
derek |
3138 |
Destroyer::Guard guard(mDestroyer); |
186 |
jason |
2856 |
std::pair<OfferAnswerType, const SdpContents*> offans; |
187 |
|
|
offans = InviteSession::getOfferOrAnswer(msg); |
188 |
derek |
3255 |
|
189 |
|
|
//ugly. non-invite-transactions(nit) don't interact with the invite |
190 |
|
|
//transaction state machine(for now we have a separate INFO state machine) |
191 |
|
|
//it's written as a gerneric NIT satet machine, but method isn't checked, and |
192 |
|
|
//info is the only NIT so far. This should eventually live in Dialog, with a |
193 |
|
|
//current method to determine valid responses. |
194 |
|
|
if (msg.header(h_CSeq).method() == INFO) |
195 |
|
|
{ |
196 |
|
|
if (msg.isRequest()) |
197 |
|
|
{ |
198 |
derek |
3261 |
SipMessage response; |
199 |
|
|
mDialog.makeResponse(response, msg, 200); |
200 |
|
|
send(response); |
201 |
derek |
3255 |
mDum.mInviteSessionHandler->onInfo(getSessionHandle(), msg); |
202 |
|
|
} |
203 |
|
|
else |
204 |
|
|
{ |
205 |
|
|
if (mNitState == NitProceeding) |
206 |
|
|
{ |
207 |
|
|
int code = msg.header(h_StatusLine).statusCode(); |
208 |
|
|
if (code < 200) |
209 |
|
|
{ |
210 |
|
|
//ignore |
211 |
|
|
} |
212 |
|
|
else if (code < 300) |
213 |
|
|
{ |
214 |
|
|
mNitState = NitComplete; |
215 |
|
|
mDum.mInviteSessionHandler->onInfoSuccess(getSessionHandle(), msg); |
216 |
|
|
} |
217 |
|
|
else |
218 |
|
|
{ |
219 |
|
|
mNitState = NitComplete; |
220 |
|
|
mDum.mInviteSessionHandler->onInfoFailure(getSessionHandle(), msg); |
221 |
|
|
} |
222 |
|
|
} |
223 |
|
|
} |
224 |
|
|
return; |
225 |
|
|
} |
226 |
jason |
2856 |
|
227 |
derek |
3255 |
if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK && |
228 |
|
|
(mState == Connected || mState == ReInviting)) |
229 |
|
|
{ |
230 |
|
|
//quench 200 retransmissions |
231 |
|
|
mFinalResponseMap.erase(msg.header(h_CSeq).sequence()); |
232 |
derek |
3291 |
if (msg.header(h_CSeq).sequence() == mLastIncomingRequest.header(h_CSeq).sequence()) |
233 |
|
|
{ |
234 |
sgodin |
3363 |
// BYE could be queued if end() is called when we are still waiting for far end ACK to be received |
235 |
|
|
if (mQueuedBye) |
236 |
|
|
{ |
237 |
|
|
mState = Terminated; |
238 |
|
|
mLastRequest = *mQueuedBye; |
239 |
|
|
delete mQueuedBye; |
240 |
|
|
mQueuedBye = 0; |
241 |
|
|
send(mLastRequest); |
242 |
|
|
return; |
243 |
|
|
} |
244 |
|
|
|
245 |
derek |
3291 |
if (offans.first != None) |
246 |
|
|
{ |
247 |
|
|
if (mOfferState == Answered) |
248 |
|
|
{ |
249 |
|
|
//SDP in invite and in ACK. |
250 |
|
|
mDum.mInviteSessionHandler->onIllegalNegotiation(getSessionHandle(), msg); |
251 |
|
|
} |
252 |
|
|
else |
253 |
|
|
{ |
254 |
|
|
//delaying onConnected until late SDP |
255 |
|
|
InviteSession::incomingSdp(msg, offans.second); |
256 |
|
|
if (!mUserConnected) |
257 |
|
|
{ |
258 |
|
|
mUserConnected = true; |
259 |
|
|
mDum.mInviteSessionHandler->onConnected(getSessionHandle(), msg); |
260 |
|
|
} |
261 |
|
|
} |
262 |
|
|
} |
263 |
derek |
3308 |
//temporary hack |
264 |
|
|
else if (mState != ReInviting && mOfferState != Answered) |
265 |
derek |
3255 |
{ |
266 |
derek |
3291 |
//no SDP in ACK when one is required |
267 |
derek |
3255 |
mDum.mInviteSessionHandler->onIllegalNegotiation(getSessionHandle(), msg); |
268 |
|
|
} |
269 |
derek |
3291 |
} |
270 |
derek |
3255 |
} |
271 |
|
|
|
272 |
derek |
2961 |
switch(mState) |
273 |
jason |
2856 |
{ |
274 |
derek |
2961 |
case Terminated: |
275 |
derek |
2978 |
//!dcm! -- 481 behaviour here, should pretty much die on anything |
276 |
derek |
2997 |
//eventually 200 to BYE could be handled further out |
277 |
|
|
if (msg.isResponse()) |
278 |
derek |
2961 |
{ |
279 |
derek |
2997 |
int code = msg.header(h_StatusLine).statusCode(); |
280 |
|
|
if ((code == 200 && msg.header(h_CSeq).method() == BYE) || code > 399) |
281 |
|
|
{ |
282 |
|
|
mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg); |
283 |
derek |
3138 |
guard.destroy(); |
284 |
derek |
3006 |
return; |
285 |
derek |
2997 |
} |
286 |
derek |
2961 |
} |
287 |
derek |
3138 |
else |
288 |
|
|
{ |
289 |
|
|
//make a function to do this & the occurences of this in DialogUsageManager |
290 |
|
|
SipMessage failure; |
291 |
|
|
mDum.makeResponse(failure, msg, 481); |
292 |
|
|
failure.header(h_AcceptLanguages) = mDum.mProfile->getSupportedLanguages(); |
293 |
|
|
mDum.sendResponse(failure); |
294 |
|
|
} |
295 |
derek |
2961 |
break; |
296 |
|
|
case Connected: |
297 |
|
|
if (msg.isRequest()) |
298 |
|
|
{ |
299 |
|
|
switch(msg.header(h_RequestLine).method()) |
300 |
|
|
{ |
301 |
sgodin |
3091 |
// reINVITE |
302 |
derek |
2961 |
case INVITE: |
303 |
derek |
3255 |
{ |
304 |
|
|
if (mOfferState == Answered) |
305 |
derek |
2961 |
{ |
306 |
derek |
3255 |
mState = ReInviting; |
307 |
|
|
mDialog.update(msg); |
308 |
derek |
3289 |
mLastIncomingRequest = msg; |
309 |
derek |
3291 |
mDum.mInviteSessionHandler->onDialogModified(getSessionHandle(), offans.first, msg); |
310 |
derek |
3255 |
if (offans.first != None) |
311 |
|
|
{ |
312 |
|
|
incomingSdp(msg, offans.second); |
313 |
|
|
} |
314 |
derek |
3291 |
else |
315 |
|
|
{ |
316 |
|
|
mDum.mInviteSessionHandler->onOfferRequired(getSessionHandle(), msg); |
317 |
|
|
} |
318 |
derek |
2961 |
} |
319 |
derek |
3255 |
else |
320 |
|
|
{ |
321 |
|
|
//4?? |
322 |
|
|
SipMessage failure; |
323 |
|
|
mDialog.makeResponse(failure, msg, 491); |
324 |
|
|
InfoLog (<< "Sending 491 - overlapping Invite transactions"); |
325 |
|
|
mDum.sendResponse(failure); |
326 |
|
|
} |
327 |
|
|
} |
328 |
|
|
break; |
329 |
derek |
2961 |
case BYE: |
330 |
derek |
2978 |
mState = Terminated; |
331 |
|
|
mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg); |
332 |
|
|
mDialog.makeResponse(mLastResponse, msg, 200); |
333 |
|
|
send(mLastResponse); |
334 |
derek |
2961 |
break; |
335 |
jason |
2856 |
|
336 |
derek |
2961 |
case UPDATE: |
337 |
|
|
assert(0); |
338 |
|
|
break; |
339 |
jason |
2856 |
|
340 |
derek |
2961 |
case INFO: |
341 |
|
|
mDum.mInviteSessionHandler->onInfo(getSessionHandle(), msg); |
342 |
derek |
3255 |
break; |
343 |
derek |
2961 |
case REFER: |
344 |
derek |
3101 |
//handled in Dialog |
345 |
|
|
assert(0); |
346 |
derek |
2961 |
break; |
347 |
sgodin |
3332 |
|
348 |
|
|
case CANCEL: |
349 |
|
|
// A Cancel can get received in an established dialog if it crosses with our 200 response |
350 |
|
|
// on the wire - it should be responsed to, but should not effect the dialog state (InviteSession). |
351 |
|
|
// RFC3261 Section 9.2 |
352 |
|
|
mDialog.makeResponse(mLastResponse, msg, 200); |
353 |
|
|
send(mLastResponse); |
354 |
|
|
break; |
355 |
jason |
2856 |
|
356 |
derek |
2961 |
default: |
357 |
|
|
InfoLog (<< "Ignoring request in an INVITE dialog: " << msg.brief()); |
358 |
|
|
break; |
359 |
|
|
} |
360 |
derek |
3006 |
} |
361 |
|
|
else |
362 |
|
|
{ |
363 |
derek |
3255 |
if ( msg.header(h_StatusLine).statusCode() == 200 && msg.header(h_CSeq).method() == INVITE) |
364 |
derek |
3006 |
{ |
365 |
derek |
3255 |
CSeqToMessageMap::iterator it = mAckMap.find(msg.header(h_CSeq).sequence()); |
366 |
|
|
if (it != mAckMap.end()) |
367 |
|
|
{ |
368 |
derek |
3282 |
mDum.send(it->second); |
369 |
derek |
3255 |
} |
370 |
derek |
3006 |
} |
371 |
|
|
} |
372 |
derek |
3064 |
break; |
373 |
|
|
case ReInviting: |
374 |
derek |
3255 |
if (msg.header(h_CSeq).method() == INVITE) |
375 |
derek |
3064 |
{ |
376 |
derek |
3255 |
if (msg.isResponse()) |
377 |
derek |
3089 |
{ |
378 |
derek |
3255 |
int code = msg.header(h_StatusLine).statusCode(); |
379 |
|
|
if (code < 200) |
380 |
derek |
3167 |
{ |
381 |
derek |
3276 |
return; |
382 |
derek |
3255 |
} |
383 |
|
|
else if (code < 300) |
384 |
|
|
{ |
385 |
|
|
if (msg.header(h_CSeq).sequence() == mLastRequest.header(h_CSeq).sequence()) |
386 |
|
|
{ |
387 |
|
|
mState = Connected; |
388 |
derek |
3276 |
//user has called end, so no more callbacks relating to |
389 |
|
|
//this usage other than onTerminated |
390 |
|
|
if (mQueuedBye) |
391 |
|
|
{ |
392 |
sgodin |
3363 |
send(makeAck()); // ACK the 200 first then send BYE |
393 |
|
|
mState = Terminated; |
394 |
derek |
3276 |
mLastRequest = *mQueuedBye; |
395 |
|
|
delete mQueuedBye; |
396 |
|
|
mQueuedBye = 0; |
397 |
|
|
send(mLastRequest); |
398 |
|
|
return; |
399 |
|
|
} |
400 |
derek |
3255 |
if (offans.first != None) |
401 |
|
|
{ |
402 |
derek |
3291 |
if (offans.first == Answer) |
403 |
|
|
{ |
404 |
|
|
//no late media required, so just send the ACK |
405 |
|
|
send(makeAck()); |
406 |
|
|
} |
407 |
derek |
3295 |
incomingSdp(msg, offans.second); |
408 |
derek |
3255 |
} |
409 |
|
|
else |
410 |
|
|
{ |
411 |
derek |
3295 |
//no offer or answer in 200, this will eventually be |
412 |
|
|
//legal with PRACK/UPDATE |
413 |
|
|
send(makeAck()); |
414 |
derek |
3255 |
if (mOfferState != Answered) |
415 |
|
|
{ |
416 |
|
|
//reset the sdp state machine |
417 |
|
|
incomingSdp(msg, 0); |
418 |
|
|
mDum.mInviteSessionHandler->onIllegalNegotiation(getSessionHandle(), msg); |
419 |
|
|
} |
420 |
|
|
} |
421 |
|
|
} |
422 |
|
|
else //200 retransmission that overlaps with this Invite transaction |
423 |
|
|
{ |
424 |
|
|
CSeqToMessageMap::iterator it = mAckMap.find(msg.header(h_CSeq).sequence()); |
425 |
|
|
if (it != mAckMap.end()) |
426 |
|
|
{ |
427 |
derek |
3282 |
mDum.send(it->second); |
428 |
derek |
3255 |
} |
429 |
|
|
} |
430 |
derek |
3167 |
} |
431 |
derek |
3241 |
else |
432 |
|
|
{ |
433 |
derek |
3276 |
mState = Connected; |
434 |
|
|
//user has called end, so no more callbacks relating to |
435 |
|
|
//this usage other than onTerminated |
436 |
|
|
if (mQueuedBye) |
437 |
|
|
{ |
438 |
sgodin |
3363 |
send(makeAck()); // ACK the 200 first then send BYE |
439 |
|
|
mState = Terminated; |
440 |
derek |
3276 |
mLastRequest = *mQueuedBye; |
441 |
|
|
delete mQueuedBye; |
442 |
|
|
mQueuedBye = 0; |
443 |
|
|
send(mLastRequest); |
444 |
|
|
return; |
445 |
|
|
} |
446 |
derek |
3291 |
//reset the sdp state machine |
447 |
|
|
incomingSdp(msg, 0); |
448 |
derek |
3255 |
mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), msg); |
449 |
derek |
3241 |
} |
450 |
derek |
3089 |
} |
451 |
derek |
3167 |
else |
452 |
|
|
{ |
453 |
derek |
3255 |
SipMessage failure; |
454 |
|
|
mDialog.makeResponse(failure, msg, 491); |
455 |
|
|
InfoLog (<< "Sending 491 - overlapping Invite transactions"); |
456 |
|
|
mDum.sendResponse(failure); |
457 |
|
|
return; |
458 |
derek |
3167 |
} |
459 |
derek |
3064 |
} |
460 |
sgodin |
3363 |
else if(msg.header(h_CSeq).method() == BYE && msg.isRequest()) |
461 |
|
|
{ |
462 |
|
|
// Inbound BYE crosses with outbound REINVITE |
463 |
|
|
mState = Terminated; |
464 |
|
|
|
465 |
|
|
mDum.mInviteSessionHandler->onTerminated(getSessionHandle(),msg); |
466 |
|
|
mDialog.makeResponse(mLastResponse, msg, 200); |
467 |
|
|
send(mLastResponse); |
468 |
|
|
} |
469 |
derek |
3064 |
else |
470 |
|
|
{ |
471 |
|
|
ErrLog ( << "Spurious message sent to UAS " << msg ); |
472 |
|
|
return; |
473 |
|
|
} |
474 |
|
|
break; |
475 |
derek |
2961 |
default: |
476 |
derek |
3024 |
DebugLog ( << "Throwing away strange message: " << msg ); |
477 |
|
|
//throw message away |
478 |
|
|
// assert(0); //all other cases should be handled in base classes |
479 |
|
|
|
480 |
jason |
2856 |
} |
481 |
|
|
} |
482 |
|
|
|
483 |
derek |
2955 |
SipMessage& |
484 |
derek |
3255 |
InviteSession::makeInfo(auto_ptr<Contents> contents) |
485 |
|
|
{ |
486 |
|
|
if (mNitState == NitProceeding) |
487 |
|
|
{ |
488 |
|
|
throw new UsageUseException("Cannot start a non-invite transaction until the previous one has completed", |
489 |
|
|
__FILE__, __LINE__); |
490 |
|
|
} |
491 |
|
|
mNitState = NitProceeding; |
492 |
|
|
mDialog.makeRequest(mLastNit, INFO); |
493 |
derek |
3293 |
mLastNit.releaseContents(); |
494 |
derek |
3261 |
mLastNit.setContents(contents); |
495 |
derek |
3255 |
return mLastNit; |
496 |
|
|
} |
497 |
|
|
|
498 |
|
|
SipMessage& |
499 |
derek |
3039 |
InviteSession::makeRefer(const NameAddr& referTo) |
500 |
derek |
2955 |
{ |
501 |
derek |
3058 |
mDialog.makeRequest(mLastRequest, REFER); |
502 |
|
|
mLastRequest.header(h_ReferTo) = referTo; |
503 |
derek |
3289 |
// mLastRequest.header(h_ReferTo).param(p_method) = getMethodName(INVITE); |
504 |
derek |
3058 |
return mLastRequest; |
505 |
derek |
2955 |
} |
506 |
jason |
2856 |
|
507 |
derek |
3112 |
SipMessage& |
508 |
|
|
InviteSession::makeRefer(const NameAddr& referTo, InviteSessionHandle sessionToReplace) |
509 |
|
|
{ |
510 |
|
|
if (!sessionToReplace.isValid()) |
511 |
|
|
{ |
512 |
|
|
throw new UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__); |
513 |
|
|
} |
514 |
|
|
|
515 |
|
|
mDialog.makeRequest(mLastRequest, REFER); |
516 |
|
|
mLastRequest.header(h_ReferTo) = referTo; |
517 |
|
|
CallId replaces; |
518 |
|
|
DialogId id = sessionToReplace->mDialog.getId(); |
519 |
|
|
replaces.value() = id.getCallId(); |
520 |
|
|
replaces.param(p_toTag) = id.getRemoteTag(); |
521 |
|
|
replaces.param(p_fromTag) = id.getLocalTag(); |
522 |
|
|
|
523 |
|
|
mLastRequest.header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces; |
524 |
|
|
return mLastRequest; |
525 |
|
|
} |
526 |
|
|
|
527 |
jason |
2809 |
SipMessage& |
528 |
jason |
2621 |
InviteSession::end() |
529 |
|
|
{ |
530 |
derek |
3006 |
InfoLog ( << "InviteSession::end, state: " << mState); |
531 |
derek |
2961 |
switch (mState) |
532 |
|
|
{ |
533 |
|
|
case Terminated: |
534 |
derek |
2965 |
throw UsageUseException("Cannot end a session that has already been cancelled.", __FILE__, __LINE__); |
535 |
derek |
2961 |
break; |
536 |
|
|
case Connected: |
537 |
sgodin |
3363 |
// Check state of 200 retrans map to see if we have recieved an ACK or not yet |
538 |
|
|
if (mFinalResponseMap.find(mLastIncomingRequest.header(h_CSeq).sequence()) != mFinalResponseMap.end()) |
539 |
|
|
{ |
540 |
|
|
if(!mQueuedBye) |
541 |
|
|
{ |
542 |
|
|
// No ACK yet - send BYE after ACK is received |
543 |
|
|
mQueuedBye = new SipMessage(mLastRequest); |
544 |
|
|
mDialog.makeRequest(*mQueuedBye, BYE); |
545 |
|
|
return *mQueuedBye; |
546 |
|
|
} |
547 |
|
|
else |
548 |
|
|
{ |
549 |
|
|
throw UsageUseException("Cannot end a session that has already been cancelled.", __FILE__, __LINE__); |
550 |
|
|
} |
551 |
|
|
} |
552 |
|
|
else |
553 |
|
|
{ |
554 |
|
|
InfoLog ( << "InviteSession::end, Connected" ); |
555 |
|
|
mDialog.makeRequest(mLastRequest, BYE); |
556 |
|
|
//new transaction |
557 |
|
|
assert(mLastRequest.header(h_Vias).size() == 1); |
558 |
|
|
// mLastRequest.header(h_Vias).front().param(p_branch).reset(); |
559 |
|
|
mState = Terminated; |
560 |
|
|
return mLastRequest; |
561 |
|
|
} |
562 |
derek |
2961 |
break; |
563 |
derek |
3276 |
case ReInviting: |
564 |
sgodin |
3363 |
if(!mQueuedBye) |
565 |
|
|
{ |
566 |
|
|
mQueuedBye = new SipMessage(mLastRequest); |
567 |
|
|
mDialog.makeRequest(*mQueuedBye, BYE); |
568 |
|
|
return *mQueuedBye; |
569 |
|
|
} |
570 |
|
|
else |
571 |
|
|
{ |
572 |
|
|
throw UsageUseException("Cannot end a session that has already been cancelled.", __FILE__, __LINE__); |
573 |
|
|
} |
574 |
derek |
3276 |
break; |
575 |
derek |
2961 |
default: |
576 |
|
|
assert(0); // out of states |
577 |
|
|
} |
578 |
derek |
2981 |
throw UsageUseException("Programmer error", __FILE__, __LINE__); //make VC++ happy |
579 |
jason |
2621 |
} |
580 |
|
|
|
581 |
jason |
2809 |
// If sdp==0, it means the last offer failed |
582 |
derek |
2965 |
// !dcm! -- eventually handle confused UA's that send offers/answers at |
583 |
|
|
// inappropriate times, probably with a different callback |
584 |
jason |
2846 |
void |
585 |
|
|
InviteSession::incomingSdp(const SipMessage& msg, const SdpContents* sdp) |
586 |
jason |
2809 |
{ |
587 |
|
|
switch (mOfferState) |
588 |
|
|
{ |
589 |
jason |
2846 |
case Nothing: |
590 |
jason |
2809 |
assert(mCurrentLocalSdp == 0); |
591 |
|
|
assert(mCurrentRemoteSdp == 0); |
592 |
sgodin |
3091 |
assert(mProposedLocalSdp == 0); |
593 |
|
|
assert(mProposedRemoteSdp == 0); |
594 |
jason |
2846 |
mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone()); |
595 |
jason |
2809 |
mOfferState = Offerred; |
596 |
jason |
2846 |
mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp); |
597 |
jason |
2809 |
break; |
598 |
|
|
|
599 |
|
|
case Offerred: |
600 |
sgodin |
3091 |
assert(mCurrentLocalSdp == 0); |
601 |
|
|
assert(mCurrentRemoteSdp == 0); |
602 |
jason |
2809 |
mCurrentLocalSdp = mProposedLocalSdp; |
603 |
jason |
2846 |
mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone()); |
604 |
sgodin |
3091 |
delete mProposedRemoteSdp; |
605 |
jason |
2809 |
mProposedLocalSdp = 0; |
606 |
|
|
mProposedRemoteSdp = 0; |
607 |
|
|
mOfferState = Answered; |
608 |
jason |
2846 |
mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp); |
609 |
jason |
2809 |
break; |
610 |
|
|
|
611 |
|
|
case Answered: |
612 |
|
|
assert(mProposedLocalSdp == 0); |
613 |
|
|
assert(mProposedRemoteSdp == 0); |
614 |
jason |
2846 |
mProposedRemoteSdp = static_cast<SdpContents*>(sdp->clone()); |
615 |
jason |
2809 |
mOfferState = CounterOfferred; |
616 |
jason |
2846 |
mDum.mInviteSessionHandler->onOffer(getSessionHandle(), msg, sdp); |
617 |
jason |
2809 |
break; |
618 |
derek |
2965 |
|
619 |
jason |
2809 |
case CounterOfferred: |
620 |
|
|
assert(mCurrentLocalSdp); |
621 |
|
|
assert(mCurrentRemoteSdp); |
622 |
jason |
2846 |
mOfferState = Answered; |
623 |
sgodin |
3071 |
if (sdp) // !slg! There currenlty doesn't seem to be anyone calling this with sdp == 0 |
624 |
jason |
2809 |
{ |
625 |
derek |
2965 |
delete mCurrentLocalSdp; |
626 |
|
|
delete mCurrentRemoteSdp; |
627 |
jason |
2809 |
mCurrentLocalSdp = mProposedLocalSdp; |
628 |
jason |
2846 |
mCurrentRemoteSdp = static_cast<SdpContents*>(sdp->clone()); |
629 |
sgodin |
3091 |
delete mProposedRemoteSdp; |
630 |
derek |
2965 |
mProposedLocalSdp = 0; |
631 |
|
|
mProposedRemoteSdp = 0; |
632 |
|
|
mOfferState = Answered; |
633 |
jason |
2846 |
mDum.mInviteSessionHandler->onAnswer(getSessionHandle(), msg, sdp); |
634 |
jason |
2809 |
} |
635 |
|
|
else |
636 |
|
|
{ |
637 |
sgodin |
3091 |
delete mProposedLocalSdp; |
638 |
|
|
delete mProposedRemoteSdp; |
639 |
jason |
2809 |
mProposedLocalSdp = 0; |
640 |
|
|
mProposedRemoteSdp = 0; |
641 |
jason |
2846 |
// !jf! is this right? |
642 |
derek |
3291 |
// mDum.mInviteSessionHandler->onOfferRejected(getSessionHandle(), msg); |
643 |
jason |
2809 |
} |
644 |
|
|
break; |
645 |
|
|
} |
646 |
|
|
} |
647 |
|
|
|
648 |
derek |
2965 |
void |
649 |
|
|
InviteSession::send(SipMessage& msg) |
650 |
|
|
{ |
651 |
derek |
3138 |
Destroyer::Guard guard(mDestroyer); |
652 |
derek |
3293 |
//handle NITs separately |
653 |
|
|
if (msg.header(h_CSeq).method() == INFO) |
654 |
|
|
{ |
655 |
|
|
mDum.send(msg); |
656 |
|
|
return; |
657 |
|
|
} |
658 |
|
|
|
659 |
derek |
3282 |
msg.releaseContents(); |
660 |
derek |
3276 |
if (mQueuedBye && (mQueuedBye == &msg)) |
661 |
|
|
{ |
662 |
|
|
//queued |
663 |
|
|
return; |
664 |
|
|
} |
665 |
|
|
|
666 |
derek |
2965 |
if (msg.isRequest()) |
667 |
|
|
{ |
668 |
derek |
3089 |
switch(msg.header(h_RequestLine).getMethod()) |
669 |
|
|
{ |
670 |
|
|
case INVITE: |
671 |
|
|
case UPDATE: |
672 |
derek |
3291 |
case ACK: |
673 |
derek |
3089 |
if (mNextOfferOrAnswerSdp) |
674 |
|
|
{ |
675 |
sgodin |
3091 |
msg.setContents(mNextOfferOrAnswerSdp); |
676 |
derek |
3089 |
sendSdp(mNextOfferOrAnswerSdp); |
677 |
|
|
mNextOfferOrAnswerSdp = 0; |
678 |
|
|
} |
679 |
|
|
break; |
680 |
|
|
default: |
681 |
|
|
break; |
682 |
|
|
} |
683 |
derek |
3282 |
mDum.send(msg); |
684 |
derek |
2965 |
} |
685 |
|
|
else |
686 |
|
|
{ |
687 |
|
|
int code = msg.header(h_StatusLine).statusCode(); |
688 |
|
|
//!dcm! -- probably kill this object earlier, handle 200 to bye in |
689 |
|
|
//DialogUsageManager...very soon |
690 |
|
|
if (msg.header(h_CSeq).method() == BYE && code == 200) //!dcm! -- not 2xx? |
691 |
|
|
|
692 |
|
|
{ |
693 |
|
|
mState = Terminated; |
694 |
|
|
mDum.send(msg); |
695 |
sgodin |
3140 |
//mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), msg); // This is actually called when recieving the BYE message so that the BYE message can be passed to onTerminated |
696 |
derek |
3138 |
guard.destroy(); |
697 |
derek |
2965 |
} |
698 |
derek |
2978 |
else if (code >= 200 && code < 300 && msg.header(h_CSeq).method() == INVITE) |
699 |
derek |
2965 |
{ |
700 |
derek |
3255 |
int seq = msg.header(h_CSeq).sequence(); |
701 |
|
|
mCurrentRetransmit200 = Timer::T1; |
702 |
|
|
mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq); |
703 |
|
|
mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq); |
704 |
derek |
2990 |
|
705 |
|
|
//!dcm! -- this should be mFinalResponse...maybe assign here in |
706 |
derek |
2965 |
//case the user wants to be very strange |
707 |
|
|
if (mNextOfferOrAnswerSdp) |
708 |
|
|
{ |
709 |
sgodin |
3091 |
msg.setContents(mNextOfferOrAnswerSdp); |
710 |
derek |
2965 |
sendSdp(mNextOfferOrAnswerSdp); |
711 |
derek |
2997 |
mNextOfferOrAnswerSdp = 0; |
712 |
derek |
2978 |
} |
713 |
|
|
mDum.send(msg); |
714 |
|
|
} |
715 |
|
|
else |
716 |
|
|
{ |
717 |
|
|
mDum.send(msg); |
718 |
|
|
} |
719 |
derek |
2965 |
} |
720 |
|
|
} |
721 |
|
|
|
722 |
jason |
2621 |
void |
723 |
derek |
2965 |
InviteSession::sendSdp(SdpContents* sdp) |
724 |
jason |
2809 |
{ |
725 |
|
|
switch (mOfferState) |
726 |
|
|
{ |
727 |
jason |
2846 |
case Nothing: |
728 |
jason |
2809 |
assert(mCurrentLocalSdp == 0); |
729 |
|
|
assert(mCurrentRemoteSdp == 0); |
730 |
derek |
2965 |
mProposedLocalSdp = sdp; |
731 |
jason |
2809 |
mOfferState = Offerred; |
732 |
|
|
break; |
733 |
|
|
|
734 |
|
|
case Offerred: |
735 |
sgodin |
3091 |
assert(mCurrentLocalSdp == 0); |
736 |
|
|
assert(mCurrentRemoteSdp == 0); |
737 |
derek |
2965 |
mCurrentLocalSdp = sdp; |
738 |
jason |
2809 |
mCurrentRemoteSdp = mProposedRemoteSdp; |
739 |
sgodin |
3091 |
delete mProposedLocalSdp; |
740 |
jason |
2809 |
mProposedLocalSdp = 0; |
741 |
|
|
mProposedRemoteSdp = 0; |
742 |
|
|
mOfferState = Answered; |
743 |
|
|
break; |
744 |
|
|
|
745 |
|
|
case Answered: |
746 |
|
|
assert(mProposedLocalSdp == 0); |
747 |
|
|
assert(mProposedRemoteSdp == 0); |
748 |
derek |
2965 |
mProposedLocalSdp = sdp; |
749 |
jason |
2809 |
mOfferState = CounterOfferred; |
750 |
|
|
break; |
751 |
|
|
|
752 |
|
|
case CounterOfferred: |
753 |
|
|
assert(mCurrentLocalSdp); |
754 |
|
|
assert(mCurrentRemoteSdp); |
755 |
derek |
3298 |
if (sdp) |
756 |
jason |
2809 |
{ |
757 |
derek |
3064 |
delete mCurrentLocalSdp; |
758 |
|
|
delete mCurrentRemoteSdp; |
759 |
sgodin |
3091 |
mCurrentLocalSdp = sdp; |
760 |
jason |
2809 |
mCurrentRemoteSdp = mProposedRemoteSdp; |
761 |
sgodin |
3091 |
delete mProposedLocalSdp; |
762 |
|
|
mProposedLocalSdp = 0; |
763 |
|
|
mProposedRemoteSdp = 0; |
764 |
jason |
2809 |
} |
765 |
sgodin |
3091 |
else |
766 |
|
|
{ |
767 |
|
|
delete mProposedLocalSdp; |
768 |
|
|
delete mProposedRemoteSdp; |
769 |
|
|
mProposedLocalSdp = 0; |
770 |
|
|
mProposedRemoteSdp = 0; |
771 |
|
|
} |
772 |
jason |
2809 |
mOfferState = Answered; |
773 |
|
|
break; |
774 |
|
|
} |
775 |
|
|
} |
776 |
|
|
|
777 |
jason |
2846 |
std::pair<InviteSession::OfferAnswerType, const SdpContents*> |
778 |
|
|
InviteSession::getOfferOrAnswer(const SipMessage& msg) const |
779 |
|
|
{ |
780 |
|
|
std::pair<InviteSession::OfferAnswerType, const SdpContents*> ret; |
781 |
|
|
ret.first = None; |
782 |
sgodin |
3338 |
const SdpContents* contents = NULL; |
783 |
|
|
|
784 |
|
|
MultipartMixedContents* mixed = dynamic_cast<MultipartMixedContents*>(msg.getContents()); |
785 |
|
|
if ( mixed ) |
786 |
|
|
{ |
787 |
|
|
// Look for first SDP Contents in a multipart contents |
788 |
|
|
MultipartMixedContents::Parts& parts = mixed->parts(); |
789 |
|
|
for( MultipartMixedContents::Parts::const_iterator i = parts.begin(); |
790 |
|
|
i != parts.end(); |
791 |
|
|
++i) |
792 |
|
|
{ |
793 |
|
|
contents = dynamic_cast<const SdpContents*>(*i); |
794 |
|
|
if(contents != NULL) break; // Found SDP contents |
795 |
|
|
} |
796 |
|
|
} |
797 |
|
|
else |
798 |
|
|
{ |
799 |
|
|
contents = dynamic_cast<const SdpContents*>(msg.getContents()); |
800 |
|
|
} |
801 |
|
|
|
802 |
jason |
2846 |
if (contents) |
803 |
|
|
{ |
804 |
|
|
static Token c100rel(Symbols::C100rel); |
805 |
derek |
2976 |
if (msg.isRequest() || msg.header(h_StatusLine).responseCode() == 200 || |
806 |
derek |
3308 |
(msg.exists(h_Requires) && msg.header(h_Requires).find(c100rel))) |
807 |
jason |
2846 |
{ |
808 |
|
|
switch (mOfferState) |
809 |
|
|
{ |
810 |
sgodin |
3340 |
case Nothing: |
811 |
jason |
2846 |
ret.first = Offer; |
812 |
|
|
ret.second = contents; |
813 |
|
|
break; |
814 |
|
|
|
815 |
|
|
case Offerred: |
816 |
|
|
ret.first = Answer; |
817 |
|
|
ret.second = contents; |
818 |
|
|
break; |
819 |
|
|
|
820 |
|
|
case Answered: |
821 |
|
|
ret.first = Offer; |
822 |
|
|
ret.second = contents; |
823 |
|
|
break; |
824 |
|
|
|
825 |
|
|
case CounterOfferred: |
826 |
|
|
ret.first = Answer; |
827 |
|
|
ret.second = contents; |
828 |
|
|
break; |
829 |
|
|
} |
830 |
|
|
} |
831 |
derek |
3255 |
else if (msg.isResponse() && |
832 |
|
|
msg.header(h_StatusLine).responseCode() < 200 && |
833 |
|
|
msg.header(h_StatusLine).responseCode() >= 180) |
834 |
|
|
{ |
835 |
|
|
ret.second = contents; |
836 |
|
|
} |
837 |
jason |
2846 |
} |
838 |
|
|
return ret; |
839 |
|
|
} |
840 |
|
|
|
841 |
derek |
2955 |
SipMessage& |
842 |
derek |
3291 |
InviteSession::rejectDialogModification(int statusCode) |
843 |
derek |
2965 |
{ |
844 |
derek |
3101 |
if (statusCode < 400) |
845 |
|
|
{ |
846 |
|
|
throw new UsageUseException("Must reject with a 4xx", __FILE__, __LINE__); |
847 |
|
|
} |
848 |
derek |
3289 |
mDialog.makeResponse(mLastResponse, mLastIncomingRequest, statusCode); |
849 |
derek |
3298 |
mState = Connected; |
850 |
|
|
sendSdp(0); |
851 |
derek |
2976 |
return mLastResponse; |
852 |
derek |
2965 |
} |
853 |
|
|
|
854 |
|
|
SipMessage& |
855 |
derek |
2955 |
InviteSession::targetRefresh(const NameAddr& localUri) |
856 |
|
|
{ |
857 |
|
|
assert(0); |
858 |
derek |
2981 |
return mLastRequest; |
859 |
derek |
2955 |
} |
860 |
davidb |
2576 |
|
861 |
derek |
3255 |
void |
862 |
|
|
InviteSession::send() |
863 |
derek |
2981 |
{ |
864 |
derek |
3295 |
InfoLog ( << "InviteSession::send(void)"); |
865 |
|
|
if (mOfferState == Answered || mState != Connected) |
866 |
derek |
3255 |
{ |
867 |
|
|
throw new UsageUseException("Cannot call send when there it no Offer/Answer negotiation to do", __FILE__, __LINE__); |
868 |
|
|
} |
869 |
|
|
send(makeAck()); |
870 |
derek |
2981 |
} |
871 |
|
|
|
872 |
derek |
3255 |
SipMessage& |
873 |
derek |
2965 |
InviteSession::makeAck() |
874 |
derek |
2849 |
{ |
875 |
derek |
3255 |
InfoLog ( << "InviteSession::makeAck" ); |
876 |
derek |
2992 |
|
877 |
derek |
3255 |
int cseq = mLastRequest.header(h_CSeq).sequence(); |
878 |
derek |
3295 |
if (mAckMap.find(cseq) != mAckMap.end()) |
879 |
|
|
{ |
880 |
|
|
InfoLog ( << "CSeq collision in ack map: " << Inserter(mAckMap) ); |
881 |
|
|
} |
882 |
|
|
|
883 |
derek |
3255 |
assert(mAckMap.find(cseq) == mAckMap.end()); |
884 |
|
|
SipMessage& ack = mAckMap[cseq]; |
885 |
|
|
ack = mLastRequest; |
886 |
|
|
mDialog.makeRequest(ack, ACK); |
887 |
|
|
mDum.addTimerMs(DumTimeout::CanDiscardAck, Timer::TH, getBaseHandle(), cseq); |
888 |
derek |
2992 |
|
889 |
derek |
3255 |
assert(ack.header(h_Vias).size() == 1); |
890 |
|
|
|
891 |
derek |
3291 |
// if (mNextOfferOrAnswerSdp) |
892 |
|
|
// { |
893 |
|
|
// ack.setContents(mNextOfferOrAnswerSdp); |
894 |
|
|
// sendSdp(mNextOfferOrAnswerSdp); |
895 |
|
|
// mNextOfferOrAnswerSdp = 0; |
896 |
|
|
// } |
897 |
derek |
3255 |
return ack; |
898 |
derek |
2849 |
} |
899 |
|
|
|
900 |
davidb |
2575 |
/* ==================================================================== |
901 |
|
|
* The Vovida Software License, Version 1.0 |
902 |
|
|
* |
903 |
|
|
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. |
904 |
|
|
* |
905 |
|
|
* Redistribution and use in source and binary forms, with or without |
906 |
|
|
* modification, are permitted provided that the following conditions |
907 |
|
|
* are met: |
908 |
|
|
* |
909 |
|
|
* 1. Redistributions of source code must retain the above copyright |
910 |
|
|
* notice, this list of conditions and the following disclaimer. |
911 |
|
|
* |
912 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
913 |
|
|
* notice, this list of conditions and the following disclaimer in |
914 |
|
|
* the documentation and/or other materials provided with the |
915 |
|
|
|
916 |
|
|
* distribution. |
917 |
|
|
* |
918 |
|
|
* 3. The names "VOCAL", "Vovida Open Communication Application Library", |
919 |
|
|
* and "Vovida Open Communication Application Library (VOCAL)" must |
920 |
|
|
* not be used to endorse or promote products derived from this |
921 |
|
|
* software without prior written permission. For written |
922 |
|
|
* permission, please contact vocal@vovida.org. |
923 |
|
|
* |
924 |
|
|
* 4. Products derived from this software may not be called "VOCAL", nor |
925 |
|
|
* may "VOCAL" appear in their name, without prior written |
926 |
|
|
* permission of Vovida Networks, Inc. |
927 |
|
|
* |
928 |
|
|
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED |
929 |
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
930 |
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND |
931 |
|
|
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA |
932 |
|
|
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES |
933 |
|
|
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, |
934 |
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
935 |
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
936 |
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
937 |
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
938 |
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
939 |
|
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
940 |
|
|
* DAMAGE. |
941 |
|
|
* |
942 |
|
|
* ==================================================================== |
943 |
|
|
* |
944 |
|
|
* This software consists of voluntary contributions made by Vovida |
945 |
|
|
* Networks, Inc. and many individuals on behalf of Vovida Networks, |
946 |
|
|
* Inc. For more information on Vovida Networks, Inc., please see |
947 |
|
|
* <http://www.vovida.org/>. |
948 |
|
|
* |
949 |
|
|
*/ |