Skip to content

Android: "unable to find socket" if there is a problem when connecting! #47

@LukasKnuthImagineOn

Description

@LukasKnuthImagineOn

I have found a quite serious Bug in the Native Android Implementation of the Sockets. Here is some example-code and the steps to reproduce:

let client: Object = net.createConnection({host: HOST, port: PORT}, () => {
    console.log('Connected successfully to ' + HOST + ':' + PORT);
});

client.on('error', (error) => {
    console.log(error);
    // The connection was not successful, close the socket here:
    client.end();
});

client.on('data', (data) => {
    console.log(data);
    // TODO do something with the data
});

client.on('close', () => {
    console.log('Connection closed');
});

This is what happens in my case:

  1. The client tries to connect to HOST:PORT, which is currently unreachable
  2. The connection cannot be established, because the host is not reachable
  3. The onError-callback is called with the expected exception.
  4. Calling client.end() in the onError-callback results in onError being called again
  5. This time with the error unable to find socket
  6. As soon as the host becomes reachable again, the socket connects to the host!
  7. Calling any of the sockets instance-methods has no effect, except for end or destroy which result in onError being called with unable to find socket again.

The Bug is in TcpSocketManager.java on line 136:

  • If ex is set when onConnectCompleted is called, the first if-branch will be skipped
  • Therefore, the new socket-instance never makes it into mClients
  • Instead, the onError-callback is triggered, which we observed in the code.
  • Any other method call (e.g. close) will try to find the socket with the given cId, which will never be there and always return null.
  • On the close-method, this will trigger another call to onError, this time with the hardcoded unable to find socket-message we got in JavaScript.
  • Other methods will just silently fail and not do anything (write for example).
  • The socket never closed either. It just exists without a way to communicate with it.

Fix: I made a quick test to see how Node.js handles this:

const net = require("net");
const client = net.createConnection(41231, "localhost", () => { // this host:port is NOT reachable!
	console.log("Connected!");
});
client.on("error", (err) => {
	console.log("Error! "+err);
});
client.on("close", () => {
	console.log("Closed...");
});

Node will try to connect, then emit an error-event with the error Error: connect ECONNREFUSED and afterwards emit a close-event.

So, closing the socket automatically if it can't connect might be the most concise way of implementing this.


If you need any further information, I'll be here to help!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions