Unspecified error when phone put to sleep during zeroconf scan
Been using the library with a recent project and very satisfied with how easy to implement it was.
However, in tightening things up recently, I've noticed that zeroconf seems to be responsible for two types of crashes in my app.
-
When the app is minimized as the user navigates to the home screen. Error is encountered on resuming the app.
-
When the phone is put to sleep by pressing the power button. Error once again encountered on resuming the app.
In both cases, the error is an 'Uncaught, unspecified "error" event. (10)' with the following log
Unhandled JS Exception: Uncaught, unspecified "error" event. (-72000)
2017-01-05 16:01:20.156716 Tavern[310:44322] [] nw_socket_get_input_frames recvmsg(fd 7, 1024 bytes): [57] Socket is not connected
2017-01-05 16:01:20.241348 Tavern[310:44322] [] nw_socket_get_input_frames recvmsg(fd 10, 1024 bytes): [57] Socket is not connected
2017-01-05 16:01:20.248243 Tavern[310:44322] [] nw_endpoint_handler_add_write_request [8.1 192.168.1.25:8081 failed socket-flow (satisfied)] cannot accept write requests
2017-01-05 16:01:20.249545 Tavern[310:43888] [] __tcp_connection_write_eof_block_invoke Write close callback received error: [22] Invalid argument
Both errors only occur when a react-native-zeroconf scan is actively running. Disabling zeroconf or stopping the scan prevents the errors.
I was able to work around the first type of crash by writing some code to stop the zeroconf scan when the app is moved to the background. This was easy enough to do with React Native AppState. However, it seems significantly trickier to write such a workaround for handling when the phone's screen is turned off, at least using pure React Native.
Any ideas as to how the library could be updated to prevent these errors when the app state is changed during a zeroconf scan?
Hum not sure actually, what does your hook look like exactly? It seems a bit related to #12.
Hey there,
Thanks for getting back so soon.
We're not doing anything fancy when starting the scan (which is what I assume you're referring to by 'hook'). In addition to registering some listeners (onScanStart, onScanStop, and onGetDevices), this function is called in componentDidMount():
function startZeroConfScan () {
try {
zeroconf.scan(type = 'http', protocol = 'tcp', domain = 'local.');
} catch (e) {parseZeroConfError(e)}
}
With regard to the other issue, this morning I tried toggling the wifi on and off and didn't encounter any crashes. I also notice that the error with the phone coming back from sleep only happened about 50% of the time. I couldn't find any pattern as to what made it either work or fail, however.
An update:
I managed to fix the red screen crashes by including a handler for the error event.
The error log are still the same as above, including that [57] Socket is not connected error, which I think is important. I've been running this app on iOS 10.2 and socket issues when the app goes to the background in iOS 10 have been noted elsewhere: http://stackoverflow.com/questions/39743686/web-service-calls-no-longer-work-in-background-when-background-audio-mode-is-ena
Hum thanks for the update! Do you have this issue only on physical devices or are you also able to reproduce on simulator? Still not sure what I can do about it.
I've only seen the error on the one physical device I'm using to develop. I have a feeling based on that stack overflow thread that it may be specifically an iOS 10 issue.
I am having the same issue as described here and I do believe it is related to #12 as well.
I am doing a new scan on network change and/or when the app state is changed to "active". I can trigger it by being in the app, double tapping the home button and then choose the app again. If I do this many times quite fast the error eventually appears and the service that is supposed to be resolved is set to nil for some reason.
At the moment I have added a check: if (service != nil) before doing anything with the service and everything seem to work fine. Of course that is not really solving the problem. Do you guys have any suggestions on why the service is nil?
@jdpigeon - why do you think it is related to the "socket is not connected" issue that lots of people got with iOS 10?
@pellepersson Landed a similar change in the latest 0.8.0 version. @SiteFlo and @jamsesso did the same thing in their forks too, and might be interested.
@jdpigeon Have you had the chance to try reproducing using 0.8.0?
Just started working on this project again, actually. I'll take a look when I'm in the office on Monday
Cool! Have a good weekend 😃
Still noticing the same problems, unfortunately.
If I don't stop the zeroconf scan before minimizing the app I'll get an Unhandled JS Exception: Uncaught, unspecified "error" event. (-72000).
I'm no longer so sure that my problems related to that iOS10 Socket issue since that error doesn't always pop up at the same time as the zeroconf one.
In any case, I have been able to work around the error by stopping the scan when the app is put to sleep and creating an error handler.
Hum, and what happens if you keep scanning with the error handler? I would assume the error get caught right?
Yup! Error gets caught.
Unfortunately, it looks like the scan stops working properly. Changes to the list of zeroconf devices aren't detected after the error's been thrown until the component is remounted
Hey! We are now doing a sanity check on the service to prevent some errors which might catch your issue. Do you mind trying that?
It's still happening on 0.8.3 ...
Same here, and it happens very randomly
Hi, any update on this? Having the same issue as listed above.
We went around this issue it by stopping all zeroconf operations on app minimize and resuming when app goes back to foreground. No idea if there's an actual fix for that.
NSNetServicesUnknownError corresponds to the 72000 status code, which is not really helpful in itself. However, it's likely the OS is putting some of the app net services on pause while in the background and resuming them on foreground, resulting in the error you guys are seeing.
The idea of @rdev is actually a good one. It might be possible to stop it seamlessly inside the module, but while waiting for that people should just pause and resume the scan themselves at the right times in order to avoid this.
@balthazar @jdpigeon I found a fix/solution to this, you can listen for the "AppState" and remove the listener when the app becomes inactive and re-add them when the app becomes active again.
Here's an example:
import {AppState} from 'react-native';
AppState.addEventListener('change', this.handleAppStateChange.bind(this));
private appState: string = 'active';
private handleAppStateChange(nextAppState: string): void {
if (this.appState === 'active' && nextAppState === 'active') {
return;
}
this.appState = nextAppState;
if (nextAppState === 'active') {
return this.zeroConf.addDeviceListeners();
}
return this.zeroConf.removeDeviceListeners();
}
The first line in the function prevents the listener to be added twice (This triggers an error as-well). Hope this helps 😄
Awesome, @DennisSnijder! That worked for me as well. This is the hook-based variation that I came up with:
const [appState, setAppState] = useState(AppState.currentState);
const previousAppState = usePrevious(appState);
const [rnZeroconf, setZeroConf] = useState<RNZeroconf | null>(null);
const handleAppStateChange = (state: AppStateStatus) => {
setAppState(state);
};
useEffect(() => {
AppState.addEventListener('change', handleAppStateChange);
return () => AppState.removeEventListener('change', handleAppStateChange);
}, []);
useEffect(() => {
if (appState === 'active' && previousAppState === 'active') {
return;
}
if (appState === 'active') {
rnZeroconf?.addDeviceListeners();
}
rnZeroconf?.removeDeviceListeners();
}, [appState, previousAppState, rnZeroconf]);
with helper:
function usePrevious<T>(value: T) {
const ref = useRef<T>();
useEffect(() => {
ref.current = value;
});
return ref.current;
}