reading from an nsIScriptableInputStream"-wrapped socket stream doesn't block, even when OPEN_BLOCKING is specified

UNCONFIRMED
Unassigned

Status

()

Core
Networking
P5
normal
UNCONFIRMED
12 years ago
7 months ago

People

(Reporter: Eric Promislow, Unassigned)

Tracking

Trunk
x86
Windows XP
Points:
---

Firefox Tracking Flags

(Not tracked)

Details

(Whiteboard: [necko-would-take])

(Reporter)

Description

12 years ago
User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3
Build Identifier: Komodo Professional, version 4.0.0-devel, build 262212, platform win32-x86.

The JS code:
function Session(console, host, port) {
    try {
        var transportService =
            get_service("@mozilla.org/network/socket-transport-service;1",
                        "nsISocketTransportService");
        var transport = transportService.createTransport(null, 0, host, port, null);
        var open_blocking_flag = Components.interfaces.nsITransport.OPEN_BLOCKING;
        this._inputStream = transport.openInputStream(open_blocking_flag, 0, 0);
        this.ostream = transport.openOutputStream(0, 0,0);
        this.istream = create_instance("@mozilla.org/scriptableinputstream;1",
                                      "nsIScriptableInputStream");
        this.istream.init(this._inputStream);
    } catch(ex) {
        log.debug("connect.start failed: " + ex);
    }
}

Session.prototype.get_command = function() {
    var num_tries = 0;
    var limit_tries = 1000000;
    while (num_tries < limit_tries) {
        try {
            var thisBuffer = this.istream.read(1024);
            if (typeof(thisBuffer) == "undefined") {
                log.debug("get_command -- input stream is closed");
                break;
            } else if (thisBuffer.length > 0) {
                log.debug("Read in [" + thisBuffer + "]");
                return thisBuffer;
            }
            if (++num_tries >= limit_tries) {
                log.debug("Giving up after " + limit_tries + " tries...");
            } else if (num_tries == 1) {
                // I often hit this
                log.debug("Didn't find anything first try, going back again (and again...)");
            }
        } catch (ex) {
            if (++num_tries == 1) {
                log.debug("Session.get_command: *** Caught " + ex + " while reading.");
            } else if (num_tries >= limit_tries) {
                log.debug("Giving up after " + limit_tries + " tries...");
            }
        }
    }
    return null;
};

This code is on the server side.  I'm logging the client as well, and often
finding this in the logs:

DEBUG: winger: Didn't find anything first try, going back again (and again...)
DEBUG: client: Writing out <string>
DEBUG: winger: Read in [...]

biesi is wondering if PR_Available() is blocking correctly.

Reproducible: Always

Steps to Reproduce:
1. Both the server (core code given above) and the client are part of Komodo.
I'm using two instances of Komodo -- a production version for the client, which
is established, and a devel version to get this server right.  I don't have
a standalone test case right now.

Actual Results:  
The input stream doesn't block.  I need to spin it in a loop until it gets some
input.

Expected Results:  
Reading from an empty stream should block until there's something in it.
It should return either null (writer has closed its endpoint), or at least
one character.  It should be up to me to keep calling inputStream.read() until
I've received a complete request.
(Reporter)

Comment 1

12 years ago
I replaced the use of nsIScriptableInputStream with nsIBinaryInputStream,
and call nsIBinaryInputStream.read(1) one char at a time -- we use null
bytes to delimit requests.  This works fine.  Reading more chars/call and
buffering is left as an internal todo for me (obviously), but this at
least isolates the problem to nsIScriptableInputStream.
hm, I was wrong on IRC, since opening a blocking socket stream really gives you a pipe. That said, I see no code that'd make it block if zero bytes are available there either.
(Reporter)

Comment 3

12 years ago
Additional note:

nsScriptableInputStream::Read() makes this call:
rv = mInputStream->Available(&count);

and if nothing's on the socket, mInputStream->Available
returns 0 immediately, instead of blocking, even when
the stream has been created with the OPEN_BLOCKING flag.
Whiteboard: [necko-would-take]
You need to log in before you can comment on or make changes to this bug.