0

I'm developing a firefox add-on that uses a server socket and I found that I can open server sockets with the same address:port, what is very weird. I have checked with netstat and I was shocked.

The behavior of this thing is that the first opened server socket accepts all connections, then, when it is closed, the second one begins to accept new connections.

More interesting is that if I open a server socket with java, then I can't open another server socket with firefox addon. So, there should be some flags that allows this issue, but I can't find anything in sdk API to avoid this problem.

I'm doing the testing under Windows 7.

I would like to detect that a server socket is already opened, instantly. I don't want to open a client socket to check this. Any ideas?

Here is how I open the socket, not very difficult...

try
{
    serverSocket = Cc["@mozilla.org/network/server-socket;1"].createInstance(Ci.nsIServerSocket);
    serverSocket.init(listenPort, true, 100);
    serverSocket.asyncListen(listener);
}
catch(error)
{
    console.log(error);
Kanowins
  • 1
  • 2

1 Answers1

0

Ok, after a lot of search, I only can offer a workaround for this issue. Just test if the server socket is opened. This solution is very fast and it works. Here is some code for creating a ServerSocket to avoid this issue:

const {Cc, Ci, Cu, components}  = require("chrome");

const gThreadManager = Cc["@mozilla.org/thread-manager;1"].getService();

function ServerSocket(){

    function checkFreePort(port, callback, error){
        try{        
            var bRead = false;
            var socket_service = Cc["@mozilla.org/network/socket-transport-service;1"].getService(Ci.nsISocketTransportService);

            // we open a socket client to test if there is a server socket listening
            socket = socket_service.createTransport(null, 0, "127.0.0.1", port, null);
            socket.setEventSink ({
                onTransportStatus : function(transport, status){
                    if (status == nsISocketTransport.STATUS_CONNECTED_TO) // connected
                    {
                        if (!bRead)
                        {
                            bRead = true;
                            try{
                                socket.close();
                            }catch(ex){
                                console.log(ex);
                            }
                            // connected to the server socket, so we return error
                            error();
                        }
                    }
                }
            }, gThreadManager.mainThread);

            // we put a timeout to avoid the block of the extension forever, 2 seconds should be enougth for localhost
            // actually tests shows that the socket replies instantly if there is no server socket listening on the onInputStreamReady
            socket.setTimeout(0, 2000);

                    var input = socket.openInputStream(Ci.nsITransport.OPEN_BLOCKING,0,0);


            input.asyncWait({
                onInputStreamReady: function(input) {
                    try
                    {
                        // if there is no server socket listening, we get onInputStreamReady and reading the stream will throw an error...

                        if (bRead) // we detected the connection before, so we have finished
                            return;
                        var sin = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
                        sin.init(input);
                        sin.read(1);
                        bRead = true;
                        // we read something, code should never execute this because we must be connected before and we have controlled it
                        // but... just in case...
                        error();

                    }
                    catch(ex) {
                        // error reading, the socket can't connect, so it is ok for us
                        bRead = true;
                        callback();
                    }           
                    finally
                    {
                        sin.close();
                        input.close();
                    }
                }
            }, 0, 0, gThreadManager.mainThread);
        }
        catch(error2)
        {
            console.log("Unexpected error: " + error2);
            error();
        }

    }

}

ServerSocket.prototype = {
    listen: function(port, listener, errorCallback){
        checkFreePort(port, function(){
            serverSocket.init(port, true, 100);
            serverSocket.asyncListen(listener);
        }, errorCallback);
    }
}


var listener = {
        onSocketAccepted: function(serverSocket, clientSocket) {
            console.log("Accepted connection on " + clientSocket.host + ":" + clientSocket.port);

            // do stuff

        }
    };  


var server = new ServerSocket(8080, listener, function(){
    console.log("Error creating server socket");
});
Kanowins
  • 1
  • 2