Hello,

we are currently programming on an integration of OpenSSL into our
existing Socket architecture. We have a problem with non-blocking
connections.

In our test scenario we coded a simple server and client that shall
communicate encrypted via SSL. But for now we simply use an unencrypted
"Socket BIO" on both ends (client and server) and no SSL or buffer BIOs.

Both, the client and the server first create a TCP socket:

    int socketDescriptor = ::socket(AF_INET, SOCK_STREAM, 0);

and then create a "Socket BIO" that will use the already created socket
(socketDescriptor):

    BIO * socketBio = 0;

    // Server
    socketBio = BIO_new(BIO_s_accept());
    BIO_set_fd(socketBio, socketDescriptor, BIO_NOCLOSE);
        
    // Client
    socketBio = BIO_new_socket(socketDescriptor, BIO_NOCLOSE);

Our scenario works fine if both, client and server operate in blocking
mode (the default in our API and in OpenSSL, right?). But when we try to
use non-blocking I/O we run into troubles and there are so many options
to choose from and tweak that we simply need some help.

Let's start with the client...

========================================================================
0. Are we using the correct BIO types for the client and server?
========================================================================

   There are so many types. We can also try BIO_new(BIO_s_socket()),
   BIO_new(BIO_s_connect()) ...

========================================================================
1. Which items need to be set to non-blocking AND in which order?
========================================================================

   Directly after we created the socketBio variable (before we do any
   connection stuff) we do this for the client:

       //------------------------------------------------------------
       // Set socket descriptor to non-blocking
       //------------------------------------------------------------

       int flags = ::fcntl( socketDescriptor, F_GETFL);

       if (flags != -1)
       {
           int rc = ::fcntl( socketDescriptor,
                             F_SETFL, flags | O_NONBLOCK );

           if (rc == -1)
           {
               print_error("Could not set socket to non-blocking");
           }
       }

       //------------------------------------------------------------
       // Set socket BIO to non-blocking
       //------------------------------------------------------------
       int mode = 1;
       BIO_socket_nbio(socketDescriptor, mode);

   We also tried this for the socket BIO:

       //------------------------------------------------------------
       // Set socket BIO to non-blocking
       //------------------------------------------------------------
       int mode = 1;
       BIO_set_nbio(socketBio, mode);

   But when we do this, we get an error when we call
   BIO_do_connect(socketBio). The error code returned is -1.

========================================================================
2. Order of connect calls?
========================================================================

   In our client example, we create a socket descriptor, the socket BIO,
   set both to non-blocking, call ::connect() on the socket descriptor
   and the BIO_do_connect() on the socket BIO.

   Is this principle correct?

   Here is the code of the connect for the socket descriptor (by the way
   in our TCP examples, this method works fine):

       bool result = false;
       int conResult;

       do
       {
           conResult = ::connect( socketDescriptor,
                                  m_address.getSockAddr(),
                                  m_address.getLength() );

           if ( conResult == 0 )
           {
               result = true;
           }
           else
           {
               print_error( "::connect() failed with: %d, errno=%d, %s",
                            conResult,
                            errno,
                            strerror(errno)
                          );
           }
       }
       while (conResult != 0 && errno == EINPROGRESS);

       return result;

   This is how we then call BIO_do_connect() on the socket BIO (for
   blocking I/O, this works fine):

       bool result = false;
       int rc;
       do
       {
           rc = BIO_do_connect(m_socketBio);

           if (rc==1)
           {
               result = true;
           }
           else
           {
               print_error("BIO_do_connect() failed: %d, errno=%d, %s",
                            conResult,
                            errno,
                            strerror(errno)
                          );
           }
       }
       while(rc != 1 && BIO_should_retry(m_socketBio));

       return result;

Addition: We are using BIO_write/BIO_read on the socket BIO.

Now back to our problem: Our function that calls BIO_do_connect always
returns false.

Has anybody a good explanation for this? Or can anybody tell us if we
are doing something completely wrong?

Thanks in advance!


______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    openssl-users@openssl.org
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to