wez             Sun Oct 13 21:27:43 2002 EDT

  Modified files:              
    /php4/main  network.c 
  Log:
  Implement better SSL error handling.
  
  
Index: php4/main/network.c
diff -u php4/main/network.c:1.77 php4/main/network.c:1.78
--- php4/main/network.c:1.77    Sun Oct 13 19:43:21 2002
+++ php4/main/network.c Sun Oct 13 21:27:43 2002
@@ -16,7 +16,7 @@
    | Streams work by Wez Furlong <[EMAIL PROTECTED]>                   |
    +----------------------------------------------------------------------+
  */
-/* $Id: network.c,v 1.77 2002/10/13 23:43:21 wez Exp $ */
+/* $Id: network.c,v 1.78 2002/10/14 01:27:43 wez Exp $ */
 
 /*#define DEBUG_MAIN_NETWORK 1*/
 
@@ -746,6 +746,84 @@
       return ret;
 }
 
+#if HAVE_OPENSSL_EXT
+static int handle_ssl_error(php_stream *stream, int nr_bytes TSRMLS_DC)
+{
+       php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
+       int err = SSL_get_error(sock->ssl_handle, nr_bytes);
+       char esbuf[512];
+       char *ebuf = NULL, *wptr = NULL;
+       size_t ebuf_size = 0;
+       unsigned long code;
+       int retry = 1;
+
+       switch(err) {
+               case SSL_ERROR_ZERO_RETURN:
+                       /* SSL terminated (but socket may still be active) */
+                       retry = 0;
+                       break;
+               case SSL_ERROR_WANT_READ:
+               case SSL_ERROR_WANT_WRITE:
+                       /* re-negotiation, or perhaps the SSL layer needs more
+                        * packets: retry in next iteration */
+                       break;
+               case SSL_ERROR_SYSCALL:
+                       if (ERR_peek_error() == 0) {
+                               if (nr_bytes == 0) {
+                                       php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                                                       "SSL: fatal protocol error");
+                                       stream->eof = 1;
+                                       retry = 0;
+                               } else {
+                                       char *estr = 
+php_socket_strerror(php_socket_errno(), NULL, 0);
+
+                                       php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                                                       "SSL: %s", estr);
+
+                                       efree(estr);
+                                       retry = 0;
+                               }
+                               break;
+                       }
+                       /* fall through */
+               default:
+                       /* some other error */
+                       while ((code = ERR_get_error()) != 0) {
+                               /* allow room for a NUL and an optional \n */
+                               if (ebuf) {
+                                       esbuf[0] = '\n';
+                                       esbuf[1] = '\0';
+                                       ERR_error_string_n(code, esbuf + 1, 
+sizeof(esbuf) - 2);
+                               } else {
+                                       esbuf[0] = '\0';
+                                       ERR_error_string_n(code, esbuf, sizeof(esbuf) 
+- 1);
+                               }
+                               code = strlen(esbuf);
+                               esbuf[code] = '\0';
+
+                               ebuf = erealloc(ebuf, ebuf_size + code + 1);
+                               if (wptr = NULL)
+                                       wptr = ebuf;
+
+                               /* also copies the NUL */
+                               memcpy(wptr, esbuf, code + 1);
+                               wptr += code;
+                       }
+
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING,
+                                       "SSL operation failed with code %d.%s%s",
+                                       err,
+                                       ebuf ? "OpenSSL Error messages:\n" : "",
+                                       ebuf ? ebuf : "");
+                               
+                       retry = 0;
+       }
+       return retry;
+}
+#endif
+
+
+
 static size_t php_sockop_write(php_stream *stream, const char *buf, size_t count 
TSRMLS_DC)
 {
        php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
@@ -753,7 +831,18 @@
        
 #if HAVE_OPENSSL_EXT
        if (sock->ssl_active) {
-               didwrite = SSL_write(sock->ssl_handle, buf, count);
+               int retry = 1;
+
+               do {
+                       didwrite = SSL_write(sock->ssl_handle, buf, count);
+
+                       if (didwrite <= 0) {
+                               retry = handle_ssl_error(stream, didwrite TSRMLS_CC);
+                       } else {
+                               break;
+                       }
+               } while(retry);
+               
        } else
 #endif
        {
@@ -768,7 +857,8 @@
                }
        }
        
-       php_stream_notify_progress_increment(stream->context, didwrite, 0);
+       if (didwrite > 0)
+               php_stream_notify_progress_increment(stream->context, didwrite, 0);
 
        return didwrite;
 }
@@ -821,26 +911,42 @@
        php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
        size_t nr_bytes = 0;
 
-       if(sock->is_blocked) {
-               php_sock_stream_wait_for_data(stream, sock TSRMLS_CC);
-               if (sock->timeout_event)
-                       return 0;
-       }
-
 #if HAVE_OPENSSL_EXT
-       /* XXX: Where is the complex OpenSSL error handling? */
-       if (sock->ssl_active)
-               nr_bytes = SSL_read(sock->ssl_handle, buf, count);
+       if (sock->ssl_active) {
+               int retry = 1;
+
+               do {
+                       nr_bytes = SSL_read(sock->ssl_handle, buf, count);
+
+                       if (nr_bytes <= 0) {
+                               retry = handle_ssl_error(stream, nr_bytes TSRMLS_CC);
+                               if (retry == 0 && !SSL_pending(sock->ssl_handle)) {
+                                       stream->eof = 1;
+                               }
+                       } else {
+                               /* we got the data */
+                               break;
+                       }
+               } while (retry);
+       }
        else
 #endif
+       {
+               if (sock->is_blocked) {
+                       php_sock_stream_wait_for_data(stream, sock TSRMLS_CC);
+                       if (sock->timeout_event)
+                               return 0;
+               }
 
-       nr_bytes = recv(sock->socket, buf, count, 0);
-
-       php_stream_notify_progress_increment(stream->context, nr_bytes, 0);
+               nr_bytes = recv(sock->socket, buf, count, 0);
 
-       if(nr_bytes == 0 || (nr_bytes < 0 && php_socket_errno() != EWOULDBLOCK)) {
-               stream->eof = 1;
+               if (nr_bytes == 0 || (nr_bytes < 0 && php_socket_errno() != 
+EWOULDBLOCK)) {
+                       stream->eof = 1;
+               }
        }
+
+       if (nr_bytes > 0)
+               php_stream_notify_progress_increment(stream->context, nr_bytes, 0);
 
        return nr_bytes;
 }



-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to