TURN-only option, and for unknown caller

Now, by default, we only use TURN for incoming calls from unknown
contacts. We will potentially directly connect for outgoing calls and
for incoming calls from known contacts.

Optionally, the user can disable direct connection altogether, at the
cost of some call quality.

// FREEBIE
pull/1/head
Michael Kirk 9 years ago
parent 7a3da3fa68
commit 4b8a5f8ccb

@ -231,6 +231,9 @@ protocol CallServiceObserver: class {
self.updateIsVideoEnabled() self.updateIsVideoEnabled()
} }
/**
* Choose whether to use CallKit or a Notification backed interface for calling.
*/
public func createCallUIAdapter() { public func createCallUIAdapter() {
AssertIsOnMainThread() AssertIsOnMainThread()
@ -299,7 +302,9 @@ protocol CallServiceObserver: class {
return getIceServers().then { iceServers -> Promise<HardenedRTCSessionDescription> in return getIceServers().then { iceServers -> Promise<HardenedRTCSessionDescription> in
Logger.debug("\(self.TAG) got ice servers:\(iceServers)") Logger.debug("\(self.TAG) got ice servers:\(iceServers)")
let peerConnectionClient = PeerConnectionClient(iceServers: iceServers, delegate: self, callDirection: .outgoing) let useTurnOnly = Environment.getCurrent().preferences.doCallsHideIPAddress()
let peerConnectionClient = PeerConnectionClient(iceServers: iceServers, delegate: self, callDirection: .outgoing, useTurnOnly: useTurnOnly)
assert(self.peerConnectionClient == nil, "Unexpected PeerConnectionClient instance") assert(self.peerConnectionClient == nil, "Unexpected PeerConnectionClient instance")
Logger.debug("\(self.TAG) setting peerConnectionClient in \(#function)") Logger.debug("\(self.TAG) setting peerConnectionClient in \(#function)")
@ -478,8 +483,15 @@ protocol CallServiceObserver: class {
throw CallError.assertionError(description: "getIceServers() response for obsolete call") throw CallError.assertionError(description: "getIceServers() response for obsolete call")
} }
assert(self.peerConnectionClient == nil, "Unexpected PeerConnectionClient instance") assert(self.peerConnectionClient == nil, "Unexpected PeerConnectionClient instance")
// For contacts not stored in our system contacts, we assume they are an unknown caller, and we force
// a TURN connection, so as not to reveal any connectivity information (IP/port) to the caller.
let unknownCaller = self.contactsManager.contact(forPhoneIdentifier: thread.contactIdentifier()) == nil
let useTurnOnly = unknownCaller || Environment.getCurrent().preferences.doCallsHideIPAddress()
Logger.debug("\(self.self.TAG) setting peerConnectionClient in \(#function)") Logger.debug("\(self.self.TAG) setting peerConnectionClient in \(#function)")
self.peerConnectionClient = PeerConnectionClient(iceServers: iceServers, delegate: self, callDirection: .incoming) self.peerConnectionClient = PeerConnectionClient(iceServers: iceServers, delegate: self, callDirection: .incoming, useTurnOnly: useTurnOnly)
let offerSessionDescription = RTCSessionDescription(type: .offer, sdp: callerSessionDescription) let offerSessionDescription = RTCSessionDescription(type: .offer, sdp: callerSessionDescription)
let constraints = RTCMediaConstraints(mandatoryConstraints: nil, optionalConstraints: nil) let constraints = RTCMediaConstraints(mandatoryConstraints: nil, optionalConstraints: nil)

@ -120,7 +120,7 @@ class PeerConnectionClient: NSObject, RTCPeerConnectionDelegate, RTCDataChannelD
private var remoteVideoTrack: RTCVideoTrack? private var remoteVideoTrack: RTCVideoTrack?
private var cameraConstraints: RTCMediaConstraints private var cameraConstraints: RTCMediaConstraints
init(iceServers: [RTCIceServer], delegate: PeerConnectionClientDelegate, callDirection: CallDirection) { init(iceServers: [RTCIceServer], delegate: PeerConnectionClientDelegate, callDirection: CallDirection, useTurnOnly: Bool) {
AssertIsOnMainThread() AssertIsOnMainThread()
self.iceServers = iceServers self.iceServers = iceServers
@ -130,6 +130,12 @@ class PeerConnectionClient: NSObject, RTCPeerConnectionDelegate, RTCDataChannelD
configuration.iceServers = iceServers configuration.iceServers = iceServers
configuration.bundlePolicy = .maxBundle configuration.bundlePolicy = .maxBundle
configuration.rtcpMuxPolicy = .require configuration.rtcpMuxPolicy = .require
if useTurnOnly {
Logger.debug("\(TAG) using iceTransportPolicy: relay")
configuration.iceTransportPolicy = .relay
} else {
Logger.debug("\(TAG) using iceTransportPolicy: default")
}
let connectionConstraintsDict = ["DtlsSrtpKeyAgreement": "true"] let connectionConstraintsDict = ["DtlsSrtpKeyAgreement": "true"]
connectionConstraints = RTCMediaConstraints(mandatoryConstraints: nil, optionalConstraints: connectionConstraintsDict) connectionConstraints = RTCMediaConstraints(mandatoryConstraints: nil, optionalConstraints: connectionConstraintsDict)

@ -71,6 +71,11 @@ extern NSString *const PropertyListPreferencesKeyEnableDebugLog;
- (BOOL)isCallKitEnabled; - (BOOL)isCallKitEnabled;
- (void)setIsCallKitEnabled:(BOOL)flag; - (void)setIsCallKitEnabled:(BOOL)flag;
#pragma mark direct call connectivity (non-TURN)
- (BOOL)doCallsHideIPAddress;
- (void)setDoCallsHideIPAddress:(BOOL)flag;
#pragma mark - Block on Identity Change #pragma mark - Block on Identity Change
- (BOOL)shouldBlockOnIdentityChange; - (BOOL)shouldBlockOnIdentityChange;

@ -23,6 +23,7 @@ NSString *const PropertyListPreferencesKeyHasRegisteredVoipPush = @"VOIPPushEnab
NSString *const PropertyListPreferencesKeyLastRecordedPushToken = @"LastRecordedPushToken"; NSString *const PropertyListPreferencesKeyLastRecordedPushToken = @"LastRecordedPushToken";
NSString *const PropertyListPreferencesKeyLastRecordedVoipToken = @"LastRecordedVoipToken"; NSString *const PropertyListPreferencesKeyLastRecordedVoipToken = @"LastRecordedVoipToken";
NSString *const PropertyListPreferencesKeyCallKitEnabled = @"CallKitEnabled"; NSString *const PropertyListPreferencesKeyCallKitEnabled = @"CallKitEnabled";
NSString *const PropertyListPreferencesKeyCallsHideIPAddress = @"CallsHideIPAddress";
@implementation PropertyListPreferences @implementation PropertyListPreferences
@ -138,6 +139,9 @@ NSString *const PropertyListPreferencesKeyCallKitEnabled = @"CallKitEnabled";
- (void)setLoggingEnabled:(BOOL)flag - (void)setLoggingEnabled:(BOOL)flag
{ {
// Logging preferences are stored in UserDefaults instead of the database, so that we can (optionally) start
// logging before the database is initialized. This is important because sometimes there are problems *with* the
// database initialization, and without logging it would be hard to track down.
[NSUserDefaults.standardUserDefaults setObject:@(flag) forKey:PropertyListPreferencesKeyEnableDebugLog]; [NSUserDefaults.standardUserDefaults setObject:@(flag) forKey:PropertyListPreferencesKeyEnableDebugLog];
[NSUserDefaults.standardUserDefaults synchronize]; [NSUserDefaults.standardUserDefaults synchronize];
} }
@ -182,6 +186,21 @@ NSString *const PropertyListPreferencesKeyCallKitEnabled = @"CallKitEnabled";
[self setValueForKey:PropertyListPreferencesKeyCallKitEnabled toValue:@(flag)]; [self setValueForKey:PropertyListPreferencesKeyCallKitEnabled toValue:@(flag)];
} }
#pragma mark direct call connectivity (non-TURN)
// Allow callers to connect directly, when desirable, vs. enforcing TURN only proxy connectivity
- (BOOL)doCallsHideIPAddress
{
NSNumber *preference = [self tryGetValueForKey:PropertyListPreferencesKeyCallsHideIPAddress];
return preference ? [preference boolValue] : NO;
}
- (void)setDoCallsHideIPAddress:(BOOL)flag
{
[self setValueForKey:PropertyListPreferencesKeyCallsHideIPAddress toValue:@(flag)];
}
#pragma mark Notification Preferences #pragma mark Notification Preferences
- (BOOL)soundInForeground - (BOOL)soundInForeground

@ -14,16 +14,23 @@ NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) { typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
PrivacySettingsTableViewControllerSectionIndexScreenSecurity, PrivacySettingsTableViewControllerSectionIndexScreenSecurity,
PrivacySettingsTableViewControllerSectionIndexCalling,
PrivacySettingsTableViewControllerSectionIndexHistoryLog, PrivacySettingsTableViewControllerSectionIndexHistoryLog,
PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange,
PrivacySettingsTableViewControllerSectionIndex_Count // meta section to track how many sections
}; };
@interface PrivacySettingsTableViewController () @interface PrivacySettingsTableViewController ()
@property (nonatomic, strong) UITableViewCell *enableScreenSecurityCell; @property (nonatomic, strong) UITableViewCell *enableScreenSecurityCell;
@property (nonatomic, strong) UISwitch *enableScreenSecuritySwitch; @property (nonatomic, strong) UISwitch *enableScreenSecuritySwitch;
@property (nonatomic) UITableViewCell *callsHideIPAddressCell;
@property (nonatomic) UISwitch *callsHideIPAddressSwitch;
@property (nonatomic, strong) UITableViewCell *blockOnIdentityChangeCell; @property (nonatomic, strong) UITableViewCell *blockOnIdentityChangeCell;
@property (nonatomic, strong) UISwitch *blockOnIdentityChangeSwitch; @property (nonatomic, strong) UISwitch *blockOnIdentityChangeSwitch;
@property (nonatomic, strong) UITableViewCell *clearHistoryLogCell; @property (nonatomic, strong) UITableViewCell *clearHistoryLogCell;
@end @end
@ -59,6 +66,17 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
action:@selector(didToggleScreenSecuritySwitch:) action:@selector(didToggleScreenSecuritySwitch:)
forControlEvents:UIControlEventTouchUpInside]; forControlEvents:UIControlEventTouchUpInside];
// Allow calls to connect directly vs. using TURN exclusively
self.callsHideIPAddressCell = [UITableViewCell new];
self.callsHideIPAddressCell.textLabel.text
= NSLocalizedString(@"SETTINGS_CALLING_HIDES_IP_ADDRESS_PREFERENCE_TITLE", @"Table cell label");
self.callsHideIPAddressSwitch = [UISwitch new];
self.callsHideIPAddressCell.accessoryView = self.callsHideIPAddressSwitch;
[self.callsHideIPAddressSwitch setOn:[Environment.preferences doCallsHideIPAddress]];
[self.callsHideIPAddressSwitch addTarget:self
action:@selector(didToggleCallsHideIPAddressSwitch:)
forControlEvents:UIControlEventTouchUpInside];
// Clear History Log Cell // Clear History Log Cell
self.clearHistoryLogCell = [[UITableViewCell alloc] init]; self.clearHistoryLogCell = [[UITableViewCell alloc] init];
self.clearHistoryLogCell.textLabel.text = NSLocalizedString(@"SETTINGS_CLEAR_HISTORY", @""); self.clearHistoryLogCell.textLabel.text = NSLocalizedString(@"SETTINGS_CLEAR_HISTORY", @"");
@ -79,13 +97,15 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
#pragma mark - Table view data source #pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3; return PrivacySettingsTableViewControllerSectionIndex_Count;
} }
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
switch (section) { switch (section) {
case PrivacySettingsTableViewControllerSectionIndexScreenSecurity: case PrivacySettingsTableViewControllerSectionIndexScreenSecurity:
return 1; return 1;
case PrivacySettingsTableViewControllerSectionIndexCalling:
return 1;
case PrivacySettingsTableViewControllerSectionIndexHistoryLog: case PrivacySettingsTableViewControllerSectionIndexHistoryLog:
return 1; return 1;
case PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange: case PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange:
@ -100,6 +120,9 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
switch (section) { switch (section) {
case PrivacySettingsTableViewControllerSectionIndexScreenSecurity: case PrivacySettingsTableViewControllerSectionIndexScreenSecurity:
return NSLocalizedString(@"SETTINGS_SCREEN_SECURITY_DETAIL", nil); return NSLocalizedString(@"SETTINGS_SCREEN_SECURITY_DETAIL", nil);
case PrivacySettingsTableViewControllerSectionIndexCalling:
return NSLocalizedString(@"SETTINGS_CALLING_HIDES_IP_ADDRESS_PREFERENCE_TITLE_DETAIL",
@"User settings section footer, a detailed explanation");
case PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange: case PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange:
return NSLocalizedString( return NSLocalizedString(
@"SETTINGS_BLOCK_ON_IDENITY_CHANGE_DETAIL", @"User settings section footer, a detailed explanation"); @"SETTINGS_BLOCK_ON_IDENITY_CHANGE_DETAIL", @"User settings section footer, a detailed explanation");
@ -112,6 +135,8 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
switch (indexPath.section) { switch (indexPath.section) {
case PrivacySettingsTableViewControllerSectionIndexScreenSecurity: case PrivacySettingsTableViewControllerSectionIndexScreenSecurity:
return self.enableScreenSecurityCell; return self.enableScreenSecurityCell;
case PrivacySettingsTableViewControllerSectionIndexCalling:
return self.callsHideIPAddressCell;
case PrivacySettingsTableViewControllerSectionIndexHistoryLog: case PrivacySettingsTableViewControllerSectionIndexHistoryLog:
return self.clearHistoryLogCell; return self.clearHistoryLogCell;
case PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange: case PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange:
@ -128,6 +153,8 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
switch (section) { switch (section) {
case PrivacySettingsTableViewControllerSectionIndexScreenSecurity: case PrivacySettingsTableViewControllerSectionIndexScreenSecurity:
return NSLocalizedString(@"SETTINGS_SECURITY_TITLE", @"Section header"); return NSLocalizedString(@"SETTINGS_SECURITY_TITLE", @"Section header");
case PrivacySettingsTableViewControllerSectionIndexCalling:
return NSLocalizedString(@"SETTINGS_SECTION_TITLE_CALLING", @"settings topic header for table section");
case PrivacySettingsTableViewControllerSectionIndexHistoryLog: case PrivacySettingsTableViewControllerSectionIndexHistoryLog:
return NSLocalizedString(@"SETTINGS_HISTORYLOG_TITLE", @"Section header"); return NSLocalizedString(@"SETTINGS_HISTORYLOG_TITLE", @"Section header");
case PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange: case PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange:
@ -182,6 +209,13 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
[Environment.preferences setShouldBlockOnIdentityChange:enabled]; [Environment.preferences setShouldBlockOnIdentityChange:enabled];
} }
- (void)didToggleCallsHideIPAddressSwitch:(UISwitch *)sender
{
BOOL enabled = sender.isOn;
DDLogInfo(@"%@ toggled callsHideIPAddress: %@", self.tag, enabled ? @"ON" : @"OFF");
[Environment.preferences setDoCallsHideIPAddress:enabled];
}
#pragma mark - Log util #pragma mark - Log util
+ (NSString *)tag + (NSString *)tag

@ -124,7 +124,7 @@
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"COUNTRYCODE_SELECT_TITLE" = "Select Country Code"; "COUNTRYCODE_SELECT_TITLE" = "Select Country Code";
/* Accessibility label for the create new group button. */ /* Accessibility label for the create group new group button */
"CREATE_NEW_GROUP" = "Create new group"; "CREATE_NEW_GROUP" = "Create new group";
/* {{number of days}} embedded in strings, e.g. 'Alice updated disappearing messages expiration to {{5 days}}'. See other *_TIME_AMOUNT strings */ /* {{number of days}} embedded in strings, e.g. 'Alice updated disappearing messages expiration to {{5 days}}'. See other *_TIME_AMOUNT strings */
@ -253,6 +253,9 @@
/* Generic notice when message failed to send. */ /* Generic notice when message failed to send. */
"ERROR_DESCRIPTION_CLIENT_SENDING_FAILURE" = "Failed to send message."; "ERROR_DESCRIPTION_CLIENT_SENDING_FAILURE" = "Failed to send message.";
/* Error mesage indicating that message send is disabled due to prekey update failures */
"ERROR_DESCRIPTION_MESSAGE_SEND_DISABLED_PREKEY_UPDATE_FAILURES" = "ERROR_DESCRIPTION_MESSAGE_SEND_DISABLED_PREKEY_UPDATE_FAILURES";
/* Generic error used whenver Signal can't contact the server */ /* Generic error used whenver Signal can't contact the server */
"ERROR_DESCRIPTION_NO_INTERNET" = "Signal was unable to connect to the internet. Please try from another WiFi network or use mobile data."; "ERROR_DESCRIPTION_NO_INTERNET" = "Signal was unable to connect to the internet. Please try from another WiFi network or use mobile data.";
@ -349,9 +352,6 @@
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"GROUP_REMOVING_FAILED" = "Failed to leave group"; "GROUP_REMOVING_FAILED" = "Failed to leave group";
/* Accessibilty label for group settings */
"GROUP_SETTINGS_LABEL" = "Group settings";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"GROUP_TITLE_CHANGED" = "Title is now '%@'. "; "GROUP_TITLE_CHANGED" = "Title is now '%@'. ";
@ -567,7 +567,8 @@
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"OK" = "Ok"; "OK" = "Ok";
/* Button text which opens the settings app */ /* Button text which opens the settings app
Label for button which opens the settings UI */
"OPEN_SETTINGS_BUTTON" = "Settings"; "OPEN_SETTINGS_BUTTON" = "Settings";
/* Info Message when {{other user}} disables or doesn't support disappearing messages */ /* Info Message when {{other user}} disables or doesn't support disappearing messages */
@ -768,24 +769,21 @@
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"SETTINGS_ADVANCED_TITLE" = "Advanced"; "SETTINGS_ADVANCED_TITLE" = "Advanced";
/* This setting is used to switch between new-style WebRTC calling and old-style RedPhone calling. */
"SETTINGS_ADVANCED_WEBRTC" = "Enable Video Calling";
/* The message of the alert shown when updates to the WebRTC property fail. */
"SETTINGS_ADVANCED_WEBRTC_FAILED_MESSAGE" = "Could not update your preferences.";
/* The title of the alert shown when updates to the WebRTC property fail. */
"SETTINGS_ADVANCED_WEBRTC_FAILED_TITLE" = "Error";
/* User settings section footer, a detailed explanation */ /* User settings section footer, a detailed explanation */
"SETTINGS_BLOCK_ON_IDENITY_CHANGE_DETAIL" = "Requires your approval before communicating with someone who has a new safety number, commonly from a reinstall of Signal."; "SETTINGS_BLOCK_ON_IDENITY_CHANGE_DETAIL" = "Requires your approval before communicating with someone who has a new safety number, commonly from a reinstall of Signal.";
/* Table cell label */ /* Table cell label */
"SETTINGS_BLOCK_ON_IDENTITY_CHANGE_TITLE" = "Require Approval on Change"; "SETTINGS_BLOCK_ON_IDENTITY_CHANGE_TITLE" = "Require Approval on Change";
/* Settings button accessibility hint */ /* Accessibility hint for the settings button */
"SETTINGS_BUTTON_ACCESSIBILITY" = "Settings"; "SETTINGS_BUTTON_ACCESSIBILITY" = "Settings";
/* Table cell label */
"SETTINGS_CALLING_HIDES_IP_ADDRESS_PREFERENCE_TITLE" = "Hide IP Address";
/* User settings section footer, a detailed explanation */
"SETTINGS_CALLING_HIDES_IP_ADDRESS_PREFERENCE_TITLE_DETAIL" = "Hiding your IP address during audio and video calls will decrease call quality.";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"SETTINGS_CLEAR_HISTORY" = "Clear History Logs"; "SETTINGS_CLEAR_HISTORY" = "Clear History Logs";

Loading…
Cancel
Save