Thanks for this explanation.  As I read more, I think I am getting a better
understanding of this.  So unlike normal tcp connections, where a read juts
reads, and a write just writes, SSL_read may write, and SSL_write may read.
This is all done under the hood, so I don't need to be concerned with that,
except to reissue the call when I get a WANT_READ or WANT_WRITE error.  And
when I get one of these, I basically just have to wait (select/poll or
whatever) until the socket is readable/writable, then reissue the call.
Does that sound right?

And regarding the use of multiple threads, if I protect the SSL object with
a lock, that should be fine right?  But it sounds like a single thread for
both read and writes is the norm.  Is this true?  And if so, other than the
fact that I need to co-ordinate access to the SSL obj with a mutex, is there
any draw back to using multiple threads?

So if I had the following:

/* Read thread */

bool ok = false;
while (!ok)
{
        mutex.lock(); // protect ssl
        int ret = SSL_read(ssl, buf, len);
        int err = SSL_get_error(ssl, ret);
        mutex.unlock();

        if (err == SSL_ERROR_NONE)
        {
                ok = true;
        }
        else if (err == SSL_ERROR_WANT_READ)
        {
                fd_set  read_fds;
                FD_ZERO(&read_fds);
                FD_SET(m_sock, &read_fds);

                // wait for socket to be readable
                if (select(1, &read_fds, 0, 0, 0) <= 0)
                        return 0; // error

                continue; // re-issue the read
        }
        else if (err == SSL_ERROR_WANT_WRITE)
        {
                fd_set  write_fds;
                FD_ZERO(&write_fds);
                FD_SET(m_sock, &write_fds);

                // wait for socket to be wriable
                if (select(1, 0, &write_fds, 0, 0) <= 0)
                        return 0; // error

                continue; // re-issue the read
        }
        else
        {
                return 0; // error
        }
}
 
/* write thread */

int offset = 0;
while (len)
{
        mutex.lock();
        int ret = SSL_write(ssl, buf+offset, len);
        int err = SSL_get_error(ssl, ret);
        mutex.unlock();

        if (err == SSL_ERROR_NONE)
        {
                offset += ret;
                len -= ret;
        }
        else if (err == SSL_ERROR_WANT_READ)
        {
                fd_set  read_fds;
                FD_ZERO(&read_fds);
                FD_SET(m_sock, &read_fds);

                // wait for socket to be readable
                if (select(1, &read_fds, 0, 0, 0) <= 0)
                        return 0; // error

                continue; // re-issue the write
        }
        else if (err == SSL_ERROR_WANT_WRITE)
        {
                fd_set  write_fds;
                FD_ZERO(&write_fds);
                FD_SET(m_sock, &write_fds);

                // wait for socket to be writable
                if (select(1, 0, &write_fds, 0, 0) <= 0)
                        return 0; // error

                continue; // re-issue the write
        }
        else
        {
                return 0; // error
        }
}

Does that look ok?

Since these the read and writes may be done in different threads, than it
could happen that the write thread got a WANT_READ and was waiting for data
to arrive.  But the read thread may also be waiting for data to arrive.  One
of these threads will wake up first.  If the read thread wakes up, it will
do SSL_read. If the write thread wakes up, it will try a SSL_write.  Only
one will happen first because they are protected by a lock.  But if the read
thread was able to read first.  Then when the write thread acquires the lock
and retries the SSL_write, it will still succeed because whatever data it
was waiting to read was read by the read thread.  Does that make sense?



> -----Original Message-----
> From: [EMAIL PROTECTED] 
> [mailto:[EMAIL PROTECTED] 
> Sent: Friday, April 15, 2005 4:58 PM
> To: openssl-users@openssl.org
> Subject: RE: Confusion about SSL_ERROR_WANT_READ/WRITE
> 
> 
> > I have an app where reads and writes happen from different threads.
> > Now, ideally, one would envision that I just replace the 
> reads/writes 
> > with SSL_read/SSL_write.  Now I know it is not as simple as that.
> 
>       You need to wrap each SSL connection with a lock and 
> hold that lock when you call SSL_read or SSL_write. This will 
> prevent concurrent accesses to the same connection from 
> different threads, which is not supported.
> 
> > What exactly is the meaning of the SSL_ERROR_WANT_READ/WRITE errors?
> [snip]
> 
>       The OpenSSL connection does not have exactly the same 
> semantics as a TCP connection. Say you try to send data 
> before the handshaking is finished.
> OpenSSL cannot send any data over the socket until it reads 
> the handshake from the other side.So a 'WANT_READ' error 
> means that OpenSSL needs to read some encrypted data from the 
> other side before it can write the application data you want to send.
> 
>       The way you deal with these is just by not doing the 
> thing that the error stops you from doing until you've made 
> some forward progress. There are four things you are happening:
> 
>       1) If the application wants to send some plaintext, 
> that plaintext has to go OpenSSL to encrypt.
> 
>       2) If OpenSSL has some decrypted data, it need to get 
> to the application.
> 
>       3) If some encrypted data is (ready on / received on) 
> the socket, it needs to get to OpenSSL.
> 
>       4) If OpenSSL has some encrypted data to send, and the 
> socket is ready to receive, the data needs to b sent.
> 
>       These operations inter-relate. Sometimes it's obvious, 
> for example, you can't receive any decrypted data until the 
> encrypted data is ready on the socket. However, sometimes 
> it's not obvious.
> 
>       So say you go to send some data using SSL_write and you 
> get 'WANT_READ'.
> That means OpenSSL wants to read some encrypted data from the 
> other side before it can do the send. So you could, for 
> example, 'select' on the socket and when there's data to 
> read, call OpenSSL again. It will then do step 3 itself.
> 
>       If you go to receive some data using SSL_read and get 
> 'WANT_WRITE, that means OpenSSL can't receive any data 
> because it has to send some data to the other side first. So 
> you could 'select' for write to wait for the socket buffer to 
> drain and then call OpenSSL again.
> 
>       DS
> 
> 
> ______________________________________________________________________
> OpenSSL Project                                 http://www.openssl.org
> User Support Mailing List                    openssl-users@openssl.org
> Automated List Manager                           [EMAIL PROTECTED]
> 
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@openssl.org
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to