Thu, 15 Jan 2015 15:59:08 +0100
Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include <errno.h>
6 #include <string>
7 #include <prcvar.h>
8 #include <prlock.h>
10 #include "CSFLog.h"
12 #include "CC_SIPCCDevice.h"
13 #include "CC_SIPCCDeviceInfo.h"
14 #include "CC_SIPCCFeatureInfo.h"
15 #include "CC_SIPCCLine.h"
16 #include "CC_SIPCCLineInfo.h"
17 #include "CC_SIPCCCallInfo.h"
18 #include "CallControlManagerImpl.h"
19 #include "csf_common.h"
21 extern "C"
22 {
23 #include "config_api.h"
24 }
27 static const char logTag[] = "CallControlManager";
29 using namespace std;
30 using namespace CSFUnified;
32 namespace CSF
33 {
36 CallControlManagerImpl::CallControlManagerImpl()
37 : m_lock("CallControlManagerImpl"),
38 multiClusterMode(false),
39 sipccLoggingMask(0xFFFFFFFF),
40 authenticationStatus(AuthenticationStatusEnum::eNotAuthenticated),
41 connectionState(ConnectionStatusEnum::eIdle)
42 {
43 CSFLogInfo(logTag, "CallControlManagerImpl()");
44 }
46 CallControlManagerImpl::~CallControlManagerImpl()
47 {
48 CSFLogInfo(logTag, "~CallControlManagerImpl()");
49 destroy();
50 }
52 bool CallControlManagerImpl::destroy()
53 {
54 CSFLogInfo(logTag, "destroy()");
55 bool retval = disconnect();
56 if(retval == false)
57 {
58 return retval;
59 }
60 return retval;
61 }
63 // Observers
64 void CallControlManagerImpl::addCCObserver ( CC_Observer * observer )
65 {
66 mozilla::MutexAutoLock lock(m_lock);
67 if (observer == nullptr)
68 {
69 CSFLogError(logTag, "NULL value for \"observer\" passed to addCCObserver().");
70 return;
71 }
73 ccObservers.insert(observer);
74 }
76 void CallControlManagerImpl::removeCCObserver ( CC_Observer * observer )
77 {
78 mozilla::MutexAutoLock lock(m_lock);
79 ccObservers.erase(observer);
80 }
82 void CallControlManagerImpl::addECCObserver ( ECC_Observer * observer )
83 {
84 mozilla::MutexAutoLock lock(m_lock);
85 if (observer == nullptr)
86 {
87 CSFLogError(logTag, "NULL value for \"observer\" passed to addECCObserver().");
88 return;
89 }
91 eccObservers.insert(observer);
92 }
94 void CallControlManagerImpl::removeECCObserver ( ECC_Observer * observer )
95 {
96 mozilla::MutexAutoLock lock(m_lock);
97 eccObservers.erase(observer);
98 }
100 void CallControlManagerImpl::setMultiClusterMode(bool allowMultipleClusters)
101 {
102 CSFLogInfo(logTag, "setMultiClusterMode(%s)",
103 allowMultipleClusters ? "TRUE" : "FALSE");
104 multiClusterMode = allowMultipleClusters;
105 }
107 void CallControlManagerImpl::setSIPCCLoggingMask(const cc_int32_t mask)
108 {
109 CSFLogInfo(logTag, "setSIPCCLoggingMask(%u)", mask);
110 sipccLoggingMask = mask;
111 }
113 void CallControlManagerImpl::setAuthenticationString(const std::string &authString)
114 {
115 CSFLogInfo(logTag, "setAuthenticationString()");
116 this->authString = authString;
117 }
119 void CallControlManagerImpl::setSecureCachePath(const std::string &secureCachePath)
120 {
121 CSFLogInfo(logTag, "setSecureCachePath(%s)", secureCachePath.c_str());
122 this->secureCachePath = secureCachePath;
123 }
125 // Add local codecs
126 void CallControlManagerImpl::setAudioCodecs(int codecMask)
127 {
128 CSFLogDebug(logTag, "setAudioCodecs %X", codecMask);
130 VcmSIPCCBinding::setAudioCodecs(codecMask);
131 }
133 void CallControlManagerImpl::setVideoCodecs(int codecMask)
134 {
135 CSFLogDebug(logTag, "setVideoCodecs %X", codecMask);
137 VcmSIPCCBinding::setVideoCodecs(codecMask);
138 }
140 AuthenticationStatusEnum::AuthenticationStatus CallControlManagerImpl::getAuthenticationStatus()
141 {
142 return authenticationStatus;
143 }
145 bool CallControlManagerImpl::registerUser( const std::string& deviceName, const std::string& user, const std::string& password, const std::string& domain )
146 {
147 setConnectionState(ConnectionStatusEnum::eRegistering);
149 CSFLogInfo(logTag, "registerUser(%s, %s )", user.c_str(), domain.c_str());
150 if(phone != nullptr)
151 {
152 setConnectionState(ConnectionStatusEnum::eReady);
154 CSFLogError(logTag, "registerUser() failed - already connected!");
155 return false;
156 }
158 softPhone = CC_SIPCCServicePtr(new CC_SIPCCService());
159 phone = softPhone;
160 phone->init(user, password, domain, deviceName);
161 softPhone->setLoggingMask(sipccLoggingMask);
162 phone->addCCObserver(this);
164 phone->setP2PMode(false);
166 bool bStarted = phone->startService();
167 if (!bStarted) {
168 setConnectionState(ConnectionStatusEnum::eFailed);
169 } else {
170 setConnectionState(ConnectionStatusEnum::eReady);
171 }
173 return bStarted;
174 }
176 bool CallControlManagerImpl::startP2PMode(const std::string& user)
177 {
178 setConnectionState(ConnectionStatusEnum::eRegistering);
180 CSFLogInfo(logTag, "startP2PMode(%s)", user.c_str());
181 if(phone != nullptr)
182 {
183 setConnectionState(ConnectionStatusEnum::eReady);
185 CSFLogError(logTag, "startP2PMode() failed - already started in p2p mode!");
186 return false;
187 }
189 softPhone = CC_SIPCCServicePtr(new CC_SIPCCService());
190 phone = softPhone;
191 phone->init(user, "", "127.0.0.1", "sipdevice");
192 softPhone->setLoggingMask(sipccLoggingMask);
193 phone->addCCObserver(this);
195 phone->setP2PMode(true);
197 bool bStarted = phone->startService();
198 if (!bStarted) {
199 setConnectionState(ConnectionStatusEnum::eFailed);
200 } else {
201 setConnectionState(ConnectionStatusEnum::eReady);
202 }
204 return bStarted;
205 }
207 bool CallControlManagerImpl::startSDPMode()
208 {
209 CSFLogInfo(logTag, "startSDPMode");
210 if(phone != nullptr)
211 {
212 CSFLogError(logTag, "%s failed - already started in SDP mode!",__FUNCTION__);
213 return false;
214 }
215 softPhone = CC_SIPCCServicePtr(new CC_SIPCCService());
216 phone = softPhone;
217 phone->init("JSEP", "", "127.0.0.1", "sipdevice");
218 softPhone->setLoggingMask(sipccLoggingMask);
219 phone->addCCObserver(this);
220 phone->setSDPMode(true);
222 return phone->startService();
223 }
225 bool CallControlManagerImpl::disconnect()
226 {
227 CSFLogInfo(logTag, "disconnect()");
228 if(phone == nullptr)
229 return true;
231 connectionState = ConnectionStatusEnum::eIdle;
232 phone->removeCCObserver(this);
233 phone->stop();
234 phone->destroy();
235 phone = nullptr;
236 softPhone = nullptr;
238 return true;
239 }
241 std::string CallControlManagerImpl::getPreferredDeviceName()
242 {
243 return preferredDevice;
244 }
246 std::string CallControlManagerImpl::getPreferredLineDN()
247 {
248 return preferredLineDN;
249 }
251 ConnectionStatusEnum::ConnectionStatus CallControlManagerImpl::getConnectionStatus()
252 {
253 return connectionState;
254 }
256 std::string CallControlManagerImpl::getCurrentServer()
257 {
258 return "";
259 }
261 // Currently controlled device
262 CC_DevicePtr CallControlManagerImpl::getActiveDevice()
263 {
264 if(phone != nullptr)
265 return phone->getActiveDevice();
267 return CC_DevicePtr();
268 }
270 // All known devices
271 PhoneDetailsVtrPtr CallControlManagerImpl::getAvailablePhoneDetails()
272 {
273 PhoneDetailsVtrPtr result = PhoneDetailsVtrPtr(new PhoneDetailsVtr());
274 for(PhoneDetailsMap::iterator it = phoneDetailsMap.begin(); it != phoneDetailsMap.end(); it++)
275 {
276 PhoneDetailsPtr details = it->second.get();
277 result->push_back(details);
278 }
279 return result;
280 }
282 PhoneDetailsPtr CallControlManagerImpl::getAvailablePhoneDetails(const std::string& deviceName)
283 {
284 PhoneDetailsMap::iterator it = phoneDetailsMap.find(deviceName);
285 if(it != phoneDetailsMap.end())
286 {
287 return it->second.get();
288 }
289 return PhoneDetailsPtr();
290 }
291 // Media setup
292 VideoControlPtr CallControlManagerImpl::getVideoControl()
293 {
294 if(phone != nullptr)
295 return phone->getVideoControl();
297 return VideoControlPtr();
298 }
300 AudioControlPtr CallControlManagerImpl::getAudioControl()
301 {
302 if(phone != nullptr)
303 return phone->getAudioControl();
305 return AudioControlPtr();
306 }
308 bool CallControlManagerImpl::setProperty(ConfigPropertyKeysEnum::ConfigPropertyKeys key, std::string& value)
309 {
310 unsigned long strtoul_result;
311 char *strtoul_end;
313 CSFLogInfo(logTag, "setProperty( %s )", value.c_str());
315 if (key == ConfigPropertyKeysEnum::eLocalVoipPort) {
316 errno = 0;
317 strtoul_result = strtoul(value.c_str(), &strtoul_end, 10);
319 if (errno || value.c_str() == strtoul_end || strtoul_result > USHRT_MAX) {
320 return false;
321 }
323 CCAPI_Config_set_local_voip_port((int) strtoul_result);
324 } else if (key == ConfigPropertyKeysEnum::eRemoteVoipPort) {
325 errno = 0;
326 strtoul_result = strtoul(value.c_str(), &strtoul_end, 10);
328 if (errno || value.c_str() == strtoul_end || strtoul_result > USHRT_MAX) {
329 return false;
330 }
332 CCAPI_Config_set_remote_voip_port((int) strtoul_result);
333 } else if (key == ConfigPropertyKeysEnum::eTransport) {
334 if (value == "tcp")
335 CCAPI_Config_set_transport_udp(false);
336 else
337 CCAPI_Config_set_transport_udp(true);
338 }
340 return true;
341 }
343 std::string CallControlManagerImpl::getProperty(ConfigPropertyKeysEnum::ConfigPropertyKeys key)
344 {
345 std::string retValue = "NONESET";
346 char tmpString[11];
348 CSFLogInfo(logTag, "getProperty()");
350 if (key == ConfigPropertyKeysEnum::eLocalVoipPort) {
351 csf_sprintf(tmpString, sizeof(tmpString), "%u", CCAPI_Config_get_local_voip_port());
352 retValue = tmpString;
353 } else if (key == ConfigPropertyKeysEnum::eRemoteVoipPort) {
354 csf_sprintf(tmpString, sizeof(tmpString), "%u", CCAPI_Config_get_remote_voip_port());
355 retValue = tmpString;
356 } else if (key == ConfigPropertyKeysEnum::eVersion) {
357 const char* version = CCAPI_Config_get_version();
358 retValue = version;
359 }
361 return retValue;
362 }
363 /*
364 There are a number of factors that determine PhoneAvailabilityType::PhoneAvailability. The supported states for this enum are:
365 { eUnknown, eAvailable, eUnAvailable, eNotAllowed }. eUnknown is the default value, which is set when there is no information
366 available that would otherwise determine the availability value. The factors that can influence PhoneAvailability are:
367 phone mode, and for a given device (described by DeviceInfo) the model, and the name of the device. For phone control mode, the
368 device registration and whether CUCM says the device is CTI controllable (or not) is a factor.
370 For Phone Control mode the state machine is:
372 is blacklisted model name? -> Yes -> NOT_ALLOWED
373 (see Note1 below)
374 ||
375 \/
376 No
377 ||
378 \/
379 is CTI Controllable?
380 (determined from CUCM) -> No -> NOT_ALLOWED
381 ||
382 \/
383 Yes
384 ||
385 \/
386 Can we tell if it's registered? -> No -> ?????? TODO: Seems to depends on other factors (look at suggestedAvailability parameter
387 || in DeviceSubProviderImpl.addOrUpdateDevice() in CSF1G Java code.
388 \/
389 Yes
390 ||
391 \/
392 is Registered?
393 (determined from CUCM) -> No -> NOT_AVAILABLE
394 ||
395 \/
396 Yes
397 ||
398 \/
399 AVAILABLE
401 ========
403 For Softphone mode the state machine is:
405 is device excluded?
406 (based on "ExcludedDevices" -> Yes -> NOT_ALLOWED
407 config settings
408 (see Note2 below))
409 ||
410 \/
411 No
412 ||
413 \/
414 isSoftphone?
418 Note1: model name has to match completely, ie it's not a sub-string match, but we are ignoring case. So, if the blacklist
419 contains a string "Cisco Unified Personal Communicator" then the model has to match this completely (but can be a
420 different case) to be a match. In CSF1G the blacklist is hard-wired to:
421 { "Cisco Unified Personal Communicator",
422 "Cisco Unified Client Services Framework",
423 "Client Services Framework",
424 "Client Services Core" }
426 Note2: The "ExcludedDevices" is a comma-separated list of device name prefixes (not model name). Unlike the above, this is
427 a sub-string match, but only a "starts with" sub-string match, not anywhere in the string. If the device name
428 is a complete match then this is also excluded, ie doesn't have to be a sub-string. For example, if the
429 ExcludeDevices list contains { "ECP", "UPC" } then assuming we're in softphone mode, then any device whose
430 name starts with the strings ECP or UPC, or whose complete name is either of these will be deemed to be excluded
431 and will be marked as NOT_ALLOWED straightaway. In Phone Control mode the "ExcludedDevices" list i not taken into
432 account at all in the determination of availability.
434 Note3: isSoftphone() function
436 The config service provides a list of "blacklisted" device name prefixes, that is, if the name of the device starts with a
437 sub-string that matches an entry in the blacklist, then it is straightaway removed from the list? marked as NOT_ALLOWED.
438 */
440 // CC_Observers
441 void CallControlManagerImpl::onDeviceEvent(ccapi_device_event_e deviceEvent, CC_DevicePtr devicePtr, CC_DeviceInfoPtr info)
442 {
443 notifyDeviceEventObservers(deviceEvent, devicePtr, info);
444 }
445 void CallControlManagerImpl::onFeatureEvent(ccapi_device_event_e deviceEvent, CC_DevicePtr devicePtr, CC_FeatureInfoPtr info)
446 {
447 notifyFeatureEventObservers(deviceEvent, devicePtr, info);
448 }
449 void CallControlManagerImpl::onLineEvent(ccapi_line_event_e lineEvent, CC_LinePtr linePtr, CC_LineInfoPtr info)
450 {
451 notifyLineEventObservers(lineEvent, linePtr, info);
452 }
453 void CallControlManagerImpl::onCallEvent(ccapi_call_event_e callEvent, CC_CallPtr callPtr, CC_CallInfoPtr info)
454 {
455 notifyCallEventObservers(callEvent, callPtr, info);
456 }
459 void CallControlManagerImpl::notifyDeviceEventObservers (ccapi_device_event_e deviceEvent, CC_DevicePtr devicePtr, CC_DeviceInfoPtr info)
460 {
461 mozilla::MutexAutoLock lock(m_lock);
462 set<CC_Observer*>::const_iterator it = ccObservers.begin();
463 for ( ; it != ccObservers.end(); it++ )
464 {
465 (*it)->onDeviceEvent(deviceEvent, devicePtr, info);
466 }
467 }
469 void CallControlManagerImpl::notifyFeatureEventObservers (ccapi_device_event_e deviceEvent, CC_DevicePtr devicePtr, CC_FeatureInfoPtr info)
470 {
471 mozilla::MutexAutoLock lock(m_lock);
472 set<CC_Observer*>::const_iterator it = ccObservers.begin();
473 for ( ; it != ccObservers.end(); it++ )
474 {
475 (*it)->onFeatureEvent(deviceEvent, devicePtr, info);
476 }
477 }
479 void CallControlManagerImpl::notifyLineEventObservers (ccapi_line_event_e lineEvent, CC_LinePtr linePtr, CC_LineInfoPtr info)
480 {
481 mozilla::MutexAutoLock lock(m_lock);
482 set<CC_Observer*>::const_iterator it = ccObservers.begin();
483 for ( ; it != ccObservers.end(); it++ )
484 {
485 (*it)->onLineEvent(lineEvent, linePtr, info);
486 }
487 }
489 void CallControlManagerImpl::notifyCallEventObservers (ccapi_call_event_e callEvent, CC_CallPtr callPtr, CC_CallInfoPtr info)
490 {
491 mozilla::MutexAutoLock lock(m_lock);
492 set<CC_Observer*>::const_iterator it = ccObservers.begin();
493 for ( ; it != ccObservers.end(); it++ )
494 {
495 (*it)->onCallEvent(callEvent, callPtr, info);
496 }
497 }
499 void CallControlManagerImpl::notifyAvailablePhoneEvent (AvailablePhoneEventType::AvailablePhoneEvent event,
500 const PhoneDetailsPtr availablePhoneDetails)
501 {
502 mozilla::MutexAutoLock lock(m_lock);
503 set<ECC_Observer*>::const_iterator it = eccObservers.begin();
504 for ( ; it != eccObservers.end(); it++ )
505 {
506 (*it)->onAvailablePhoneEvent(event, availablePhoneDetails);
507 }
508 }
510 void CallControlManagerImpl::notifyAuthenticationStatusChange (AuthenticationStatusEnum::AuthenticationStatus status)
511 {
512 mozilla::MutexAutoLock lock(m_lock);
513 set<ECC_Observer*>::const_iterator it = eccObservers.begin();
514 for ( ; it != eccObservers.end(); it++ )
515 {
516 (*it)->onAuthenticationStatusChange(status);
517 }
518 }
520 void CallControlManagerImpl::notifyConnectionStatusChange(ConnectionStatusEnum::ConnectionStatus status)
521 {
522 mozilla::MutexAutoLock lock(m_lock);
523 set<ECC_Observer*>::const_iterator it = eccObservers.begin();
524 for ( ; it != eccObservers.end(); it++ )
525 {
526 (*it)->onConnectionStatusChange(status);
527 }
528 }
530 void CallControlManagerImpl::setConnectionState(ConnectionStatusEnum::ConnectionStatus status)
531 {
532 connectionState = status;
533 notifyConnectionStatusChange(status);
534 }
535 }