summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/network.c79
-rw-r--r--main/php_network.h5
2 files changed, 83 insertions, 1 deletions
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);