PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/sockets - multicast.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 166 216 76.9 %
Date: 2014-07-21 Functions: 18 18 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 5                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2014 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Gustavo Lopes    <cataphract@php.net>                       |
      16             :    +----------------------------------------------------------------------+
      17             :  */
      18             : 
      19             : /* $Id$ */
      20             : 
      21             : #ifdef HAVE_CONFIG_H
      22             : #include "config.h"
      23             : #endif
      24             : 
      25             : #include "php.h"
      26             : 
      27             : #include "php_network.h"
      28             : #ifdef PHP_WIN32
      29             : # include "windows_common.h"
      30             : #else
      31             : #include <sys/socket.h>
      32             : #include <sys/ioctl.h>
      33             : #include <net/if.h>
      34             : #ifdef HAVE_SYS_SOCKIO_H
      35             : #include <sys/sockio.h>
      36             : #endif
      37             : #include <netinet/in.h>
      38             : #include <arpa/inet.h>
      39             : #endif
      40             : 
      41             : #include "php_sockets.h"
      42             : #include "multicast.h"
      43             : #include "sockaddr_conv.h"
      44             : #include "main/php_network.h"
      45             : 
      46             : 
      47             : enum source_op {
      48             :         JOIN_SOURCE,
      49             :         LEAVE_SOURCE,
      50             :         BLOCK_SOURCE,
      51             :         UNBLOCK_SOURCE
      52             : };
      53             : 
      54             : static int _php_mcast_join_leave(php_socket *sock, int level, struct sockaddr *group, socklen_t group_len, unsigned int if_index, int join TSRMLS_DC);
      55             : #ifdef HAS_MCAST_EXT
      56             : static int _php_mcast_source_op(php_socket *sock, int level, struct sockaddr *group, socklen_t group_len, struct sockaddr *source, socklen_t source_len, unsigned int if_index, enum source_op sop TSRMLS_DC);
      57             : #endif
      58             : 
      59             : #ifdef RFC3678_API
      60             : static int _php_source_op_to_rfc3678_op(enum source_op sop);
      61             : #elif HAS_MCAST_EXT
      62             : static const char *_php_source_op_to_string(enum source_op sop);
      63             : static int _php_source_op_to_ipv4_op(enum source_op sop);
      64             : #endif
      65             : 
      66          11 : int php_string_to_if_index(const char *val, unsigned *out TSRMLS_DC)
      67             : {
      68             : #if HAVE_IF_NAMETOINDEX
      69             :         unsigned int ind;
      70             : 
      71          11 :         ind = if_nametoindex(val);
      72          11 :         if (ind == 0) {
      73           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING,
      74             :                         "no interface with name \"%s\" could be found", val);
      75           0 :                 return FAILURE;
      76             :         } else {
      77          11 :                 *out = ind;
      78          11 :                 return SUCCESS;
      79             :         }
      80             : #else
      81             :         php_error_docref(NULL TSRMLS_CC, E_WARNING,
      82             :                         "this platform does not support looking up an interface by "
      83             :                         "name, an integer interface index must be supplied instead");
      84             :         return FAILURE;
      85             : #endif
      86             : }
      87             : 
      88          24 : static int php_get_if_index_from_zval(zval *val, unsigned *out TSRMLS_DC)
      89             : {
      90             :         int ret;
      91             : 
      92          24 :         if (Z_TYPE_P(val) == IS_LONG) {
      93          13 :                 if (Z_LVAL_P(val) < 0 || Z_LVAL_P(val) > UINT_MAX) {
      94           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING,
      95             :                                 "the interface index cannot be negative or larger than %u;"
      96           0 :                                 " given %ld", UINT_MAX, Z_LVAL_P(val));
      97           0 :                         ret = FAILURE;
      98             :                 } else {
      99          13 :                         *out = Z_LVAL_P(val);
     100          13 :                         ret = SUCCESS;
     101             :                 }
     102             :         } else {
     103          11 :                 zval_add_ref(&val);
     104          11 :                 convert_to_string_ex(&val);
     105          11 :                 ret = php_string_to_if_index(Z_STRVAL_P(val), out TSRMLS_CC);
     106          11 :                 zval_ptr_dtor(&val);
     107             :         }
     108             : 
     109          24 :         return ret;
     110             : }
     111             : 
     112             : 
     113             : 
     114          19 : static int php_get_if_index_from_array(const HashTable *ht, const char *key,
     115             :         php_socket *sock, unsigned int *if_index TSRMLS_DC)
     116             : {
     117             :         zval **val;
     118             : 
     119          19 :         if (zend_hash_find(ht, key, strlen(key) + 1, (void **)&val) == FAILURE) {
     120           0 :                 *if_index = 0; /* default: 0 */
     121           0 :                 return SUCCESS;
     122             :         }
     123             : 
     124          19 :         return php_get_if_index_from_zval(*val, if_index TSRMLS_CC);
     125             : }
     126             : 
     127          25 : static int php_get_address_from_array(const HashTable *ht, const char *key,
     128             :         php_socket *sock, php_sockaddr_storage *ss, socklen_t *ss_len TSRMLS_DC)
     129             : {
     130             :         zval **val,
     131             :                  *valcp;
     132             : 
     133          25 :         if (zend_hash_find(ht, key, strlen(key) + 1, (void **)&val) == FAILURE) {
     134           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", key);
     135           0 :                 return FAILURE;
     136             :         }
     137          25 :         valcp = *val;
     138          25 :         zval_add_ref(&valcp);
     139          25 :         convert_to_string_ex(val);
     140          25 :         if (!php_set_inet46_addr(ss, ss_len, Z_STRVAL_P(valcp), sock TSRMLS_CC)) {
     141           0 :                 zval_ptr_dtor(&valcp);
     142           0 :                 return FAILURE;
     143             :         }
     144          25 :         zval_ptr_dtor(&valcp);
     145          25 :         return SUCCESS;
     146             : }
     147             : 
     148          19 : static int php_do_mcast_opt(php_socket *php_sock, int level, int optname, zval **arg4 TSRMLS_DC)
     149             : {
     150             :         HashTable                               *opt_ht;
     151             :         unsigned int                    if_index;
     152             :         int                                             retval;
     153             :         int (*mcast_req_fun)(php_socket *, int, struct sockaddr *, socklen_t,
     154             :                 unsigned TSRMLS_DC);
     155             : #ifdef HAS_MCAST_EXT
     156             :         int (*mcast_sreq_fun)(php_socket *, int, struct sockaddr *, socklen_t,
     157             :                 struct sockaddr *, socklen_t, unsigned TSRMLS_DC);
     158             : #endif
     159             : 
     160          19 :         switch (optname) {
     161             :         case PHP_MCAST_JOIN_GROUP:
     162           9 :                 mcast_req_fun = &php_mcast_join;
     163           9 :                 goto mcast_req_fun;
     164             :         case PHP_MCAST_LEAVE_GROUP:
     165             :                 {
     166           4 :                         php_sockaddr_storage    group = {0};
     167             :                         socklen_t                               glen;
     168             : 
     169           4 :                         mcast_req_fun = &php_mcast_leave;
     170             : mcast_req_fun:
     171          13 :                         convert_to_array_ex(arg4);
     172          13 :                         opt_ht = HASH_OF(*arg4);
     173             : 
     174          13 :                         if (php_get_address_from_array(opt_ht, "group", php_sock, &group,
     175             :                                 &glen TSRMLS_CC) == FAILURE) {
     176           0 :                                         return FAILURE;
     177             :                         }
     178          13 :                         if (php_get_if_index_from_array(opt_ht, "interface", php_sock,
     179             :                                 &if_index TSRMLS_CC) == FAILURE) {
     180           0 :                                         return FAILURE;
     181             :                         }
     182             : 
     183          13 :                         retval = mcast_req_fun(php_sock, level, (struct sockaddr*)&group,
     184             :                                 glen, if_index TSRMLS_CC);
     185          13 :                         break;
     186             :                 }
     187             : 
     188             : #ifdef HAS_MCAST_EXT
     189             :         case PHP_MCAST_BLOCK_SOURCE:
     190           1 :                 mcast_sreq_fun = &php_mcast_block_source;
     191           1 :                 goto mcast_sreq_fun;
     192             :         case PHP_MCAST_UNBLOCK_SOURCE:
     193           1 :                 mcast_sreq_fun = &php_mcast_unblock_source;
     194           1 :                 goto mcast_sreq_fun;
     195             :         case PHP_MCAST_JOIN_SOURCE_GROUP:
     196           3 :                 mcast_sreq_fun = &php_mcast_join_source;
     197           3 :                 goto mcast_sreq_fun;
     198             :         case PHP_MCAST_LEAVE_SOURCE_GROUP:
     199             :                 {
     200           1 :                         php_sockaddr_storage    group = {0},
     201           1 :                                                                         source = {0};
     202             :                         socklen_t                               glen,
     203             :                                                                         slen;
     204             : 
     205           1 :                         mcast_sreq_fun = &php_mcast_leave_source;
     206             :                 mcast_sreq_fun:
     207           6 :                         convert_to_array_ex(arg4);
     208           6 :                         opt_ht = HASH_OF(*arg4);
     209             : 
     210           6 :                         if (php_get_address_from_array(opt_ht, "group", php_sock, &group,
     211             :                                         &glen TSRMLS_CC) == FAILURE) {
     212           0 :                                 return FAILURE;
     213             :                         }
     214           6 :                         if (php_get_address_from_array(opt_ht, "source", php_sock, &source,
     215             :                                         &slen TSRMLS_CC) == FAILURE) {
     216           0 :                                 return FAILURE;
     217             :                         }
     218           6 :                         if (php_get_if_index_from_array(opt_ht, "interface", php_sock,
     219             :                                         &if_index TSRMLS_CC) == FAILURE) {
     220           0 :                                 return FAILURE;
     221             :                         }
     222             : 
     223           6 :                         retval = mcast_sreq_fun(php_sock, level, (struct sockaddr*)&group,
     224             :                                         glen, (struct sockaddr*)&source, slen, if_index TSRMLS_CC);
     225           6 :                         break;
     226             :                 }
     227             : #endif
     228             :         default:
     229           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING,
     230             :                         "unexpected option in php_do_mcast_opt (level %d, option %d). "
     231             :                         "This is a bug.", level, optname);
     232           0 :                 return FAILURE;
     233             :         }
     234             : 
     235          19 :         if (retval != 0) {
     236           0 :                 if (retval != -2) { /* error, but message already emitted */
     237           0 :                         PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
     238             :                 }
     239           0 :                 return FAILURE;
     240             :         }
     241          19 :         return SUCCESS;
     242             : }
     243             : 
     244          22 : int php_do_setsockopt_ip_mcast(php_socket *php_sock,
     245             :                                                            int level,
     246             :                                                            int optname,
     247             :                                                            zval **arg4 TSRMLS_DC)
     248             : {
     249             :         unsigned int    if_index;
     250             :         struct in_addr  if_addr;
     251             :         void                    *opt_ptr;
     252             :         socklen_t               optlen;
     253             :         unsigned char   ipv4_mcast_ttl_lback;
     254             :         int                             retval;
     255             : 
     256          22 :         switch (optname) {
     257             :         case PHP_MCAST_JOIN_GROUP:
     258             :         case PHP_MCAST_LEAVE_GROUP:
     259             : #ifdef HAS_MCAST_EXT
     260             :         case PHP_MCAST_BLOCK_SOURCE:
     261             :         case PHP_MCAST_UNBLOCK_SOURCE:
     262             :         case PHP_MCAST_JOIN_SOURCE_GROUP:
     263             :         case PHP_MCAST_LEAVE_SOURCE_GROUP:
     264             : #endif
     265          12 :                 if (php_do_mcast_opt(php_sock, level, optname, arg4 TSRMLS_CC) == FAILURE) {
     266           0 :                         return FAILURE;
     267             :                 } else {
     268          12 :                         return SUCCESS;
     269             :                 }
     270             : 
     271             :         case IP_MULTICAST_IF:
     272           2 :                 if (php_get_if_index_from_zval(*arg4, &if_index TSRMLS_CC) == FAILURE) {
     273           0 :                         return FAILURE;
     274             :                 }
     275             : 
     276           2 :                 if (php_if_index_to_addr4(if_index, php_sock, &if_addr TSRMLS_CC) == FAILURE) {
     277           0 :                         return FAILURE;
     278             :                 }
     279           2 :                 opt_ptr = &if_addr;
     280           2 :                 optlen  = sizeof(if_addr);
     281           2 :                 goto dosockopt;
     282             : 
     283             :         case IP_MULTICAST_LOOP:
     284          13 :                 convert_to_boolean_ex(arg4);
     285           4 :                 goto ipv4_loop_ttl;
     286             : 
     287             :         case IP_MULTICAST_TTL:
     288           7 :                 convert_to_long_ex(arg4);
     289           4 :                 if (Z_LVAL_PP(arg4) < 0L || Z_LVAL_PP(arg4) > 255L) {
     290           2 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING,
     291             :                                         "Expected a value between 0 and 255");
     292           2 :                         return FAILURE;
     293             :                 }
     294             : ipv4_loop_ttl:
     295           6 :                 ipv4_mcast_ttl_lback = (unsigned char) Z_LVAL_PP(arg4);
     296           6 :                 opt_ptr = &ipv4_mcast_ttl_lback;
     297           6 :                 optlen  = sizeof(ipv4_mcast_ttl_lback);
     298           6 :                 goto dosockopt;
     299             :         }
     300             : 
     301           0 :         return 1;
     302             : 
     303             : dosockopt:
     304           8 :         retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
     305           8 :         if (retval != 0) {
     306           0 :                 PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
     307           0 :                 return FAILURE;
     308             :         }
     309             : 
     310           8 :         return SUCCESS;
     311             : }
     312             : 
     313          18 : int php_do_setsockopt_ipv6_mcast(php_socket *php_sock,
     314             :                                                                  int level,
     315             :                                                                  int optname,
     316             :                                                                  zval **arg4 TSRMLS_DC)
     317             : {
     318             :         unsigned int    if_index;
     319             :         void                    *opt_ptr;
     320             :         socklen_t               optlen;
     321             :         int                             ov;
     322             :         int                             retval;
     323             : 
     324          18 :         switch (optname) {
     325             :         case PHP_MCAST_JOIN_GROUP:
     326             :         case PHP_MCAST_LEAVE_GROUP:
     327             : #ifdef HAS_MCAST_EXT
     328             :         case PHP_MCAST_BLOCK_SOURCE:
     329             :         case PHP_MCAST_UNBLOCK_SOURCE:
     330             :         case PHP_MCAST_JOIN_SOURCE_GROUP:
     331             :         case PHP_MCAST_LEAVE_SOURCE_GROUP:
     332             : #endif
     333           7 :                 if (php_do_mcast_opt(php_sock, level, optname, arg4 TSRMLS_CC) == FAILURE) {
     334           0 :                         return FAILURE;
     335             :                 } else {
     336           7 :                         return SUCCESS;
     337             :                 }
     338             : 
     339             :         case IPV6_MULTICAST_IF:
     340           3 :                 if (php_get_if_index_from_zval(*arg4, &if_index TSRMLS_CC) == FAILURE) {
     341           0 :                         return FAILURE;
     342             :                 }
     343             : 
     344           3 :                 opt_ptr = &if_index;
     345           3 :                 optlen  = sizeof(if_index);
     346           3 :                 goto dosockopt;
     347             : 
     348             :         case IPV6_MULTICAST_LOOP:
     349           8 :                 convert_to_boolean_ex(arg4);
     350           2 :                 goto ipv6_loop_hops;
     351             :         case IPV6_MULTICAST_HOPS:
     352           1 :                 convert_to_long_ex(arg4);
     353           1 :                 if (Z_LVAL_PP(arg4) < -1L || Z_LVAL_PP(arg4) > 255L) {
     354           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING,
     355             :                                         "Expected a value between -1 and 255");
     356           0 :                         return FAILURE;
     357             :                 }
     358             : ipv6_loop_hops:
     359           3 :                 ov = (int) Z_LVAL_PP(arg4);
     360           3 :                 opt_ptr = &ov;
     361           3 :                 optlen  = sizeof(ov);
     362           3 :                 goto dosockopt;
     363             :         }
     364             : 
     365           5 :         return 1; /* not handled */
     366             : 
     367             : dosockopt:
     368           6 :         retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
     369           6 :         if (retval != 0) {
     370           0 :                 PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
     371           0 :                 return FAILURE;
     372             :         }
     373             : 
     374           6 :         return SUCCESS;
     375             : }
     376             : 
     377           9 : int php_mcast_join(
     378             :         php_socket *sock,
     379             :         int level,
     380             :         struct sockaddr *group,
     381             :         socklen_t group_len,
     382             :         unsigned int if_index TSRMLS_DC)
     383             : {
     384           9 :         return _php_mcast_join_leave(sock, level, group, group_len, if_index, 1 TSRMLS_CC);
     385             : }
     386             : 
     387           4 : int php_mcast_leave(
     388             :         php_socket *sock,
     389             :         int level,
     390             :         struct sockaddr *group,
     391             :         socklen_t group_len,
     392             :         unsigned int if_index TSRMLS_DC)
     393             : {
     394           4 :         return _php_mcast_join_leave(sock, level, group, group_len, if_index, 0 TSRMLS_CC);
     395             : }
     396             : 
     397             : #ifdef HAS_MCAST_EXT
     398           3 : int php_mcast_join_source(
     399             :         php_socket *sock,
     400             :         int level,
     401             :         struct sockaddr *group,
     402             :         socklen_t group_len,
     403             :         struct sockaddr *source,
     404             :         socklen_t source_len,
     405             :         unsigned int if_index TSRMLS_DC)
     406             : {
     407           3 :         return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, JOIN_SOURCE TSRMLS_CC);
     408             : }
     409             : 
     410           1 : int php_mcast_leave_source(
     411             :         php_socket *sock,
     412             :         int level,
     413             :         struct sockaddr *group,
     414             :         socklen_t group_len,
     415             :         struct sockaddr *source,
     416             :         socklen_t source_len,
     417             :         unsigned int if_index TSRMLS_DC)
     418             : {
     419           1 :         return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, LEAVE_SOURCE TSRMLS_CC);
     420             : }
     421             : 
     422           1 : int php_mcast_block_source(
     423             :         php_socket *sock,
     424             :         int level,
     425             :         struct sockaddr *group,
     426             :         socklen_t group_len,
     427             :         struct sockaddr *source,
     428             :         socklen_t source_len,
     429             :         unsigned int if_index TSRMLS_DC)
     430             : {
     431           1 :         return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, BLOCK_SOURCE TSRMLS_CC);
     432             : }
     433             : 
     434           1 : int php_mcast_unblock_source(
     435             :         php_socket *sock,
     436             :         int level,
     437             :         struct sockaddr *group,
     438             :         socklen_t group_len,
     439             :         struct sockaddr *source,
     440             :         socklen_t source_len,
     441             :         unsigned int if_index TSRMLS_DC)
     442             : {
     443           1 :         return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, UNBLOCK_SOURCE TSRMLS_CC);
     444             : }
     445             : #endif /* HAS_MCAST_EXT */
     446             : 
     447             : 
     448          13 : static int _php_mcast_join_leave(
     449             :         php_socket *sock,
     450             :         int level,
     451             :         struct sockaddr *group, /* struct sockaddr_in/sockaddr_in6 */
     452             :         socklen_t group_len,
     453             :         unsigned int if_index,
     454             :         int join TSRMLS_DC)
     455             : {
     456             : #ifdef RFC3678_API
     457          13 :         struct group_req greq = {0};
     458             : 
     459          13 :         memcpy(&greq.gr_group, group, group_len);
     460             :         assert(greq.gr_group.ss_family != 0); /* the caller has set this */
     461          13 :         greq.gr_interface = if_index;
     462             : 
     463          13 :         return setsockopt(sock->bsd_socket, level,
     464             :                         join ? MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP, (char*)&greq,
     465             :                         sizeof(greq));
     466             : #else
     467             :         if (sock->type == AF_INET) {
     468             :                 struct ip_mreq mreq = {0};
     469             :                 struct in_addr addr;
     470             : 
     471             :                 assert(group_len == sizeof(struct sockaddr_in));
     472             : 
     473             :                 if (if_index != 0) {
     474             :                         if (php_if_index_to_addr4(if_index, sock, &addr TSRMLS_CC) ==
     475             :                                         FAILURE)
     476             :                                 return -2; /* failure, but notice already emitted */
     477             :                         mreq.imr_interface = addr;
     478             :                 } else {
     479             :                         mreq.imr_interface.s_addr = htonl(INADDR_ANY);
     480             :                 }
     481             :                 mreq.imr_multiaddr = ((struct sockaddr_in*)group)->sin_addr;
     482             :                 return setsockopt(sock->bsd_socket, level,
     483             :                                 join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, (char*)&mreq,
     484             :                                 sizeof(mreq));
     485             :         }
     486             : #if HAVE_IPV6
     487             :         else if (sock->type == AF_INET6) {
     488             :                 struct ipv6_mreq mreq = {0};
     489             : 
     490             :                 assert(group_len == sizeof(struct sockaddr_in6));
     491             : 
     492             :                 mreq.ipv6mr_multiaddr = ((struct sockaddr_in6*)group)->sin6_addr;
     493             :                 mreq.ipv6mr_interface = if_index;
     494             : 
     495             :                 return setsockopt(sock->bsd_socket, level,
     496             :                                 join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP, (char*)&mreq,
     497             :                                 sizeof(mreq));
     498             :         }
     499             : #endif
     500             :         else {
     501             :                 php_error_docref(NULL TSRMLS_CC, E_WARNING,
     502             :                         "Option %s is inapplicable to this socket type",
     503             :                         join ? "MCAST_JOIN_GROUP" : "MCAST_LEAVE_GROUP");
     504             :                 return -2;
     505             :         }
     506             : #endif
     507             : }
     508             : 
     509             : #ifdef HAS_MCAST_EXT
     510           6 : static int _php_mcast_source_op(
     511             :         php_socket *sock,
     512             :         int level,
     513             :         struct sockaddr *group,
     514             :         socklen_t group_len,
     515             :         struct sockaddr *source,
     516             :         socklen_t source_len,
     517             :         unsigned int if_index,
     518             :         enum source_op sop TSRMLS_DC)
     519             : {
     520             : #ifdef RFC3678_API
     521           6 :         struct group_source_req gsreq = {0};
     522             : 
     523           6 :         memcpy(&gsreq.gsr_group, group, group_len);
     524             :         assert(gsreq.gsr_group.ss_family != 0);
     525           6 :         memcpy(&gsreq.gsr_source, source, source_len);
     526             :         assert(gsreq.gsr_source.ss_family != 0);
     527           6 :         gsreq.gsr_interface = if_index;
     528             : 
     529           6 :         return setsockopt(sock->bsd_socket, level,
     530             :                         _php_source_op_to_rfc3678_op(sop), (char*)&gsreq, sizeof(gsreq));
     531             : #else
     532             :         if (sock->type == AF_INET) {
     533             :                 struct ip_mreq_source mreqs = {0};
     534             :                 struct in_addr addr;
     535             : 
     536             :                 mreqs.imr_multiaddr = ((struct sockaddr_in*)group)->sin_addr;
     537             :                 mreqs.imr_sourceaddr =  ((struct sockaddr_in*)source)->sin_addr;
     538             : 
     539             :                 assert(group_len == sizeof(struct sockaddr_in));
     540             :                 assert(source_len == sizeof(struct sockaddr_in));
     541             : 
     542             :                 if (if_index != 0) {
     543             :                         if (php_if_index_to_addr4(if_index, sock, &addr TSRMLS_CC) ==
     544             :                                         FAILURE)
     545             :                                 return -2; /* failure, but notice already emitted */
     546             :                         mreqs.imr_interface = addr;
     547             :                 } else {
     548             :                         mreqs.imr_interface.s_addr = htonl(INADDR_ANY);
     549             :                 }
     550             : 
     551             :                 return setsockopt(sock->bsd_socket, level,
     552             :                                 _php_source_op_to_ipv4_op(sop), (char*)&mreqs, sizeof(mreqs));
     553             :         }
     554             : #if HAVE_IPV6
     555             :         else if (sock->type == AF_INET6) {
     556             :                 php_error_docref(NULL TSRMLS_CC, E_WARNING,
     557             :                         "This platform does not support %s for IPv6 sockets",
     558             :                         _php_source_op_to_string(sop));
     559             :                 return -2;
     560             :         }
     561             : #endif
     562             :         else {
     563             :                 php_error_docref(NULL TSRMLS_CC, E_WARNING,
     564             :                         "Option %s is inapplicable to this socket type",
     565             :                         _php_source_op_to_string(sop));
     566             :                 return -2;
     567             :         }
     568             : #endif
     569             : }
     570             : 
     571             : #if RFC3678_API
     572           6 : static int _php_source_op_to_rfc3678_op(enum source_op sop)
     573             : {
     574           6 :         switch (sop) {
     575             :         case JOIN_SOURCE:
     576           3 :                 return MCAST_JOIN_SOURCE_GROUP;
     577             :         case LEAVE_SOURCE:
     578           1 :                 return MCAST_LEAVE_SOURCE_GROUP;
     579             :         case BLOCK_SOURCE:
     580           1 :                 return MCAST_BLOCK_SOURCE;
     581             :         case UNBLOCK_SOURCE:
     582           1 :                 return MCAST_UNBLOCK_SOURCE;
     583             :         }
     584             : 
     585             :         assert(0);
     586           0 :         return 0;
     587             : }
     588             : #else
     589             : static const char *_php_source_op_to_string(enum source_op sop)
     590             : {
     591             :         switch (sop) {
     592             :         case JOIN_SOURCE:
     593             :                 return "MCAST_JOIN_SOURCE_GROUP";
     594             :         case LEAVE_SOURCE:
     595             :                 return "MCAST_LEAVE_SOURCE_GROUP";
     596             :         case BLOCK_SOURCE:
     597             :                 return "MCAST_BLOCK_SOURCE";
     598             :         case UNBLOCK_SOURCE:
     599             :                 return "MCAST_UNBLOCK_SOURCE";
     600             :         }
     601             : 
     602             :         assert(0);
     603             :         return "";
     604             : }
     605             : 
     606             : static int _php_source_op_to_ipv4_op(enum source_op sop)
     607             : {
     608             :         switch (sop) {
     609             :         case JOIN_SOURCE:
     610             :                 return IP_ADD_SOURCE_MEMBERSHIP;
     611             :         case LEAVE_SOURCE:
     612             :                 return IP_DROP_SOURCE_MEMBERSHIP;
     613             :         case BLOCK_SOURCE:
     614             :                 return IP_BLOCK_SOURCE;
     615             :         case UNBLOCK_SOURCE:
     616             :                 return IP_UNBLOCK_SOURCE;
     617             :         }
     618             : 
     619             :         assert(0);
     620             :         return 0;
     621             : }
     622             : #endif
     623             : 
     624             : #endif /* HAS_MCAST_EXT */
     625             : 
     626             : #if PHP_WIN32
     627             : int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr TSRMLS_DC)
     628             : {
     629             :         MIB_IPADDRTABLE *addr_table;
     630             :     ULONG size;
     631             :     DWORD retval;
     632             :         DWORD i;
     633             : 
     634             :         (void) php_sock; /* not necessary */
     635             : 
     636             :         if (if_index == 0) {
     637             :                 out_addr->s_addr = INADDR_ANY;
     638             :                 return SUCCESS;
     639             :         }
     640             : 
     641             :         size = 4 * (sizeof *addr_table);
     642             :         addr_table = emalloc(size);
     643             : retry:
     644             :         retval = GetIpAddrTable(addr_table, &size, 0);
     645             :         if (retval == ERROR_INSUFFICIENT_BUFFER) {
     646             :                 efree(addr_table);
     647             :                 addr_table = emalloc(size);
     648             :                 goto retry;
     649             :         }
     650             :         if (retval != NO_ERROR) {
     651             :                 php_error_docref(NULL TSRMLS_CC, E_WARNING,
     652             :                         "GetIpAddrTable failed with error %lu", retval);
     653             :                 return FAILURE;
     654             :         }
     655             :         for (i = 0; i < addr_table->dwNumEntries; i++) {
     656             :                 MIB_IPADDRROW r = addr_table->table[i];
     657             :                 if (r.dwIndex == if_index) {
     658             :                         out_addr->s_addr = r.dwAddr;
     659             :                         return SUCCESS;
     660             :                 }
     661             :         }
     662             :         php_error_docref(NULL TSRMLS_CC, E_WARNING,
     663             :                 "No interface with index %u was found", if_index);
     664             :         return FAILURE;
     665             : }
     666             : 
     667             : int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *if_index TSRMLS_DC)
     668             : {
     669             :         MIB_IPADDRTABLE *addr_table;
     670             :     ULONG size;
     671             :     DWORD retval;
     672             :         DWORD i;
     673             : 
     674             :         (void) php_sock; /* not necessary */
     675             : 
     676             :         if (addr->s_addr == INADDR_ANY) {
     677             :                 *if_index = 0;
     678             :                 return SUCCESS;
     679             :         }
     680             : 
     681             :         size = 4 * (sizeof *addr_table);
     682             :         addr_table = emalloc(size);
     683             : retry:
     684             :         retval = GetIpAddrTable(addr_table, &size, 0);
     685             :         if (retval == ERROR_INSUFFICIENT_BUFFER) {
     686             :                 efree(addr_table);
     687             :                 addr_table = emalloc(size);
     688             :                 goto retry;
     689             :         }
     690             :         if (retval != NO_ERROR) {
     691             :                 php_error_docref(NULL TSRMLS_CC, E_WARNING,
     692             :                         "GetIpAddrTable failed with error %lu", retval);
     693             :                 return FAILURE;
     694             :         }
     695             :         for (i = 0; i < addr_table->dwNumEntries; i++) {
     696             :                 MIB_IPADDRROW r = addr_table->table[i];
     697             :                 if (r.dwAddr == addr->s_addr) {
     698             :                         *if_index = r.dwIndex;
     699             :                         return SUCCESS;
     700             :                 }
     701             :         }
     702             : 
     703             :         {
     704             :                 char addr_str[17] = {0};
     705             :                 inet_ntop(AF_INET, addr, addr_str, sizeof(addr_str));
     706             :                 php_error_docref(NULL TSRMLS_CC, E_WARNING,
     707             :                         "The interface with IP address %s was not found", addr_str);
     708             :         }
     709             :         return FAILURE;
     710             : }
     711             : 
     712             : #else
     713             : 
     714           2 : int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr TSRMLS_DC)
     715             : {
     716             :         struct ifreq if_req;
     717             : 
     718           2 :         if (if_index == 0) {
     719           1 :                 out_addr->s_addr = INADDR_ANY;
     720           1 :                 return SUCCESS;
     721             :         }
     722             : 
     723             : #if !defined(ifr_ifindex) && defined(ifr_index)
     724             : #define ifr_ifindex ifr_index
     725             : #endif
     726             : 
     727             : #if defined(SIOCGIFNAME)
     728           1 :         if_req.ifr_ifindex = if_index;
     729           1 :         if (ioctl(php_sock->bsd_socket, SIOCGIFNAME, &if_req) == -1) {
     730             : #elif defined(HAVE_IF_INDEXTONAME)
     731             :         if (if_indextoname(if_index, if_req.ifr_name) == NULL) {
     732             : #else
     733             : #error Neither SIOCGIFNAME nor if_indextoname are available
     734             : #endif
     735           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING,
     736             :                         "Failed obtaining address for interface %u: error %d", if_index, errno);
     737           0 :                 return FAILURE;
     738             :         }
     739             : 
     740           1 :         if (ioctl(php_sock->bsd_socket, SIOCGIFADDR, &if_req) == -1) {
     741           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING,
     742             :                         "Failed obtaining address for interface %u: error %d", if_index, errno);
     743           0 :                 return FAILURE;
     744             :         }
     745             : 
     746           1 :         memcpy(out_addr, &((struct sockaddr_in *) &if_req.ifr_addr)->sin_addr,
     747             :                 sizeof *out_addr);
     748           1 :         return SUCCESS;
     749             : }
     750             : 
     751           2 : int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *if_index TSRMLS_DC)
     752             : {
     753           2 :         struct ifconf   if_conf = {0};
     754           2 :         char                    *buf = NULL,
     755             :                                         *p;
     756           2 :         int                             size = 0,
     757           2 :                                         lastsize = 0;
     758             :         size_t                  entry_len;
     759             : 
     760           2 :         if (addr->s_addr == INADDR_ANY) {
     761           1 :                 *if_index = 0;
     762           1 :                 return SUCCESS;
     763             :         }
     764             : 
     765             :         for(;;) {
     766           2 :                 size += 5 * sizeof(struct ifreq);
     767           2 :                 buf = ecalloc(size, 1);
     768           2 :                 if_conf.ifc_len = size;
     769           2 :                 if_conf.ifc_buf = buf;
     770             : 
     771           2 :                 if (ioctl(php_sock->bsd_socket, SIOCGIFCONF, (char*)&if_conf) == -1 &&
     772           0 :                                 (errno != EINVAL || lastsize != 0)) {
     773           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING,
     774             :                                 "Failed obtaining interfaces list: error %d", errno);
     775           0 :                         goto err;
     776             :                 }
     777             : 
     778           2 :                 if (if_conf.ifc_len == lastsize)
     779             :                         /* not increasing anymore */
     780           1 :                         break;
     781             :                 else {
     782           1 :                         lastsize = if_conf.ifc_len;
     783           1 :                         efree(buf);
     784           1 :                         buf = NULL;
     785             :                 }
     786           1 :         }
     787             : 
     788           2 :         for (p = if_conf.ifc_buf;
     789           1 :                  p < if_conf.ifc_buf + if_conf.ifc_len;
     790           0 :                  p += entry_len) {
     791             :                 struct ifreq *cur_req;
     792             : 
     793             :                 /* let's hope the pointer is aligned */
     794           1 :                 cur_req = (struct ifreq*) p;
     795             : 
     796             : #ifdef HAVE_SOCKADDR_SA_LEN
     797             :                 entry_len = cur_req->ifr_addr.sa_len + sizeof(cur_req->ifr_name);
     798             : #else
     799             :                 /* if there's no sa_len, assume the ifr_addr field is a sockaddr */
     800           1 :                 entry_len = sizeof(struct sockaddr) + sizeof(cur_req->ifr_name);
     801             : #endif
     802           1 :                 entry_len = MAX(entry_len, sizeof(*cur_req));
     803             : 
     804           2 :                 if ((((struct sockaddr*)&cur_req->ifr_addr)->sa_family == AF_INET) &&
     805           1 :                                 (((struct sockaddr_in*)&cur_req->ifr_addr)->sin_addr.s_addr ==
     806             :                                         addr->s_addr)) {
     807             : #if defined(SIOCGIFINDEX)
     808           1 :                         if (ioctl(php_sock->bsd_socket, SIOCGIFINDEX, (char*)cur_req)
     809             :                                         == -1) {
     810             : #elif defined(HAVE_IF_NAMETOINDEX)
     811             :                         unsigned index_tmp;
     812             :                         if ((index_tmp = if_nametoindex(cur_req->ifr_name)) == 0) {
     813             : #else
     814             : #error Neither SIOCGIFINDEX nor if_nametoindex are available
     815             : #endif
     816           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING,
     817             :                                         "Error converting interface name to index: error %d",
     818             :                                         errno);
     819           0 :                                 goto err;
     820             :                         } else {
     821             : #if defined(SIOCGIFINDEX)
     822           1 :                                 *if_index = cur_req->ifr_ifindex;
     823             : #else
     824             :                                 *if_index = index_tmp;
     825             : #endif
     826           1 :                                 efree(buf);
     827           1 :                                 return SUCCESS;
     828             :                         }
     829             :                 }
     830             :         }
     831             : 
     832             :         {
     833           0 :                 char addr_str[17] = {0};
     834           0 :                 inet_ntop(AF_INET, addr, addr_str, sizeof(addr_str));
     835           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING,
     836             :                         "The interface with IP address %s was not found", addr_str);
     837             :         }
     838             : 
     839             : err:
     840           0 :         if (buf != NULL)
     841           0 :                 efree(buf);
     842           0 :         return FAILURE;
     843             : }
     844             : #endif

Generated by: LCOV version 1.10

Generated at Tue, 22 Jul 2014 01:33:18 +0000 (3 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.