php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #63767
Patch windows_ssl_handshake revision 2012-12-14 08:33 UTC by lior dot k at zend dot com

Patch windows_ssl_handshake for FTP related Bug #63767

Patch version 2012-12-14 08:33 UTC

Return to Bug #63767 | Download this patch
Patch Revisions:

Developer: lior.k@zend.com

diff -ruN php-5.4.9.orig/ext/ftp/ftp.c php-5.4.9/ext/ftp/ftp.c
--- php-5.4.9.orig/ext/ftp/ftp.c	2012-11-21 07:12:20.000000000 +0200
+++ php-5.4.9/ext/ftp/ftp.c	2012-12-13 11:25:19.320989668 +0200
@@ -69,6 +69,10 @@
 #include <openssl/ssl.h>
 #endif
 
+#ifdef PHP_WIN32
+#include "win32/time.h"
+#endif
+
 #include "ftp.h"
 #include "ext/standard/fsock.h"
 
@@ -118,6 +122,17 @@
 	unsigned char	c[8];
 };
 
+#define FTP_TIME_DIFF(start, end, diff)              \
+    diff.tv_sec = end.tv_sec - start.tv_sec;         \
+    diff.tv_usec = end.tv_usec - start.tv_usec;      \
+    if(end.tv_usec < start.tv_usec) {                \
+        diff.tv_usec += 1000000L;                    \
+        --diff.tv_usec;                              \
+    }
+
+#define FTP_TIME_PASSED(time,timeout) \
+	((time.tv_sec > timeout.tv_sec) || (time.tv_sec == timeout.tv_sec && time.tv_usec >= timeout.tv_usec))
+
 /* {{{ ftp_open
  */
 ftpbuf_t*
@@ -244,6 +259,9 @@
 #if HAVE_OPENSSL_EXT
 	SSL_CTX	*ctx = NULL;
 	long ssl_ctx_options = SSL_OP_ALL;
+	int retry;
+	struct timeval start_time,timeout = {FTP_DEFAULT_TIMEOUT,0};
+	struct timeval left_time = timeout;
 #endif
 	if (ftp == NULL) {
 		return 0;
@@ -294,11 +312,35 @@
 
 		SSL_set_fd(ftp->ssl_handle, ftp->fd);
 
-		if (SSL_connect(ftp->ssl_handle) <= 0) {
+		gettimeofday(&start_time,NULL);
+		do {
+			int poll_flag = POLLOUT;
+			struct timeval current_time,elapsed_time;
+			int n = SSL_connect(ftp->ssl_handle);
+			int err;
+			if(n > 0) {
+				break;
+			}
+			/* in case of SSL_ERROR_WANT_READ/WRITE, do not retry in non-blocking mode */
+			err = SSL_get_error(ftp->ssl_handle, n);
+			switch(err) {
+				case SSL_ERROR_WANT_READ:
+				poll_flag = POLLIN|POLLPRI;
+				case SSL_ERROR_WANT_WRITE:
+				err = php_pollfd_for(ftp->fd, poll_flag, &left_time );
+				if(err > 0) {
+					gettimeofday(&current_time,NULL);
+					FTP_TIME_DIFF(start_time,current_time,elapsed_time);
+					if(!FTP_TIME_PASSED(elapsed_time,timeout)) { /* Just in case */
+							FTP_TIME_DIFF(timeout,elapsed_time,left_time);
+							continue;
+					}
+				}
+			}
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS handshake failed");
 			SSL_shutdown(ftp->ssl_handle);
 			return 0;
-		}
+		} while (1);
 
 		ftp->ssl_active = 1;
 
@@ -1520,6 +1562,8 @@
 	
 	/* now enable ssl if we need to */
 	if (ftp->use_ssl && ftp->use_ssl_for_data) {
+		struct timeval start_time,timeout = {FTP_DEFAULT_TIMEOUT,0};
+		struct timeval left_time = timeout;
 		ctx = SSL_CTX_new(SSLv23_client_method());
 		if (ctx == NULL) {
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: failed to create the SSL context");
@@ -1545,11 +1589,35 @@
 			SSL_copy_session_id(data->ssl_handle, ftp->ssl_handle);
 		}
 			
-		if (SSL_connect(data->ssl_handle) <= 0) {
-			php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: SSL/TLS handshake failed");
+		gettimeofday(&start_time,NULL);
+		do {
+			int poll_flag = POLLOUT;
+			struct timeval current_time,elapsed_time;
+			int n = SSL_connect(data->ssl_handle);
+			int err;
+			if(n > 0) {
+				break;
+			}
+			/* in case of SSL_ERROR_WANT_READ/WRITE, do not retry in non-blocking mode */
+			err = SSL_get_error(data->ssl_handle, n);
+			switch(err) {
+				case SSL_ERROR_WANT_READ:
+				poll_flag = POLLIN|POLLPRI;
+				case SSL_ERROR_WANT_WRITE:
+				err = php_pollfd_for(data->fd, poll_flag, &left_time );
+				if(err > 0) {
+					gettimeofday(&current_time,NULL);
+					FTP_TIME_DIFF(start_time,current_time,elapsed_time);
+					if(!FTP_TIME_PASSED(elapsed_time,timeout)) { /* Just in case */
+							FTP_TIME_DIFF(timeout,elapsed_time,left_time);
+							continue;
+					}
+				}
+			}
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS handshake failed");
 			SSL_shutdown(data->ssl_handle);
 			return 0;
-		}
+		} while (1);
 			
 		data->ssl_active = 1;
 	}	
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Wed Apr 24 13:01:29 2024 UTC