Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(SIGPIPE) Apps built with Xcode 7 crash if phone is locked while app is running and device receives a phone/facetime call #47

Open
ThuggishNuggets opened this issue May 12, 2016 · 2 comments

Comments

@ThuggishNuggets
Copy link

ThuggishNuggets commented May 12, 2016

I've spent the last week tracking down an issue in MumbleKit that we're experiencing attempting to use it in our app. For a while we thought it was something we were doing as we were not able to reproduce the crash in the Mumble for iOS app on the App Store.

Yesterday it occurred to me to check the last updated date for the Mumble for iOS app and, sure enough, it had been just over 2 years since it was updated. In iOS it is practically ancient at this point. So what did this mean? It meant that just building the same code base with a newer version of Xcode might actually cause the problem to be reproducible in the Mumble for iOS app.

So I downloaded the code base and dependencies for Mumble for iOS and put it to the test and it crashed in the same way as our app was crashing. So what is this crash?

The crash occurs in -[MKConnection _sendMessageHelper:]:Line 722. What appears to be happening is that, when the Phone call or FaceTime call audio interruption completes, something is happening to the network and _outputStream becomes a "Broken Pipe" even though its streamStatus property and streamError method do not indicate that there is an issue.

So typically as soon as the call is over, the ping message gets sent, and this triggers a write on that Broken Pipe which triggers iOS to send the SIGPIPE mach signal effectively terminating the app because SIGPIPE is not being handled in MumbleKit.

Things I have tried:

  • I have tried adding checks to the streamStatus property and streamError method on _outputStream inside _sendMessageHelper: to just flat out drop whatever message is going out, but as I mentioned before: these do not appear to be in the correct state when the ping comes through.
  • Adding a naive reconnection mechanism in _handleError: to check for the NSPOSIXErrorDomain code 32 (Broken Pipe) and call _reconnect. This works sometimes, but only if the ping doesn't fire immediately upon call ending.
  • Adding signal(SIGPIPE, SIG_IGN); to globally ignore the SIGPIPE mach signal being sent. this does not appear to be working or the SIGPIPE handler is being reset elsewhere (possibly somewhere in OpenSSL).

Device Console Output showing SIGPIPE and iOS daemons killing Mumble for iOS app built in Xcode 7.3

May 12 11:02:26 Marks-iPhone Mumble[13089] <Warning>: MKConnection: Sent ping message.
May 12 11:02:26 Marks-iPhone Mumble[13089] <Warning>: UDP ping = 17096 usec
May 12 11:02:26 Marks-iPhone Mumble[13089] <Warning>: MKConnection: pingResponseFromServer
…
May 12 11:02:26 Marks-iPhone Mumble[13089] <Warning>: MKVoiceProcessingDevice: teardown finished.
May 12 11:02:27 Marks-iPhone Mumble[13089] <Warning>: MKAudio: audio route changed, skipping; reason=8
May 12 11:02:27 Marks-iPhone Mumble[13089] <Warning>: MKAudio: audio route changed, skipping; reason=3
…
May 12 11:02:38 Marks-iPhone Mumble[13089] <Warning>: MKConnection: CFSocketSendData failed with err=-1
May 12 11:02:38 Marks-iPhone Mumble[13089] <Warning>: MKConnection: write error, wrote -1, expected 43
May 12 11:02:38 Marks-iPhone Mumble[13089] <Warning>: MKConnection: Sent ping message.
…
May 12 11:02:38 Marks-iPhone SpringBoard[11648] <Warning>: Unable to get short BSD proc info for 13089: No such process
May 12 11:02:38 Marks-iPhone SpringBoard[11648] <Warning>: Unable to get short BSD proc info for 13089: No such process
…
May 12 11:02:38 Marks-iPhone mediaserverd[11613] <Notice>: '' com.redacted.redacted(pid = 13089) setting DiscoveryMode = DiscoveryMode_None, currentDiscoveryMode = DiscoveryMode_None
May 12 11:02:38 Marks-iPhone com.apple.xpc.launchd[1] (UIKitApplication:com.redacted.redacted[0xb8ca][13089]) <Notice>: Service exited due to signal: Broken pipe: 13

At this point I am running out of options and I am not exactly the most familiar with the inner workings of MumbleKit.

Has anyone else experienced this crash or potentially found a fix for it?

@mkrautz Do you have anything that I should try to resolve this? Anything off the top of your head?

@ThuggishNuggets
Copy link
Author

ThuggishNuggets commented May 28, 2016

Just a heads up, you can prevent the crash by calling the following line of code (comments optional, obviously) before any sockets are created:

    /*

     Ignore SIGPIPE mach signals encountered from broken pipes when receiving a phone call.

     Without this, the app will crash if it receives a phone call interruption that lasts more 
     than a few seconds or if an audio interruption occurs while the app is backgrounded, again 
     lasting more than a few seconds.

     We're doing this instead of adopting the new iOS 8+ VOIP paradigms because those require
     a complete overhaul of the underlying VOIP technologies this App is based on.

    */
    signal(SIGPIPE, SIG_IGN);

It turns out that many of the issues we've had with MumbleKit are because it was built for much earlier versions of iOS and in iOS 8 and later, Apple drastically changed the VOIP background mode so that VOIP apps can no longer maintain an active connection to the server rendering MumbleKit practically useless unless the app is foregrounded.

Workarounds for the background limitations Apple imposes include starting and restarting a background task when an audio interruption occurs to attempt to keep the app (and its connection) running in the background for as long as possible. If not, the network will be killed and the mumble server connection lost, however the app will not be notified of anything until it is relaunched because losing the audio session causes the app to be forced into the suspended application state (where code cannot be run).

Using this background task juggling workaround can buy your app up to 10 minutes of background processing time, which may be enough to allow the audio interruption to be resolved. Using this method you could also schedule a local notification to warn the user that they will be disconnected unless they resolve the audio interruption in time (generally by ending the phone call or similar audio task that caused the interruption in the first place).

Hope this helps!

@Sega-Zero
Copy link

Those one who will find this page while searching the solution to Service exited due to signal: Broken pipe: 13, I recommend to look at SO_NOPIPE option also. See this great article.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants