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