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: 167 216 77.3 %
Date: 2014-12-13 Functions: 18 18 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 13 Dec 2014 06:16:21 +0000 (7 days ago)

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