From c6a36d585bd6a7508e8f8722d044454fe3cceea4 Mon Sep 17 00:00:00 2001 From: Jason Greene Date: Tue, 11 Jun 2002 03:55:28 +0000 Subject: [PATCH] @Impelemented timeout functionality, and fixed error handling of fsockopen() on win32 Also fixed error handling on unix (micropatch) Closes Bug #14740 --- ext/standard/fsock.c | 30 ++++++++++++++--- main/network.c | 79 +++++++++++++++++++++++++++++++++++++++++++- main/php_network.h | 5 +++ 3 files changed, 109 insertions(+), 5 deletions(-) diff --git a/ext/standard/fsock.c b/ext/standard/fsock.c index 9d90788298..7b57267e2d 100644 --- a/ext/standard/fsock.c +++ b/ext/standard/fsock.c @@ -121,6 +121,7 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent) char *host; int host_len; int port = -1; + int err; zval *zerrno = NULL, *zerrstr = NULL; double timeout = 60; unsigned long conv; @@ -152,7 +153,7 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent) zval_dtor(zerrno); ZVAL_LONG(zerrno, 0); } - if (zerrstr) { + if (zerrstr) { zval_dtor(zerrstr); ZVAL_STRING(zerrno, "", 1); } @@ -192,6 +193,10 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent) else #endif stream = php_stream_sock_open_host(host, (unsigned short)port, socktype, (int)timeout, persistent); +#ifdef PHP_WIN32 + /* Preserve error */ + err = WSAGetLastError(); +#endif if (stream == NULL) { zend_error(E_WARNING, "%s(): unable to connect to %s:%d", @@ -227,15 +232,32 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent) efree(hashkey); if (stream == NULL) { - if (zerrno) { + if (zerrno) { zval_dtor(zerrno); +#ifndef PHP_WIN32 ZVAL_LONG(zerrno, errno); +#else + ZVAL_LONG(zerrno, err); +#endif } - if (zerrstr) { +#ifndef PHP_WIN32 + if (zerrstr) { zval_dtor(zerrstr); - ZVAL_STRING(zerrno, strerror(errno), 1); + ZVAL_STRING(zerrstr, strerror(errno), 1); } +#else + if (zerrstr) { + char *buf; + if (! FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, + Z_LVAL_P(zerrno), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, 0, NULL)) { + RETURN_FALSE; + } + + ZVAL_STRING(zerrstr, buf, 1); + LocalFree(buf); + } +#endif RETURN_FALSE; } diff --git a/main/network.c b/main/network.c index 54b3cb0892..4022601feb 100644 --- a/main/network.c +++ b/main/network.c @@ -289,11 +289,78 @@ ok: } return ret; #else /* !defined(PHP_WIN32) && ... */ +#ifdef PHP_WIN32 + return php_connect_nonb_win32((SOCKET) sockfd, addr, addrlen, timeout); +#endif return connect(sockfd, addr, addrlen); #endif } /* }}} */ +#ifdef PHP_WIN32 +/* {{{ php_connect_nonb_win32 */ +PHPAPI int php_connect_nonb_win32(SOCKET sockfd, + const struct sockaddr *addr, + socklen_t addrlen, + struct timeval *timeout) +{ + int error = 0, error_len, ret; + u_long non_block = TRUE, block = FALSE; + + fd_set rset, wset; + + if (timeout == NULL) { + /* blocking mode */ + return connect(sockfd, addr, addrlen); + } + + /* Set the socket to be non-blocking */ + ioctlsocket(sockfd, FIONBIO, &non_block); + + if (connect(sockfd, addr, addrlen) == SOCKET_ERROR) { + if (WSAGetLastError() != WSAEWOULDBLOCK) { + return SOCKET_ERROR; + } + } + + FD_ZERO(&rset); + FD_SET(sockfd, &rset); + + FD_ZERO(&wset); + FD_SET(sockfd, &wset); + + if ((ret = select(sockfd + 1, &rset, &wset, NULL, timeout)) == 0) { + WSASetLastError(WSAETIMEDOUT); + return SOCKET_ERROR; + } + + if (ret == SOCKET_ERROR) { + return SOCKET_ERROR; + } + + if(FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) { + error_len = sizeof(error); + if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *) &error, &error_len) == SOCKET_ERROR) { + return SOCKET_ERROR; + } + } else { + /* whoops: sockfd has disappeared */ + return SOCKET_ERROR; + } + + /* Set the socket back to blocking */ + ioctlsocket(sockfd, FIONBIO, &block); + + if (error) { + WSASetLastError(error); + return SOCKET_ERROR; + } + + return 0; +} +/* }}} */ +#endif + /* {{{ php_hostconnect * Creates a socket of type socktype and connects to the given host and * port, returns the created socket on success, else returns -1. @@ -301,7 +368,7 @@ ok: */ int php_hostconnect(const char *host, unsigned short port, int socktype, int timeout) { - int n, repeatto, s; + int n, repeatto, s, err; struct sockaddr **sal, **psal; struct timeval timeoutval; @@ -351,6 +418,10 @@ int php_hostconnect(const char *host, unsigned short port, int socktype, int tim } break; } +#ifdef PHP_WIN32 + /* Preserve the last error */ + err = WSAGetLastError(); +#endif close (s); } sal++; @@ -361,6 +432,12 @@ int php_hostconnect(const char *host, unsigned short port, int socktype, int tim } php_network_freeaddresses(psal); php_error(E_WARNING, "php_hostconnect: connect failed"); + +#ifdef PHP_WIN32 + /* Restore the last error */ + WSASetLastError(err); +#endif + return -1; ok: diff --git a/main/php_network.h b/main/php_network.h index 37e0a1add5..8e67f7ead8 100644 --- a/main/php_network.h +++ b/main/php_network.h @@ -87,6 +87,11 @@ typedef struct { int php_hostconnect(const char *host, unsigned short port, int socktype, int timeout); PHPAPI int php_connect_nonb(int sockfd, const struct sockaddr *addr, socklen_t addrlen, struct timeval *timeout); + +#ifdef PHP_WIN32 +PHPAPI int php_connect_nonb_win32(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen, struct timeval *timeout); +#endif + void php_any_addr(int family, php_sockaddr_storage *addr, unsigned short port); int php_sockaddr_size(php_sockaddr_storage *addr); -- 2.50.1