27#include <sys/socket.h>
30#ifdef HAVE_SYS_SOCKIO_H
31#include <sys/sockio.h>
33#include <netinet/in.h>
50static int _php_mcast_join_leave(php_socket *sock,
int level,
struct sockaddr *group,
socklen_t group_len,
unsigned int if_index,
int join);
52static 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);
56static int _php_source_op_to_rfc3678_op(
enum source_op sop);
57#elif defined(HAS_MCAST_EXT)
58static const char *_php_source_op_to_string(
enum source_op sop);
59static int _php_source_op_to_ipv4_op(
enum source_op sop);
64#ifdef HAVE_IF_NAMETOINDEX
67 ind = if_nametoindex(
val);
70 "No interface with name \"%s\" could be found",
val);
78 "This platform does not support looking up an interface by "
79 "name, an integer interface index must be supplied instead");
99 zend_tmp_string_release(tmp_str);
108 php_socket *sock,
unsigned int *if_index)
117 return php_get_if_index_from_zval(
val, if_index);
130 str = zval_get_tmp_string(
val, &tmp_str);
132 zend_tmp_string_release(tmp_str);
135 zend_tmp_string_release(tmp_str);
139static zend_result php_do_mcast_opt(php_socket *php_sock,
int level,
int optname,
zval *arg4)
142 unsigned int if_index;
144 int (*mcast_req_fun)(php_socket *, int,
struct sockaddr *,
socklen_t,
147 int (*mcast_sreq_fun)(php_socket *, int,
struct sockaddr *,
socklen_t,
165 if (php_get_address_from_array(opt_ht,
"group", php_sock, &group,
169 if (php_get_if_index_from_array(opt_ht,
"interface", php_sock,
174 retval = mcast_req_fun(php_sock, level, (
struct sockaddr*)&group,
180 case PHP_MCAST_BLOCK_SOURCE:
181 mcast_sreq_fun = &php_mcast_block_source;
183 case PHP_MCAST_UNBLOCK_SOURCE:
184 mcast_sreq_fun = &php_mcast_unblock_source;
186 case PHP_MCAST_JOIN_SOURCE_GROUP:
187 mcast_sreq_fun = &php_mcast_join_source;
189 case PHP_MCAST_LEAVE_SOURCE_GROUP:
191 mcast_sreq_fun = &php_mcast_leave_source;
201 if (php_get_address_from_array(opt_ht,
"group", php_sock, &group,
205 if (php_get_address_from_array(opt_ht,
"source", php_sock, &source,
209 if (php_get_if_index_from_array(opt_ht,
"interface", php_sock,
214 retval = mcast_sreq_fun(php_sock, level, (
struct sockaddr*)&group,
215 glen, (
struct sockaddr*)&source, slen, if_index);
221 "Unexpected option in php_do_mcast_opt (level %d, option %d). "
222 "This is a bug.", level, optname);
228 PHP_SOCKET_ERROR(php_sock,
"Unable to set socket option",
errno);
240 unsigned int if_index;
241 struct in_addr if_addr;
244 unsigned char ipv4_mcast_ttl_lback;
251 case PHP_MCAST_BLOCK_SOURCE:
252 case PHP_MCAST_UNBLOCK_SOURCE:
253 case PHP_MCAST_JOIN_SOURCE_GROUP:
254 case PHP_MCAST_LEAVE_SOURCE_GROUP:
256 if (php_do_mcast_opt(php_sock, level, optname, arg4) ==
FAILURE) {
263 if (php_get_if_index_from_zval(arg4, &if_index) ==
FAILURE) {
271 optlen =
sizeof(if_addr);
285 ipv4_mcast_ttl_lback = (
unsigned char)
Z_LVAL_P(arg4);
287 opt_ptr = &ipv4_mcast_ttl_lback;
288 optlen =
sizeof(ipv4_mcast_ttl_lback);
295 retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
297 PHP_SOCKET_ERROR(php_sock,
"Unable to set socket option",
errno);
309 unsigned int if_index;
319 case PHP_MCAST_BLOCK_SOURCE:
320 case PHP_MCAST_UNBLOCK_SOURCE:
321 case PHP_MCAST_JOIN_SOURCE_GROUP:
322 case PHP_MCAST_LEAVE_SOURCE_GROUP:
324 if (php_do_mcast_opt(php_sock, level, optname, arg4) ==
FAILURE) {
331 if (php_get_if_index_from_zval(arg4, &if_index) ==
FAILURE) {
336 optlen =
sizeof(if_index);
359 retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
361 PHP_SOCKET_ERROR(php_sock,
"Unable to set socket option",
errno);
371 struct sockaddr *group,
373 unsigned int if_index)
375 return _php_mcast_join_leave(sock, level, group, group_len, if_index, 1);
381 struct sockaddr *group,
383 unsigned int if_index)
385 return _php_mcast_join_leave(sock, level, group, group_len, if_index, 0);
389int php_mcast_join_source(
392 struct sockaddr *group,
394 struct sockaddr *source,
396 unsigned int if_index)
398 return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index,
JOIN_SOURCE);
401int php_mcast_leave_source(
404 struct sockaddr *group,
406 struct sockaddr *source,
408 unsigned int if_index)
410 return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index,
LEAVE_SOURCE);
413int php_mcast_block_source(
416 struct sockaddr *group,
418 struct sockaddr *source,
420 unsigned int if_index)
422 return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index,
BLOCK_SOURCE);
425int php_mcast_unblock_source(
428 struct sockaddr *group,
430 struct sockaddr *source,
432 unsigned int if_index)
434 return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index,
UNBLOCK_SOURCE);
439static int _php_mcast_join_leave(
442 struct sockaddr *group,
444 unsigned int if_index,
448 struct group_req greq = {0};
450 memcpy(&greq.gr_group, group, group_len);
451 assert(greq.gr_group.ss_family != 0);
452 greq.gr_interface = if_index;
454 return setsockopt(sock->bsd_socket, level,
461 memset(&mreq, 0,
sizeof(
struct ip_mreq));
463 assert(group_len ==
sizeof(
struct sockaddr_in));
469 mreq.imr_interface =
addr;
471 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
473 mreq.imr_multiaddr = ((
struct sockaddr_in*)group)->sin_addr;
474 return setsockopt(sock->bsd_socket, level,
475 join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, (
char*)&mreq,
480 struct ipv6_mreq mreq;
481 memset(&mreq, 0,
sizeof(
struct ipv6_mreq));
483 assert(group_len ==
sizeof(
struct sockaddr_in6));
485 mreq.ipv6mr_multiaddr = ((
struct sockaddr_in6*)group)->sin6_addr;
486 mreq.ipv6mr_interface = if_index;
488 return setsockopt(sock->bsd_socket, level,
489 join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP, (
char*)&mreq,
495 join ?
"MCAST_JOIN_GROUP" :
"MCAST_LEAVE_GROUP");
502static int _php_mcast_source_op(
505 struct sockaddr *group,
507 struct sockaddr *source,
509 unsigned int if_index,
513 struct group_source_req gsreq = {0};
515 memcpy(&gsreq.gsr_group, group, group_len);
516 assert(gsreq.gsr_group.ss_family != 0);
517 memcpy(&gsreq.gsr_source, source, source_len);
518 assert(gsreq.gsr_source.ss_family != 0);
519 gsreq.gsr_interface = if_index;
521 return setsockopt(sock->bsd_socket, level,
522 _php_source_op_to_rfc3678_op(sop), (
char*)&gsreq,
sizeof(gsreq));
525 struct ip_mreq_source mreqs = {0};
528 mreqs.imr_multiaddr = ((
struct sockaddr_in*)group)->sin_addr;
529 mreqs.imr_sourceaddr = ((
struct sockaddr_in*)source)->sin_addr;
531 assert(group_len ==
sizeof(
struct sockaddr_in));
532 assert(source_len ==
sizeof(
struct sockaddr_in));
538 mreqs.imr_interface =
addr;
540 mreqs.imr_interface.s_addr = htonl(INADDR_ANY);
543 return setsockopt(sock->bsd_socket, level,
544 _php_source_op_to_ipv4_op(sop), (
char*)&mreqs,
sizeof(mreqs));
549 "This platform does not support %s for IPv6 sockets",
550 _php_source_op_to_string(sop));
556 "Option %s is inapplicable to this socket type",
557 _php_source_op_to_string(sop));
564static int _php_source_op_to_rfc3678_op(
enum source_op sop)
581static const char *_php_source_op_to_string(
enum source_op sop)
585 return "MCAST_JOIN_SOURCE_GROUP";
587 return "MCAST_LEAVE_SOURCE_GROUP";
589 return "MCAST_BLOCK_SOURCE";
591 return "MCAST_UNBLOCK_SOURCE";
598static int _php_source_op_to_ipv4_op(
enum source_op sop)
602 return IP_ADD_SOURCE_MEMBERSHIP;
604 return IP_DROP_SOURCE_MEMBERSHIP;
606 return IP_BLOCK_SOURCE;
608 return IP_UNBLOCK_SOURCE;
621 MIB_IPADDRTABLE *addr_table;
629 out_addr->s_addr = INADDR_ANY;
633 size = 4 * (
sizeof *addr_table);
636 retval = GetIpAddrTable(addr_table, &
size, 0);
637 if (
retval == ERROR_INSUFFICIENT_BUFFER) {
644 "GetIpAddrTable failed with error %lu",
retval);
647 for (i = 0; i < addr_table->dwNumEntries; i++) {
648 MIB_IPADDRROW r = addr_table->table[i];
649 if (r.dwIndex == if_index) {
650 out_addr->s_addr = r.dwAddr;
657 "No interface with index %u was found", if_index);
663 MIB_IPADDRTABLE *addr_table;
670 if (
addr->s_addr == INADDR_ANY) {
675 size = 4 * (
sizeof *addr_table);
678 retval = GetIpAddrTable(addr_table, &
size, 0);
679 if (
retval == ERROR_INSUFFICIENT_BUFFER) {
686 "GetIpAddrTable failed with error %lu",
retval);
689 for (i = 0; i < addr_table->dwNumEntries; i++) {
690 MIB_IPADDRROW r = addr_table->table[i];
691 if (r.dwAddr ==
addr->s_addr) {
692 *if_index = r.dwIndex;
700 char addr_str[17] = {0};
703 "The interface with IP address %s was not found", addr_str);
715 out_addr->s_addr = INADDR_ANY;
719#if !defined(ifr_ifindex) && (defined(ifr_index) || defined(__HAIKU__))
720#define ifr_ifindex ifr_index
723#if defined(SIOCGIFNAME)
724 if_req.ifr_ifindex = if_index;
725 if (ioctl(php_sock->bsd_socket, SIOCGIFNAME, &if_req) == -1) {
726#elif defined(HAVE_IF_INDEXTONAME)
727 if (if_indextoname(if_index, if_req.ifr_name) ==
NULL) {
729#error Neither SIOCGIFNAME nor if_indextoname are available
732 "Failed obtaining address for interface %u: error %d", if_index,
errno);
736 if (ioctl(php_sock->bsd_socket, SIOCGIFADDR, &if_req) == -1) {
738 "Failed obtaining address for interface %u: error %d", if_index,
errno);
742 memcpy(out_addr, &((
struct sockaddr_in *) &if_req.ifr_addr)->sin_addr,
749 struct ifconf if_conf = {0};
756 if (
addr->s_addr == INADDR_ANY) {
762 size += 5 *
sizeof(
struct ifreq);
764 if_conf.ifc_len =
size;
765 if_conf.ifc_buf =
buf;
767 if (ioctl(php_sock->bsd_socket, SIOCGIFCONF, (
char*)&if_conf) == -1 &&
768 (
errno != EINVAL || lastsize != 0)) {
770 "Failed obtaining interfaces list: error %d",
errno);
774 if (if_conf.ifc_len == lastsize)
778 lastsize = if_conf.ifc_len;
784 for (
p = if_conf.ifc_buf;
785 p < ((
char *)if_conf.ifc_buf) + if_conf.ifc_len;
788 struct ifreq cur_req;
789 memcpy(&cur_req,
p,
sizeof(
struct ifreq));
791#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
792 entry_len = cur_req.ifr_addr.sa_len +
sizeof(cur_req.ifr_name);
795 entry_len =
sizeof(
struct sockaddr) +
sizeof(cur_req.ifr_name);
797 entry_len =
MAX(entry_len,
sizeof(cur_req));
799 if ((((
struct sockaddr*)&cur_req.ifr_addr)->sa_family ==
AF_INET) &&
800 (((
struct sockaddr_in*)&cur_req.ifr_addr)->sin_addr.s_addr ==
802#if defined(SIOCGIFINDEX)
803 if (ioctl(php_sock->bsd_socket, SIOCGIFINDEX, (
char*)&cur_req)
805#elif defined(HAVE_IF_NAMETOINDEX)
807 if ((index_tmp = if_nametoindex(cur_req.ifr_name)) == 0) {
809#error Neither SIOCGIFINDEX nor if_nametoindex are available
812 "Error converting interface name to index: error %d",
816#if defined(SIOCGIFINDEX)
817 *if_index = cur_req.ifr_ifindex;
819 *if_index = index_tmp;
828 char addr_str[17] = {0};
831 "The interface with IP address %s was not found", addr_str);
sizeof(Countable|array $value, int $mode=COUNT_NORMAL)
join(string|array $separator, ?array $array=null)
assert(mixed $assertion, Throwable|string|null $description=null)
memset(ptr, 0, type->size)
zend_ffi_ctype_name_buf buf
zend_result php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *if_index)
int php_mcast_join(php_socket *sock, int level, struct sockaddr *group, socklen_t group_len, unsigned int if_index)
zend_result php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr)
memcpy(out_addr, &((struct sockaddr_in *) &if_req.ifr_addr) ->sin_addr, sizeof *out_addr)
php_error_docref(NULL, E_WARNING, "The interface with IP address %s was not found", addr_str)
int php_mcast_leave(php_socket *sock, int level, struct sockaddr *group, socklen_t group_len, unsigned int if_index)
int php_do_setsockopt_ip_mcast(php_socket *php_sock, int level, int optname, zval *arg4)
zend_result php_string_to_if_index(const char *val, unsigned *out)
inet_ntop(AF_INET, addr, addr_str, sizeof(addr_str))
int php_do_setsockopt_ipv6_mcast(php_socket *php_sock, int level, int optname, zval *arg4)
#define PHP_MCAST_LEAVE_GROUP
#define PHP_MCAST_JOIN_GROUP
unsigned char key[REFLECTION_KEY_LEN]
int php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *string, php_socket *php_sock)
const IPV6_MULTICAST_LOOP
const MCAST_UNBLOCK_SOURCE
const MCAST_LEAVE_SOURCE_GROUP
const MCAST_JOIN_SOURCE_GROUP
const IPV6_MULTICAST_HOPS
ZEND_API ZEND_COLD void zend_value_error(const char *format,...)
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format,...)
#define ecalloc(nmemb, size)
#define erealloc(ptr, size)
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)
ZEND_API zval *ZEND_FASTCALL zend_hash_str_find(const HashTable *ht, const char *str, size_t len)
struct _zend_string zend_string
ZEND_API void ZEND_FASTCALL convert_to_boolean(zval *op)
ZEND_API void ZEND_FASTCALL convert_to_array(zval *op)
ZEND_API void ZEND_FASTCALL convert_to_long(zval *op)
#define Z_ARRVAL_P(zval_p)
struct _zend_array HashTable
ZEND_RESULT_CODE zend_result