root/ext/sockets/multicast.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_string_to_if_index
  2. php_get_if_index_from_zval
  3. php_get_if_index_from_array
  4. php_get_address_from_array
  5. php_do_mcast_opt
  6. php_do_setsockopt_ip_mcast
  7. php_do_setsockopt_ipv6_mcast
  8. php_mcast_join
  9. php_mcast_leave
  10. php_mcast_join_source
  11. php_mcast_leave_source
  12. php_mcast_block_source
  13. php_mcast_unblock_source
  14. _php_mcast_join_leave
  15. _php_mcast_source_op
  16. _php_source_op_to_rfc3678_op
  17. _php_source_op_to_string
  18. _php_source_op_to_ipv4_op
  19. php_if_index_to_addr4
  20. php_add4_to_if_index
  21. php_if_index_to_addr4
  22. php_add4_to_if_index

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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);
  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);
  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 int php_string_to_if_index(const char *val, unsigned *out)
  67 {
  68 #if HAVE_IF_NAMETOINDEX
  69         unsigned int ind;
  70 
  71         ind = if_nametoindex(val);
  72         if (ind == 0) {
  73                 php_error_docref(NULL, E_WARNING,
  74                         "no interface with name \"%s\" could be found", val);
  75                 return FAILURE;
  76         } else {
  77                 *out = ind;
  78                 return SUCCESS;
  79         }
  80 #else
  81         php_error_docref(NULL, 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 static int php_get_if_index_from_zval(zval *val, unsigned *out)
  89 {
  90         int ret;
  91 
  92         if (Z_TYPE_P(val) == IS_LONG) {
  93                 if (Z_LVAL_P(val) < 0 || Z_LVAL_P(val) > UINT_MAX) {
  94                         php_error_docref(NULL, E_WARNING,
  95                                 "the interface index cannot be negative or larger than %u;"
  96                                 " given %pd", UINT_MAX, Z_LVAL_P(val));
  97                         ret = FAILURE;
  98                 } else {
  99                         *out = Z_LVAL_P(val);
 100                         ret = SUCCESS;
 101                 }
 102         } else {
 103                 if (Z_REFCOUNTED_P(val)) {
 104                         Z_ADDREF_P(val);
 105                 }
 106                 convert_to_string_ex(val);
 107                 ret = php_string_to_if_index(Z_STRVAL_P(val), out);
 108                 zval_ptr_dtor(val);
 109         }
 110 
 111         return ret;
 112 }
 113 
 114 
 115 
 116 static int php_get_if_index_from_array(const HashTable *ht, const char *key,
 117         php_socket *sock, unsigned int *if_index)
 118 {
 119         zval *val;
 120 
 121         if ((val = zend_hash_str_find(ht, key, strlen(key))) == NULL) {
 122                 *if_index = 0; /* default: 0 */
 123                 return SUCCESS;
 124         }
 125 
 126         return php_get_if_index_from_zval(val, if_index);
 127 }
 128 
 129 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)
 131 {
 132         zval *val;
 133 
 134         if ((val = zend_hash_str_find(ht, key, strlen(key))) == NULL) {
 135                 php_error_docref(NULL, E_WARNING, "no key \"%s\" passed in optval", key);
 136                 return FAILURE;
 137         }
 138         if (Z_REFCOUNTED_P(val)) {
 139                 Z_ADDREF_P(val);
 140         }
 141         convert_to_string_ex(val);
 142         if (!php_set_inet46_addr(ss, ss_len, Z_STRVAL_P(val), sock)) {
 143                 zval_ptr_dtor(val);
 144                 return FAILURE;
 145         }
 146         zval_ptr_dtor(val);
 147         return SUCCESS;
 148 }
 149 
 150 static int php_do_mcast_opt(php_socket *php_sock, int level, int optname, zval *arg4)
 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);
 157 #ifdef HAS_MCAST_EXT
 158         int (*mcast_sreq_fun)(php_socket *, int, struct sockaddr *, socklen_t,
 159                 struct sockaddr *, socklen_t, unsigned);
 160 #endif
 161 
 162         switch (optname) {
 163         case PHP_MCAST_JOIN_GROUP:
 164                 mcast_req_fun = &php_mcast_join;
 165                 goto mcast_req_fun;
 166         case PHP_MCAST_LEAVE_GROUP:
 167                 {
 168                         php_sockaddr_storage    group = {0};
 169                         socklen_t                               glen;
 170 
 171                         mcast_req_fun = &php_mcast_leave;
 172 mcast_req_fun:
 173                         convert_to_array_ex(arg4);
 174                         opt_ht = Z_ARRVAL_P(arg4);
 175 
 176                         if (php_get_address_from_array(opt_ht, "group", php_sock, &group,
 177                                 &glen) == FAILURE) {
 178                                         return FAILURE;
 179                         }
 180                         if (php_get_if_index_from_array(opt_ht, "interface", php_sock,
 181                                 &if_index) == FAILURE) {
 182                                         return FAILURE;
 183                         }
 184 
 185                         retval = mcast_req_fun(php_sock, level, (struct sockaddr*)&group,
 186                                 glen, if_index);
 187                         break;
 188                 }
 189 
 190 #ifdef HAS_MCAST_EXT
 191         case PHP_MCAST_BLOCK_SOURCE:
 192                 mcast_sreq_fun = &php_mcast_block_source;
 193                 goto mcast_sreq_fun;
 194         case PHP_MCAST_UNBLOCK_SOURCE:
 195                 mcast_sreq_fun = &php_mcast_unblock_source;
 196                 goto mcast_sreq_fun;
 197         case PHP_MCAST_JOIN_SOURCE_GROUP:
 198                 mcast_sreq_fun = &php_mcast_join_source;
 199                 goto mcast_sreq_fun;
 200         case PHP_MCAST_LEAVE_SOURCE_GROUP:
 201                 {
 202                         php_sockaddr_storage    group = {0},
 203                                                                         source = {0};
 204                         socklen_t                               glen,
 205                                                                         slen;
 206 
 207                         mcast_sreq_fun = &php_mcast_leave_source;
 208                 mcast_sreq_fun:
 209                         convert_to_array_ex(arg4);
 210                         opt_ht = Z_ARRVAL_P(arg4);
 211 
 212                         if (php_get_address_from_array(opt_ht, "group", php_sock, &group,
 213                                         &glen) == FAILURE) {
 214                                 return FAILURE;
 215                         }
 216                         if (php_get_address_from_array(opt_ht, "source", php_sock, &source,
 217                                         &slen) == FAILURE) {
 218                                 return FAILURE;
 219                         }
 220                         if (php_get_if_index_from_array(opt_ht, "interface", php_sock,
 221                                         &if_index) == FAILURE) {
 222                                 return FAILURE;
 223                         }
 224 
 225                         retval = mcast_sreq_fun(php_sock, level, (struct sockaddr*)&group,
 226                                         glen, (struct sockaddr*)&source, slen, if_index);
 227                         break;
 228                 }
 229 #endif
 230         default:
 231                 php_error_docref(NULL, E_WARNING,
 232                         "unexpected option in php_do_mcast_opt (level %d, option %d). "
 233                         "This is a bug.", level, optname);
 234                 return FAILURE;
 235         }
 236 
 237         if (retval != 0) {
 238                 if (retval != -2) { /* error, but message already emitted */
 239                         PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
 240                 }
 241                 return FAILURE;
 242         }
 243         return SUCCESS;
 244 }
 245 
 246 int php_do_setsockopt_ip_mcast(php_socket *php_sock,
 247                                                            int level,
 248                                                            int optname,
 249                                                            zval *arg4)
 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         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                 if (php_do_mcast_opt(php_sock, level, optname, arg4) == FAILURE) {
 268                         return FAILURE;
 269                 } else {
 270                         return SUCCESS;
 271                 }
 272 
 273         case IP_MULTICAST_IF:
 274                 if (php_get_if_index_from_zval(arg4, &if_index) == FAILURE) {
 275                         return FAILURE;
 276                 }
 277 
 278                 if (php_if_index_to_addr4(if_index, php_sock, &if_addr) == FAILURE) {
 279                         return FAILURE;
 280                 }
 281                 opt_ptr = &if_addr;
 282                 optlen  = sizeof(if_addr);
 283                 goto dosockopt;
 284 
 285         case IP_MULTICAST_LOOP:
 286                 convert_to_boolean_ex(arg4);
 287                 ipv4_mcast_ttl_lback = (unsigned char) (Z_TYPE_P(arg4) == IS_TRUE);
 288                 goto ipv4_loop_ttl;
 289 
 290         case IP_MULTICAST_TTL:
 291                 convert_to_long_ex(arg4);
 292                 if (Z_LVAL_P(arg4) < 0L || Z_LVAL_P(arg4) > 255L) {
 293                         php_error_docref(NULL, E_WARNING,
 294                                         "Expected a value between 0 and 255");
 295                         return FAILURE;
 296                 }
 297                 ipv4_mcast_ttl_lback = (unsigned char) Z_LVAL_P(arg4);
 298 ipv4_loop_ttl:
 299                 opt_ptr = &ipv4_mcast_ttl_lback;
 300                 optlen  = sizeof(ipv4_mcast_ttl_lback);
 301                 goto dosockopt;
 302         }
 303 
 304         return 1;
 305 
 306 dosockopt:
 307         retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
 308         if (retval != 0) {
 309                 PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
 310                 return FAILURE;
 311         }
 312 
 313         return SUCCESS;
 314 }
 315 
 316 int php_do_setsockopt_ipv6_mcast(php_socket *php_sock,
 317                                                                  int level,
 318                                                                  int optname,
 319                                                                  zval *arg4)
 320 {
 321         unsigned int    if_index;
 322         void                    *opt_ptr;
 323         socklen_t               optlen;
 324         int                             ov;
 325         int                             retval;
 326 
 327         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                 if (php_do_mcast_opt(php_sock, level, optname, arg4) == FAILURE) {
 337                         return FAILURE;
 338                 } else {
 339                         return SUCCESS;
 340                 }
 341 
 342         case IPV6_MULTICAST_IF:
 343                 if (php_get_if_index_from_zval(arg4, &if_index) == FAILURE) {
 344                         return FAILURE;
 345                 }
 346 
 347                 opt_ptr = &if_index;
 348                 optlen  = sizeof(if_index);
 349                 goto dosockopt;
 350 
 351         case IPV6_MULTICAST_LOOP:
 352                 convert_to_boolean_ex(arg4);
 353                 ov = (int) Z_TYPE_P(arg4) == IS_TRUE;
 354                 goto ipv6_loop_hops;
 355         case IPV6_MULTICAST_HOPS:
 356                 convert_to_long_ex(arg4);
 357                 if (Z_LVAL_P(arg4) < -1L || Z_LVAL_P(arg4) > 255L) {
 358                         php_error_docref(NULL, E_WARNING,
 359                                         "Expected a value between -1 and 255");
 360                         return FAILURE;
 361                 }
 362                 ov = (int) Z_LVAL_P(arg4);
 363 ipv6_loop_hops:
 364                 opt_ptr = &ov;
 365                 optlen  = sizeof(ov);
 366                 goto dosockopt;
 367         }
 368 
 369         return 1; /* not handled */
 370 
 371 dosockopt:
 372         retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
 373         if (retval != 0) {
 374                 PHP_SOCKET_ERROR(php_sock, "unable to set socket option", errno);
 375                 return FAILURE;
 376         }
 377 
 378         return SUCCESS;
 379 }
 380 
 381 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)
 387 {
 388         return _php_mcast_join_leave(sock, level, group, group_len, if_index, 1);
 389 }
 390 
 391 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)
 397 {
 398         return _php_mcast_join_leave(sock, level, group, group_len, if_index, 0);
 399 }
 400 
 401 #ifdef HAS_MCAST_EXT
 402 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)
 410 {
 411         return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, JOIN_SOURCE);
 412 }
 413 
 414 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)
 422 {
 423         return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, LEAVE_SOURCE);
 424 }
 425 
 426 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)
 434 {
 435         return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, BLOCK_SOURCE);
 436 }
 437 
 438 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)
 446 {
 447         return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, UNBLOCK_SOURCE);
 448 }
 449 #endif /* HAS_MCAST_EXT */
 450 
 451 
 452 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)
 459 {
 460 #ifdef RFC3678_API
 461         struct group_req greq = {0};
 462 
 463         memcpy(&greq.gr_group, group, group_len);
 464         assert(greq.gr_group.ss_family != 0); /* the caller has set this */
 465         greq.gr_interface = if_index;
 466 
 467         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) ==
 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, 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 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)
 523 {
 524 #ifdef RFC3678_API
 525         struct group_source_req gsreq = {0};
 526 
 527         memcpy(&gsreq.gsr_group, group, group_len);
 528         assert(gsreq.gsr_group.ss_family != 0);
 529         memcpy(&gsreq.gsr_source, source, source_len);
 530         assert(gsreq.gsr_source.ss_family != 0);
 531         gsreq.gsr_interface = if_index;
 532 
 533         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) ==
 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, 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, 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 static int _php_source_op_to_rfc3678_op(enum source_op sop)
 577 {
 578         switch (sop) {
 579         case JOIN_SOURCE:
 580                 return MCAST_JOIN_SOURCE_GROUP;
 581         case LEAVE_SOURCE:
 582                 return MCAST_LEAVE_SOURCE_GROUP;
 583         case BLOCK_SOURCE:
 584                 return MCAST_BLOCK_SOURCE;
 585         case UNBLOCK_SOURCE:
 586                 return MCAST_UNBLOCK_SOURCE;
 587         }
 588 
 589         assert(0);
 590         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)
 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, 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, 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)
 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, 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, E_WARNING,
 711                         "The interface with IP address %s was not found", addr_str);
 712         }
 713         return FAILURE;
 714 }
 715 
 716 #else
 717 
 718 int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr)
 719 {
 720         struct ifreq if_req;
 721 
 722         if (if_index == 0) {
 723                 out_addr->s_addr = INADDR_ANY;
 724                 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         if_req.ifr_ifindex = if_index;
 733         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                 php_error_docref(NULL, E_WARNING,
 740                         "Failed obtaining address for interface %u: error %d", if_index, errno);
 741                 return FAILURE;
 742         }
 743 
 744         if (ioctl(php_sock->bsd_socket, SIOCGIFADDR, &if_req) == -1) {
 745                 php_error_docref(NULL, E_WARNING,
 746                         "Failed obtaining address for interface %u: error %d", if_index, errno);
 747                 return FAILURE;
 748         }
 749 
 750         memcpy(out_addr, &((struct sockaddr_in *) &if_req.ifr_addr)->sin_addr,
 751                 sizeof *out_addr);
 752         return SUCCESS;
 753 }
 754 
 755 int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *if_index)
 756 {
 757         struct ifconf   if_conf = {0};
 758         char                    *buf = NULL,
 759                                         *p;
 760         int                             size = 0,
 761                                         lastsize = 0;
 762         size_t                  entry_len;
 763 
 764         if (addr->s_addr == INADDR_ANY) {
 765                 *if_index = 0;
 766                 return SUCCESS;
 767         }
 768 
 769         for(;;) {
 770                 size += 5 * sizeof(struct ifreq);
 771                 buf = ecalloc(size, 1);
 772                 if_conf.ifc_len = size;
 773                 if_conf.ifc_buf = buf;
 774 
 775                 if (ioctl(php_sock->bsd_socket, SIOCGIFCONF, (char*)&if_conf) == -1 &&
 776                                 (errno != EINVAL || lastsize != 0)) {
 777                         php_error_docref(NULL, E_WARNING,
 778                                 "Failed obtaining interfaces list: error %d", errno);
 779                         goto err;
 780                 }
 781 
 782                 if (if_conf.ifc_len == lastsize)
 783                         /* not increasing anymore */
 784                         break;
 785                 else {
 786                         lastsize = if_conf.ifc_len;
 787                         efree(buf);
 788                         buf = NULL;
 789                 }
 790         }
 791 
 792         for (p = if_conf.ifc_buf;
 793                  p < if_conf.ifc_buf + if_conf.ifc_len;
 794                  p += entry_len) {
 795                 struct ifreq *cur_req;
 796 
 797                 /* let's hope the pointer is aligned */
 798                 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                 entry_len = sizeof(struct sockaddr) + sizeof(cur_req->ifr_name);
 805 #endif
 806                 entry_len = MAX(entry_len, sizeof(*cur_req));
 807 
 808                 if ((((struct sockaddr*)&cur_req->ifr_addr)->sa_family == AF_INET) &&
 809                                 (((struct sockaddr_in*)&cur_req->ifr_addr)->sin_addr.s_addr ==
 810                                         addr->s_addr)) {
 811 #if defined(SIOCGIFINDEX)
 812                         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                                 php_error_docref(NULL, E_WARNING,
 821                                         "Error converting interface name to index: error %d",
 822                                         errno);
 823                                 goto err;
 824                         } else {
 825 #if defined(SIOCGIFINDEX)
 826                                 *if_index = cur_req->ifr_ifindex;
 827 #else
 828                                 *if_index = index_tmp;
 829 #endif
 830                                 efree(buf);
 831                                 return SUCCESS;
 832                         }
 833                 }
 834         }
 835 
 836         {
 837                 char addr_str[17] = {0};
 838                 inet_ntop(AF_INET, addr, addr_str, sizeof(addr_str));
 839                 php_error_docref(NULL, E_WARNING,
 840                         "The interface with IP address %s was not found", addr_str);
 841         }
 842 
 843 err:
 844         if (buf != NULL)
 845                 efree(buf);
 846         return FAILURE;
 847 }
 848 #endif

/* [<][>][^][v][top][bottom][index][help] */