1--TEST--
2Multicast support: IPv6 receive options
3--SKIPIF--
4<?php
5if (!extension_loaded('sockets')) {
6    die('skip sockets extension not available.');
7}
8if (!defined('IPPROTO_IPV6')) {
9	die('skip IPv6 not available.');
10}
11$s = socket_create(AF_INET6, SOCK_DGRAM, SOL_UDP);
12if ($s === false) {
13  die("skip unable to create socket");
14}
15$br = socket_bind($s, '::', 3000);
16/* On Linux, there is no route ff00::/8 by default on lo, which makes it
17 * troublesome to send multicast traffic from lo, which we must since
18 * we're dealing with interface-local traffic... */
19$so = socket_set_option($s, IPPROTO_IPV6, MCAST_JOIN_GROUP, array(
20	"group"	=> 'ff01::114',
21	"interface" => 0,
22));
23if ($so === false) {
24    die('skip unable to join multicast group on any interface.');
25}
26$r = socket_sendto($s, $m = "testing packet", strlen($m), 0, 'ff01::114', 3000);
27if ($r === false) {
28	die('skip unable to send multicast packet.');
29}
30
31if (!defined("MCAST_JOIN_SOURCE_GROUP"))
32    die('skip source operations are unavailable');
33
34$so = socket_set_option($s, IPPROTO_IPV6, MCAST_LEAVE_GROUP, array(
35	"group"	=> 'ff01::114',
36	"interface" => 0,
37));
38$so = socket_set_option($s, IPPROTO_IPV6, MCAST_JOIN_SOURCE_GROUP, array(
39	"group"	=> 'ff01::114',
40	"interface" => 0,
41	"source" => '2001::dead:beef',
42));
43if ($so === false) {
44    die('skip protocol independent multicast API is unavailable.');
45}
46
47--FILE--
48<?php
49include __DIR__."/mcast_helpers.php.inc";
50$domain = AF_INET6;
51$level = IPPROTO_IPV6;
52$interface = 0;
53$mcastaddr = 'ff01::114';
54$sblock = "?";
55
56echo "creating send socket\n";
57$sends1 = socket_create($domain, SOCK_DGRAM, SOL_UDP) or die("err");
58var_dump($sends1);
59
60echo "creating receive socket\n";
61$s = socket_create($domain, SOCK_DGRAM, SOL_UDP) or die("err");
62var_dump($s);
63$br = socket_bind($s, '::0', 3000) or die("err");
64var_dump($br);
65
66$so = socket_set_option($s, $level, MCAST_JOIN_GROUP, array(
67	"group"	=> $mcastaddr,
68	"interface" => $interface,
69)) or die("err");
70var_dump($so);
71
72$r = socket_sendto($sends1, $m = "testing packet", strlen($m), 0, $mcastaddr, 3000);
73var_dump($r);
74checktimeout($s, 500);
75$r = socket_recvfrom($s, $str, 2000, 0, $from, $fromPort);
76var_dump($r, $str, $from);
77$sblock = $from;
78
79$r = socket_sendto($sends1, $m = "initial packet", strlen($m), 0, $mcastaddr, 3000);
80var_dump($r);
81
82$i = 0;
83checktimeout($s, 500);
84while (($str = socket_read($s, 3000)) !== FALSE) {
85	$i++;
86	echo "$i> ", $str, "\n";
87
88if ($i == 1) {
89	echo "leaving group\n";
90	$so = socket_set_option($s, $level, MCAST_LEAVE_GROUP, array(
91		"group"	=> $mcastaddr,
92		"interface" => $interface,
93	));
94	var_dump($so);
95	$r = socket_sendto($sends1, $m = "ignored mcast packet", strlen($m), 0, $mcastaddr, 3000);
96	var_dump($r);
97	$r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "::1", 3000);
98	var_dump($r);
99}
100if ($i == 2) {
101	echo "re-joining group\n";
102	$so = socket_set_option($s, $level, MCAST_JOIN_GROUP, array(
103		"group"	=> $mcastaddr,
104		"interface" => $interface,
105	));
106	var_dump($so);
107	$r = socket_sendto($sends1, $m = "mcast packet", strlen($m), 0, $mcastaddr, 3000);
108	var_dump($r);
109}
110if ($i == 3) {
111	echo "blocking source\n";
112	$so = socket_set_option($s, $level, MCAST_BLOCK_SOURCE, array(
113		"group"	=> $mcastaddr,
114		"interface" => $interface,
115		"source" => $sblock,
116	));
117	var_dump($so);
118	$r = socket_sendto($sends1, $m = "ignored packet (blocked source)", strlen($m), 0, $mcastaddr, 3000);
119	var_dump($r);
120	$r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "::1", 3000);
121	var_dump($r);
122}
123if ($i == 4) {
124	echo "unblocking source\n";
125	$so = socket_set_option($s, $level, MCAST_UNBLOCK_SOURCE, array(
126		"group"	=> $mcastaddr,
127		"interface" => $interface,
128		"source" => $sblock,
129	));
130	var_dump($so);
131	$r = socket_sendto($sends1, $m = "mcast packet", strlen($m), 0, $mcastaddr, 3000);
132	var_dump($r);
133}
134if ($i == 5) {
135	echo "leaving group\n";
136	$so = socket_set_option($s, $level, MCAST_LEAVE_GROUP, array(
137		"group"	=> $mcastaddr,
138		"interface" => $interface,
139	));
140	var_dump($so);
141	$r = socket_sendto($sends1, $m = "ignored mcast packet", strlen($m), 0, $mcastaddr, 3000);
142	var_dump($r);
143	$r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "::1", 3000);
144	var_dump($r);
145}
146if ($i == 6) {
147	echo "joining source group\n";
148	$so = socket_set_option($s, $level, MCAST_JOIN_SOURCE_GROUP, array(
149		"group"	=> $mcastaddr,
150		"interface" => $interface,
151		"source" => $sblock,
152	));
153	var_dump($so);
154	$r = socket_sendto($sends1, $m = "mcast packet from desired source", strlen($m), 0, $mcastaddr, 3000);
155	var_dump($r);
156}
157if ($i == 7) {
158	echo "leaving source group\n";
159	$so = socket_set_option($s, $level, MCAST_LEAVE_SOURCE_GROUP, array(
160		"group"	=> $mcastaddr,
161		"interface" => $interface,
162		"source" => $sblock,
163	));
164	var_dump($so);
165	$r = socket_sendto($sends1, $m = "ignored mcast packet", strlen($m), 0, $mcastaddr, 3000);
166	var_dump($r);
167	$r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "::1", 3000);
168	var_dump($r);
169}
170if ($i == 8) {
171	/*echo "joining source group\n";
172	$so = socket_set_option($s, $level, MCAST_JOIN_SOURCE_GROUP, array(
173		"group"	=> $mcastaddr,
174		"interface" => $interface,
175		"source" => $sblock,
176	));
177	var_dump($so);*/
178	break;
179}
180
181}
182--EXPECTF--
183creating send socket
184resource(%d) of type (Socket)
185creating receive socket
186resource(%d) of type (Socket)
187bool(true)
188bool(true)
189int(14)
190int(14)
191string(14) "testing packet"
192string(%d) "%s"
193int(14)
1941> initial packet
195leaving group
196bool(true)
197int(20)
198int(14)
1992> unicast packet
200re-joining group
201bool(true)
202int(12)
2033> mcast packet
204blocking source
205bool(true)
206int(31)
207int(14)
2084> unicast packet
209unblocking source
210bool(true)
211int(12)
2125> mcast packet
213leaving group
214bool(true)
215int(20)
216int(14)
2176> unicast packet
218joining source group
219bool(true)
220int(32)
2217> mcast packet from desired source
222leaving source group
223bool(true)
224int(20)
225int(14)
2268> unicast packet
227