Nelson B Bolyard wrote:
On 2009-06-19 12:48 PDT, Rich Megginson wrote:

 Does NSS support non-blocking sockets?

Yes.

I'm running into a problem while using NSS with non-blocking sockets. I have my own PR_Recv function that does something like this:

Although you called it a "PR_Recv" function, I gather that it is actually
an NSPR IO layer's recv method (a method in the layer's PRIOMethods struct).
I will assume that is correct.

Yes. This is an implementation of a PRIOMethods stack. So what I mean is "this is the function that implements the PR_Recv functionality for this layer".

static int PR_CALLBACK
my_PR_Recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags, PRIntervalTime timeout)
{
...
    rc = my_real_read_function( realfd, buf, len );
    if (rc <= 0) {
        if ( errno == EAGAIN || errno == EWOULDBLOCK ) {
            PR_SetError( PR_WOULD_BLOCK_ERROR, errno );
        }
    }

    return rc;
}



In the particular stack trace I'm looking at, this is called via

ssl_DefRecv ssl3_GatherData ssl3_GatherCompleteHandshake ssl_GatherRecord1stHandshake

I'm guessing the rest of the stack resembles this

  ssl_Do1stHandshake
  ssl_SecureRecv
  PR_Recv

No.

    ssl_Do1stHandshake
    SSL_ForceHandshake
    my_accept

This is a server accepting an SSL connection.

I think the problem is that ssl3_GatherData does not check for WOULD_BLOCK:

Before we look at potential causes of the problem, I think we need a
description of the problem.

Ok. The problem is that, in the above code, realfd is set to non-blocking, and my_real_read_function is returning rc == -1 with errno set to EAGAIN. This means that the read operation would block. If I simply set the error to PR_WOULD_BLOCK_ERROR and pass the error condition back up through the SSL layer, SSL interprets this as a hard error - FAIL.


This is the problem here. I think it should check to see if ssl_SocketIsBlocking(), then check to see if the error is WOULD_BLOCK, then return rv = SECWouldBlock

Why do you think that?
SECWouldBlock doesn't mean "underlying socket would block".

Ok.


Because when it returns rv = SECFailure, this goes up to the caller, ssl3_GatherCompleteHandshake, which just returns it:

Correct.  It should be returned all the way out to the caller of PR_Recv.

So then to SSL_ForceHandshake and my_accept() function.


ssl_GatherRecord1stHandshake gets rv SECFailure instead of SECWouldBlock.

Correct.

It looks as though it can properly handle SECWouldBlock, but
ssl3_GatherData -> ssl3_GatherCompleteHandshake do not return that rv in
this case.

Correct.  PRIOMethods functions do not return SECStatus values.
SECWouldBlock is not a valid return value from any NSPR function.

Ok.


Moreover, inside of libSSL, SECWouldBlock does not mean exactly the same
thing as PR_FAILURE with error code PR_WOULD_BLOCK_ERROR.  Inside of
libSSL, SECWouldBlock means that progress on this SSL socket is blocked
by something OTHER THAN blockage of the underlying socket on network IO
activity, such as waiting for a browser user to dismiss a dialog, or
waiting for some activity to complete on ANOTHER socket, such as when
fetching OCSP responses.

Ok.


Note that even if my PR_Recv function returned 0 here, the NSS code would interpret that as a closed socket:

Not closed, but at EOF.  Yes, that's exactly as expected.

Is NSS supposed to support non-blocking sockets?

Yes.

If so, what am I doing wrong?

Since you haven't told us what the problem is, what its symptoms are,
I can only guess.  I would guess that the problem is in the caller of
PR_Recv.  I would guess that it is expecting to get back SECWouldBlock
from PR_Recv, and when it gets PR_FAILURE, it doesn't check the error
code for PR_WOULD_BLOCK_ERROR, and then call PR_Poll to wait for IO
completion.  Or, maybe, it calls PR_Poll, but gets the "wrong answer"
due to a problem in some IO layer's poll method.

The problem is that my read_function(realfd) is returning EAGAIN, and I need to somehow propagate that back up to the SSL layer (via setting the pr error to PR_WOULD_BLOCK_ERROR) to tell the SSL layer that data is not yet available.

Or, my_PR_Recv function needs to do a poll() to wait until all of the requested data has been read, and not return until that happens, or some real error condition has occurred.
--
dev-tech-crypto mailing list
dev-tech-crypto@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-tech-crypto

Reply via email to