1 |
jason |
4010 |
#include "resiprocate/MultipartMixedContents.hxx" |
2 |
daniel |
5068 |
#include "resiprocate/MultipartAlternativeContents.hxx" |
3 |
derek |
3138 |
#include "resiprocate/SdpContents.hxx" |
4 |
jason |
2725 |
#include "resiprocate/SipMessage.hxx" |
5 |
jason |
4010 |
#include "resiprocate/Helper.hxx" |
6 |
jason |
2725 |
#include "resiprocate/dum/Dialog.hxx" |
7 |
|
|
#include "resiprocate/dum/DialogUsageManager.hxx" |
8 |
|
|
#include "resiprocate/dum/InviteSession.hxx" |
9 |
jason |
4010 |
#include "resiprocate/dum/ServerInviteSession.hxx" |
10 |
|
|
#include "resiprocate/dum/ClientSubscription.hxx" |
11 |
|
|
#include "resiprocate/dum/ServerSubscription.hxx" |
12 |
sgodin |
3392 |
#include "resiprocate/dum/ClientInviteSession.hxx" |
13 |
jason |
2846 |
#include "resiprocate/dum/InviteSessionHandler.hxx" |
14 |
jason |
4010 |
#include "resiprocate/dum/MasterProfile.hxx" |
15 |
derek |
2961 |
#include "resiprocate/dum/UsageUseException.hxx" |
16 |
jason |
4010 |
#include "resiprocate/os/Inserter.hxx" |
17 |
jason |
2856 |
#include "resiprocate/os/Logger.hxx" |
18 |
derek |
3255 |
#include "resiprocate/os/Timer.hxx" |
19 |
jason |
4010 |
#include "resiprocate/os/Random.hxx" |
20 |
|
|
#include "resiprocate/os/compat.hxx" |
21 |
|
|
#include "resiprocate/os/WinLeakCheck.hxx" |
22 |
jason |
2555 |
|
23 |
sgodin |
3314 |
// Remove warning about 'this' use in initiator list - pointer is only stored |
24 |
|
|
#if defined(WIN32) |
25 |
jason |
4010 |
#pragma warning( disable : 4355 ) // using this in base member initializer list |
26 |
|
|
#pragma warning( disable : 4800 ) // forcing value to bool (performance warning) |
27 |
sgodin |
3314 |
#endif |
28 |
derek |
3092 |
|
29 |
jason |
2856 |
#define RESIPROCATE_SUBSYSTEM Subsystem::DUM |
30 |
jason |
4010 |
#define THROW(msg) throw DialogUsage::Exception(msg, __FILE__,__LINE__); |
31 |
jason |
2846 |
|
32 |
davidb |
2603 |
using namespace resip; |
33 |
derek |
3255 |
using namespace std; |
34 |
davidb |
2603 |
|
35 |
jason |
4010 |
InviteSession::InviteSession(DialogUsageManager& dum, Dialog& dialog) |
36 |
derek |
3089 |
: DialogUsage(dum, dialog), |
37 |
jason |
4010 |
mState(Undefined), |
38 |
derek |
3255 |
mNitState(NitComplete), |
39 |
jason |
4010 |
mCurrentRetransmit200(0), |
40 |
sgodin |
3392 |
mSessionInterval(0), |
41 |
sgodin |
4691 |
mMinSE(90), |
42 |
|
|
mSessionRefresher(false), |
43 |
sgodin |
3392 |
mSessionTimerSeq(0), |
44 |
daniel |
5068 |
mSentRefer(false), |
45 |
|
|
mCurrentEncryptionLevel(DialogUsageManager::None), |
46 |
|
|
mProposedEncryptionLevel(DialogUsageManager::None) |
47 |
jason |
2555 |
{ |
48 |
jason |
4010 |
DebugLog ( << "^^^ InviteSession::InviteSession " << this); |
49 |
jason |
2846 |
assert(mDum.mInviteSessionHandler); |
50 |
jason |
2555 |
} |
51 |
|
|
|
52 |
derek |
2858 |
InviteSession::~InviteSession() |
53 |
|
|
{ |
54 |
jason |
4010 |
DebugLog ( << "^^^ InviteSession::~InviteSession " << this); |
55 |
derek |
2858 |
mDialog.mInviteSession = 0; |
56 |
|
|
} |
57 |
jason |
2846 |
|
58 |
jason |
4010 |
void |
59 |
|
|
InviteSession::dialogDestroyed(const SipMessage& msg) |
60 |
derek |
3064 |
{ |
61 |
jason |
4010 |
assert(0); |
62 |
|
|
|
63 |
|
|
// !jf! Is this correct? Merged from main... |
64 |
|
|
// !jf! what reason - guessed for now? |
65 |
|
|
//mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, msg); |
66 |
|
|
//delete this; |
67 |
|
|
} |
68 |
|
|
|
69 |
|
|
const SdpContents& |
70 |
|
|
InviteSession::getLocalSdp() const |
71 |
|
|
{ |
72 |
|
|
return *mCurrentLocalSdp; |
73 |
|
|
} |
74 |
|
|
|
75 |
|
|
const SdpContents& |
76 |
|
|
InviteSession::getRemoteSdp() const |
77 |
|
|
{ |
78 |
|
|
return *mCurrentRemoteSdp; |
79 |
|
|
} |
80 |
|
|
|
81 |
cktam |
4408 |
const Data& |
82 |
|
|
InviteSession::getDialogId() const |
83 |
|
|
{ |
84 |
|
|
return mDialog.getId().getCallId(); |
85 |
|
|
} |
86 |
|
|
|
87 |
jason |
4010 |
InviteSessionHandle |
88 |
|
|
InviteSession::getSessionHandle() |
89 |
|
|
{ |
90 |
|
|
return InviteSessionHandle(mDum, getBaseHandle().getId()); |
91 |
|
|
} |
92 |
|
|
|
93 |
|
|
void InviteSession::storePeerCapabilities(const SipMessage& msg) |
94 |
|
|
{ |
95 |
|
|
// !slg! ToDo - add methods to get this data, App may be interested |
96 |
|
|
if (msg.exists(h_Allows)) |
97 |
derek |
3064 |
{ |
98 |
jason |
4010 |
mPeerSupportedMethods = msg.header(h_Allows); |
99 |
derek |
3064 |
} |
100 |
jason |
4010 |
if (msg.exists(h_Supporteds)) |
101 |
|
|
{ |
102 |
|
|
mPeerSupportedOptionTags = msg.header(h_Supporteds); |
103 |
|
|
} |
104 |
|
|
if (msg.exists(h_AcceptEncodings)) |
105 |
|
|
{ |
106 |
|
|
mPeerSupportedEncodings = msg.header(h_AcceptEncodings); |
107 |
|
|
} |
108 |
|
|
if (msg.exists(h_AcceptLanguages)) |
109 |
|
|
{ |
110 |
|
|
mPeerSupportedLanguages = msg.header(h_AcceptLanguages); |
111 |
|
|
} |
112 |
|
|
if (msg.exists(h_Accepts)) |
113 |
|
|
{ |
114 |
|
|
mPeerSupportedMimeTypes = msg.header(h_Accepts); |
115 |
|
|
} |
116 |
derek |
3064 |
} |
117 |
|
|
|
118 |
jason |
4010 |
bool |
119 |
|
|
InviteSession::updateMethodSupported() const |
120 |
derek |
3255 |
{ |
121 |
jason |
4010 |
// Check if Update is supported locally |
122 |
|
|
if(mDum.getMasterProfile()->isMethodSupported(UPDATE)) |
123 |
|
|
{ |
124 |
|
|
// Check if peer supports UPDATE |
125 |
|
|
return mPeerSupportedMethods.find(Token("UPDATE")); |
126 |
|
|
} |
127 |
|
|
return false; |
128 |
|
|
} |
129 |
sgodin |
3392 |
|
130 |
jason |
4010 |
const NameAddr& |
131 |
|
|
InviteSession::myAddr() const |
132 |
|
|
{ |
133 |
|
|
return mDialog.mLocalNameAddr; |
134 |
|
|
} |
135 |
sgodin |
3392 |
|
136 |
jason |
4010 |
const NameAddr& |
137 |
|
|
InviteSession::peerAddr() const |
138 |
|
|
{ |
139 |
|
|
return mDialog.mRemoteNameAddr; |
140 |
|
|
} |
141 |
sgodin |
3392 |
|
142 |
jason |
4010 |
bool |
143 |
|
|
InviteSession::isConnected() const |
144 |
|
|
{ |
145 |
|
|
switch (mState) |
146 |
|
|
{ |
147 |
|
|
case Connected: |
148 |
|
|
case SentUpdate: |
149 |
|
|
case SentUpdateGlare: |
150 |
|
|
case SentReinvite: |
151 |
|
|
case SentReinviteGlare: |
152 |
|
|
case ReceivedUpdate: |
153 |
|
|
case ReceivedReinvite: |
154 |
|
|
case ReceivedReinviteNoOffer: |
155 |
|
|
case Answered: |
156 |
|
|
case WaitingToOffer: |
157 |
|
|
return true; |
158 |
|
|
|
159 |
|
|
default: |
160 |
|
|
return false; |
161 |
|
|
} |
162 |
derek |
3255 |
} |
163 |
derek |
3064 |
|
164 |
jason |
4010 |
bool |
165 |
|
|
InviteSession::isEarly() const |
166 |
derek |
3064 |
{ |
167 |
jason |
4010 |
switch (mState) |
168 |
derek |
3064 |
{ |
169 |
jason |
4010 |
case UAC_Start: |
170 |
|
|
case UAC_Early: |
171 |
|
|
case UAC_EarlyWithOffer: |
172 |
|
|
case UAC_EarlyWithAnswer: |
173 |
|
|
//case UAC_Answered: |
174 |
|
|
//case UAC_Terminated: |
175 |
|
|
case UAC_SentUpdateEarly: |
176 |
|
|
case UAC_SentUpdateConnected: |
177 |
|
|
case UAC_ReceivedUpdateEarly: |
178 |
|
|
//case UAC_SentAnswer: |
179 |
|
|
case UAC_QueuedUpdate: |
180 |
|
|
return true; |
181 |
|
|
|
182 |
|
|
default: |
183 |
|
|
return false; |
184 |
derek |
3064 |
} |
185 |
jason |
4010 |
} |
186 |
derek |
3064 |
|
187 |
jason |
4010 |
|
188 |
|
|
bool |
189 |
|
|
InviteSession::isTerminated() const |
190 |
|
|
{ |
191 |
|
|
switch (mState) |
192 |
|
|
{ |
193 |
|
|
case Terminated: |
194 |
|
|
case WaitingToTerminate: |
195 |
|
|
case UAC_Cancelled: |
196 |
|
|
case UAS_WaitingToTerminate: |
197 |
|
|
case UAS_WaitingToHangup: |
198 |
|
|
return true; |
199 |
|
|
default: |
200 |
|
|
return false; |
201 |
|
|
} |
202 |
|
|
} |
203 |
|
|
|
204 |
|
|
std::ostream& |
205 |
|
|
InviteSession::dump(std::ostream& strm) const |
206 |
|
|
{ |
207 |
|
|
strm << "INVITE: " << mId |
208 |
|
|
<< " " << toData(mState) |
209 |
|
|
<< " ADDR=" << myAddr() |
210 |
|
|
<< " PEER=" << peerAddr(); |
211 |
|
|
return strm; |
212 |
|
|
} |
213 |
|
|
|
214 |
jason |
2866 |
void |
215 |
daniel |
5068 |
InviteSession::provideOffer(const SdpContents& offer, |
216 |
|
|
DialogUsageManager::EncryptionLevel level, |
217 |
|
|
const SdpContents* alternative) |
218 |
jason |
2866 |
{ |
219 |
jason |
4010 |
switch (mState) |
220 |
derek |
2965 |
{ |
221 |
jason |
4010 |
case Connected: |
222 |
|
|
case WaitingToOffer: |
223 |
|
|
case UAS_WaitingToOffer: |
224 |
|
|
if (updateMethodSupported()) |
225 |
|
|
{ |
226 |
|
|
transition(SentUpdate); |
227 |
|
|
mDialog.makeRequest(mLastSessionModification, UPDATE); |
228 |
|
|
} |
229 |
|
|
else |
230 |
|
|
{ |
231 |
|
|
transition(SentReinvite); |
232 |
|
|
mDialog.makeRequest(mLastSessionModification, INVITE); |
233 |
|
|
} |
234 |
sgodin |
4369 |
setSessionTimerHeaders(mLastSessionModification); |
235 |
jason |
4010 |
|
236 |
|
|
InfoLog (<< "Sending " << mLastSessionModification.brief()); |
237 |
daniel |
5068 |
InviteSession::setSdp(mLastSessionModification, offer, alternative); |
238 |
|
|
mProposedLocalSdp = InviteSession::makeSdp(offer, alternative); |
239 |
|
|
mProposedEncryptionLevel = level; |
240 |
|
|
mDialog.send(mLastSessionModification, mProposedEncryptionLevel); |
241 |
jason |
4010 |
break; |
242 |
|
|
|
243 |
|
|
case Answered: |
244 |
|
|
// queue the offer to be sent after the ACK is received |
245 |
|
|
transition(WaitingToOffer); |
246 |
daniel |
5068 |
mProposedEncryptionLevel = level; |
247 |
|
|
mProposedLocalSdp = InviteSession::makeSdp(offer, alternative); |
248 |
jason |
4010 |
break; |
249 |
|
|
|
250 |
sgodin |
5001 |
// ?slg? Can we handle all of the states listed in isConnected() ??? |
251 |
jason |
4010 |
default: |
252 |
|
|
WarningLog (<< "Can't provideOffer when not in Connected state"); |
253 |
|
|
throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__); |
254 |
derek |
2965 |
} |
255 |
jason |
2866 |
} |
256 |
|
|
|
257 |
|
|
void |
258 |
daniel |
5068 |
InviteSession::provideOffer(const SdpContents& offer) |
259 |
|
|
{ |
260 |
|
|
return provideOffer(offer, mCurrentEncryptionLevel, 0); |
261 |
|
|
} |
262 |
|
|
|
263 |
|
|
void |
264 |
jason |
4010 |
InviteSession::provideAnswer(const SdpContents& answer) |
265 |
jason |
2866 |
{ |
266 |
jason |
4010 |
switch (mState) |
267 |
derek |
2965 |
{ |
268 |
jason |
4010 |
case ReceivedReinvite: |
269 |
|
|
transition(Connected); |
270 |
|
|
mDialog.makeResponse(mInvite200, mLastSessionModification, 200); |
271 |
|
|
handleSessionTimerRequest(mInvite200, mLastSessionModification); |
272 |
daniel |
5068 |
InviteSession::setSdp(mInvite200, answer, 0); |
273 |
jason |
4010 |
mCurrentLocalSdp = InviteSession::makeSdp(answer); |
274 |
|
|
mCurrentRemoteSdp = mProposedRemoteSdp; |
275 |
|
|
InfoLog (<< "Sending " << mInvite200.brief()); |
276 |
daniel |
5068 |
mDialog.send(mInvite200, mCurrentEncryptionLevel); |
277 |
jason |
4010 |
startRetransmit200Timer(); |
278 |
|
|
break; |
279 |
|
|
|
280 |
|
|
case ReceivedUpdate: // same as ReceivedReinvite case. |
281 |
|
|
{ |
282 |
|
|
transition(Connected); |
283 |
|
|
|
284 |
|
|
SipMessage response; |
285 |
|
|
mDialog.makeResponse(response, mLastSessionModification, 200); |
286 |
|
|
handleSessionTimerRequest(response, mLastSessionModification); |
287 |
daniel |
5068 |
InviteSession::setSdp(response, answer, 0); |
288 |
jason |
4010 |
mCurrentLocalSdp = InviteSession::makeSdp(answer); |
289 |
|
|
mCurrentRemoteSdp = mProposedRemoteSdp; |
290 |
|
|
InfoLog (<< "Sending " << response.brief()); |
291 |
daniel |
5068 |
mDialog.send(response, mCurrentEncryptionLevel); |
292 |
jason |
4010 |
break; |
293 |
|
|
} |
294 |
|
|
|
295 |
|
|
default: |
296 |
sgodin |
4394 |
WarningLog (<< "Can't provideAnswer when not in Connected state"); |
297 |
jason |
4010 |
throw DialogUsage::Exception("Can't provide an offer", __FILE__,__LINE__); |
298 |
derek |
2965 |
} |
299 |
jason |
2866 |
} |
300 |
|
|
|
301 |
jason |
4010 |
void |
302 |
|
|
InviteSession::end() |
303 |
jason |
2555 |
{ |
304 |
jason |
4010 |
InviteSessionHandler* handler = mDum.mInviteSessionHandler; |
305 |
|
|
|
306 |
|
|
switch (mState) |
307 |
|
|
{ |
308 |
|
|
case Connected: |
309 |
|
|
{ |
310 |
|
|
// !jf! do we need to store the BYE somewhere? |
311 |
|
|
sendBye(); |
312 |
|
|
transition(Terminated); |
313 |
|
|
handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended); |
314 |
|
|
break; |
315 |
|
|
} |
316 |
|
|
|
317 |
|
|
case SentUpdate: |
318 |
|
|
sendBye(); |
319 |
|
|
transition(Terminated); |
320 |
|
|
handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended); |
321 |
|
|
break; |
322 |
|
|
|
323 |
|
|
case SentReinvite: |
324 |
|
|
transition(WaitingToTerminate); |
325 |
|
|
break; |
326 |
|
|
|
327 |
|
|
case ReceivedUpdate: |
328 |
|
|
case ReceivedReinvite: |
329 |
|
|
case ReceivedReinviteNoOffer: |
330 |
|
|
{ |
331 |
|
|
SipMessage response; |
332 |
|
|
mDialog.makeResponse(response, mLastSessionModification, 488); |
333 |
|
|
InfoLog (<< "Sending " << response.brief()); |
334 |
|
|
mDialog.send(response); |
335 |
|
|
|
336 |
|
|
sendBye(); |
337 |
|
|
transition(Terminated); |
338 |
|
|
handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended); |
339 |
|
|
break; |
340 |
|
|
} |
341 |
|
|
|
342 |
|
|
case WaitingToTerminate: |
343 |
|
|
{ |
344 |
|
|
sendBye(); |
345 |
|
|
transition(Terminated); |
346 |
|
|
handler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended); |
347 |
|
|
break; |
348 |
|
|
} |
349 |
|
|
|
350 |
|
|
case Terminated: |
351 |
|
|
// no-op. |
352 |
|
|
break; |
353 |
|
|
|
354 |
|
|
default: |
355 |
|
|
assert(0); |
356 |
|
|
break; |
357 |
|
|
} |
358 |
jason |
2555 |
} |
359 |
|
|
|
360 |
jason |
4010 |
void |
361 |
|
|
InviteSession::reject(int statusCode, WarningCategory *warning) |
362 |
jason |
2555 |
{ |
363 |
jason |
4010 |
switch (mState) |
364 |
|
|
{ |
365 |
|
|
case ReceivedUpdate: |
366 |
|
|
case ReceivedReinvite: |
367 |
|
|
case ReceivedReinviteNoOffer: |
368 |
|
|
{ |
369 |
|
|
transition(Connected); |
370 |
|
|
|
371 |
|
|
SipMessage response; |
372 |
|
|
mDialog.makeResponse(response, mLastSessionModification, statusCode); |
373 |
|
|
if(warning) |
374 |
|
|
{ |
375 |
|
|
response.header(h_Warnings).push_back(*warning); |
376 |
|
|
} |
377 |
|
|
InfoLog (<< "Sending " << response.brief()); |
378 |
|
|
mDialog.send(response); |
379 |
|
|
break; |
380 |
|
|
} |
381 |
|
|
|
382 |
|
|
default: |
383 |
|
|
assert(0); |
384 |
|
|
break; |
385 |
|
|
} |
386 |
jason |
2555 |
} |
387 |
davidb |
2575 |
|
388 |
jason |
4010 |
void |
389 |
|
|
InviteSession::targetRefresh(const NameAddr& localUri) |
390 |
jason |
2941 |
{ |
391 |
sgodin |
5001 |
if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite? |
392 |
jason |
4010 |
{ |
393 |
|
|
// !jf! add interface to Dialog |
394 |
|
|
//mDialog.setLocalContact(localUri); |
395 |
|
|
provideOffer(*mCurrentLocalSdp); |
396 |
|
|
} |
397 |
|
|
else |
398 |
|
|
{ |
399 |
|
|
WarningLog (<< "Can't targetRefresh before Connected"); |
400 |
|
|
assert(0); |
401 |
|
|
throw UsageUseException("targetRefresh not allowed in this context", __FILE__, __LINE__); |
402 |
|
|
} |
403 |
jason |
2941 |
} |
404 |
|
|
|
405 |
jason |
2856 |
void |
406 |
jason |
4010 |
InviteSession::refer(const NameAddr& referTo) |
407 |
|
|
{ |
408 |
|
|
if (mSentRefer) |
409 |
|
|
{ |
410 |
|
|
throw UsageUseException("Attempted to send overlapping refer", __FILE__, __LINE__); |
411 |
|
|
} |
412 |
|
|
|
413 |
sgodin |
5001 |
if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite? |
414 |
jason |
4010 |
{ |
415 |
|
|
mSentRefer = true; |
416 |
|
|
SipMessage refer; |
417 |
|
|
mDialog.makeRequest(refer, REFER); |
418 |
|
|
refer.header(h_ReferTo) = referTo; |
419 |
|
|
refer.header(h_ReferredBy) = mDialog.mLocalContact; // !slg! is it ok to do this - should it be an option? |
420 |
|
|
mDialog.send(refer); |
421 |
|
|
} |
422 |
|
|
else |
423 |
|
|
{ |
424 |
|
|
WarningLog (<< "Can't refer before Connected"); |
425 |
|
|
assert(0); |
426 |
|
|
throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__); |
427 |
|
|
} |
428 |
|
|
} |
429 |
|
|
|
430 |
|
|
void |
431 |
|
|
InviteSession::refer(const NameAddr& referTo, InviteSessionHandle sessionToReplace) |
432 |
|
|
{ |
433 |
|
|
if (!sessionToReplace.isValid()) |
434 |
|
|
{ |
435 |
|
|
throw UsageUseException("Attempted to make a refer w/ and invalid replacement target", __FILE__, __LINE__); |
436 |
|
|
} |
437 |
|
|
|
438 |
|
|
if (mSentRefer) |
439 |
|
|
{ |
440 |
|
|
throw UsageUseException("Attempted to send overlapping refer", __FILE__, __LINE__); |
441 |
|
|
} |
442 |
|
|
|
443 |
sgodin |
5001 |
if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite? |
444 |
jason |
4010 |
{ |
445 |
|
|
mSentRefer = true; |
446 |
|
|
SipMessage refer; |
447 |
|
|
mDialog.makeRequest(refer, REFER); |
448 |
|
|
|
449 |
|
|
refer.header(h_ReferTo) = referTo; |
450 |
sgodin |
5001 |
refer.header(h_ReferredBy) = mDialog.mLocalContact; // ?slg? is it ok to do this - should it be an option? |
451 |
jason |
4010 |
CallId replaces; |
452 |
|
|
DialogId id = sessionToReplace->mDialog.getId(); |
453 |
|
|
replaces.value() = id.getCallId(); |
454 |
|
|
replaces.param(p_toTag) = id.getRemoteTag(); |
455 |
|
|
replaces.param(p_fromTag) = id.getLocalTag(); |
456 |
|
|
|
457 |
|
|
refer.header(h_ReferTo).uri().embedded().header(h_Replaces) = replaces; |
458 |
|
|
mDialog.send(refer); |
459 |
|
|
} |
460 |
|
|
else |
461 |
|
|
{ |
462 |
|
|
WarningLog (<< "Can't refer before Connected"); |
463 |
|
|
assert(0); |
464 |
|
|
throw UsageUseException("REFER not allowed in this context", __FILE__, __LINE__); |
465 |
|
|
} |
466 |
|
|
} |
467 |
|
|
|
468 |
|
|
void |
469 |
|
|
InviteSession::info(const Contents& contents) |
470 |
|
|
{ |
471 |
|
|
if (mNitState == NitComplete) |
472 |
|
|
{ |
473 |
sgodin |
5001 |
if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite? |
474 |
jason |
4010 |
{ |
475 |
|
|
mNitState = NitProceeding; |
476 |
|
|
SipMessage info; |
477 |
|
|
mDialog.makeRequest(info, INFO); |
478 |
|
|
// !jf! handle multipart here |
479 |
|
|
info.setContents(&contents); |
480 |
daniel |
5068 |
mDialog.send(info, mCurrentEncryptionLevel); |
481 |
jason |
4010 |
} |
482 |
|
|
else |
483 |
|
|
{ |
484 |
|
|
WarningLog (<< "Can't send INFO before Connected"); |
485 |
|
|
assert(0); |
486 |
|
|
throw UsageUseException("Can't send INFO before Connected", __FILE__, __LINE__); |
487 |
|
|
} |
488 |
|
|
} |
489 |
|
|
else |
490 |
|
|
{ |
491 |
|
|
throw UsageUseException("Cannot start a non-invite transaction until the previous one has completed", |
492 |
|
|
__FILE__, __LINE__); |
493 |
|
|
} |
494 |
|
|
} |
495 |
|
|
|
496 |
|
|
void |
497 |
sgodin |
5265 |
InviteSession::message(const Contents& contents) |
498 |
|
|
{ |
499 |
|
|
if (mNitState == NitComplete) |
500 |
|
|
{ |
501 |
|
|
if (isConnected()) // ?slg? likely not safe in any state except Connected - what should behaviour be if state is ReceivedReinvite? |
502 |
|
|
{ |
503 |
|
|
mNitState = NitProceeding; |
504 |
|
|
SipMessage message; |
505 |
|
|
mDialog.makeRequest(message, MESSAGE); |
506 |
|
|
// !jf! handle multipart here |
507 |
|
|
message.setContents(&contents); |
508 |
|
|
mDialog.send(message, mCurrentEncryptionLevel); |
509 |
|
|
InfoLog (<< "Trying to send MESSAGE: " << message); |
510 |
|
|
} |
511 |
|
|
else |
512 |
|
|
{ |
513 |
|
|
WarningLog (<< "Can't send MESSAGE before Connected"); |
514 |
|
|
assert(0); |
515 |
|
|
throw UsageUseException("Can't send MESSAGE before Connected", __FILE__, __LINE__); |
516 |
|
|
} |
517 |
|
|
} |
518 |
|
|
else |
519 |
|
|
{ |
520 |
|
|
throw UsageUseException("Cannot start a non-invite transaction until the previous one has completed", |
521 |
|
|
__FILE__, __LINE__); |
522 |
|
|
} |
523 |
|
|
} |
524 |
|
|
|
525 |
|
|
void |
526 |
jason |
4010 |
InviteSession::dispatch(const SipMessage& msg) |
527 |
|
|
{ |
528 |
|
|
// !jf! do we need to handle 3xx here or is it handled elsewhere? |
529 |
|
|
switch (mState) |
530 |
|
|
{ |
531 |
|
|
case Connected: |
532 |
|
|
dispatchConnected(msg); |
533 |
|
|
break; |
534 |
|
|
case SentUpdate: |
535 |
|
|
dispatchSentUpdate(msg); |
536 |
|
|
break; |
537 |
|
|
case SentReinvite: |
538 |
|
|
dispatchSentReinvite(msg); |
539 |
|
|
break; |
540 |
|
|
case SentUpdateGlare: |
541 |
|
|
case SentReinviteGlare: |
542 |
|
|
// The behavior is the same except for timer which is handled in dispatch(Timer) |
543 |
|
|
dispatchGlare(msg); |
544 |
|
|
break; |
545 |
|
|
case ReceivedUpdate: |
546 |
|
|
case ReceivedReinvite: |
547 |
|
|
case ReceivedReinviteNoOffer: |
548 |
|
|
dispatchReceivedUpdateOrReinvite(msg); |
549 |
|
|
break; |
550 |
|
|
case Answered: |
551 |
|
|
dispatchAnswered(msg); |
552 |
|
|
break; |
553 |
|
|
case WaitingToOffer: |
554 |
|
|
dispatchWaitingToOffer(msg); |
555 |
|
|
break; |
556 |
|
|
case WaitingToTerminate: |
557 |
|
|
dispatchWaitingToTerminate(msg); |
558 |
|
|
break; |
559 |
|
|
case Terminated: |
560 |
|
|
dispatchTerminated(msg); |
561 |
|
|
break; |
562 |
|
|
case Undefined: |
563 |
|
|
default: |
564 |
|
|
assert(0); |
565 |
|
|
break; |
566 |
|
|
} |
567 |
|
|
} |
568 |
|
|
|
569 |
|
|
void |
570 |
derek |
2990 |
InviteSession::dispatch(const DumTimeout& timeout) |
571 |
|
|
{ |
572 |
derek |
3255 |
if (timeout.type() == DumTimeout::Retransmit200) |
573 |
derek |
2990 |
{ |
574 |
jason |
4010 |
if (mCurrentRetransmit200) |
575 |
derek |
3255 |
{ |
576 |
jason |
4010 |
InfoLog (<< "Retransmitting: " << endl << mInvite200); |
577 |
daniel |
5214 |
mDialog.send(mInvite200, mCurrentEncryptionLevel); |
578 |
derek |
3255 |
mCurrentRetransmit200 *= 2; |
579 |
|
|
mDum.addTimerMs(DumTimeout::Retransmit200, resipMin(Timer::T2, mCurrentRetransmit200), getBaseHandle(), timeout.seq()); |
580 |
|
|
} |
581 |
derek |
2990 |
} |
582 |
derek |
3255 |
else if (timeout.type() == DumTimeout::WaitForAck) |
583 |
derek |
2990 |
{ |
584 |
jason |
4010 |
if(mCurrentRetransmit200) // If retransmit200 timer is active then ACK is not received yet |
585 |
derek |
3255 |
{ |
586 |
jason |
4010 |
mCurrentRetransmit200 = 0; // stop the 200 retransmit timer |
587 |
|
|
|
588 |
|
|
// this is so the app can decided to ignore this. default implementation |
589 |
|
|
// will call end next |
590 |
|
|
mDum.mInviteSessionHandler->onAckNotReceived(getSessionHandle()); |
591 |
|
|
|
592 |
|
|
// If we are waiting for an Ack and it times out, then end with a BYE |
593 |
|
|
if(mState == UAS_WaitingToHangup) |
594 |
sgodin |
3363 |
{ |
595 |
jason |
4010 |
sendBye(); |
596 |
|
|
transition(Terminated); |
597 |
|
|
mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended); |
598 |
sgodin |
3363 |
} |
599 |
derek |
3255 |
} |
600 |
derek |
2990 |
} |
601 |
jason |
4010 |
else if (timeout.type() == DumTimeout::Glare) |
602 |
derek |
3255 |
{ |
603 |
jason |
4010 |
if (mState == SentUpdateGlare) |
604 |
|
|
{ |
605 |
|
|
transition(SentUpdate); |
606 |
|
|
|
607 |
|
|
InfoLog (<< "Retransmitting the UPDATE (glare condition timer)"); |
608 |
daniel |
5068 |
mDialog.send(mLastSessionModification, DialogUsageManager::None); |
609 |
jason |
4010 |
} |
610 |
|
|
else if (mState == SentReinviteGlare) |
611 |
|
|
{ |
612 |
|
|
transition(SentReinvite); |
613 |
|
|
|
614 |
|
|
InfoLog (<< "Retransmitting the reINVITE (glare condition timer)"); |
615 |
daniel |
5068 |
mDialog.send(mLastSessionModification, DialogUsageManager::None); |
616 |
jason |
4010 |
} |
617 |
derek |
3255 |
} |
618 |
sgodin |
3392 |
else if (timeout.type() == DumTimeout::SessionExpiration) |
619 |
|
|
{ |
620 |
|
|
if(timeout.seq() == mSessionTimerSeq) |
621 |
|
|
{ |
622 |
jason |
4010 |
// this is so the app can decided to ignore this. default implementation |
623 |
|
|
// will call end next |
624 |
|
|
mDum.mInviteSessionHandler->onSessionExpired(getSessionHandle()); |
625 |
sgodin |
3392 |
} |
626 |
|
|
} |
627 |
|
|
else if (timeout.type() == DumTimeout::SessionRefresh) |
628 |
|
|
{ |
629 |
jason |
4010 |
if(timeout.seq() == mSessionTimerSeq) |
630 |
sgodin |
3392 |
{ |
631 |
jason |
4010 |
if(mState == Connected) // Note: If not connected then we must be issueing a reinvite/update or receiving one - in either case the session timer stuff will get reset/renegotiated - thus just ignore this referesh |
632 |
sgodin |
3392 |
{ |
633 |
sgodin |
4369 |
sessionRefresh(); |
634 |
sgodin |
3392 |
} |
635 |
|
|
} |
636 |
|
|
} |
637 |
derek |
2990 |
} |
638 |
|
|
|
639 |
jason |
4010 |
void |
640 |
|
|
InviteSession::dispatchConnected(const SipMessage& msg) |
641 |
sgodin |
3392 |
{ |
642 |
jason |
4010 |
InviteSessionHandler* handler = mDum.mInviteSessionHandler; |
643 |
|
|
std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg); |
644 |
|
|
|
645 |
|
|
switch (toEvent(msg, sdp.get())) |
646 |
sgodin |
3392 |
{ |
647 |
jason |
4010 |
case OnInvite: |
648 |
|
|
case OnInviteReliable: |
649 |
|
|
mLastSessionModification = msg; |
650 |
|
|
transition(ReceivedReinviteNoOffer); |
651 |
|
|
//handler->onDialogModified(getSessionHandle(), None, msg); |
652 |
|
|
handler->onOfferRequired(getSessionHandle(), msg); |
653 |
|
|
break; |
654 |
sgodin |
3392 |
|
655 |
jason |
4010 |
case OnInviteOffer: |
656 |
|
|
case OnInviteReliableOffer: |
657 |
|
|
mLastSessionModification = msg; |
658 |
|
|
transition(ReceivedReinvite); |
659 |
daniel |
5068 |
mCurrentEncryptionLevel = getEncryptionLevel(msg); |
660 |
jason |
4010 |
//handler->onDialogModified(getSessionHandle(), Offer, msg); |
661 |
|
|
handler->onOffer(getSessionHandle(), msg, *sdp); |
662 |
|
|
break; |
663 |
|
|
|
664 |
|
|
case On2xx: |
665 |
|
|
case On2xxOffer: |
666 |
|
|
case On2xxAnswer: |
667 |
|
|
// retransmission of 200I |
668 |
|
|
// !jf! Need to include the answer here. |
669 |
|
|
sendAck(); |
670 |
|
|
break; |
671 |
|
|
|
672 |
sgodin |
4369 |
case OnUpdateOffer: |
673 |
jason |
4010 |
transition(ReceivedUpdate); |
674 |
|
|
|
675 |
|
|
// !kh! |
676 |
|
|
// Find out if it's an UPDATE requiring state change. |
677 |
|
|
// See rfc3311 5.2, 4th paragraph. |
678 |
|
|
mLastSessionModification = msg; |
679 |
daniel |
5068 |
mCurrentEncryptionLevel = getEncryptionLevel(msg); |
680 |
jason |
4010 |
handler->onOffer(getSessionHandle(), msg, *sdp); |
681 |
|
|
break; |
682 |
|
|
|
683 |
sgodin |
4369 |
case OnUpdate: |
684 |
|
|
{ |
685 |
sgodin |
5001 |
// ?slg? no sdp in update - just responsd immediately (likely session timer) - do we need a callback? |
686 |
sgodin |
4369 |
SipMessage response; |
687 |
|
|
mLastSessionModification = msg; |
688 |
|
|
mDialog.makeResponse(response, mLastSessionModification, 200); |
689 |
|
|
handleSessionTimerRequest(response, mLastSessionModification); |
690 |
|
|
send(response); |
691 |
|
|
break; |
692 |
|
|
} |
693 |
|
|
|
694 |
jason |
4010 |
case OnUpdateRejected: |
695 |
|
|
case On200Update: |
696 |
|
|
WarningLog (<< "DUM delivered an UPDATE response in an incorrect state " << endl << msg); |
697 |
|
|
assert(0); |
698 |
|
|
break; |
699 |
|
|
|
700 |
|
|
case OnAck: |
701 |
|
|
mCurrentRetransmit200 = 0; // stop the 200 retransmit timer |
702 |
|
|
break; |
703 |
|
|
|
704 |
|
|
default: |
705 |
|
|
dispatchOthers(msg); |
706 |
|
|
break; |
707 |
|
|
} |
708 |
|
|
} |
709 |
|
|
|
710 |
|
|
void |
711 |
|
|
InviteSession::dispatchSentUpdate(const SipMessage& msg) |
712 |
|
|
{ |
713 |
|
|
InviteSessionHandler* handler = mDum.mInviteSessionHandler; |
714 |
|
|
std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg); |
715 |
|
|
|
716 |
|
|
switch (toEvent(msg, sdp.get())) |
717 |
|
|
{ |
718 |
|
|
case OnInvite: |
719 |
|
|
case OnInviteReliable: |
720 |
|
|
case OnInviteOffer: |
721 |
|
|
case OnInviteReliableOffer: |
722 |
|
|
case OnUpdate: |
723 |
sgodin |
4369 |
case OnUpdateOffer: |
724 |
sgodin |
3392 |
{ |
725 |
jason |
4010 |
// glare |
726 |
|
|
SipMessage response; |
727 |
|
|
mDialog.makeResponse(response, msg, 491); |
728 |
|
|
send(response); |
729 |
|
|
break; |
730 |
|
|
} |
731 |
|
|
|
732 |
|
|
case On200Update: |
733 |
|
|
transition(Connected); |
734 |
|
|
handleSessionTimerResponse(msg); |
735 |
|
|
if (sdp.get()) |
736 |
sgodin |
3392 |
{ |
737 |
daniel |
5068 |
mCurrentEncryptionLevel = getEncryptionLevel(msg); |
738 |
|
|
setCurrentLocalSdp(msg); |
739 |
jason |
4010 |
mCurrentRemoteSdp = InviteSession::makeSdp(*sdp); |
740 |
|
|
handler->onAnswer(getSessionHandle(), msg, *sdp); |
741 |
sgodin |
3392 |
} |
742 |
sgodin |
4369 |
else if(mProposedLocalSdp.get()) |
743 |
sgodin |
3392 |
{ |
744 |
sgodin |
4369 |
// If we sent an offer in the Update Request and no answer is received |
745 |
jason |
4010 |
handler->onIllegalNegotiation(getSessionHandle(), msg); |
746 |
sgodin |
4369 |
mProposedLocalSdp.release(); |
747 |
daniel |
5068 |
mProposedEncryptionLevel = DialogUsageManager::None; |
748 |
jason |
4010 |
} |
749 |
|
|
break; |
750 |
|
|
|
751 |
|
|
case On491Update: |
752 |
sgodin |
4369 |
transition(SentUpdateGlare); |
753 |
jason |
4010 |
start491Timer(); |
754 |
|
|
break; |
755 |
|
|
|
756 |
daniel |
5068 |
case On422Update: // session timer |
757 |
sgodin |
4394 |
if(msg.exists(h_MinSE)) |
758 |
|
|
{ |
759 |
|
|
// Change interval to min from 422 response |
760 |
|
|
mSessionInterval = msg.header(h_MinSE).value(); |
761 |
sgodin |
4691 |
mMinSE = mSessionInterval; |
762 |
sgodin |
4394 |
sessionRefresh(); |
763 |
|
|
} |
764 |
|
|
else |
765 |
|
|
{ |
766 |
|
|
// Response must contact Min_SE - if not - just ignore |
767 |
sgodin |
5001 |
// ?slg? callback? |
768 |
sgodin |
4394 |
transition(Connected); |
769 |
|
|
mProposedLocalSdp.release(); |
770 |
daniel |
5068 |
mProposedEncryptionLevel = DialogUsageManager::None; |
771 |
sgodin |
4394 |
} |
772 |
|
|
break; |
773 |
|
|
|
774 |
jason |
4010 |
case OnUpdateRejected: |
775 |
sgodin |
4369 |
// !jf! - callback? |
776 |
|
|
mProposedLocalSdp.release(); |
777 |
daniel |
5068 |
mProposedEncryptionLevel = DialogUsageManager::None; |
778 |
sgodin |
4369 |
transition(Connected); |
779 |
jason |
4010 |
break; |
780 |
|
|
|
781 |
|
|
case OnGeneralFailure: |
782 |
|
|
sendBye(); |
783 |
|
|
transition(Terminated); |
784 |
|
|
handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg); |
785 |
|
|
break; |
786 |
|
|
|
787 |
|
|
default: |
788 |
|
|
dispatchOthers(msg); |
789 |
|
|
break; |
790 |
|
|
} |
791 |
|
|
} |
792 |
|
|
|
793 |
|
|
void |
794 |
|
|
InviteSession::dispatchSentReinvite(const SipMessage& msg) |
795 |
|
|
{ |
796 |
|
|
InviteSessionHandler* handler = mDum.mInviteSessionHandler; |
797 |
|
|
std::auto_ptr<SdpContents> sdp = InviteSession::getSdp(msg); |
798 |
|
|
|
799 |
|
|
switch (toEvent(msg, sdp.get())) |
800 |
|
|
{ |
801 |
|
|
case OnInvite: |
802 |
|
|
case OnInviteReliable: |
803 |
|
|
case OnInviteOffer: |
804 |
|
|
case OnInviteReliableOffer: |
805 |
|
|
case OnUpdate: |
806 |
sgodin |
4369 |
case OnUpdateOffer: |
807 |
jason |
4010 |
{ |
808 |
|
|
SipMessage response; |
809 |
|
|
mDialog.makeResponse(response, msg, 491); |
810 |
|
|
send(response); |
811 |
|
|
break; |
812 |
sgodin |
3392 |
} |
813 |
jason |
4010 |
|
814 |
|
|
case On1xx: |
815 |
|
|
case On1xxEarly: |
816 |
sgodin |
5001 |
// Some UA's send a 100 response to a ReInvite - just ignore it |
817 |
jason |
4010 |
break; |
818 |
|
|
|
819 |
|
|
case On2xxAnswer: |
820 |
|
|
case On2xxOffer: |
821 |
sgodin |
3392 |
{ |
822 |
jason |
4010 |
transition(Connected); |
823 |
|
|
handleSessionTimerResponse(msg); |
824 |
daniel |
5068 |
setCurrentLocalSdp(msg); |
825 |
jason |
4010 |
mCurrentRemoteSdp = InviteSession::makeSdp(*sdp); |
826 |
daniel |
5068 |
mCurrentEncryptionLevel = getEncryptionLevel(msg); |
827 |
jason |
4010 |
// !jf! I need to potentially include an answer in the ACK here |
828 |
|
|
sendAck(); |
829 |
|
|
handler->onAnswer(getSessionHandle(), msg, *sdp); |
830 |
|
|
|
831 |
|
|
|
832 |
|
|
// !jf! do I need to allow a reINVITE overlapping the retransmission of |
833 |
|
|
// the ACK when a 200I is received? If yes, then I need to store all |
834 |
|
|
// ACK messages for 64*T1 |
835 |
|
|
break; |
836 |
|
|
} |
837 |
|
|
case On2xx: |
838 |
|
|
sendAck(); |
839 |
|
|
transition(Connected); |
840 |
|
|
handleSessionTimerResponse(msg); |
841 |
|
|
handler->onIllegalNegotiation(getSessionHandle(), msg); |
842 |
sgodin |
4369 |
mProposedLocalSdp.release(); |
843 |
daniel |
5068 |
mProposedEncryptionLevel = DialogUsageManager::None; |
844 |
jason |
4010 |
break; |
845 |
|
|
|
846 |
sgodin |
4394 |
case On422Invite: |
847 |
|
|
if(msg.exists(h_MinSE)) |
848 |
|
|
{ |
849 |
|
|
// Change interval to min from 422 response |
850 |
|
|
mSessionInterval = msg.header(h_MinSE).value(); |
851 |
sgodin |
4691 |
mMinSE = mSessionInterval; |
852 |
sgodin |
4394 |
sessionRefresh(); |
853 |
|
|
} |
854 |
|
|
else |
855 |
|
|
{ |
856 |
|
|
// Response must contact Min_SE - if not - just ignore |
857 |
sgodin |
5001 |
// ?slg? callback? |
858 |
sgodin |
4394 |
transition(Connected); |
859 |
|
|
mProposedLocalSdp.release(); |
860 |
daniel |
5068 |
mProposedEncryptionLevel = DialogUsageManager::None; |
861 |
sgodin |
4394 |
} |
862 |
|
|
break; |
863 |
|
|
|
864 |
jason |
4010 |
case On491Invite: |
865 |
sgodin |
4369 |
transition(SentReinviteGlare); |
866 |
jason |
4010 |
start491Timer(); |
867 |
|
|
break; |
868 |
|
|
|
869 |
|
|
case OnGeneralFailure: |
870 |
|
|
sendBye(); |
871 |
|
|
transition(Terminated); |
872 |
|
|
handler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg); |
873 |
|
|
break; |
874 |
|
|
|
875 |
|
|
case OnInviteFailure: |
876 |
sgodin |
5130 |
case On487Invite: |
877 |
|
|
case On489Invite: |
878 |
jason |
4010 |
transition(Connected); |
879 |
sgodin |
4369 |
mProposedLocalSdp.release(); |
880 |
jason |
4010 |
handler->onOfferRejected(getSessionHandle(), msg); |
881 |
|
|
break; |
882 |
|
|
|
883 |
|
|
default: |
884 |
|
|
dispatchOthers(msg); |
885 |
|
|
break; |
886 |
|
|
} |
887 |
|
|
} |
888 |
|
|
|
889 |
|
|
void |
890 |
|
|
InviteSession::dispatchGlare(const SipMessage& msg) |
891 |
|
|
{ |
892 |
|
|
InviteSessionHandler* handler = mDum.mInviteSessionHandler; |
893 |
|
|
MethodTypes method = msg.header(h_CSeq).method(); |
894 |
|
|
if (method == INVITE && msg.isRequest()) |
895 |
|
|
{ |
896 |
|
|
// Received inbound reinvite, when waiting to resend outbound reinvite or update |
897 |
|
|
transition(ReceivedReinvite); |
898 |
|
|
handler->onOfferRejected(getSessionHandle(), msg); |
899 |
|
|
} |
900 |
|
|
else if (method == UPDATE && msg.isRequest()) |
901 |
|
|
{ |
902 |
|
|
// Received inbound update, when waiting to resend outbound reinvite or update |
903 |
|
|
transition(ReceivedUpdate); |
904 |
|
|
handler->onOfferRejected(getSessionHandle(), msg); |
905 |
|
|
} |
906 |
|
|
else |
907 |
|
|
{ |
908 |
|
|
dispatchOthers(msg); |
909 |
|
|
} |
910 |
|
|
} |
911 |
|
|
|
912 |
|
|
void |
913 |
|
|
InviteSession::dispatchReceivedUpdateOrReinvite(const SipMessage& msg) |
914 |
|
|
{ |
915 |
|
|
MethodTypes method = msg.header(h_CSeq).method(); |
916 |
|
|
if (method == INVITE || method == UPDATE) |
917 |
|
|
{ |
918 |
|
|
// Means that the UAC has sent us a second reINVITE or UPDATE before we |
919 |
|
|
// responded to the first one. Bastard! |
920 |
|
|
SipMessage response; |
921 |
|
|
mDialog.makeResponse(response, msg, 500); |
922 |
|
|
response.header(h_RetryAfter).value() = Random::getRandom() % 10; |
923 |
|
|
mDialog.send(response); |
924 |
|
|
} |
925 |
|
|
else |
926 |
|
|
{ |
927 |
|
|
dispatchOthers(msg); |
928 |
|
|
} |
929 |
|
|
} |
930 |
|
|
|
931 |
|
|
|
932 |
|
|
void |
933 |
|
|
InviteSession::dispatchAnswered(const SipMessage& msg) |
934 |
|
|
{ |
935 |
|
|
if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK) |
936 |
|
|
{ |
937 |
|
|
mCurrentRetransmit200 = 0; // stop the 200 retransmit timer |
938 |
|
|
transition(Connected); |
939 |
|
|
} |
940 |
|
|
else |
941 |
|
|
{ |
942 |
|
|
dispatchOthers(msg); |
943 |
|
|
} |
944 |
|
|
} |
945 |
|
|
|
946 |
|
|
void |
947 |
|
|
InviteSession::dispatchWaitingToOffer(const SipMessage& msg) |
948 |
|
|
{ |
949 |
|
|
if (msg.isRequest() && msg.header(h_RequestLine).method() == ACK) |
950 |
|
|
{ |
951 |
daniel |
5068 |
|
952 |
|
|
assert(mProposedLocalSdp.get()); |
953 |
jason |
4010 |
mCurrentRetransmit200 = 0; // stop the 200 retransmit timer |
954 |
daniel |
5068 |
if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get())) |
955 |
|
|
{ |
956 |
|
|
provideOffer( *(dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back())), |
957 |
|
|
mProposedEncryptionLevel, |
958 |
|
|
dynamic_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front())); |
959 |
|
|
} |
960 |
|
|
else |
961 |
|
|
{ |
962 |
|
|
provideOffer(*(dynamic_cast<SdpContents*>(mProposedLocalSdp.get())), mProposedEncryptionLevel, 0); |
963 |
|
|
} |
964 |
jason |
4010 |
} |
965 |
|
|
else |
966 |
|
|
{ |
967 |
|
|
dispatchOthers(msg); |
968 |
|
|
} |
969 |
|
|
} |
970 |
|
|
|
971 |
|
|
void |
972 |
|
|
InviteSession::dispatchWaitingToTerminate(const SipMessage& msg) |
973 |
|
|
{ |
974 |
|
|
if (msg.isResponse() && |
975 |
|
|
msg.header(h_CSeq).method() == INVITE) |
976 |
|
|
{ |
977 |
|
|
if(msg.header(h_StatusLine).statusCode() / 200 == 1) // Note: stack ACK's non-2xx final responses only |
978 |
|
|
{ |
979 |
|
|
// !jf! Need to include the answer here. |
980 |
|
|
sendAck(); |
981 |
|
|
} |
982 |
|
|
sendBye(); |
983 |
|
|
transition(Terminated); |
984 |
|
|
mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::Ended); |
985 |
|
|
} |
986 |
|
|
} |
987 |
|
|
|
988 |
|
|
void |
989 |
|
|
InviteSession::dispatchTerminated(const SipMessage& msg) |
990 |
|
|
{ |
991 |
|
|
InfoLog (<< "InviteSession::dispatchTerminated " << msg.brief()); |
992 |
|
|
|
993 |
|
|
if (msg.isRequest()) |
994 |
|
|
{ |
995 |
|
|
SipMessage response; |
996 |
|
|
mDialog.makeResponse(response, msg, 481); |
997 |
|
|
mDialog.send(response); |
998 |
|
|
|
999 |
|
|
// !jf! means the peer sent BYE while we are waiting for response to BYE |
1000 |
|
|
//mDum.destroy(this); |
1001 |
|
|
} |
1002 |
|
|
else |
1003 |
|
|
{ |
1004 |
|
|
mDum.destroy(this); |
1005 |
|
|
} |
1006 |
|
|
} |
1007 |
|
|
|
1008 |
|
|
void |
1009 |
|
|
InviteSession::dispatchOthers(const SipMessage& msg) |
1010 |
|
|
{ |
1011 |
|
|
// handle OnGeneralFailure |
1012 |
|
|
// handle OnRedirect |
1013 |
|
|
|
1014 |
|
|
switch (msg.header(h_CSeq).method()) |
1015 |
|
|
{ |
1016 |
|
|
case PRACK: |
1017 |
|
|
dispatchPrack(msg); |
1018 |
|
|
break; |
1019 |
|
|
case CANCEL: |
1020 |
|
|
dispatchCancel(msg); |
1021 |
|
|
break; |
1022 |
|
|
case BYE: |
1023 |
|
|
dispatchBye(msg); |
1024 |
|
|
break; |
1025 |
|
|
case INFO: |
1026 |
|
|
dispatchInfo(msg); |
1027 |
|
|
break; |
1028 |
sgodin |
5265 |
case MESSAGE: |
1029 |
|
|
dispatchMessage(msg); |
1030 |
|
|
break; |
1031 |
jason |
4010 |
case ACK: |
1032 |
|
|
// Ignore duplicate ACKs from 2xx reTransmissions |
1033 |
|
|
break; |
1034 |
|
|
default: |
1035 |
|
|
// handled in Dialog |
1036 |
|
|
WarningLog (<< "DUM delivered a " |
1037 |
|
|
<< msg.header(h_CSeq).unknownMethodName() |
1038 |
|
|
<< " to the InviteSession " |
1039 |
|
|
<< endl |
1040 |
|
|
<< msg); |
1041 |
|
|
assert(0); |
1042 |
|
|
break; |
1043 |
|
|
} |
1044 |
|
|
} |
1045 |
|
|
|
1046 |
|
|
void |
1047 |
|
|
InviteSession::dispatchUnhandledInvite(const SipMessage& msg) |
1048 |
|
|
{ |
1049 |
|
|
assert(msg.isRequest()); |
1050 |
|
|
assert(msg.header(h_CSeq).method() == INVITE); |
1051 |
|
|
|
1052 |
|
|
// If we get an INVITE request from the wire and we are not in |
1053 |
|
|
// Connected state, reject the request and send a BYE |
1054 |
|
|
SipMessage response; |
1055 |
|
|
mDialog.makeResponse(response, msg, 400); // !jf! what code to use? |
1056 |
|
|
InfoLog (<< "Sending " << response.brief()); |
1057 |
|
|
mDialog.send(response); |
1058 |
|
|
|
1059 |
|
|
sendBye(); |
1060 |
|
|
transition(Terminated); |
1061 |
|
|
mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg); |
1062 |
|
|
} |
1063 |
|
|
|
1064 |
|
|
void |
1065 |
|
|
InviteSession::dispatchPrack(const SipMessage& msg) |
1066 |
|
|
{ |
1067 |
|
|
assert(msg.header(h_CSeq).method() == PRACK); |
1068 |
|
|
if(msg.isRequest()) |
1069 |
|
|
{ |
1070 |
|
|
SipMessage rsp; |
1071 |
|
|
mDialog.makeResponse(rsp, msg, 481); |
1072 |
|
|
mDialog.send(rsp); |
1073 |
|
|
|
1074 |
|
|
sendBye(); |
1075 |
|
|
// !jf! should we make some other callback here |
1076 |
|
|
transition(Terminated); |
1077 |
|
|
mDum.mInviteSessionHandler->onTerminated(getSessionHandle(), InviteSessionHandler::GeneralFailure, &msg); |
1078 |
|
|
} |
1079 |
|
|
else |
1080 |
|
|
{ |
1081 |
|
|
// ignore. could be PRACK/200 |
1082 |
|
|
} |
1083 |
|
|
} |
1084 |
|
|
|
1085 |
|
|
void |
1086 |
|
|
InviteSession::dispatchCancel(const SipMessage& msg) |
1087 |
|
|
{ |
1088 |
|
|
InviteSessionHandler* handler = mDum.mInviteSessionHandler; |
1089 |
|
|
assert(msg.header(h_CSeq).method() == CANCEL); |
1090 |
|
|
if(msg.isRequest()) |
1091 |
|
|
{ |
1092 |
|
|
SipMessage rsp; |
1093 |
|
|
mDialog.makeResponse(rsp, msg, 200); |
1094 |
|
|
mDialog.send(rsp); |
1095 |
|
|
|
1096 |
|
|
sendBye(); |
1097 |
|
|
// !jf! should we make some other callback here |
1098 |
|
|
transition(Terminated); |
1099 |
|
|
handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg); |
1100 |
|
|
} |
1101 |
|
|
else |
1102 |
|
|
{ |
1103 |
|
|
WarningLog (<< "DUM let me send a CANCEL at an incorrect state " << endl << msg); |
1104 |
|
|
assert(0); |
1105 |
|
|
} |
1106 |
|
|
} |
1107 |
|
|
|
1108 |
|
|
void |
1109 |
|
|
InviteSession::dispatchBye(const SipMessage& msg) |
1110 |
|
|
{ |
1111 |
|
|
InviteSessionHandler* handler = mDum.mInviteSessionHandler; |
1112 |
|
|
|
1113 |
|
|
if (msg.isRequest()) |
1114 |
|
|
{ |
1115 |
|
|
|
1116 |
|
|
SipMessage rsp; |
1117 |
|
|
InfoLog (<< "Received " << msg.brief()); |
1118 |
|
|
mDialog.makeResponse(rsp, msg, 200); |
1119 |
|
|
mDialog.send(rsp); |
1120 |
|
|
|
1121 |
|
|
// !jf! should we make some other callback here |
1122 |
|
|
transition(Terminated); |
1123 |
|
|
handler->onTerminated(getSessionHandle(), InviteSessionHandler::PeerEnded, &msg); |
1124 |
|
|
mDum.destroy(this); |
1125 |
|
|
} |
1126 |
|
|
else |
1127 |
|
|
{ |
1128 |
|
|
WarningLog (<< "DUM let me send a BYE at an incorrect state " << endl << msg); |
1129 |
|
|
assert(0); |
1130 |
|
|
} |
1131 |
|
|
} |
1132 |
|
|
|
1133 |
|
|
void |
1134 |
|
|
InviteSession::dispatchInfo(const SipMessage& msg) |
1135 |
|
|
{ |
1136 |
|
|
InviteSessionHandler* handler = mDum.mInviteSessionHandler; |
1137 |
|
|
if (msg.isRequest()) |
1138 |
|
|
{ |
1139 |
|
|
InfoLog (<< "Received " << msg.brief()); |
1140 |
|
|
mDialog.makeResponse(mLastNitResponse, msg, 200); |
1141 |
|
|
handler->onInfo(getSessionHandle(), msg); |
1142 |
|
|
} |
1143 |
|
|
else |
1144 |
|
|
{ |
1145 |
|
|
assert(mNitState == NitProceeding); |
1146 |
|
|
mNitState = NitComplete; |
1147 |
|
|
//!dcm! -- toss away 1xx to an info? |
1148 |
|
|
if (msg.header(h_StatusLine).statusCode() >= 300) |
1149 |
|
|
{ |
1150 |
|
|
handler->onInfoFailure(getSessionHandle(), msg); |
1151 |
|
|
} |
1152 |
|
|
else if (msg.header(h_StatusLine).statusCode() >= 200) |
1153 |
|
|
{ |
1154 |
|
|
handler->onInfoSuccess(getSessionHandle(), msg); |
1155 |
|
|
} |
1156 |
|
|
} |
1157 |
|
|
} |
1158 |
|
|
|
1159 |
|
|
void |
1160 |
sgodin |
5265 |
InviteSession::acceptNIT(int statusCode) |
1161 |
jason |
4010 |
{ |
1162 |
|
|
if (statusCode / 100 != 2) |
1163 |
|
|
{ |
1164 |
|
|
throw UsageUseException("Must accept with a 2xx", __FILE__, __LINE__); |
1165 |
|
|
} |
1166 |
|
|
|
1167 |
|
|
mLastNitResponse.header(h_StatusLine).statusCode() = statusCode; |
1168 |
|
|
send(mLastNitResponse); |
1169 |
|
|
} |
1170 |
|
|
|
1171 |
|
|
void |
1172 |
sgodin |
5265 |
InviteSession::rejectNIT(int statusCode) |
1173 |
jason |
4010 |
{ |
1174 |
|
|
if (statusCode < 400) |
1175 |
|
|
{ |
1176 |
|
|
throw UsageUseException("Must reject with a >= 4xx", __FILE__, __LINE__); |
1177 |
|
|
} |
1178 |
|
|
mLastNitResponse.header(h_StatusLine).statusCode() = statusCode; |
1179 |
|
|
send(mLastNitResponse); |
1180 |
|
|
} |
1181 |
|
|
|
1182 |
|
|
void |
1183 |
sgodin |
5265 |
InviteSession::dispatchMessage(const SipMessage& msg) |
1184 |
|
|
{ |
1185 |
|
|
InviteSessionHandler* handler = mDum.mInviteSessionHandler; |
1186 |
|
|
if (msg.isRequest()) |
1187 |
|
|
{ |
1188 |
|
|
InfoLog (<< "Received " << msg.brief()); |
1189 |
|
|
mDialog.makeResponse(mLastNitResponse, msg, 200); |
1190 |
|
|
handler->onMessage(getSessionHandle(), msg); |
1191 |
|
|
} |
1192 |
|
|
else |
1193 |
|
|
{ |
1194 |
|
|
assert(mNitState == NitProceeding); |
1195 |
|
|
mNitState = NitComplete; |
1196 |
|
|
//!dcm! -- toss away 1xx to an message? |
1197 |
|
|
if (msg.header(h_StatusLine).statusCode() >= 300) |
1198 |
|
|
{ |
1199 |
|
|
handler->onMessageFailure(getSessionHandle(), msg); |
1200 |
|
|
} |
1201 |
|
|
else if (msg.header(h_StatusLine).statusCode() >= 200) |
1202 |
|
|
{ |
1203 |
|
|
handler->onMessageSuccess(getSessionHandle(), msg); |
1204 |
|
|
} |
1205 |
|
|
} |
1206 |
|
|
} |
1207 |
|
|
|
1208 |
|
|
void |
1209 |
jason |
4010 |
InviteSession::startRetransmit200Timer() |
1210 |
|
|
{ |
1211 |
|
|
mCurrentRetransmit200 = Timer::T1; |
1212 |
|
|
int seq = mLastSessionModification.header(h_CSeq).sequence(); |
1213 |
|
|
mDum.addTimerMs(DumTimeout::Retransmit200, mCurrentRetransmit200, getBaseHandle(), seq); |
1214 |
|
|
mDum.addTimerMs(DumTimeout::WaitForAck, Timer::TH, getBaseHandle(), seq); |
1215 |
|
|
} |
1216 |
|
|
|
1217 |
|
|
void |
1218 |
|
|
InviteSession::start491Timer() |
1219 |
|
|
{ |
1220 |
|
|
int seq = mLastSessionModification.header(h_CSeq).sequence(); |
1221 |
|
|
int timer = Random::getRandom() % 4000; |
1222 |
|
|
mDum.addTimerMs(DumTimeout::Glare, timer, getBaseHandle(), seq); |
1223 |
|
|
} |
1224 |
|
|
|
1225 |
sgodin |
4369 |
void |
1226 |
|
|
InviteSession::setSessionTimerHeaders(SipMessage &msg) |
1227 |
|
|
{ |
1228 |
|
|
if(mSessionInterval >= 90) // If mSessionInterval is 0 then SessionTimers are considered disabled |
1229 |
|
|
{ |
1230 |
|
|
msg.header(h_SessionExpires).value() = mSessionInterval; |
1231 |
sgodin |
4691 |
if(msg.isRequest()) |
1232 |
|
|
{ |
1233 |
|
|
msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uac" : "uas"); |
1234 |
|
|
} |
1235 |
|
|
else |
1236 |
|
|
{ |
1237 |
|
|
msg.header(h_SessionExpires).param(p_refresher) = Data(mSessionRefresher ? "uas" : "uac"); |
1238 |
|
|
} |
1239 |
|
|
msg.header(h_MinSE).value() = mMinSE; |
1240 |
sgodin |
4369 |
} |
1241 |
|
|
else |
1242 |
|
|
{ |
1243 |
|
|
msg.remove(h_SessionExpires); |
1244 |
|
|
msg.remove(h_MinSE); |
1245 |
|
|
} |
1246 |
|
|
} |
1247 |
|
|
|
1248 |
jason |
4010 |
void |
1249 |
sgodin |
4369 |
InviteSession::sessionRefresh() |
1250 |
|
|
{ |
1251 |
|
|
if (updateMethodSupported()) |
1252 |
|
|
{ |
1253 |
|
|
transition(SentUpdate); |
1254 |
|
|
mDialog.makeRequest(mLastSessionModification, UPDATE); |
1255 |
|
|
mLastSessionModification.releaseContents(); // Don't send SDP |
1256 |
|
|
} |
1257 |
|
|
else |
1258 |
|
|
{ |
1259 |
|
|
transition(SentReinvite); |
1260 |
|
|
mDialog.makeRequest(mLastSessionModification, INVITE); |
1261 |
daniel |
5068 |
InviteSession::setSdp(mLastSessionModification, mCurrentLocalSdp.get()); |
1262 |
|
|
mProposedLocalSdp = InviteSession::makeSdp(*mCurrentLocalSdp.get(), 0); |
1263 |
sgodin |
4369 |
} |
1264 |
|
|
setSessionTimerHeaders(mLastSessionModification); |
1265 |
|
|
|
1266 |
sgodin |
4691 |
InfoLog (<< "sessionRefresh: Sending " << mLastSessionModification.brief()); |
1267 |
daniel |
5068 |
mDialog.send(mLastSessionModification, mCurrentEncryptionLevel); |
1268 |
sgodin |
4369 |
} |
1269 |
|
|
|
1270 |
|
|
void |
1271 |
sgodin |
4691 |
InviteSession::setSessionTimerPreferences() |
1272 |
|
|
{ |
1273 |
|
|
mSessionInterval = mDialog.mDialogSet.getUserProfile()->getDefaultSessionTime(); // Used only if remote doesn't request a time |
1274 |
|
|
if(mSessionInterval != 0) |
1275 |
|
|
{ |
1276 |
|
|
// If session timers are no disabled then ensure interval is greater than or equal to MinSE |
1277 |
|
|
mSessionInterval = resipMax(mMinSE, mSessionInterval); |
1278 |
|
|
} |
1279 |
|
|
switch(mDialog.mDialogSet.getUserProfile()->getDefaultSessionTimerMode()) |
1280 |
|
|
{ |
1281 |
|
|
case Profile::PreferLocalRefreshes: |
1282 |
|
|
mSessionRefresher = true; // Default refresher is Local |
1283 |
|
|
break; |
1284 |
|
|
case Profile::PreferRemoteRefreshes: |
1285 |
|
|
mSessionRefresher = false; // Default refresher is Remote |
1286 |
|
|
break; |
1287 |
|
|
case Profile::PreferUASRefreshes: |
1288 |
|
|
mSessionRefresher = dynamic_cast<ServerInviteSession*>(this) != NULL; // Default refresher is UAS (for the session) - callee |
1289 |
|
|
break; |
1290 |
|
|
case Profile::PreferUACRefreshes: |
1291 |
|
|
mSessionRefresher = dynamic_cast<ClientInviteSession*>(this) != NULL; // Default refresher is UAC (for the session) - caller |
1292 |
|
|
break; |
1293 |
|
|
} |
1294 |
|
|
} |
1295 |
|
|
|
1296 |
|
|
void |
1297 |
|
|
InviteSession::startSessionTimer() |
1298 |
|
|
{ |
1299 |
|
|
if(mSessionInterval >= 90) // 90 is the absolute minimum - RFC4028 |
1300 |
|
|
{ |
1301 |
|
|
// Check if we are the refresher |
1302 |
|
|
if(mSessionRefresher) |
1303 |
|
|
{ |
1304 |
|
|
// Start Session-Refresh Timer to mSessionInterval / 2 (recommended by RFC4028) |
1305 |
|
|
mDum.addTimer(DumTimeout::SessionRefresh, mSessionInterval / 2, getBaseHandle(), ++mSessionTimerSeq); |
1306 |
|
|
} |
1307 |
|
|
else |
1308 |
|
|
{ |
1309 |
|
|
// Start Session-Expiration Timer to mSessionInterval - BYE should be sent a minimum of 32 and one third of the SessionInterval, seconds before the session expires (recommended by RFC4028) |
1310 |
|
|
mDum.addTimer(DumTimeout::SessionExpiration, mSessionInterval - resipMin(32,mSessionInterval/3), getBaseHandle(), ++mSessionTimerSeq); |
1311 |
|
|
} |
1312 |
|
|
} |
1313 |
|
|
else // Session Interval less than 90 - consider timers disabled |
1314 |
|
|
{ |
1315 |
|
|
++mSessionTimerSeq; // increment seq, incase old timers are running and now session timers are disabled |
1316 |
|
|
} |
1317 |
|
|
} |
1318 |
|
|
|
1319 |
|
|
void |
1320 |
jason |
4010 |
InviteSession::handleSessionTimerResponse(const SipMessage& msg) |
1321 |
|
|
{ |
1322 |
|
|
assert(msg.header(h_CSeq).method() == INVITE || msg.header(h_CSeq).method() == UPDATE); |
1323 |
|
|
|
1324 |
|
|
// If session timers are locally supported then handle response |
1325 |
|
|
if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer))) |
1326 |
|
|
{ |
1327 |
sgodin |
4691 |
setSessionTimerPreferences(); |
1328 |
jason |
4010 |
|
1329 |
|
|
if(msg.exists(h_Requires) && msg.header(h_Requires).find(Token(Symbols::Timer)) |
1330 |
|
|
&& !msg.exists(h_SessionExpires)) |
1331 |
|
|
{ |
1332 |
|
|
// If no Session Expires in response and Requires header is present then session timer is to be 'turned off' |
1333 |
|
|
mSessionInterval = 0; |
1334 |
|
|
} |
1335 |
|
|
// Process Session Timer headers |
1336 |
|
|
else if(msg.exists(h_SessionExpires)) |
1337 |
|
|
{ |
1338 |
sgodin |
3392 |
mSessionInterval = msg.header(h_SessionExpires).value(); |
1339 |
|
|
if(msg.header(h_SessionExpires).exists(p_refresher)) |
1340 |
|
|
{ |
1341 |
jason |
4010 |
// Remote end specified refresher preference |
1342 |
sgodin |
4691 |
mSessionRefresher = (msg.header(h_SessionExpires).param(p_refresher) == Data("uac")); |
1343 |
sgodin |
3392 |
} |
1344 |
|
|
} |
1345 |
jason |
4010 |
else |
1346 |
|
|
{ |
1347 |
|
|
// Note: If no Requires or Session-Expires, then UAS does not support Session Timers |
1348 |
|
|
// - we are free to use our SessionInterval settings (set above as a default) |
1349 |
|
|
// If far end doesn't support then refresher must be local |
1350 |
sgodin |
4691 |
mSessionRefresher = true; |
1351 |
jason |
4010 |
} |
1352 |
sgodin |
3392 |
|
1353 |
sgodin |
4691 |
// Update MinSE if specified and longer than current value |
1354 |
|
|
if(msg.exists(h_MinSE)) |
1355 |
sgodin |
3392 |
{ |
1356 |
sgodin |
4691 |
mMinSE = resipMax(mMinSE, msg.header(h_MinSE).value()); |
1357 |
sgodin |
3392 |
} |
1358 |
sgodin |
4691 |
|
1359 |
|
|
startSessionTimer(); |
1360 |
sgodin |
3392 |
} |
1361 |
|
|
} |
1362 |
|
|
|
1363 |
jason |
4010 |
void |
1364 |
|
|
InviteSession::handleSessionTimerRequest(SipMessage &response, const SipMessage& request) |
1365 |
sgodin |
3392 |
{ |
1366 |
jason |
4010 |
assert(request.header(h_CSeq).method() == INVITE || request.header(h_CSeq).method() == UPDATE); |
1367 |
|
|
|
1368 |
sgodin |
3392 |
// If session timers are locally supported then add necessary headers to response |
1369 |
jason |
4010 |
if(mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::Timer))) |
1370 |
sgodin |
3392 |
{ |
1371 |
sgodin |
4691 |
setSessionTimerPreferences(); |
1372 |
sgodin |
3392 |
|
1373 |
|
|
// Check if far-end supports |
1374 |
|
|
bool farEndSupportsTimer = false; |
1375 |
|
|
if(request.exists(h_Supporteds) && request.header(h_Supporteds).find(Token(Symbols::Timer))) |
1376 |
|
|
{ |
1377 |
|
|
farEndSupportsTimer = true; |
1378 |
|
|
if(request.exists(h_SessionExpires)) |
1379 |
|
|
{ |
1380 |
jason |
4010 |
// Use Session Interval requested by remote - if none then use local settings |
1381 |
sgodin |
3392 |
mSessionInterval = request.header(h_SessionExpires).value(); |
1382 |
|
|
if(request.header(h_SessionExpires).exists(p_refresher)) |
1383 |
|
|
{ |
1384 |
sgodin |
4691 |
mSessionRefresher = (request.header(h_SessionExpires).param(p_refresher) == Data("uas")); |
1385 |
sgodin |
3392 |
} |
1386 |
|
|
} |
1387 |
sgodin |
4691 |
|
1388 |
|
|
// Update MinSE if specified and longer than current value |
1389 |
|
|
if(request.exists(h_MinSE)) |
1390 |
|
|
{ |
1391 |
|
|
mMinSE = resipMax(mMinSE, request.header(h_MinSE).value()); |
1392 |
|
|
} |
1393 |
sgodin |
3392 |
} |
1394 |
jason |
4010 |
else |
1395 |
|
|
{ |
1396 |
|
|
// If far end doesn't support then refresher must be local |
1397 |
sgodin |
4691 |
mSessionRefresher = true; |
1398 |
jason |
4010 |
} |
1399 |
sgodin |
3392 |
|
1400 |
jason |
4010 |
// Add Session-Expires to response if required |
1401 |
sgodin |
3392 |
if(mSessionInterval >= 90) |
1402 |
|
|
{ |
1403 |
jason |
4010 |
if(farEndSupportsTimer) |
1404 |
sgodin |
3392 |
{ |
1405 |
jason |
4010 |
// If far end supports session-timer then require it, if not already present |
1406 |
|
|
if(!response.header(h_Requires).find(Token(Symbols::Timer))) |
1407 |
|
|
{ |
1408 |
|
|
response.header(h_Requires).push_back(Token(Symbols::Timer)); |
1409 |
|
|
} |
1410 |
sgodin |
3392 |
} |
1411 |
sgodin |
4691 |
setSessionTimerHeaders(response); |
1412 |
|
|
} |
1413 |
sgodin |
3392 |
|
1414 |
sgodin |
4691 |
startSessionTimer(); |
1415 |
sgodin |
3392 |
} |
1416 |
|
|
} |
1417 |
|
|
|
1418 |
jason |
4010 |
Data |
1419 |
|
|
InviteSession::toData(State state) |
1420 |
jason |
2856 |
{ |
1421 |
jason |
4010 |
switch (state) |
1422 |
derek |
3255 |
{ |
1423 |
jason |
4010 |
case Undefined: |
1424 |
|
|
return "InviteSession::Undefined"; |
1425 |
|
|
case Connected: |
1426 |
|
|
return "InviteSession::Connected"; |
1427 |
|
|
case SentUpdate: |
1428 |
|
|
return "InviteSession::SentUpdate"; |
1429 |
|
|
case SentUpdateGlare: |
1430 |
|
|
return "InviteSession::SentUpdateGlare"; |
1431 |
|
|
case SentReinvite: |
1432 |
|
|
return "InviteSession::SentReinvite"; |
1433 |
|
|
case SentReinviteGlare: |
1434 |
|
|
return "InviteSession::SentReinviteGlare"; |
1435 |
|
|
case ReceivedUpdate: |
1436 |
|
|
return "InviteSession::ReceivedUpdate"; |
1437 |
|
|
case ReceivedReinvite: |
1438 |
|
|
return "InviteSession::ReceivedReinvite"; |
1439 |
|
|
case ReceivedReinviteNoOffer: |
1440 |
|
|
return "InviteSession::ReceivedReinviteNoOffer"; |
1441 |
|
|
case Answered: |
1442 |
|
|
return "InviteSession::Answered"; |
1443 |
|
|
case WaitingToOffer: |
1444 |
|
|
return "InviteSession::WaitingToOffer"; |
1445 |
|
|
case WaitingToTerminate: |
1446 |
|
|
return "InviteSession::WaitingToTerminate"; |
1447 |
derek |
2961 |
case Terminated: |
1448 |
jason |
4010 |
return "InviteSession::Terminated"; |
1449 |
jason |
2856 |
|
1450 |
jason |
4010 |
case UAC_Start: |
1451 |
|
|
return "UAC_Start"; |
1452 |
|
|
case UAS_Offer: |
1453 |
|
|
return "UAS_Offer"; |
1454 |
|
|
case UAS_OfferProvidedAnswer: |
1455 |
|
|
return "UAS_OfferProvidedAnswer"; |
1456 |
|
|
case UAS_EarlyOffer: |
1457 |
|
|
return "UAS_EarlyOffer"; |
1458 |
|
|
case UAS_EarlyProvidedAnswer: |
1459 |
|
|
return "UAS_EarlyProvidedAnswer"; |
1460 |
|
|
case UAS_NoOffer: |
1461 |
|
|
return "UAS_NoOffer"; |
1462 |
|
|
case UAS_ProvidedOffer: |
1463 |
|
|
return "UAS_ProvidedOffer"; |
1464 |
|
|
case UAS_EarlyNoOffer: |
1465 |
|
|
return "UAS_EarlyNoOffer"; |
1466 |
|
|
case UAS_EarlyProvidedOffer: |
1467 |
|
|
return "UAS_EarlyProvidedOffer"; |
1468 |
|
|
case UAS_Accepted: |
1469 |
|
|
return "UAS_Accepted"; |
1470 |
|
|
case UAS_WaitingToOffer: |
1471 |
|
|
return "UAS_WaitingToOffer"; |
1472 |
|
|
case UAS_AcceptedWaitingAnswer: |
1473 |
|
|
return "UAS_AcceptedWaitingAnswer"; |
1474 |
|
|
case UAC_Early: |
1475 |
|
|
return "UAC_Early"; |
1476 |
|
|
case UAC_EarlyWithOffer: |
1477 |
|
|
return "UAC_EarlyWithOffer"; |
1478 |
|
|
case UAC_EarlyWithAnswer: |
1479 |
|
|
return "UAC_EarlyWithAnswer"; |
1480 |
|
|
case UAC_Answered: |
1481 |
|
|
return "UAC_Answered"; |
1482 |
|
|
case UAC_SentUpdateEarly: |
1483 |
|
|
return "UAC_SentUpdateEarly"; |
1484 |
|
|
case UAC_SentUpdateConnected: |
1485 |
|
|
return "UAC_SentUpdateConnected"; |
1486 |
|
|
case UAC_ReceivedUpdateEarly: |
1487 |
|
|
return "UAC_ReceivedUpdateEarly"; |
1488 |
|
|
case UAC_SentAnswer: |
1489 |
|
|
return "UAC_SentAnswer"; |
1490 |
|
|
case UAC_QueuedUpdate: |
1491 |
|
|
return "UAC_QueuedUpdate"; |
1492 |
|
|
case UAC_Cancelled: |
1493 |
|
|
return "UAC_Cancelled"; |
1494 |
sgodin |
3332 |
|
1495 |
jason |
4010 |
case UAS_Start: |
1496 |
|
|
return "UAS_Start"; |
1497 |
|
|
case UAS_OfferReliable: |
1498 |
|
|
return "UAS_OfferReliable"; |
1499 |
|
|
case UAS_NoOfferReliable: |
1500 |
|
|
return "UAS_NoOfferReliable"; |
1501 |
|
|
case UAS_FirstSentOfferReliable: |
1502 |
|
|
return "UAS_FirstSentOfferReliable"; |
1503 |
|
|
case UAS_FirstEarlyReliable: |
1504 |
|
|
return "UAS_FirstEarlyReliable"; |
1505 |
|
|
case UAS_EarlyReliable: |
1506 |
|
|
return "UAS_EarlyReliable"; |
1507 |
|
|
case UAS_SentUpdate: |
1508 |
|
|
return "UAS_SentUpdate"; |
1509 |
|
|
case UAS_SentUpdateAccepted: |
1510 |
|
|
return "UAS_SentUpdateAccepted"; |
1511 |
|
|
case UAS_ReceivedUpdate: |
1512 |
|
|
return "UAS_ReceivedUpdate"; |
1513 |
|
|
case UAS_ReceivedUpdateWaitingAnswer: |
1514 |
|
|
return "UAS_ReceivedUpdateWaitingAnswer"; |
1515 |
|
|
case UAS_WaitingToTerminate: |
1516 |
|
|
return "UAS_WaitingToTerminate"; |
1517 |
|
|
case UAS_WaitingToHangup: |
1518 |
|
|
return "UAS_WaitingToHangup"; |
1519 |
|
|
} |
1520 |
|
|
assert(0); |
1521 |
|
|
return "Undefined"; |
1522 |
|
|
} |
1523 |
sgodin |
3392 |
|
1524 |
|
|
|
1525 |
jason |
4010 |
void |
1526 |
|
|
InviteSession::transition(State target) |
1527 |
|
|
{ |
1528 |
|
|
InfoLog (<< "Transition " << toData(mState) << " -> " << toData(target)); |
1529 |
|
|
mState = target; |
1530 |
|
|
} |
1531 |
sgodin |
3392 |
|
1532 |
jason |
4010 |
bool |
1533 |
|
|
InviteSession::isReliable(const SipMessage& msg) |
1534 |
|
|
{ |
1535 |
|
|
// Ensure supported both locally and remotely |
1536 |
|
|
return msg.exists(h_Supporteds) && msg.header(h_Supporteds).find(Token(Symbols::C100rel)) && |
1537 |
|
|
mDum.getMasterProfile()->getSupportedOptionTags().find(Token(Symbols::C100rel)); |
1538 |
jason |
2856 |
} |
1539 |
|
|
|
1540 |
jason |
4010 |
std::auto_ptr<SdpContents> |
1541 |
|
|
InviteSession::getSdp(const SipMessage& msg) |
1542 |
derek |
3255 |
{ |
1543 |
jason |
4010 |
// !jf! this code doesn't yet work - definitely if USE_SSL=false |
1544 |
|
|
//Helper::ContentsSecAttrs attrs = Helper::extractFromPkcs7(msg, mDum.getSecurity()); |
1545 |
|
|
//return std::auto_ptr<SdpContents>(dynamic_cast<SdpContents*>(attrs.mContents.get())); |
1546 |
|
|
SdpContents* sdp = dynamic_cast<SdpContents*>(msg.getContents()); |
1547 |
|
|
if (sdp) |
1548 |
derek |
3255 |
{ |
1549 |
jason |
4010 |
SdpContents* cloned = static_cast<SdpContents*>(sdp->clone()); |
1550 |
|
|
return std::auto_ptr<SdpContents>(cloned); |
1551 |
derek |
3255 |
} |
1552 |
jason |
4010 |
else |
1553 |
|
|
{ |
1554 |
|
|
static std::auto_ptr<SdpContents> empty; |
1555 |
|
|
return empty; |
1556 |
|
|
} |
1557 |
derek |
3255 |
} |
1558 |
|
|
|
1559 |
jason |
4010 |
std::auto_ptr<SdpContents> |
1560 |
|
|
InviteSession::makeSdp(const SdpContents& sdp) |
1561 |
derek |
2955 |
{ |
1562 |
jason |
4010 |
return std::auto_ptr<SdpContents>(static_cast<SdpContents*>(sdp.clone())); |
1563 |
derek |
2955 |
} |
1564 |
jason |
2856 |
|
1565 |
daniel |
5068 |
auto_ptr<Contents> |
1566 |
|
|
InviteSession::makeSdp(const SdpContents& sdp, |
1567 |
|
|
const SdpContents* alternative) |
1568 |
|
|
{ |
1569 |
|
|
if (alternative) |
1570 |
|
|
{ |
1571 |
|
|
MultipartAlternativeContents* mac = new MultipartAlternativeContents; |
1572 |
|
|
mac->parts().push_back(alternative->clone()); |
1573 |
|
|
mac->parts().push_back(sdp.clone()); |
1574 |
|
|
return auto_ptr<Contents>(mac); |
1575 |
|
|
} |
1576 |
|
|
else |
1577 |
|
|
{ |
1578 |
|
|
return auto_ptr<Contents>(sdp.clone()); |
1579 |
|
|
} |
1580 |
|
|
} |
1581 |
|
|
|
1582 |
jason |
4010 |
void |
1583 |
daniel |
5068 |
InviteSession::setSdp(SipMessage& msg, const SdpContents& sdp, const SdpContents* alternative) |
1584 |
derek |
3112 |
{ |
1585 |
jason |
4010 |
// !jf! should deal with multipart here |
1586 |
derek |
3112 |
|
1587 |
jason |
4010 |
// This will clone the sdp since the InviteSession also wants to keep its own |
1588 |
|
|
// copy of the sdp around for the application to access |
1589 |
daniel |
5068 |
if (alternative) |
1590 |
|
|
{ |
1591 |
|
|
MultipartAlternativeContents* mac = new MultipartAlternativeContents; |
1592 |
|
|
mac->parts().push_back(alternative->clone()); |
1593 |
|
|
mac->parts().push_back(sdp.clone()); |
1594 |
|
|
msg.setContents(auto_ptr<Contents>(mac)); |
1595 |
|
|
} |
1596 |
|
|
else |
1597 |
|
|
{ |
1598 |
|
|
msg.setContents(&sdp); |
1599 |
|
|
} |
1600 |
derek |
3112 |
} |
1601 |
|
|
|
1602 |
daniel |
5068 |
void |
1603 |
|
|
InviteSession::setSdp(SipMessage& msg, const Contents* sdp) |
1604 |
|
|
{ |
1605 |
|
|
assert(sdp); |
1606 |
|
|
msg.setContents(sdp); |
1607 |
|
|
} |
1608 |
|
|
|
1609 |
jason |
4010 |
InviteSession::Event |
1610 |
|
|
InviteSession::toEvent(const SipMessage& msg, const SdpContents* sdp) |
1611 |
jason |
2621 |
{ |
1612 |
jason |
4010 |
MethodTypes method = msg.header(h_CSeq).method(); |
1613 |
|
|
int code = msg.isResponse() ? msg.header(h_StatusLine).statusCode() : 0; |
1614 |
|
|
bool reliable = isReliable(msg); |
1615 |
|
|
bool sentOffer = mProposedLocalSdp.get(); |
1616 |
|
|
|
1617 |
|
|
if (code == 481 || code == 408) |
1618 |
derek |
2961 |
{ |
1619 |
jason |
4010 |
return OnGeneralFailure; |
1620 |
|
|
} |
1621 |
|
|
else if (code >= 300 && code <= 399) |
1622 |
|
|
{ |
1623 |
|
|
return OnRedirect; |
1624 |
|
|
} |
1625 |
|
|
else if (method == INVITE && code == 0) |
1626 |
|
|
{ |
1627 |
|
|
if (sdp) |
1628 |
|
|
{ |
1629 |
|
|
if (reliable) |
1630 |
sgodin |
3363 |
{ |
1631 |
jason |
4010 |
return OnInviteReliableOffer; |
1632 |
|
|
} |
1633 |
|
|
else |
1634 |
|
|
{ |
1635 |
|
|
return OnInviteOffer; |
1636 |
|
|
} |
1637 |
|
|
} |
1638 |
|
|
else |
1639 |
|
|
{ |
1640 |
|
|
if (reliable) |
1641 |
|
|
{ |
1642 |
|
|
return OnInviteReliable; |
1643 |
|
|
} |
1644 |
|
|
else |
1645 |
|
|
{ |
1646 |
|
|
return OnInvite; |
1647 |
|
|
} |
1648 |
|
|
} |
1649 |
|
|
} |
1650 |
|
|
else if (method == INVITE && code > 100 && code < 200) // !kh! 100 is handled by transaction layer. |
1651 |
|
|
{ |
1652 |
|
|
if (reliable) |
1653 |
|
|
{ |
1654 |
|
|
if (sdp) |
1655 |
|
|
{ |
1656 |
|
|
if (sentOffer) |
1657 |
sgodin |
3363 |
{ |
1658 |
jason |
4010 |
return On1xxAnswer; |
1659 |
sgodin |
3363 |
} |
1660 |
|
|
else |
1661 |
|
|
{ |
1662 |
jason |
4010 |
return On1xxOffer; |
1663 |
sgodin |
3363 |
} |
1664 |
|
|
} |
1665 |
|
|
else |
1666 |
|
|
{ |
1667 |
jason |
4010 |
return On1xx; |
1668 |
sgodin |
3363 |
} |
1669 |
jason |
4010 |
} |
1670 |
|
|
else |
1671 |
|
|
{ |
1672 |
|
|
if (sdp) |
1673 |
sgodin |
3363 |
{ |
1674 |
jason |
4010 |
return On1xxEarly; |
1675 |
sgodin |
3363 |
} |
1676 |
|
|
else |
1677 |
|
|
{ |
1678 |
jason |
4010 |
return On1xx; |
1679 |
sgodin |
3363 |
} |
1680 |
jason |
4010 |
} |
1681 |
derek |
2961 |
} |
1682 |
jason |
4010 |
else if (method == INVITE && code >= 200 && code < 300) |
1683 |
jason |
2809 |
{ |
1684 |
jason |
4010 |
if (sdp) |
1685 |
|
|
{ |
1686 |
|
|
if (sentOffer) |
1687 |
jason |
2809 |
{ |
1688 |
jason |
4010 |
return On2xxAnswer; |
1689 |
jason |
2809 |
} |
1690 |
|
|
else |
1691 |
|
|
{ |
1692 |
jason |
4010 |
return On2xxOffer; |
1693 |
jason |
2809 |
} |
1694 |
jason |
4010 |
} |
1695 |
|
|
else |
1696 |
|
|
{ |
1697 |
|
|
return On2xx; |
1698 |
|
|
} |
1699 |
jason |
2809 |
} |
1700 |
sgodin |
4394 |
else if (method == INVITE && code == 422) |
1701 |
|
|
{ |
1702 |
|
|
return On422Invite; |
1703 |
|
|
} |
1704 |
jason |
4010 |
else if (method == INVITE && code == 487) |
1705 |
derek |
3293 |
{ |
1706 |
jason |
4010 |
return On487Invite; |
1707 |
derek |
3293 |
} |
1708 |
jason |
4010 |
else if (method == INVITE && code == 489) |
1709 |
derek |
3276 |
{ |
1710 |
jason |
4010 |
return On489Invite; |
1711 |
derek |
3276 |
} |
1712 |
jason |
4010 |
else if (method == INVITE && code == 491) |
1713 |
derek |
2965 |
{ |
1714 |
jason |
4010 |
return On491Invite; |
1715 |
derek |
2965 |
} |
1716 |
jason |
4010 |
else if (method == INVITE && code >= 400) |
1717 |
derek |
2965 |
{ |
1718 |
jason |
4010 |
return OnInviteFailure; |
1719 |
|
|
} |
1720 |
|
|
else if (method == ACK) |
1721 |
|
|
{ |
1722 |
|
|
if (sdp) |
1723 |
derek |
2965 |
{ |
1724 |
jason |
4010 |
return OnAckAnswer; |
1725 |
derek |
2965 |
} |
1726 |
derek |
2978 |
else |
1727 |
|
|
{ |
1728 |
jason |
4010 |
return OnAck; |
1729 |
derek |
2978 |
} |
1730 |
jason |
4010 |
} |
1731 |
|
|
else if (method == CANCEL && code == 0) |
1732 |
jason |
2809 |
{ |
1733 |
jason |
4010 |
return OnCancel; |
1734 |
jason |
2809 |
} |
1735 |
jason |
4010 |
else if (method == CANCEL && code / 200 == 1) |
1736 |
sgodin |
3338 |
{ |
1737 |
jason |
4010 |
return On200Cancel; |
1738 |
sgodin |
3338 |
} |
1739 |
jason |
4010 |
else if (method == CANCEL && code >= 400) |
1740 |
sgodin |
3338 |
{ |
1741 |
jason |
4010 |
return OnCancelFailure; |
1742 |
sgodin |
3338 |
} |
1743 |
jason |
4010 |
else if (method == BYE && code == 0) |
1744 |
jason |
2846 |
{ |
1745 |
jason |
4010 |
return OnBye; |
1746 |
jason |
2846 |
} |
1747 |
jason |
4010 |
else if (method == BYE && code / 200 == 1) |
1748 |
derek |
3101 |
{ |
1749 |
jason |
4010 |
return On200Bye; |
1750 |
derek |
3101 |
} |
1751 |
jason |
4010 |
else if (method == PRACK && code == 0) |
1752 |
|
|
{ |
1753 |
|
|
return OnPrack; |
1754 |
|
|
} |
1755 |
|
|
else if (method == PRACK && code / 200 == 1) |
1756 |
|
|
{ |
1757 |
|
|
return On200Prack; |
1758 |
|
|
} |
1759 |
|
|
else if (method == UPDATE && code == 0) |
1760 |
|
|
{ |
1761 |
sgodin |
4369 |
if (sdp) |
1762 |
|
|
{ |
1763 |
|
|
return OnUpdateOffer; |
1764 |
|
|
} |
1765 |
|
|
else |
1766 |
|
|
{ |
1767 |
|
|
return OnUpdate; |
1768 |
|
|
} |
1769 |
jason |
4010 |
} |
1770 |
|
|
else if (method == UPDATE && code / 200 == 1) |
1771 |
|
|
{ |
1772 |
|
|
return On200Update; |
1773 |
|
|
} |
1774 |
sgodin |
4394 |
else if (method == UPDATE && code == 422) |
1775 |
|
|
{ |
1776 |
|
|
return On422Update; |
1777 |
|
|
} |
1778 |
jason |
4010 |
else if (method == UPDATE && code == 489) |
1779 |
|
|
{ |
1780 |
|
|
return On489Update; |
1781 |
|
|
} |
1782 |
|
|
else if (method == UPDATE && code == 491) |
1783 |
|
|
{ |
1784 |
|
|
return On491Update; |
1785 |
|
|
} |
1786 |
|
|
else if (method == UPDATE && code >= 400) |
1787 |
|
|
{ |
1788 |
|
|
return OnUpdateRejected; |
1789 |
|
|
} |
1790 |
|
|
else |
1791 |
|
|
{ |
1792 |
sgodin |
5012 |
//assert(0); // dispatchOthers will throw if the message type is really unknown |
1793 |
jason |
4010 |
return Unknown; |
1794 |
|
|
} |
1795 |
derek |
2965 |
} |
1796 |
|
|
|
1797 |
jason |
4010 |
void InviteSession::sendAck(const SdpContents *sdp) |
1798 |
derek |
2955 |
{ |
1799 |
jason |
4010 |
SipMessage ack; |
1800 |
|
|
mDialog.makeRequest(ack, ACK); |
1801 |
|
|
if(sdp != 0) |
1802 |
derek |
3255 |
{ |
1803 |
jason |
4010 |
setSdp(ack, *sdp); |
1804 |
derek |
3255 |
} |
1805 |
jason |
4010 |
InfoLog (<< "Sending " << ack.brief()); |
1806 |
|
|
mDialog.send(ack); |
1807 |
derek |
2981 |
} |
1808 |
|
|
|
1809 |
jason |
4010 |
void InviteSession::sendBye() |
1810 |
derek |
2849 |
{ |
1811 |
jason |
4010 |
SipMessage bye; |
1812 |
|
|
mDialog.makeRequest(bye, BYE); |
1813 |
|
|
InfoLog (<< "Sending " << bye.brief()); |
1814 |
|
|
mDialog.send(bye); |
1815 |
|
|
} |
1816 |
derek |
2992 |
|
1817 |
daniel |
5068 |
DialogUsageManager::EncryptionLevel InviteSession::getEncryptionLevel(const SipMessage& msg) |
1818 |
|
|
{ |
1819 |
|
|
DialogUsageManager::EncryptionLevel level = DialogUsageManager::None; |
1820 |
|
|
const SecurityAttributes* secAttr = msg.getSecurityAttributes(); |
1821 |
|
|
if (secAttr) |
1822 |
|
|
{ |
1823 |
|
|
SignatureStatus sig = secAttr->getSignatureStatus(); |
1824 |
|
|
bool sign = (SignatureTrusted == sig || SignatureCATrusted == sig || SignatureSelfSigned == sig); |
1825 |
|
|
bool encrypted = secAttr->isEncrypted(); |
1826 |
|
|
if (encrypted && sign ) level = DialogUsageManager::SignAndEncrypt; |
1827 |
|
|
else if (encrypted) level = DialogUsageManager::Encrypt; |
1828 |
|
|
else if (sign) level = DialogUsageManager::Sign; |
1829 |
|
|
} |
1830 |
|
|
return level; |
1831 |
|
|
} |
1832 |
derek |
2992 |
|
1833 |
daniel |
5068 |
void InviteSession::setCurrentLocalSdp(const SipMessage& msg) |
1834 |
|
|
{ |
1835 |
|
|
assert(mProposedLocalSdp.get()); |
1836 |
|
|
if (dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get())) |
1837 |
|
|
{ |
1838 |
|
|
if (DialogUsageManager::Encrypt == getEncryptionLevel(msg) || DialogUsageManager::SignAndEncrypt == getEncryptionLevel(msg)) |
1839 |
|
|
{ |
1840 |
|
|
mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().back()->clone())); |
1841 |
|
|
} |
1842 |
|
|
else |
1843 |
|
|
{ |
1844 |
|
|
mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>((dynamic_cast<MultipartAlternativeContents*>(mProposedLocalSdp.get()))->parts().front()->clone())); |
1845 |
|
|
} |
1846 |
|
|
} |
1847 |
|
|
else |
1848 |
|
|
{ |
1849 |
|
|
mCurrentLocalSdp = auto_ptr<SdpContents>(static_cast<SdpContents*>(mProposedLocalSdp.get()->clone())); |
1850 |
|
|
} |
1851 |
|
|
mProposedLocalSdp.release(); |
1852 |
|
|
} |
1853 |
|
|
|
1854 |
|
|
|
1855 |
davidb |
2575 |
/* ==================================================================== |
1856 |
jason |
4010 |
* The Vovida Software License, Version 1.0 |
1857 |
|
|
* |
1858 |
davidb |
2575 |
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. |
1859 |
jason |
4010 |
* |
1860 |
davidb |
2575 |
* Redistribution and use in source and binary forms, with or without |
1861 |
|
|
* modification, are permitted provided that the following conditions |
1862 |
|
|
* are met: |
1863 |
jason |
4010 |
* |
1864 |
davidb |
2575 |
* 1. Redistributions of source code must retain the above copyright |
1865 |
|
|
* notice, this list of conditions and the following disclaimer. |
1866 |
jason |
4010 |
* |
1867 |
davidb |
2575 |
* 2. Redistributions in binary form must reproduce the above copyright |
1868 |
|
|
* notice, this list of conditions and the following disclaimer in |
1869 |
|
|
* the documentation and/or other materials provided with the |
1870 |
|
|
|
1871 |
|
|
* distribution. |
1872 |
jason |
4010 |
* |
1873 |
davidb |
2575 |
* 3. The names "VOCAL", "Vovida Open Communication Application Library", |
1874 |
|
|
* and "Vovida Open Communication Application Library (VOCAL)" must |
1875 |
|
|
* not be used to endorse or promote products derived from this |
1876 |
|
|
* software without prior written permission. For written |
1877 |
|
|
* permission, please contact vocal@vovida.org. |
1878 |
|
|
* |
1879 |
|
|
* 4. Products derived from this software may not be called "VOCAL", nor |
1880 |
|
|
* may "VOCAL" appear in their name, without prior written |
1881 |
|
|
* permission of Vovida Networks, Inc. |
1882 |
jason |
4010 |
* |
1883 |
davidb |
2575 |
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED |
1884 |
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
1885 |
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND |
1886 |
|
|
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA |
1887 |
|
|
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES |
1888 |
|
|
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, |
1889 |
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
1890 |
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
1891 |
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
1892 |
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
1893 |
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
1894 |
|
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
1895 |
|
|
* DAMAGE. |
1896 |
jason |
4010 |
* |
1897 |
davidb |
2575 |
* ==================================================================== |
1898 |
jason |
4010 |
* |
1899 |
davidb |
2575 |
* This software consists of voluntary contributions made by Vovida |
1900 |
|
|
* Networks, Inc. and many individuals on behalf of Vovida Networks, |
1901 |
|
|
* Inc. For more information on Vovida Networks, Inc., please see |
1902 |
|
|
* <http://www.vovida.org/>. |
1903 |
|
|
* |
1904 |
|
|
*/ |