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

Reply via email to