diff options
Diffstat (limited to 'main/network.c')
-rw-r--r-- | main/network.c | 195 |
1 files changed, 124 insertions, 71 deletions
diff --git a/main/network.c b/main/network.c index 636afc62b0..e4c99ec064 100644 --- a/main/network.c +++ b/main/network.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 7 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2015 The PHP Group | +----------------------------------------------------------------------+ @@ -166,7 +166,7 @@ PHPAPI void php_network_freeaddresses(struct sockaddr **sal) /* {{{ php_network_getaddresses * Returns number of addresses, 0 for none/error */ -PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, char **error_string TSRMLS_DC) +PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string) { struct sockaddr **sap; int n; @@ -212,18 +212,18 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka if ((n = getaddrinfo(host, NULL, &hints, &res))) { if (error_string) { - spprintf(error_string, 0, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n)); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", *error_string); + *error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n)); + php_error_docref(NULL, E_WARNING, "%s", (*error_string)->val); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n)); + php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n)); } return 0; } else if (res == NULL) { if (error_string) { - spprintf(error_string, 0, "php_network_getaddresses: getaddrinfo failed (null result pointer) errno=%d", errno); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", *error_string); + *error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo failed (null result pointer) errno=%d", errno); + php_error_docref(NULL, E_WARNING, "%s", (*error_string)->val); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_network_getaddresses: getaddrinfo failed (null result pointer)"); + php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo failed (null result pointer)"); } return 0; } @@ -254,10 +254,10 @@ PHPAPI int php_network_getaddresses(const char *host, int socktype, struct socka } if (host_info == NULL) { if (error_string) { - spprintf(error_string, 0, "php_network_getaddresses: gethostbyname failed. errno=%d", errno); - php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", *error_string); + error_string = strpprintf(0, "php_network_getaddresses: gethostbyname failed. errno=%d", errno); + php_error_docref(NULL, E_WARNING, "%s", (*error_string)->val); } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_network_getaddresses: gethostbyname failed"); + php_error_docref(NULL, E_WARNING, "php_network_getaddresses: gethostbyname failed"); } return 0; } @@ -310,7 +310,7 @@ PHPAPI int php_network_connect_socket(php_socket_t sockfd, socklen_t addrlen, int asynchronous, struct timeval *timeout, - char **error_string, + zend_string **error_string, int *error_code) { #if HAVE_NON_BLOCKING_CONNECT @@ -331,7 +331,7 @@ PHPAPI int php_network_connect_socket(php_socket_t sockfd, if (error != EINPROGRESS) { if (error_string) { - *error_string = php_socket_strerror(error, NULL, 0); + *error_string = php_socket_error_str(error); } return -1; @@ -387,13 +387,13 @@ ok: if (error) { ret = -1; if (error_string) { - *error_string = php_socket_strerror(error, NULL, 0); + *error_string = php_socket_error_str(error); } } return ret; #else if (asynchronous) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Asynchronous connect() not supported on this platform"); + php_error_docref(NULL, E_WARNING, "Asynchronous connect() not supported on this platform"); } return (connect(sockfd, addr, addrlen) == 0) ? 0 : -1; #endif @@ -421,15 +421,16 @@ static inline void sub_times(struct timeval a, struct timeval b, struct timeval * */ /* {{{ php_network_bind_socket_to_local_addr */ php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port, - int socktype, char **error_string, int *error_code - TSRMLS_DC) + int socktype, long sockopts, zend_string **error_string, int *error_code + ) { int num_addrs, n, err = 0; php_socket_t sock; struct sockaddr **sal, **psal, *sa; socklen_t socklen; + int sockoptval = 1; - num_addrs = php_network_getaddresses(host, socktype, &psal, error_string TSRMLS_CC); + num_addrs = php_network_getaddresses(host, socktype, &psal, error_string); if (num_addrs == 0) { /* could not resolve address(es) */ @@ -469,9 +470,16 @@ php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned po /* attempt to bind */ #ifdef SO_REUSEADDR - { - int val = 1; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val)); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&sockoptval, sizeof(sockoptval)); +#endif +#ifdef SO_REUSEPORT + if (sockopts & STREAM_SOCKOP_SO_REUSEPORT) { + setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char*)&sockoptval, sizeof(sockoptval)); + } +#endif +#ifdef SO_BROADCAST + if (sockopts & STREAM_SOCKOP_SO_BROADCAST) { + setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&sockoptval, sizeof(sockoptval)); } #endif @@ -492,7 +500,7 @@ php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned po *error_code = err; } if (error_string) { - *error_string = php_socket_strerror(err, NULL, 0); + *error_string = php_socket_error_str(err); } bound: @@ -504,7 +512,7 @@ bound: } /* }}} */ -PHPAPI int php_network_parse_network_address_with_port(const char *addr, long addrlen, struct sockaddr *sa, socklen_t *sl TSRMLS_DC) +PHPAPI int php_network_parse_network_address_with_port(const char *addr, zend_long addrlen, struct sockaddr *sa, socklen_t *sl) { char *colon; char *tmp; @@ -513,7 +521,7 @@ PHPAPI int php_network_parse_network_address_with_port(const char *addr, long ad struct sockaddr_in *in4 = (struct sockaddr_in*)sa; struct sockaddr **psal; int n; - char *errstr = NULL; + zend_string *errstr = NULL; #if HAVE_IPV6 struct sockaddr_in6 *in6 = (struct sockaddr_in6*)sa; #endif @@ -555,12 +563,12 @@ PHPAPI int php_network_parse_network_address_with_port(const char *addr, long ad } /* looks like we'll need to resolve it */ - n = php_network_getaddresses(tmp, SOCK_DGRAM, &psal, &errstr TSRMLS_CC); + n = php_network_getaddresses(tmp, SOCK_DGRAM, &psal, &errstr); if (n == 0) { if (errstr) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to resolve `%s': %s", tmp, errstr); - STR_FREE(errstr); + php_error_docref(NULL, E_WARNING, "Failed to resolve `%s': %s", tmp, errstr->val); + zend_string_release(errstr); } goto out; } @@ -586,7 +594,7 @@ PHPAPI int php_network_parse_network_address_with_port(const char *addr, long ad php_network_freeaddresses(psal); out: - STR_FREE(tmp); + efree(tmp); return ret; } @@ -595,11 +603,11 @@ PHPAPI void php_network_populate_name_from_sockaddr( /* input address */ struct sockaddr *sa, socklen_t sl, /* output readable address */ - char **textaddr, long *textaddrlen, + zend_string **textaddr, /* output address */ struct sockaddr **addr, socklen_t *addrlen - TSRMLS_DC) + ) { if (addr) { *addr = emalloc(sl); @@ -618,7 +626,7 @@ PHPAPI void php_network_populate_name_from_sockaddr( /* generally not thread safe, but it *is* thread safe under win32 */ buf = inet_ntoa(((struct sockaddr_in*)sa)->sin_addr); if (buf) { - *textaddrlen = spprintf(textaddr, 0, "%s:%d", + *textaddr = strpprintf(0, "%s:%d", buf, ntohs(((struct sockaddr_in*)sa)->sin_port)); } @@ -628,7 +636,7 @@ PHPAPI void php_network_populate_name_from_sockaddr( case AF_INET6: buf = (char*)inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, (char *)&abuf, sizeof(abuf)); if (buf) { - *textaddrlen = spprintf(textaddr, 0, "%s:%d", + *textaddr = strpprintf(0, "%s:%d", buf, ntohs(((struct sockaddr_in6*)sa)->sin6_port)); } @@ -642,13 +650,10 @@ PHPAPI void php_network_populate_name_from_sockaddr( if (ua->sun_path[0] == '\0') { /* abstract name */ int len = strlen(ua->sun_path + 1) + 1; - *textaddrlen = len; - *textaddr = emalloc(len + 1); - memcpy(*textaddr, ua->sun_path, len); - (*textaddr)[len] = '\0'; + *textaddr = zend_string_init((char*)ua->sun_path, len, 0); } else { - *textaddrlen = strlen(ua->sun_path); - *textaddr = estrndup(ua->sun_path, *textaddrlen); + int len = strlen(ua->sun_path); + *textaddr = zend_string_init((char*)ua->sun_path, len, 0); } } break; @@ -660,10 +665,10 @@ PHPAPI void php_network_populate_name_from_sockaddr( } PHPAPI int php_network_get_peer_name(php_socket_t sock, - char **textaddr, long *textaddrlen, + zend_string **textaddr, struct sockaddr **addr, socklen_t *addrlen - TSRMLS_DC) + ) { php_sockaddr_storage sa; socklen_t sl = sizeof(sa); @@ -671,19 +676,19 @@ PHPAPI int php_network_get_peer_name(php_socket_t sock, if (getpeername(sock, (struct sockaddr*)&sa, &sl) == 0) { php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl, - textaddr, textaddrlen, + textaddr, addr, addrlen - TSRMLS_CC); + ); return 0; } return -1; } PHPAPI int php_network_get_sock_name(php_socket_t sock, - char **textaddr, long *textaddrlen, + zend_string **textaddr, struct sockaddr **addr, socklen_t *addrlen - TSRMLS_DC) + ) { php_sockaddr_storage sa; socklen_t sl = sizeof(sa); @@ -691,9 +696,9 @@ PHPAPI int php_network_get_sock_name(php_socket_t sock, if (getsockname(sock, (struct sockaddr*)&sa, &sl) == 0) { php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl, - textaddr, textaddrlen, + textaddr, addr, addrlen - TSRMLS_CC); + ); return 0; } return -1; @@ -705,19 +710,19 @@ PHPAPI int php_network_get_sock_name(php_socket_t sock, * using an optional timeout. * Returns the peer address in addr/addrlen (it will emalloc * these, so be sure to efree the result). - * If you specify textaddr/textaddrlen, a text-printable + * If you specify textaddr, a text-printable * version of the address will be emalloc'd and returned. * */ /* {{{ php_network_accept_incoming */ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock, - char **textaddr, long *textaddrlen, + zend_string **textaddr, struct sockaddr **addr, socklen_t *addrlen, struct timeval *timeout, - char **error_string, + zend_string **error_string, int *error_code - TSRMLS_DC) + ) { php_socket_t clisock = -1; int error = 0, n; @@ -737,9 +742,9 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock, if (clisock != SOCK_ERR) { php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl, - textaddr, textaddrlen, + textaddr, addr, addrlen - TSRMLS_CC); + ); } else { error = php_socket_errno(); } @@ -749,7 +754,7 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock, *error_code = error; } if (error_string) { - *error_string = php_socket_strerror(error, NULL, 0); + *error_string = php_socket_error_str(error); } return clisock; @@ -766,9 +771,9 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock, /* {{{ php_network_connect_socket_to_host */ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port, - int socktype, int asynchronous, struct timeval *timeout, char **error_string, - int *error_code, char *bindto, unsigned short bindport - TSRMLS_DC) + int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string, + int *error_code, char *bindto, unsigned short bindport, long sockopts + ) { int num_addrs, n, fatal = 0; php_socket_t sock; @@ -779,7 +784,7 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short struct timeval limit_time, time_now; #endif - num_addrs = php_network_getaddresses(host, socktype, &psal, error_string TSRMLS_CC); + num_addrs = php_network_getaddresses(host, socktype, &psal, error_string); if (num_addrs == 0) { /* could not resolve address(es) */ @@ -849,7 +854,7 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short in4->sin_family = sa->sa_family; in4->sin_port = htons(bindport); if (!inet_aton(bindto, &in4->sin_addr)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid IP Address: %s", bindto); + php_error_docref(NULL, E_WARNING, "Invalid IP Address: %s", bindto); goto skip_bind; } memset(&(in4->sin_zero), 0, sizeof(in4->sin_zero)); @@ -864,13 +869,14 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short in6->sin6_family = sa->sa_family; in6->sin6_port = htons(bindport); if (inet_pton(AF_INET6, bindto, &in6->sin6_addr) < 1) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid IP Address: %s", bindto); + php_error_docref(NULL, E_WARNING, "Invalid IP Address: %s", bindto); goto skip_bind; } } #endif + if (!local_address || bind(sock, local_address, local_address_len)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to bind to '%s:%d', system said: %s", bindto, bindport, strerror(errno)); + php_error_docref(NULL, E_WARNING, "failed to bind to '%s:%d', system said: %s", bindto, bindport, strerror(errno)); } skip_bind: if (local_address) { @@ -879,10 +885,18 @@ skip_bind: } /* free error string received during previous iteration (if any) */ if (error_string && *error_string) { - efree(*error_string); + zend_string_release(*error_string); *error_string = NULL; } +#ifdef SO_BROADCAST + { + int val = 1; + if (sockopts & STREAM_SOCKOP_SO_BROADCAST) { + setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&val, sizeof(val)); + } + } +#endif n = php_network_connect_socket(sock, sa, socklen, asynchronous, timeout ? &working_timeout : NULL, error_string, error_code); @@ -1034,8 +1048,46 @@ PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize) } /* }}} */ +/* {{{ php_socket_error_str */ +PHPAPI zend_string *php_socket_error_str(long err) +{ +#ifndef PHP_WIN32 + char *errstr; + + errstr = strerror(err); + return zend_string_init(errstr, strlen(errstr), 0); +#else + zend_string *ret; + char *sysbuf; + int free_it = 1; + + if (!FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&sysbuf, + 0, + NULL)) { + free_it = 0; + sysbuf = "Unknown Error"; + } + + ret = zend_string_init(sysbuf, strlen(sysbuf), 0); + + if (free_it) { + LocalFree(sysbuf); + } + + return ret; +#endif +} +/* }}} */ + /* deprecated */ -PHPAPI php_stream *_php_stream_sock_open_from_socket(php_socket_t socket, const char *persistent_id STREAMS_DC TSRMLS_DC) +PHPAPI php_stream *_php_stream_sock_open_from_socket(php_socket_t socket, const char *persistent_id STREAMS_DC) { php_stream *stream; php_netstream_data_t *sock; @@ -1060,10 +1112,10 @@ PHPAPI php_stream *_php_stream_sock_open_from_socket(php_socket_t socket, const } PHPAPI php_stream *_php_stream_sock_open_host(const char *host, unsigned short port, - int socktype, struct timeval *timeout, const char *persistent_id STREAMS_DC TSRMLS_DC) + int socktype, struct timeval *timeout, const char *persistent_id STREAMS_DC) { char *res; - long reslen; + zend_long reslen; php_stream *stream; reslen = spprintf(&res, 0, "tcp://%s:%d", host, port); @@ -1076,20 +1128,22 @@ PHPAPI php_stream *_php_stream_sock_open_host(const char *host, unsigned short p return stream; } -PHPAPI int php_set_sock_blocking(int socketd, int block TSRMLS_DC) +PHPAPI int php_set_sock_blocking(php_socket_t socketd, int block) { int ret = SUCCESS; - int flags; - int myflag = 0; #ifdef PHP_WIN32 + u_long flags; + /* with ioctlsocket, a non-zero sets nonblocking, a zero sets blocking */ flags = !block; if (ioctlsocket(socketd, FIONBIO, &flags) == SOCKET_ERROR) { ret = FAILURE; } #else - flags = fcntl(socketd, F_GETFL); + int myflag = 0; + int flags = fcntl(socketd, F_GETFL); + #ifdef O_NONBLOCK myflag = O_NONBLOCK; /* POSIX version */ #elif defined(O_NDELAY) @@ -1109,10 +1163,9 @@ PHPAPI int php_set_sock_blocking(int socketd, int block TSRMLS_DC) PHPAPI void _php_emit_fd_setsize_warning(int max_fd) { - TSRMLS_FETCH(); #ifdef PHP_WIN32 - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "PHP needs to be recompiled with a larger value of FD_SETSIZE.\n" "If this binary is from an official www.php.net package, file a bug report\n" "at http://bugs.php.net, including the following information:\n" @@ -1122,7 +1175,7 @@ PHPAPI void _php_emit_fd_setsize_warning(int max_fd) "one time, in order to avoid seeing this error again at a later date.", FD_SETSIZE, max_fd, (max_fd + 128) & ~127); #else - php_error_docref(NULL TSRMLS_CC, E_WARNING, + php_error_docref(NULL, E_WARNING, "You MUST recompile PHP with a larger value of FD_SETSIZE.\n" "It is set to %d, but you have descriptors numbered at least as high as %d.\n" " --enable-fd-setsize=%d is recommended, but you may want to set it\n" |