diff --git a/Signal/src/call/CallService.swift b/Signal/src/call/CallService.swift index fbdf5e9d0..1763380b2 100644 --- a/Signal/src/call/CallService.swift +++ b/Signal/src/call/CallService.swift @@ -399,7 +399,7 @@ protocol CallServiceObserver: class { } guard call.signalingId == callId else { - Logger.warn("\(self.TAG) ignoring obsolete call: \(callId) in \(#function)") + Logger.warn("\(self.TAG) ignoring mismatched call: \(callId) currentCall: \(call.signalingId) in \(#function)") return } @@ -480,12 +480,17 @@ protocol CallServiceObserver: class { /** * The callee was already in another call. */ - public func handleRemoteBusy(thread: TSContactThread) { + public func handleRemoteBusy(thread: TSContactThread, callId: UInt64) { Logger.info("\(TAG) \(#function) for thread: \(thread.contactIdentifier())") AssertIsOnMainThread() guard let call = self.call else { - Logger.warn("\(self.TAG) ignoring obsolete call in \(#function)") + Logger.warn("\(self.TAG) ignoring obsolete call: \(callId) in \(#function)") + return + } + + guard call.signalingId == callId else { + Logger.warn("\(self.TAG) ignoring mismatched call: \(callId) currentCall: \(call.signalingId) in \(#function)") return } @@ -541,13 +546,15 @@ protocol CallServiceObserver: class { } guard self.call == nil else { + let existingCall = self.call! + // TODO on iOS10+ we can use CallKit to swap calls rather than just returning busy immediately. - Logger.info("\(TAG) receivedCallOffer: \(newCall.identifiersForLogs) but we're already in call: \(call!.identifiersForLogs)") + Logger.info("\(TAG) receivedCallOffer: \(newCall.identifiersForLogs) but we're already in call: \(existingCall.identifiersForLogs)") handleLocalBusyCall(newCall, thread: thread) - if self.call!.remotePhoneNumber == newCall.remotePhoneNumber { - Logger.info("\(TAG) handling call from current call user as remote busy.: \(newCall.identifiersForLogs) but we're already in call: \(call!.identifiersForLogs)") + if existingCall.remotePhoneNumber == newCall.remotePhoneNumber { + Logger.info("\(TAG) handling call from current call user as remote busy.: \(newCall.identifiersForLogs) but we're already in call: \(existingCall.identifiersForLogs)") // If we're receiving a new call offer from the user we already think we have a call with, // terminate our current call to get back to a known good state. If they call back, we'll @@ -556,11 +563,11 @@ protocol CallServiceObserver: class { // TODO: Auto-accept this incoming call if our current call was either a) outgoing or // b) never connected. There will be a bit of complexity around making sure that two // parties that call each other at the same time end up connected. - switch self.call!.state { + switch existingCall.state { case .idle, .dialing, .remoteRinging: // If both users are trying to call each other at the same time, // both should see busy. - handleRemoteBusy(thread:self.call!.thread) + handleRemoteBusy(thread:existingCall.thread, callId:existingCall.signalingId) case .answering, .localRinging, .connected, .localFailure, .localHangup, .remoteHangup, .remoteBusy: // If one user calls another while the other has a "vestigial" call with // that same user, fail the old call. @@ -683,7 +690,7 @@ protocol CallServiceObserver: class { } guard call.signalingId == callId else { - Logger.warn("ignoring remote ice update for thread: \(thread.uniqueId) due to callId mismatch. Call already ended?") + Logger.warn("\(self.TAG) ignoring mismatched call: \(callId) currentCall: \(call.signalingId) in \(#function)") return } @@ -791,7 +798,7 @@ protocol CallServiceObserver: class { /** * The remote client (caller or callee) ended the call. */ - public func handleRemoteHangup(thread: TSContactThread) { + public func handleRemoteHangup(thread: TSContactThread, callId: UInt64) { Logger.debug("\(TAG) in \(#function)") AssertIsOnMainThread() @@ -801,6 +808,11 @@ protocol CallServiceObserver: class { return } + guard call.signalingId == callId else { + Logger.warn("\(self.TAG) ignoring mismatched call: \(callId) currentCall: \(call.signalingId) in \(#function)") + return + } + guard thread.contactIdentifier() == call.thread.contactIdentifier() else { // This can safely be ignored. // We don't want to fail the current call because an old call was slow to send us the hangup message. @@ -1161,7 +1173,7 @@ protocol CallServiceObserver: class { return } - handleRemoteHangup(thread: call.thread) + handleRemoteHangup(thread: call.thread, callId: hangup.id) } else if message.hasVideoStreamingStatus() { Logger.debug("\(TAG) remote participant sent VideoStreamingStatus via data channel: \(call.identifiersForLogs).") diff --git a/Signal/src/call/WebRTCCallMessageHandler.swift b/Signal/src/call/WebRTCCallMessageHandler.swift index 80adc4b21..304c2a739 100644 --- a/Signal/src/call/WebRTCCallMessageHandler.swift +++ b/Signal/src/call/WebRTCCallMessageHandler.swift @@ -29,6 +29,10 @@ class WebRTCCallMessageHandler: NSObject, OWSCallMessageHandler { public func receivedOffer(_ offer: OWSSignalServiceProtosCallMessageOffer, from callerId: String) { AssertIsOnMainThread() + guard offer.hasId() else { + owsFail("no callId in \(#function)") + return + } let thread = TSContactThread.getOrCreateThread(contactId: callerId) self.callService.handleReceivedOffer(thread: thread, callId: offer.id, sessionDescription: offer.sessionDescription) @@ -36,6 +40,10 @@ class WebRTCCallMessageHandler: NSObject, OWSCallMessageHandler { public func receivedAnswer(_ answer: OWSSignalServiceProtosCallMessageAnswer, from callerId: String) { AssertIsOnMainThread() + guard answer.hasId() else { + owsFail("no callId in \(#function)") + return + } let thread = TSContactThread.getOrCreateThread(contactId: callerId) self.callService.handleReceivedAnswer(thread: thread, callId: answer.id, sessionDescription: answer.sessionDescription) @@ -43,6 +51,10 @@ class WebRTCCallMessageHandler: NSObject, OWSCallMessageHandler { public func receivedIceUpdate(_ iceUpdate: OWSSignalServiceProtosCallMessageIceUpdate, from callerId: String) { AssertIsOnMainThread() + guard iceUpdate.hasId() else { + owsFail("no callId in \(#function)") + return + } let thread = TSContactThread.getOrCreateThread(contactId: callerId) @@ -55,18 +67,24 @@ class WebRTCCallMessageHandler: NSObject, OWSCallMessageHandler { public func receivedHangup(_ hangup: OWSSignalServiceProtosCallMessageHangup, from callerId: String) { AssertIsOnMainThread() + guard hangup.hasId() else { + owsFail("no callId in \(#function)") + return + } let thread = TSContactThread.getOrCreateThread(contactId: callerId) - - self.callService.handleRemoteHangup(thread: thread) + self.callService.handleRemoteHangup(thread: thread, callId: hangup.id) } public func receivedBusy(_ busy: OWSSignalServiceProtosCallMessageBusy, from callerId: String) { AssertIsOnMainThread() + guard busy.hasId() else { + owsFail("no callId in \(#function)") + return + } let thread = TSContactThread.getOrCreateThread(contactId: callerId) - - self.callService.handleRemoteBusy(thread: thread) + self.callService.handleRemoteBusy(thread: thread, callId: busy.id) } }