diff options
author | Gustavo Lopes <glopes@nebm.ist.utl.pt> | 2012-11-06 12:48:47 +0100 |
---|---|---|
committer | Gustavo Lopes <glopes@nebm.ist.utl.pt> | 2013-02-02 16:38:07 +0100 |
commit | 51394f76a5fca718fbf218888d97402f845ee261 (patch) | |
tree | 5ccbab24fb871d3c32ae1c9a4a36c4df9b10baa7 /ext/sockets | |
parent | 3e515a2fd93204594c80ad2379f42fbb2db18d78 (diff) | |
download | php-git-51394f76a5fca718fbf218888d97402f845ee261.tar.gz |
Move some multicast stuff to multicast.c
Diffstat (limited to 'ext/sockets')
-rw-r--r-- | ext/sockets/multicast.c | 362 | ||||
-rw-r--r-- | ext/sockets/multicast.h | 10 | ||||
-rw-r--r-- | ext/sockets/php_sockets.h | 6 | ||||
-rw-r--r-- | ext/sockets/sockets.c | 274 |
4 files changed, 362 insertions, 290 deletions
diff --git a/ext/sockets/multicast.c b/ext/sockets/multicast.c index d4a00a8d17..dc242693ac 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 498a71f67a..c363b58472 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 3138eb60c4..78da0c29e6 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 37e2e9fe98..9f11594425 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; } |