tradle / react-native-udp

node's dgram for react-native
MIT License
339 stars 154 forks source link

Receiving "Address Already in Use" error when binding two sockets to same port on iOS #53

Closed intmainvoid closed 6 years ago

intmainvoid commented 7 years ago

The Problem: If two sockets running in the same app try to bind to the same port, an error occurs to the tune of:

Error Domain=NSPOSIXErrorDomain Code=48 "Address already in use" UserInfo={NSLocalizedDescription=Address already in use, NSLocalizedFailureReason=Error in bind() function}

Proposed Solution (for iOS): GCDAsyncUdpSocket needs updating and react-native-udp needs to make use of enableReusePort:flag:error:

Proposed Solution (for Android): TBC - (not even sure it is a problem)

More info here: https://github.com/robbiehanson/CocoaAsyncSocket/issues/422

Will test the proposed solution for iOS ASAP and post results here.

intmainvoid commented 7 years ago

The fix appears to work really well. No more errors of this kind were encountered after implementation.

Double-Dude commented 7 years ago

Can someone please follow up this. This issue happens very often to my app when another app is also using UDP and being kill by OS in the background(you can see from the multi-task screen). I think somehow OS wakes up the other app and that app binds the port, so my app using this library can't bind the port. Have used "enableReusePort", but it didn't help.

sebastiancoke commented 6 years ago

I have tried: try socket.enableReusePort(true) but does not work. what else should I do?

        try socket.enableReusePort(true)
        try socket.bind(toPort: PORT)
        try socket.enableBroadcast(true)
        try socket.joinMulticastGroup(IP)
        try socket.beginReceiving()

update: I checked the documentation and I had to use also the same Port for both IPs then It worked fine :) and has to be before .bind(toPort: PORT).

Double-Dude commented 6 years ago

Hi @intmainvoid , did you find a solution for this? I'm using the CocoaAsyncSocket. This issue happens very often to my app when another app is also using UDP and being kill by OS in the background(you can see from the multi-task screen). I think somehow OS wakes up the other app and that app binds the port, so my app using this library can't bind the port. Have used "enableReusePort", but it didn't help.

intmainvoid commented 6 years ago

@quhaoran007 - Yes I did. This PR fixed the problem: https://github.com/tradle/react-native-udp/pull/54. You might still see "Address already in use" in your logs but it won't be a fatal error and that application will behave as intended. Make sure you set the reusePort option to true like so

dgram.createSocket({
  type: 'udp4',
  reusePort: true
}).bind('127.0.0.1', (err) => {
  console.log("Connected Successfully?: ", err ? "false" : "true");
});
Double-Dude commented 6 years ago

@intmainvoid Do you if that bug has been fixed in the original CocoaAsyncSocket lib? Because I'm using CocoaAsyncSocket and the last time I tried with reusePort = true and which has no effect. Thanks

intmainvoid commented 6 years ago

Do you if that bug has been fixed in the original CocoaAsyncSocket lib?

The original CocoaAsyncSocket lib that has been included in this library contains all the necessary logic to support the SO_REUSEPORT option. See https://github.com/tradle/react-native-udp/blob/master/ios/CocoaAsyncSocket/GCDAsyncUdpSocket.h#L493.

For react-native-udp this option is set in the bridging module: https://github.com/tradle/react-native-udp/blob/master/ios/UdpSocketClient.m#L100.

Everything is there and we are using in production on one heavily tested project. Maybe you could post your sample code here that isn't working?

rimzici commented 6 years ago

@intmainvoid : looks like port/address reuse is done specifically for iOS https://github.com/tradle/react-native-udp/blob/master/UdpSocket.js#L95

Any suggestion for Android ? I am facing same crash in Android due to the address already being used.

bind failed: EADDRINUSE (Address already in use)
rimzici commented 6 years ago

My apologies, reuse address seem to be true by default in Android. https://github.com/tradle/react-native-udp/blob/master/android/src/main/java/com/tradle/react/UdpSocketClient.java#L252

So with that being true, what could be the reason for the error/crash?

from crashlytics:

Fatal Exception: com.facebook.react.common.JavascriptException: bind failed: EADDRINUSE (Address already in use), stack:
<unknown>@1052:773
<unknown>@1054:1418
value@18:3872
<unknown>@18:1396
value@18:3009
value@18:1366

       at com.facebook.react.modules.core.ExceptionsManagerModule.showOrThrowError(ExceptionsManagerModule.java:54)
       at com.facebook.react.modules.core.ExceptionsManagerModule.reportFatalException(ExceptionsManagerModule.java:38)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372)
       at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:160)
       at com.facebook.react.bridge.queue.NativeRunnable.run(NativeRunnable.java)
       at android.os.Handler.handleCallback(Handler.java:809)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29)
       at android.os.Looper.loop(Looper.java:166)
       at com.facebook.react.bridge.queue.MessageQueueThreadImpl$3.run(MessageQueueThreadImpl.java:192)
       at java.lang.Thread.run(Thread.java:784)

Any help will be appreciated. Thanks!

ghost commented 5 years ago

@rimzici Did you find out a solution for the issue?