Commit: 2ba39268151549f03140ec3d260cf9489336ec93
Author: Michael Wallner <m...@php.net> Wed, 2 Oct 2013 15:55:38 +0200
Parents: 60e38b3243577abc80ce6bbcfb0b4125b08acb85
9209c19f8f7eef807cb457b32d3ab517ff8dc178
Branches: PHP-5.5 master
Link:
http://git.php.net/?p=php-src.git;a=commitdiff;h=2ba39268151549f03140ec3d260cf9489336ec93
Log:
Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
fix bug #65808 the socket_connect() won't work with IPv6 address
5.4.22-dev now
Conflicts:
configure.in
ext/sockets/sockets.c
main/php_version.h
Bugs:
https://bugs.php.net/65808
Changed paths:
MM ext/sockets/multicast.c
MM ext/sockets/multicast.h
MA ext/sockets/sockaddr_conv.c
diff --cc ext/sockets/multicast.c
index 7466c62,43b6f7d..ecf3a65
--- a/ext/sockets/multicast.c
+++ b/ext/sockets/multicast.c
@@@ -63,309 -73,6 +63,317 @@@ static const char *_php_source_op_to_st
static int _php_source_op_to_ipv4_op(enum source_op sop);
#endif
++int php_string_to_if_index(const char *val, unsigned *out TSRMLS_DC)
++{
++#if HAVE_IF_NAMETOINDEX
++ unsigned int ind;
++
++ ind = if_nametoindex(val);
++ if (ind == 0) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING,
++ "no interface with name \"%s\" could be found", val);
++ return FAILURE;
++ } else {
++ *out = ind;
++ return SUCCESS;
++ }
++#else
++ php_error_docref(NULL TSRMLS_CC, E_WARNING,
++ "this platform does not support looking up an interface
by "
++ "name, an integer interface index must be supplied
instead");
++ return FAILURE;
++#endif
++}
++
+static int php_get_if_index_from_zval(zval *val, unsigned *out TSRMLS_DC)
+{
+ int ret;
+
+ if (Z_TYPE_P(val) == IS_LONG) {
+ if (Z_LVAL_P(val) < 0 || Z_LVAL_P(val) > UINT_MAX) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "the interface index cannot be negative or
larger than %u;"
+ " given %ld", UINT_MAX, Z_LVAL_P(val));
+ ret = FAILURE;
+ } else {
+ *out = Z_LVAL_P(val);
+ ret = SUCCESS;
+ }
+ } else {
- #if HAVE_IF_NAMETOINDEX
- unsigned int ind;
+ zval_add_ref(&val);
+ convert_to_string_ex(&val);
- ind = if_nametoindex(Z_STRVAL_P(val));
- if (ind == 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING,
- "no interface with name \"%s\" could be found",
Z_STRVAL_P(val));
- ret = FAILURE;
- } else {
- *out = ind;
- ret = SUCCESS;
- }
++ ret = php_string_to_if_index(Z_STRVAL_P(val), out TSRMLS_CC);
+ zval_ptr_dtor(&val);
- #else
- php_error_docref(NULL TSRMLS_CC, E_WARNING,
- "this platform does not support looking up an
interface by "
- "name, an integer interface index must be
supplied instead");
- ret = FAILURE;
- #endif
+ }
+
+ return ret;
+}
+
++
++
+static int php_get_if_index_from_array(const HashTable *ht, const char *key,
+ php_socket *sock, unsigned int *if_index TSRMLS_DC)
+{
+ zval **val;
+
+ if (zend_hash_find(ht, key, strlen(key) + 1, (void **)&val) == FAILURE)
{
+ *if_index = 0; /* default: 0 */
+ return SUCCESS;
+ }
+
+ return php_get_if_index_from_zval(*val, if_index TSRMLS_CC);
+}
+
+static int php_get_address_from_array(const HashTable *ht, const char *key,
+ php_socket *sock, php_sockaddr_storage *ss, socklen_t *ss_len TSRMLS_DC)
+{
+ zval **val,
+ *valcp;
+
+ if (zend_hash_find(ht, key, strlen(key) + 1, (void **)&val) == FAILURE)
{
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\"
passed in optval", key);
+ return FAILURE;
+ }
+ valcp = *val;
+ zval_add_ref(&valcp);
+ convert_to_string_ex(val);
+ if (!php_set_inet46_addr(ss, ss_len, Z_STRVAL_P(valcp), sock
TSRMLS_CC)) {
+ zval_ptr_dtor(&valcp);
+ return FAILURE;
+ }
+ zval_ptr_dtor(&valcp);
+ return SUCCESS;
+}
+
+static int php_do_mcast_opt(php_socket *php_sock, int level, int optname,
zval **arg4 TSRMLS_DC)
+{
+ HashTable *opt_ht;
+ unsigned int if_index;
+ int retval;
+ int (*mcast_req_fun)(php_socket *, int, struct sockaddr *, socklen_t,
+ unsigned TSRMLS_DC);
+#ifdef HAS_MCAST_EXT
+ int (*mcast_sreq_fun)(php_socket *, int, struct sockaddr *, socklen_t,
+ struct sockaddr *, socklen_t, unsigned TSRMLS_DC);
+#endif
+
+ switch (optname) {
+ case PHP_MCAST_JOIN_GROUP:
+ mcast_req_fun = &php_mcast_join;
+ goto mcast_req_fun;
+ case PHP_MCAST_LEAVE_GROUP:
+ {
+ php_sockaddr_storage group = {0};
+ socklen_t glen;
+
+ mcast_req_fun = &php_mcast_leave;
+mcast_req_fun:
+ convert_to_array_ex(arg4);
+ opt_ht = HASH_OF(*arg4);
+
+ if (php_get_address_from_array(opt_ht, "group",
php_sock, &group,
+ &glen TSRMLS_CC) == FAILURE) {
+ return FAILURE;
+ }
+ if (php_get_if_index_from_array(opt_ht, "interface",
php_sock,
+ &if_index TSRMLS_CC) == FAILURE) {
+ return FAILURE;
+ }
+
+ retval = mcast_req_fun(php_sock, level, (struct
sockaddr*)&group,
+ glen, if_index TSRMLS_CC);
+ break;
+ }
+
+#ifdef HAS_MCAST_EXT
+ case PHP_MCAST_BLOCK_SOURCE:
+ mcast_sreq_fun = &php_mcast_block_source;
+ goto mcast_sreq_fun;
+ case PHP_MCAST_UNBLOCK_SOURCE:
+ mcast_sreq_fun = &php_mcast_unblock_source;
+ goto mcast_sreq_fun;
+ case PHP_MCAST_JOIN_SOURCE_GROUP:
+ mcast_sreq_fun = &php_mcast_join_source;
+ goto mcast_sreq_fun;
+ case PHP_MCAST_LEAVE_SOURCE_GROUP:
+ {
+ php_sockaddr_storage group = {0},
+ source
= {0};
+ socklen_t glen,
+ slen;
+
+ mcast_sreq_fun = &php_mcast_leave_source;
+ mcast_sreq_fun:
+ convert_to_array_ex(arg4);
+ opt_ht = HASH_OF(*arg4);
+
+ if (php_get_address_from_array(opt_ht, "group",
php_sock, &group,
+ &glen TSRMLS_CC) == FAILURE) {
+ return FAILURE;
+ }
+ if (php_get_address_from_array(opt_ht, "source",
php_sock, &source,
+ &slen TSRMLS_CC) == FAILURE) {
+ return FAILURE;
+ }
+ if (php_get_if_index_from_array(opt_ht, "interface",
php_sock,
+ &if_index TSRMLS_CC) == FAILURE) {
+ return FAILURE;
+ }
+
+ retval = mcast_sreq_fun(php_sock, level, (struct
sockaddr*)&group,
+ glen, (struct sockaddr*)&source, slen,
if_index TSRMLS_CC);
+ break;
+ }
+#endif
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "unexpected option in php_do_mcast_opt (level %d,
option %d). "
+ "This is a bug.", level, optname);
+ return FAILURE;
+ }
+
+ if (retval != 0) {
+ if (retval != -2) { /* error, but message already emitted */
+ PHP_SOCKET_ERROR(php_sock, "unable to set socket
option", errno);
+ }
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+int php_do_setsockopt_ip_mcast(php_socket *php_sock,
+ int level,
+ int optname,
+ zval **arg4
TSRMLS_DC)
+{
+ unsigned int if_index;
+ struct in_addr if_addr;
+ void *opt_ptr;
+ socklen_t optlen;
+ unsigned char ipv4_mcast_ttl_lback;
+ int retval;
+
+ switch (optname) {
+ case PHP_MCAST_JOIN_GROUP:
+ case PHP_MCAST_LEAVE_GROUP:
+#ifdef HAS_MCAST_EXT
+ case PHP_MCAST_BLOCK_SOURCE:
+ case PHP_MCAST_UNBLOCK_SOURCE:
+ case PHP_MCAST_JOIN_SOURCE_GROUP:
+ case PHP_MCAST_LEAVE_SOURCE_GROUP:
+#endif
+ if (php_do_mcast_opt(php_sock, level, optname, arg4 TSRMLS_CC)
== FAILURE) {
+ return FAILURE;
+ } else {
+ return SUCCESS;
+ }
+
+ case IP_MULTICAST_IF:
+ if (php_get_if_index_from_zval(*arg4, &if_index TSRMLS_CC) ==
FAILURE) {
+ return FAILURE;
+ }
+
+ if (php_if_index_to_addr4(if_index, php_sock, &if_addr
TSRMLS_CC) == FAILURE) {
+ return FAILURE;
+ }
+ opt_ptr = &if_addr;
+ optlen = sizeof(if_addr);
+ goto dosockopt;
+
+ case IP_MULTICAST_LOOP:
+ convert_to_boolean_ex(arg4);
+ goto ipv4_loop_ttl;
+
+ case IP_MULTICAST_TTL:
+ convert_to_long_ex(arg4);
+ if (Z_LVAL_PP(arg4) < 0L || Z_LVAL_PP(arg4) > 255L) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Expected a value between 0 and 255");
+ return FAILURE;
+ }
+ipv4_loop_ttl:
+ ipv4_mcast_ttl_lback = (unsigned char) Z_LVAL_PP(arg4);
+ opt_ptr = &ipv4_mcast_ttl_lback;
+ optlen = sizeof(ipv4_mcast_ttl_lback);
+ goto dosockopt;
+ }
+
+ return 1;
+
+dosockopt:
+ retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr,
optlen);
+ if (retval != 0) {
+ PHP_SOCKET_ERROR(php_sock, "unable to set socket option",
errno);
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+int php_do_setsockopt_ipv6_mcast(php_socket *php_sock,
+ int level,
+ int optname,
+ zval **arg4
TSRMLS_DC)
+{
+ unsigned int if_index;
+ void *opt_ptr;
+ socklen_t optlen;
+ int ov;
+ int retval;
+
+ switch (optname) {
+ case PHP_MCAST_JOIN_GROUP:
+ case PHP_MCAST_LEAVE_GROUP:
+#ifdef HAS_MCAST_EXT
+ case PHP_MCAST_BLOCK_SOURCE:
+ case PHP_MCAST_UNBLOCK_SOURCE:
+ case PHP_MCAST_JOIN_SOURCE_GROUP:
+ case PHP_MCAST_LEAVE_SOURCE_GROUP:
+#endif
+ if (php_do_mcast_opt(php_sock, level, optname, arg4 TSRMLS_CC)
== FAILURE) {
+ return FAILURE;
+ } else {
+ return SUCCESS;
+ }
+
+ case IPV6_MULTICAST_IF:
+ if (php_get_if_index_from_zval(*arg4, &if_index TSRMLS_CC) ==
FAILURE) {
+ return FAILURE;
+ }
+
+ opt_ptr = &if_index;
+ optlen = sizeof(if_index);
+ goto dosockopt;
+
+ case IPV6_MULTICAST_LOOP:
+ convert_to_boolean_ex(arg4);
+ goto ipv6_loop_hops;
+ case IPV6_MULTICAST_HOPS:
+ convert_to_long_ex(arg4);
+ if (Z_LVAL_PP(arg4) < -1L || Z_LVAL_PP(arg4) > 255L) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Expected a value between -1 and 255");
+ return FAILURE;
+ }
+ipv6_loop_hops:
+ ov = (int) Z_LVAL_PP(arg4);
+ opt_ptr = &ov;
+ optlen = sizeof(ov);
+ goto dosockopt;
+ }
+
+ return 1; /* not handled */
+
+dosockopt:
+ retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr,
optlen);
+ if (retval != 0) {
+ PHP_SOCKET_ERROR(php_sock, "unable to set socket option",
errno);
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
int php_mcast_join(
php_socket *sock,
int level,
diff --cc ext/sockets/multicast.h
index 3614306,f46a6a8..81a1bca
--- a/ext/sockets/multicast.h
+++ b/ext/sockets/multicast.h
@@@ -65,6 -39,6 +65,8 @@@ int php_add4_to_if_index
php_socket *php_sock,
unsigned *if_index TSRMLS_DC);
++int php_string_to_if_index(const char *val, unsigned *out TSRMLS_DC);
++
int php_mcast_join(
php_socket *sock,
int level,
diff --cc ext/sockets/sockaddr_conv.c
index a40b6b4,0000000..64523c3
mode 100644,000000..100644
--- a/ext/sockets/sockaddr_conv.c
+++ b/ext/sockets/sockaddr_conv.c
@@@ -1,119 -1,0 +1,136 @@@
+#include <php.h>
+#include <php_network.h>
+#include "php_sockets.h"
+
+#ifdef PHP_WIN32
+#include "windows_common.h"
+#else
+#include <netdb.h>
+#include <arpa/inet.h>
+#endif
+
+#if HAVE_IPV6
+/* Sets addr by hostname, or by ip in string form (AF_INET6) */
+int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket
*php_sock TSRMLS_DC) /* {{{ */
+{
+ struct in6_addr tmp;
+#if HAVE_GETADDRINFO
+ struct addrinfo hints;
+ struct addrinfo *addrinfo = NULL;
+#endif
++ char *scope = strchr(string, '%');
+
+ if (inet_pton(AF_INET6, string, &tmp)) {
+ memcpy(&(sin6->sin6_addr.s6_addr), &(tmp.s6_addr),
sizeof(struct in6_addr));
+ } else {
+#if HAVE_GETADDRINFO
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_INET6;
+ hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
+ getaddrinfo(string, NULL, &hints, &addrinfo);
+ if (!addrinfo) {
+#ifdef PHP_WIN32
+ PHP_SOCKET_ERROR(php_sock, "Host lookup failed",
WSAGetLastError());
+#else
+ PHP_SOCKET_ERROR(php_sock, "Host lookup failed",
(-10000 - h_errno));
+#endif
+ return 0;
+ }
+ if (addrinfo->ai_family != PF_INET6 || addrinfo->ai_addrlen !=
sizeof(struct sockaddr_in6)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host
lookup failed: Non AF_INET6 domain returned on AF_INET6 socket");
+ freeaddrinfo(addrinfo);
+ return 0;
+ }
+
+ memcpy(&(sin6->sin6_addr.s6_addr), ((struct
sockaddr_in6*)(addrinfo->ai_addr))->sin6_addr.s6_addr, sizeof(struct in6_addr));
+ freeaddrinfo(addrinfo);
+
+#else
+ /* No IPv6 specific hostname resolution is available on this
system? */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host lookup
failed: getaddrinfo() not available on this system");
+ return 0;
+#endif
+
+ }
+
++ if (scope++) {
++ long lval = 0;
++ double dval = 0;
++ unsigned scope_id = 0;
++
++ if (IS_LONG == is_numeric_string(scope, strlen(scope), &lval,
&dval, 0)) {
++ if (lval > 0 && lval <= UINT_MAX) {
++ scope_id = lval;
++ }
++ } else {
++ php_string_to_if_index(scope, &scope_id TSRMLS_CC);
++ }
++
++ sin6->sin6_scope_id = scope_id;
++ }
++
+ return 1;
+}
+/* }}} */
+#endif
+
+/* Sets addr by hostname, or by ip in string form (AF_INET) */
+int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket
*php_sock TSRMLS_DC) /* {{{ */
+{
+ struct in_addr tmp;
+ struct hostent *host_entry;
+
+ if (inet_aton(string, &tmp)) {
+ sin->sin_addr.s_addr = tmp.s_addr;
+ } else {
+ if (! (host_entry = gethostbyname(string))) {
+ /* Note: < -10000 indicates a host lookup error */
+#ifdef PHP_WIN32
+ PHP_SOCKET_ERROR(php_sock, "Host lookup failed",
WSAGetLastError());
+#else
+ PHP_SOCKET_ERROR(php_sock, "Host lookup failed",
(-10000 - h_errno));
+#endif
+ return 0;
+ }
+ if (host_entry->h_addrtype != AF_INET) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Host
lookup failed: Non AF_INET domain returned on AF_INET socket");
+ return 0;
+ }
+ memcpy(&(sin->sin_addr.s_addr), host_entry->h_addr_list[0],
host_entry->h_length);
+ }
+
+ return 1;
+}
+/* }}} */
+
+/* Sets addr by hostname or by ip in string form (AF_INET or AF_INET6,
+ * depending on the socket) */
+int php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char
*string, php_socket *php_sock TSRMLS_DC) /* {{{ */
+{
+ if (php_sock->type == AF_INET) {
+ struct sockaddr_in t = {0};
+ if (php_set_inet_addr(&t, string, php_sock TSRMLS_CC)) {
+ memcpy(ss, &t, sizeof t);
+ ss->ss_family = AF_INET;
+ *ss_len = sizeof(t);
+ return 1;
+ }
+ }
+#if HAVE_IPV6
+ else if (php_sock->type == AF_INET6) {
+ struct sockaddr_in6 t = {0};
+ if (php_set_inet6_addr(&t, string, php_sock TSRMLS_CC)) {
+ memcpy(ss, &t, sizeof t);
+ ss->ss_family = AF_INET6;
+ *ss_len = sizeof(t);
+ return 1;
+ }
+ }
+#endif
+ else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "IP address used in the context of an unexpected type
of socket");
+ }
+ return 0;
+}
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php