1

I'm working on a project where my android application should behave as a server for other android clients .. I'm using Eneter messaging framework which uses Sockets and Google Protobuf .. on wifi everything works like a charm but once I switch to 3g network (try to start server using phone's 3g public ip adress and port 80/81) I get the following error : EACCES (Permission denied)

E/EneterMessaging: ~24216 eneter.messaging.messagingsystems.tcpmessagingsystem.internal.TcpListenerProvider.startListening TcpListenerProvider  failed to start listening.
                   Exception:
                   java.net.BindException: bind failed: EACCES (Permission denied)
                   libcore.io.IoBridge.bind(IoBridge.java:99)
                   java.net.PlainSocketImpl.bind(PlainSocketImpl.java:132)
                   java.net.ServerSocket.bind(ServerSocket.java:335)
                   eneter.messaging.messagingsystems.tcpmessagingsystem.NoneSecurityServerFactory.createServerSocket(NoneSecurityServerFactory.java:51)
                   eneter.messaging.messagingsystems.tcpmessagingsystem.internal.TcpListenerProvider.startListening(TcpListenerProvider.java:123)
                   eneter.messaging.messagingsystems.tcpmessagingsystem.TcpInputConnector.startListening(TcpInputConnector.java:134)
                   eneter.messaging.messagingsystems.simplemessagingsystembase.internal.DefaultDuplexInputChannel.startListening(DefaultDuplexInputChannel.java:96)
                   eneter.messaging.infrastructure.attachable.internal.AttachableDuplexInputChannelBase.attachDuplexInputChannel(AttachableDuplexInputChannelBase.java:40)
                   com.inactivity.magamine.teatime.services.TCPService.StartServer(TCPService.java:261)
                   com.inactivity.magamine.teatime.services.TCPService$6.run(TCPService.java:279)
                   java.lang.Thread.run(Thread.java:818) 

I have these permissions in my manifest:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET"/>

and this is the code that starts the server:

public void StartServer() throws Exception
    {
        // Create sender sending MyRequest and as a response receiving MyResponse
        // Instantiate Protocol Buffer based serializer.
        ISerializer aSerializer = new ProtoBufSerializer();

        // Create sender sending MyRequest and as a response receiving MyResponse
        // The sender will use Protocol Buffers to serialize/deserialize messages.
        IDuplexTypedMessagesFactory aRecieverFactory = new DuplexTypedMessagesFactory(aSerializer);
        myReceiver = aRecieverFactory.createDuplexTypedMessageReceiver(MessageDeclarations.MyMsg.class, MessageDeclarations.MyMsg.class);
        myReceiver.messageReceived().subscribe(myOnRequestHandler);

        if(aMessaging == null)aMessaging = new TcpMessagingSystemFactory();

        IDuplexInputChannel anInputChannel
                = aMessaging.createDuplexInputChannel(Service_URL);//Service_URL = "tcp://xxx.xxx.x.xx:80/ with public ip adress


        // Attach the output channel to the sender and be able to send
        // messages and receive responses.
        myReceiver.attachDuplexInputChannel(anInputChannel);

        isConnected = true;
        showNotification("Server Started","url: "+Service_URL,Color.GREEN);
    }

The exception occurs on

myReceiver.attachDuplexInputChannel(anInputChannel);

Thats where Eneter starts the socket server.

EDIT: From this I found that to bind on ports < 1024 you need root privileges. So I tried ports like 1025, 8080, 8081 , I now get this exception instead: Cannot assign requested address, is it that I cant use 3G network public ip adress to start a socket server or am I missing something ?

E/EneterMessaging: ~25710 eneter.messaging.messagingsystems.simplemessagingsystembase.internal.DefaultDuplexInputChannel.startListening DefaultDuplexInputChannel 'tcp://105.66.131.38:8080/'  failed to start listening.
                   Exception:
                   java.net.BindException: bind failed: EADDRNOTAVAIL (Cannot assign requested address)
                   libcore.io.IoBridge.bind(IoBridge.java:99)
                   java.net.PlainSocketImpl.bind(PlainSocketImpl.java:132)
                   java.net.ServerSocket.bind(ServerSocket.java:335)
                   eneter.messaging.messagingsystems.tcpmessagingsystem.NoneSecurityServerFactory.createServerSocket(NoneSecurityServerFactory.java:51)
                   eneter.messaging.messagingsystems.tcpmessagingsystem.internal.TcpListenerProvider.startListening(TcpListenerProvider.java:123)
                   eneter.messaging.messagingsystems.tcpmessagingsystem.TcpInputConnector.startListening(TcpInputConnector.java:134)
                   eneter.messaging.messagingsystems.simplemessagingsystembase.internal.DefaultDuplexInputChannel.startListening(DefaultDuplexInputChannel.java:96)
                   eneter.messaging.infrastructure.attachable.internal.AttachableDuplexInputChannelBase.attachDuplexInputChannel(AttachableDuplexInputChannelBase.java:40)
                   com.inactivity.magamine.teatime.services.TCPService.StartServer(TCPService.java:261)
                   com.inactivity.magamine.teatime.services.TCPService$6.run(TCPService.java:279)
                   java.lang.Thread.run(Thread.java:818)

I will appreciate your help.

Kindly

Mag_Amine
  • 135
  • 1
  • 9
  • Yeah try using 0.0.0.0 as the ip address in `Service_URL`. – greeble31 Oct 15 '18 at 23:12
  • using 0.0.0.0 fixes the error and starts the server, but then I can't connect to it from a client over 3G/4G network using the server phone's public ip adress, I get the following: `java.net.SocketTimeoutException: failed to connect to /xx.xx.xx.xx (port 8080) after 30000ms` .. xx.xx.xx.xx is the public IP of the phone – Mag_Amine Oct 15 '18 at 23:41

2 Answers2

2

Answer to original question

The port assignment is failing because, as you noted, 80 is a privileged port.

Answer to updated question

The IP address assignment failed because, as it turned out, you had the wrong IP address in your code. Once you turned off your WiFi network (presumably) to get onto the mobile network, the address you were using was removed from the system, and you were assigned a different address by your wireless carrier. Using 0.0.0.0 essentially tells your server library, "I want to listen on all interfaces". (The other option is to figure out your mobile IP address, and use that instead.) But that brings us to the last problem:

A comment on your current issue

There could be a lot of reasons why it's not connecting. I suspect it's probably NAT, as described in this question. Long story short, very few apps (if any), use the architecture you've chosen (running a server on a subscriber handset connected to the mobile network). Because of NAT, handsets almost always have to "dial out" in order to form a connection (on a mobile network). And your server isn't dialing out; it's listening.

These limitations won't apply to your local WiFi network, as long as you're not crossing a NAT boundary.

To solve this problem, you'll probably need to know the network architecture, and some training in network debugging. Capture tools like Wireshark are a big help.

If you need more assistance on that, and none of the other answers on SO help you, it is probably best to start a new question.

greeble31
  • 4,894
  • 2
  • 16
  • 30
1

UPDATE: I Fixed it

Thank you greeble31 for your clarifications, this link was useful.

After switching from wifi to 3G the network carrier assign to the phone a private IP address 10.xx.xx.xx which is later translated by NAT to a shared public IP address.

If all nodes (phones trying to reach each others) are on the same ISP and -(not sure about effectiveness of this one)- are relatively close as in my case, using the assigned ISP address (in my case 10.xx.xx.xx) instead of the public IP address should do the trick.

I used this to get the working IP Address:

public String getAndroidIP() {
        try {
            String interfaces = "";
            for (Enumeration<NetworkInterface> en = NetworkInterface
                    .getNetworkInterfaces(); en.hasMoreElements();) {
                NetworkInterface intf = en.nextElement();
                for (Enumeration<InetAddress> enumIpAddr = intf
                        .getInetAddresses(); enumIpAddr.hasMoreElements();) {
                    InetAddress inetAddress = enumIpAddr.nextElement();
                    if (!inetAddress.isLoopbackAddress()
                            && inetAddress instanceof Inet4Address) {

                        interfaces = interfaces
                                + inetAddress.getHostAddress().toString();
                        Log.d("interface NET",interfaces);
                    }
                    Log.d("interface Adress",inetAddress.getHostAddress().toString());
                }
            }
            return (interfaces);
        } catch (SocketException ex) {
            Log.d("getAndroidIP", ex.toString());
        }
        return null;
    }

However, I should test it under different carriers and different locations to ensure the phone don't share the same 3G antenna. I'll edit this with the results as I get them.

Thank you.

Mag_Amine
  • 135
  • 1
  • 9