Commit:    51394f76a5fca718fbf218888d97402f845ee261
Author:    Gustavo Lopes <glo...@nebm.ist.utl.pt>         Tue, 6 Nov 2012 
12:48:47 +0100
Parents:   3e515a2fd93204594c80ad2379f42fbb2db18d78
Branches:  PHP-5.5 master

Link:       
http://git.php.net/?p=php-src.git;a=commitdiff;h=51394f76a5fca718fbf218888d97402f845ee261

Log:
Move some multicast stuff to multicast.c

Changed paths:
  M  ext/sockets/multicast.c
  M  ext/sockets/multicast.h
  M  ext/sockets/php_sockets.h
  M  ext/sockets/sockets.c

diff --git a/ext/sockets/multicast.c b/ext/sockets/multicast.c
index d4a00a8..dc24269 100644
--- a/ext/sockets/multicast.c
+++ b/ext/sockets/multicast.c
@@ -54,6 +54,7 @@
 
 #include "php_sockets.h"
 #include "multicast.h"
+#include "sockaddr_conv.h"
 #include "main/php_network.h"
 
 
@@ -76,6 +77,309 @@ static const char *_php_source_op_to_string(enum source_op 
sop);
 static int _php_source_op_to_ipv4_op(enum source_op sop);
 #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;
