views:

129

answers:

1

PLEASE READ THE UPDATE #2 BELOW IF YOU ARE INTERESTED IN THIS PROBLEM ;)

Say I put this code into the JS of my extension.

var reader = {
    onInputStreamReady : function(input) {
        var sin = Cc["@mozilla.org/scriptableinputstream;1"]
                    .createInstance(Ci.nsIScriptableInputStream);
        sin.init(input);
        sin.available();
        var request = '';
        while (sin.available()) {
          request = request + sin.read(512);
        }
        console.log('Received: ' + request);
        input.asyncWait(reader,0,0,null);
    } 
}        
var listener = {
    onSocketAccepted: function(serverSocket, clientSocket) {
        console.log("Accepted connection on "+clientSocket.host+":"+clientSocket.port);
        input = clientSocket.openInputStream(0, 0, 0).QueryInterface(Ci.nsIAsyncInputStream);
        output = clientSocket.openOutputStream(Ci.nsITransport.OPEN_BLOCKING, 0, 0);
        input.asyncWait(reader,0,0,null);
    }
}
var serverSocket = Cc["@mozilla.org/network/server-socket;1"].
                    createInstance(Ci.nsIServerSocket);
serverSocket.init(-1, true, 5);
console.log("Opened socket on " + serverSocket.port);
serverSocket.asyncListen(listener);

Then I run Firefox and connect to the socket via telnet

telnet localhost PORT

I send 5 messages and they get printed out, but when I try to send 6th message I get

firefox-bin: Fatal IO error 11 (Resource temporarily unavailable) on X server :0.0.

Even worse, when I try to put this same code into an XPCOM component (because that's where I actually need it), after I try sending a message via telnet I get

Segmentation fault

or sometimes

GLib-ERROR **: /build/buildd/glib2.0-2.24.1/glib/gmem.c:137: failed to allocate 32 bytes
aborting...
Aborted

printed to the terminal from which I launched firefox.

This is really weird stuff.. Can you spot something wrong with the code I've pasted or is smth wrong with my firefox/system or is the nsIServerSocket interface deprecated?

I'm testing with Firefox 3.6.6.

I would really appreciate some answer. Perhaps you could point me to a good example of using Sockets within an XPCOM component. I haven't seen many of those around.

UPDATE

I just realised that it used to work so now I think that my Console component breaks it. I have no idea how this is related. But if I don't use this component the sockets are working fine.

Here is the code of my Console component. I will try to figure out what's wrong and why it interferes and I'll post my findings later. Likely I'm doing something terribly wrong here to cause Segmentation faults with my javascript =)

Voodoo..

components/Console.js:

const Cc = Components.classes; 
const Ci = Components.interfaces; 
const Cr = Components.results; 
Console.prototype = (function() { 
    var win; 
    var initialized = false; 
    var ready = false; 
    var _log = function(m, level, location) { 
        if (initialized&&ready) { 
            var prefix = "INFO: "; 
            switch (level) { 
                case "empty": 
                    prefix = "" 
                    break; 
                case "error": 
                    prefix = "ERORR: " 
                    break; 
                case "warning": 
                    prefix = "WARNING: " 
                    break; 
            } 
            win.document.getElementById(location).value = 
win.document.getElementById(location).value + prefix + m + "\n"; 
            win.focus(); 
        } else if (initialized&&!ready) { 
            // Now it is time to create the timer... 
            var timer = Components.classes["@mozilla.org/timer;1"] 
               .createInstance(Components.interfaces.nsITimer); 
            // ... and to initialize it, we want to call 
event.notify() ... 
            // ... one time after exactly ten second. 
            timer.initWithCallback( 
                { notify: function() { log(m); } }, 
                10, 
                Components.interfaces.nsITimer.TYPE_ONE_SHOT 
            ); 
        } else { 
            init(); 
            log(m); 
        } 
    } 
    var log = function(m, level) { 
        _log(m, level, 'debug'); 
    } 
    var poly = function(m, level) { 
        _log(m, "empty", 'polyml'); 
    } 
    var close = function() { 
        win.close(); 
    } 
    var setReady = function() { 
        ready = true; 
    } 
    var init = function() { 
        initialized = true; 
        var ww = Components.classes["@mozilla.org/embedcomp/window- 
watcher;1"] 
                    .getService(Components.interfaces.nsIWindowWatcher); 
        win = ww.openWindow(null, "chrome://polymlext/content/ 
console.xul", 
                         "console", "chrome,centerscreen, 
resizable=no", null); 
        win.onload = setReady; 
        return win; 
    } 
    return { 
        init: init, 
        log : log, 
        poly : poly, 
    } 
}()); 

// turning Console Class into an XPCOM component 
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); 
function Console() { 
    this.wrappedJSObject = this; 
} 

prototype2 = { 
  classDescription: "A special Console for PolyML extension", 
  classID: Components.ID("{483aecbc-42e7-456e-b5b3-2197ea7e1fb4}"), 
  contractID: "@ed.ac.uk/poly/console;1", 
  QueryInterface: XPCOMUtils.generateQI(), 
} 

//add the required XPCOM glue into the Poly class 
for (attr in prototype2) { 
    Console.prototype[attr] = prototype2[attr]; 
} 

var components = [Console]; 
function NSGetModule(compMgr, fileSpec) { 
  return XPCOMUtils.generateModule(components); 
} 

I'm using this component like this:

console = Cc["@ed.ac.uk/poly/console;1"].getService().wrappedJSObject; 
console.log("something");

And this breaks the sockets :-S =)

UPDATE #2 Ok, if anyone is interested in checking this thing out I would really appreciate it + I think this is likely some kind of bug (Seg fault from javascript shouldn't happen) I've made a minimal version of the extension that causes the problem, you can install it from here:

http://dl.dropbox.com/u/645579/segfault.xpi

The important part is chrome/content/main.js:

http://pastebin.com/zV0e73Na

The way my friend and me can reproduce the error is by launching the firefox, then a new window should appear saying "Opened socket on 9999". Connect using "telnet localhost 9999" and send a few messages. After 2-6 messages you get one of the following printed out in the terminal where firefox was launched:

1 (most common)

Segmentation fault

2 (saw multiple times)

firefox-bin: Fatal IO error 11 (Resource temporarily unavailable) on X server :0.0.

3 (saw a couple of times)

GLib-ERROR **: /build/buildd/glib2.0-2.24.1/glib/gmem.c:137: failed to allocate 32 bytes aborting... Aborted

4 (saw once)

firefox-bin: ../../src/xcb_io.c:249: process_responses: Assertion `(((long) (dpy->last_request_read) - (long) (dpy->request)) <= 0)' failed. Aborted

If you need any more info or could point me to where to post a bug report :-/ I'll be glad to do that.

I know this is just one of the many bugs... but perhaps you have an idea of what should I do differently to avoid this? I would like to use that "console" of mine in such way.

I'll try doing it with buffer/flushing/try/catch as people are suggesting, but I wonder whether try/catch will catch the Seg fault...

+1  A: 

This is a thread problem. The callback onInputStreamReady happened to be executed in a different thread and accessing UI / DOM is only allowed from the main thread. Solution is really simple:

change

input.asyncWait(reader,0,0,null);

to

var tm = Cc["@mozilla.org/thread-manager;1"].getService();
input.asyncWait(reader,0,0,tm.mainThread);
Karolis