Hi all, I'm working on adding OpenSSL support to my server program, and generally it's working pretty well, but I have come across a problem.
First, some background: The server is single-threaded and uses non-blocking I/O and a select() loop to handle multiple clients simultaneously. The server is linked to libssl.0.9.8.dylib and lib crypto.0.9.8.dylib (i.e. the libraries provided in /usr/lib by MacOS/X 10.8.5). The client<->server protocol is a proprietary full-duplex messaging protocol; that is, the clients and the server are all allowed to send and receive data at any time, and the client<->server TCP connections remain connected indefinitely (i.e. until the client or server decides to disconnect). The issue is this: my clients can connect to the server, and sending and receiving data works fine (now that I got the SSL_ERROR_WANT_WRITE and SSL_ERROR_WANT_READ logic sorted out)… but if a the server accept()'s a new client connection *while* other clients are in the middle of sending or receiving data, the SSL layer seems to break. In particular, immediately after the server runs the setup routine below to set up the newly-accepted socket, SSL_read() on one or more of the other (pre-existing) clients' sockets will return -1, and ERR_print_errors_fp(stderr) gives this output: SSL_read() ERROR: 5673:error:140F3042:SSL routines:SSL_UNDEFINED_CONST_FUNCTION:called a function you should not call:/SourceCache/OpenSSL098/OpenSSL098-47.2/src/ssl/ssl_lib.c:2248: After this error first appears, the server largely stops working. Data movement stops, and if I try to connect another client I often get this error: SSL_read() ERROR: 5673:error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol:/SourceCache/OpenSSL098/OpenSSL098-47.2/src/ssl/s23_srvr.c:578: This happens about 25% of the time in my test scenario. If I make sure that my pre-existing client connections are idle (no data being sent or received) at the moment when the new client connects, it never happens. Does anyone know what might be going wrong here? Have I found an OpenSSL bug, or is there some detail that I'm overlooking? Some relevant code from my program is pasted below, in case it's helpful. Thanks, Jeremy ----------- // Socket setup routine, called when the server accepts a new TCP socket int SSLSession :: SetupSSL(int sockfd) { _ctx = SSL_CTX_new(SSLv23_method()); if (_ctx) { SSL_CTX_set_mode(_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); _ssl = SSL_new(_ctx); if (_ssl) { _sbio = BIO_new_socket(sockfd, BIO_NOCLOSE); if (_sbio) { SSL_set_bio(_ssl, _sbio, _sbio); SSL_set_accept_state(_ssl); BIO_set_nbio(_sbio, !blocking); ERR_print_errors_fp(stderr); return RESULT_SUCCESS; } else fprintf(stderr, "SSLSession: BIO_new_socket() failed!\n"); } else fprintf(stderr, "SSLSession: SSL_new() failed!\n"); } else fprintf(stderr, "SSLSession: SSL_CTX_new() failed!\n"); return RESULT_FAILURE; } // Socket read routine -- returns number of bytes read from SSL-land int32 SSLSession :: Read(void *buffer, uint32 size) { if (_ssl == NULL) return -1; int32 bytes = SSL_read(_ssl, buffer, size); if (bytes > 0) { _sslState &= ~(SSL_STATE_READ_WANTS_READABLE_SOCKET | SSL_STATE_READ_WANTS_WRITEABLE_SOCKET); } else if (bytes == 0) return -1; // connection was terminated else { int err = SSL_get_error(_ssl, bytes); if (err == SSL_ERROR_WANT_WRITE) { // We have to wait until our socket is writeable, and then repeat our SSL_read() call. _sslState &= ~SSL_STATE_READ_WANTS_READABLE_SOCKET; _sslState |= SSL_STATE_READ_WANTS_WRITEABLE_SOCKET; bytes = 0; } else if (err == SSL_ERROR_WANT_READ) { // We have to wait until our socket is readable, and then repeat our SSL_read() call. _sslState |= SSL_STATE_READ_WANTS_READABLE_SOCKET; _sslState &= ~SSL_STATE_READ_WANTS_WRITEABLE_SOCKET; bytes = 0; } else { fprintf(stderr, "SSL_read() ERROR: "); ERR_print_errors_fp(stderr); } } return bytes; } // Socket write routine -- returns number of bytes written to SSL-land int32 SSLSession :: Write(const void *buffer, uint32 size) { if (_ssl == NULL) return -1; int32 bytes = SSL_write(_ssl, buffer, size); if (bytes > 0) { _sslState &= ~(SSL_STATE_WRITE_WANTS_READABLE_SOCKET | SSL_STATE_WRITE_WANTS_WRITEABLE_SOCKET); } else if (bytes == 0) return -1; // connection was terminated else { int err = SSL_get_error(_ssl, bytes); if (err == SSL_ERROR_WANT_READ) { // We have to wait until our socket is readable, and then repeat our SSL_write() call. _sslState |= SSL_STATE_WRITE_WANTS_READABLE_SOCKET; _sslState &= ~SSL_STATE_WRITE_WANTS_WRITEABLE_SOCKET; bytes = 0; } else if (err == SSL_ERROR_WANT_WRITE) { // We have to wait until our socket is writeable, and then repeat our SSL_write() call. _sslState &= ~SSL_STATE_WRITE_WANTS_READABLE_SOCKET; _sslState |= SSL_STATE_WRITE_WANTS_WRITEABLE_SOCKET; bytes = 0; } else { fprintf(stderr,"SSL_write() ERROR!"); ERR_print_errors_fp(stderr); } } return bytes; } ______________________________________________________________________ OpenSSL Project http://www.openssl.org User Support Mailing List openssl-users@openssl.org Automated List Manager majord...@openssl.org