+               }
+               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 MCAST_JOIN_GROUP:
+               mcast_req_fun = &php_mcast_join;
+               goto mcast_req_fun;
+       case 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 MCAST_BLOCK_SOURCE:
+               mcast_sreq_fun = &php_mcast_block_source;
+               goto mcast_sreq_fun;
+       case MCAST_UNBLOCK_SOURCE:
+               mcast_sreq_fun = &php_mcast_unblock_source;
+               goto mcast_sreq_fun;
+       case MCAST_JOIN_SOURCE_GROUP:
+               mcast_sreq_fun = &php_mcast_join_source;
+               goto mcast_sreq_fun;
+       case 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)
+{
+       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 MCAST_JOIN_GROUP:
+       case MCAST_LEAVE_GROUP:
+#ifdef HAS_MCAST_EXT
+       case MCAST_BLOCK_SOURCE:
+       case MCAST_UNBLOCK_SOURCE:
+       case MCAST_JOIN_SOURCE_GROUP:
+       case 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)
+{
+       unsigned int    if_index;
+       void                    *opt_ptr;
+       socklen_t               optlen;
+       int                             ov;
+       int                             retval;
+
+       switch (optname) {
+       case MCAST_JOIN_GROUP:
+       case MCAST_LEAVE_GROUP:
+#ifdef HAS_MCAST_EXT
+       case MCAST_BLOCK_SOURCE:
+       case MCAST_UNBLOCK_SOURCE:
+       case MCAST_JOIN_SOURCE_GROUP:
+       case 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,
@@ -157,21 +461,21 @@ static int _php_mcast_join_leave(
 {
 #ifdef RFC3678_API
        struct group_req greq = {0};
-       
+
        memcpy(&greq.gr_group, group, group_len);
        assert(greq.gr_group.ss_family != 0); /* the caller has set this */
        greq.gr_interface = if_index;
 
        return setsockopt(sock->bsd_socket, level,
                        join ? MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP, 
(char*)&greq,
-                       sizeof(greq));  
+                       sizeof(greq));
 #else
        if (sock->type == AF_INET) {
                struct ip_mreq mreq = {0};
                struct in_addr addr;
-               
+
                assert(group_len == sizeof(struct sockaddr_in));
-               
+
                if (if_index != 0) {
                        if (php_if_index_to_addr4(if_index, sock, &addr 
TSRMLS_CC) ==
                                        FAILURE)
@@ -188,12 +492,12 @@ static int _php_mcast_join_leave(
 #if HAVE_IPV6
        else if (sock->type == AF_INET6) {
                struct ipv6_mreq mreq = {0};
-               
+
                assert(group_len == sizeof(struct sockaddr_in6));
 
                mreq.ipv6mr_multiaddr = ((struct 
sockaddr_in6*)group)->sin6_addr;
                mreq.ipv6mr_interface = if_index;
-               
+
                return setsockopt(sock->bsd_socket, level,
                                join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP, 
(char*)&mreq,
                                sizeof(mreq));
@@ -221,26 +525,26 @@ static int _php_mcast_source_op(
 {
 #ifdef RFC3678_API
        struct group_source_req gsreq = {0};
-       
+
        memcpy(&gsreq.gsr_group, group, group_len);
        assert(gsreq.gsr_group.ss_family != 0);
        memcpy(&gsreq.gsr_source, source, source_len);
        assert(gsreq.gsr_source.ss_family != 0);
        gsreq.gsr_interface = if_index;
-       
+
        return setsockopt(sock->bsd_socket, level,
                        _php_source_op_to_rfc3678_op(sop), (char*)&gsreq, 
sizeof(gsreq));
 #else
        if (sock->type == AF_INET) {
                struct ip_mreq_source mreqs = {0};
                struct in_addr addr;
-               
+
                mreqs.imr_multiaddr = ((struct sockaddr_in*)group)->sin_addr;
                mreqs.imr_sourceaddr =  ((struct sockaddr_in*)source)->sin_addr;
-               
+
                assert(group_len == sizeof(struct sockaddr_in));
                assert(source_len == sizeof(struct sockaddr_in));
-               
+
                if (if_index != 0) {
                        if (php_if_index_to_addr4(if_index, sock, &addr 
TSRMLS_CC) ==
                                        FAILURE)
@@ -249,7 +553,7 @@ static int _php_mcast_source_op(
                } else {
                        mreqs.imr_interface.s_addr = htonl(INADDR_ANY);
                }
-               
+
                return setsockopt(sock->bsd_socket, level,
                                _php_source_op_to_ipv4_op(sop), (char*)&mreqs, 
sizeof(mreqs));
        }
@@ -283,7 +587,7 @@ static int _php_source_op_to_rfc3678_op(enum source_op sop)
        case UNBLOCK_SOURCE:
                return MCAST_UNBLOCK_SOURCE;
        }
-       
+
        assert(0);
        return 0;
 }
@@ -300,7 +604,7 @@ static const char *_php_source_op_to_string(enum source_op 
sop)
        case UNBLOCK_SOURCE:
                return "MCAST_UNBLOCK_SOURCE";
        }
-       
+
        assert(0);
        return "";
 }
@@ -317,7 +621,7 @@ static int _php_source_op_to_ipv4_op(enum source_op sop)
        case UNBLOCK_SOURCE:
                return IP_UNBLOCK_SOURCE;
        }
-       
+
        assert(0);
        return 0;
 }
@@ -416,16 +720,16 @@ retry:
 int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct 
in_addr *out_addr TSRMLS_DC)
 {
        struct ifreq if_req;
-       
+
        if (if_index == 0) {
                out_addr->s_addr = INADDR_ANY;
                return SUCCESS;
        }
-       
+
 #if !defined(ifr_ifindex) && defined(ifr_index)
 #define ifr_ifindex ifr_index
 #endif
-       
+
 #if defined(SIOCGIFNAME)
        if_req.ifr_ifindex = if_index;
        if (ioctl(php_sock->bsd_socket, SIOCGIFNAME, &if_req) == -1) {
@@ -438,13 +742,13 @@ int php_if_index_to_addr4(unsigned if_index, php_socket 
*php_sock, struct in_add
                        "Failed obtaining address for interface %u: error %d", 
if_index, errno);
                return FAILURE;
        }
-       
+
        if (ioctl(php_sock->bsd_socket, SIOCGIFADDR, &if_req) == -1) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING,
                        "Failed obtaining address for interface %u: error %d", 
if_index, errno);
                return FAILURE;
        }
-       
+
        memcpy(out_addr, &((struct sockaddr_in *) &if_req.ifr_addr)->sin_addr,
                sizeof *out_addr);
        return SUCCESS;
@@ -458,25 +762,25 @@ int php_add4_to_if_index(struct in_addr *addr, php_socket 
*php_sock, unsigned *i
        int                             size = 0,
                                        lastsize = 0;
        size_t                  entry_len;
-       
+
        if (addr->s_addr == INADDR_ANY) {
                *if_index = 0;
                return SUCCESS;
        }
-       
+
        for(;;) {
                size += 5 * sizeof(struct ifreq);
                buf = ecalloc(size, 1);
                if_conf.ifc_len = size;
                if_conf.ifc_buf = buf;
-               
+
                if (ioctl(php_sock->bsd_socket, SIOCGIFCONF, (char*)&if_conf) 
== -1 &&
                                (errno != EINVAL || lastsize != 0)) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING,
                                "Failed obtaining interfaces list: error %d", 
errno);
                        goto err;
                }
-               
+
                if (if_conf.ifc_len == lastsize)
                        /* not increasing anymore */
                        break;
@@ -486,15 +790,15 @@ int php_add4_to_if_index(struct in_addr *addr, php_socket 
*php_sock, unsigned *i
                        buf = NULL;
                }
        }
-       
+
        for (p = if_conf.ifc_buf;
                 p < if_conf.ifc_buf + if_conf.ifc_len;
                 p += entry_len) {
                struct ifreq *cur_req;
-               
+
                /* let's hope the pointer is aligned */
                cur_req = (struct ifreq*) p;
-               
+
 #ifdef HAVE_SOCKADDR_SA_LEN
                entry_len = cur_req->ifr_addr.sa_len + 
sizeof(cur_req->ifr_name);
 #else
@@ -502,7 +806,7 @@ int php_add4_to_if_index(struct in_addr *addr, php_socket 
*php_sock, unsigned *i
                entry_len = sizeof(struct sockaddr) + sizeof(cur_req->ifr_name);
 #endif
                entry_len = MAX(entry_len, sizeof(*cur_req));
-               
+
                if ((((struct sockaddr*)&cur_req->ifr_addr)->sa_family == 
AF_INET) &&
                                (((struct 
sockaddr_in*)&cur_req->ifr_addr)->sin_addr.s_addr ==
                                        addr->s_addr)) {
@@ -537,7 +841,7 @@ int php_add4_to_if_index(struct in_addr *addr, php_socket 
*php_sock, unsigned *i
                php_error_docref(NULL TSRMLS_CC, E_WARNING,
                        "The interface with IP address %s was not found", 
addr_str);
        }
-       
+
 err:
        if (buf != NULL)
                efree(buf);
diff --git a/ext/sockets/multicast.h b/ext/sockets/multicast.h
index 498a71f..c363b58 100644
--- a/ext/sockets/multicast.h
+++ b/ext/sockets/multicast.h
@@ -27,6 +27,16 @@
 #define HAS_MCAST_EXT 1
 #endif
 
+int php_do_setsockopt_ip_mcast(php_socket *php_sock,
+                                                          int level,
+                                                          int optname,
+                                                          zval **arg4);
+
+int php_do_setsockopt_ipv6_mcast(php_socket *php_sock,
+                                                                int level,
+                                                                int optname,
+                                                                zval **arg4);
+
 int php_if_index_to_addr4(
         unsigned if_index,
         php_socket *php_sock,
diff --git a/ext/sockets/php_sockets.h b/ext/sockets/php_sockets.h
index 3138eb6..78da0c2 100644
--- a/ext/sockets/php_sockets.h
+++ b/ext/sockets/php_sockets.h
@@ -87,6 +87,12 @@ ZEND_END_MODULE_GLOBALS(sockets)
 
 ZEND_EXTERN_MODULE_GLOBALS(sockets);
 
+enum sockopt_return {
+       SOCKOPT_ERROR,
+       SOCKOPT_CONTINUE,
+       SOCKOPT_SUCCESS
+};
+
 char *sockets_strerror(int error TSRMLS_DC);
 php_socket *socket_import_file_descriptor(PHP_SOCKET sock TSRMLS_DC);
 
diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c
index 37e2e9f..9f11594 100644
--- a/ext/sockets/sockets.c
+++ b/ext/sockets/sockets.c
@@ -619,81 +619,6 @@ char *sockets_strerror(int error TSRMLS_DC) /* {{{ */
 }
 /* }}} */
 
-
-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;
-               }
-               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;
-}
-
 /* {{{ PHP_GINIT_FUNCTION */
 static PHP_GINIT_FUNCTION(sockets)
 {
@@ -2012,102 +1937,6 @@ PHP_FUNCTION(socket_get_option)
 }
 /* }}} */
 
-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 MCAST_JOIN_GROUP:
-               mcast_req_fun = &php_mcast_join;
-               goto mcast_req_fun;
-       case 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 MCAST_BLOCK_SOURCE:
-               mcast_sreq_fun = &php_mcast_block_source;
-               goto mcast_sreq_fun;
-       case MCAST_UNBLOCK_SOURCE:
-               mcast_sreq_fun = &php_mcast_unblock_source;
-               goto mcast_sreq_fun;
-       case MCAST_JOIN_SOURCE_GROUP:
-               mcast_sreq_fun = &php_mcast_join_source;
-               goto mcast_sreq_fun;
-       case 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;
-}
-
 /* {{{ proto bool socket_set_option(resource socket, int level, int optname, 
int|array optval)
    Sets socket options for the socket */
 PHP_FUNCTION(socket_set_option)
@@ -2127,10 +1956,6 @@ PHP_FUNCTION(socket_set_option)
        zval                                    **l_onoff, **l_linger;
        zval                                    **sec, **usec;
 
-       /* Multicast */
-       unsigned int                    if_index;
-       struct in_addr                  if_addr;
-       unsigned char                   ipv4_mcast_ttl_lback;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rllZ", &arg1, 
&level, &optname, &arg4) == FAILURE) {
                return;
@@ -2140,94 +1965,23 @@ PHP_FUNCTION(socket_set_option)
 
        set_errno(0);
 
-       if (level == IPPROTO_IP) {
-               switch (optname) {
-               case MCAST_JOIN_GROUP:
-               case MCAST_LEAVE_GROUP:
-#ifdef HAS_MCAST_EXT
-               case MCAST_BLOCK_SOURCE:
-               case MCAST_UNBLOCK_SOURCE:
-               case MCAST_JOIN_SOURCE_GROUP:
-               case MCAST_LEAVE_SOURCE_GROUP:
-#endif
-                       if (php_do_mcast_opt(php_sock, level, optname, arg4 
TSRMLS_CC) == FAILURE) {
-                               RETURN_FALSE;
-                       } else {
-                               RETURN_TRUE;
-                       }
+#define HANDLE_SUBCALL(res) \
+       do { \
+               if (res == 1) { goto default_case; } \
+               else if (res == SUCCESS) { RETURN_TRUE; } \
+               else { RETURN_FALSE; } \
+       } while (0)
 
-               case IP_MULTICAST_IF:
-                       if (php_get_if_index_from_zval(*arg4, &if_index 
TSRMLS_CC) == FAILURE) {
-                               RETURN_FALSE;
-                       }
 
-                       if (php_if_index_to_addr4(if_index, php_sock, &if_addr 
TSRMLS_CC) == FAILURE) {
-                               RETURN_FALSE;
-                       }
-                       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_FALSE;
-                       }
-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;
-               }
+       if (level == IPPROTO_IP) {
+               int res = php_do_setsockopt_ip_mcast(php_sock, level, optname, 
arg4);
+               HANDLE_SUBCALL(res);
        }
 
 #if HAVE_IPV6
        else if (level == IPPROTO_IPV6) {
-               switch (optname) {
-               case MCAST_JOIN_GROUP:
-               case MCAST_LEAVE_GROUP:
-#ifdef HAS_MCAST_EXT
-               case MCAST_BLOCK_SOURCE:
-               case MCAST_UNBLOCK_SOURCE:
-               case MCAST_JOIN_SOURCE_GROUP:
-               case MCAST_LEAVE_SOURCE_GROUP:
-#endif
-                       if (php_do_mcast_opt(php_sock, level, optname, arg4 
TSRMLS_CC) == FAILURE) {
-                               RETURN_FALSE;
-                       } else {
-                               RETURN_TRUE;
-                       }
-
-               case IPV6_MULTICAST_IF:
-                       if (php_get_if_index_from_zval(*arg4, &if_index 
TSRMLS_CC) == FAILURE) {
-                               RETURN_FALSE;
-                       }
-
-                       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_FALSE;
-                       }
-ipv6_loop_hops:
-                       ov = (int) Z_LVAL_PP(arg4);
-                       opt_ptr = &ov;
-                       optlen  = sizeof(ov);
-                       goto dosockopt;
-               }
+               int res = php_do_setsockopt_ipv6_mcast(php_sock, level, 
optname, arg4);
+               HANDLE_SUBCALL(res);
        }
 #endif
 
@@ -2292,6 +2046,7 @@ ipv6_loop_hops:
                }
 
                default:
+default_case:
                        convert_to_long_ex(arg4);
                        ov = Z_LVAL_PP(arg4);
 
@@ -2300,12 +2055,9 @@ ipv6_loop_hops:
                        break;
        }
 
-dosockopt:
        retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, 
optlen);
        if (retval != 0) {
-               if (retval != -2) { /* error, but message already emitted */
-                       PHP_SOCKET_ERROR(php_sock, "unable to set socket 
option", errno);
-               }
+               PHP_SOCKET_ERROR(php_sock, "unable to set socket option", 
errno);
                RETURN_FALSE;
        }
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to