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, '::', 0);
16socket_getsockname($s, $unused, $port);
17/* On Linux, there is no route ff00::/8 by default on lo, which makes it
18 * troublesome to send multicast traffic from lo, which we must since
19 * we're dealing with interface-local traffic... */
20$so = @socket_set_option($s, IPPROTO_IPV6, MCAST_JOIN_GROUP, array(
21    "group"	=> 'ff01::114',
22    "interface" => 0,
23));
24if ($so === false) {
25    die('skip unable to join multicast group on any interface.');
26}
27$r = socket_sendto($s, $m = "testing packet", strlen($m), 0, 'ff01::114', $port);
28if ($r === false) {
29    die('skip unable to send multicast packet.');
30}
31
32if (!defined("MCAST_JOIN_SOURCE_GROUP"))
33    die('skip source operations are unavailable');
34
35$so = @socket_set_option($s, IPPROTO_IPV6, MCAST_LEAVE_GROUP, array(
36    "group"	=> 'ff01::114',
37    "interface" => 0,
38));
39$so = @socket_set_option($s, IPPROTO_IPV6, MCAST_JOIN_SOURCE_GROUP, array(
40    "group"	=> 'ff01::114',
41    "interface" => 0,
42    "source" => '2001::dead:beef',
43));
44if ($so === false) {
45    die('skip protocol independent multicast API is unavailable.');
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', 0) or die("err");
64var_dump($br);
65socket_getsockname($s, $unused, $port);
66
67$so = socket_set_option($s, $level, MCAST_JOIN_GROUP, array(
68    "group"	=> $mcastaddr,
69    "interface" => $interface,
70)) or die("err");
71var_dump($so);
72
73$r = socket_sendto($sends1, $m = "testing packet", strlen($m), 0, $mcastaddr, $port);
74var_dump($r);
75checktimeout($s, 500);
76$r = socket_recvfrom($s, $str, 2000, 0, $from, $fromPort);
77var_dump($r, $str, $from);
78$sblock = $from;
79
80$r = socket_sendto($sends1, $m = "initial packet", strlen($m), 0, $mcastaddr, $port);
81var_dump($r);
82
83$i = 0;
84checktimeout($s, 500);
85while (($str = socket_read($s, 3000)) !== FALSE) {
86    $i++;
87    echo "$i> ", $str, "\n";
88
89if ($i == 1) {
90    echo "leaving group\n";
91    $so = socket_set_option($s, $level, MCAST_LEAVE_GROUP, array(
92        "group"	=> $mcastaddr,
93        "interface" => $interface,
94    ));
95    var_dump($so);
96    $r = socket_sendto($sends1, $m = "ignored mcast packet", strlen($m), 0, $mcastaddr, $port);
97    var_dump($r);
98    $r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "::1", $port);
99    var_dump($r);
100}
101if ($i == 2) {
102    echo "re-joining group\n";
103    $so = socket_set_option($s, $level, MCAST_JOIN_GROUP, array(
104        "group"	=> $mcastaddr,
105        "interface" => $interface,
106    ));
107    var_dump($so);
108    $r = socket_sendto($sends1, $m = "mcast packet", strlen($m), 0, $mcastaddr, $port);
109    var_dump($r);
110}
111if ($i == 3) {
112    echo "blocking source\n";
113    $so = socket_set_option($s, $level, MCAST_BLOCK_SOURCE, array(
114        "group"	=> $mcastaddr,
115        "interface" => $interface,
116        "source" => $sblock,
117    ));
118    var_dump($so);
119    $r = socket_sendto($sends1, $m = "ignored packet (blocked source)", strlen($m), 0, $mcastaddr, $port);
120    var_dump($r);
121    $r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "::1", $port);
122    var_dump($r);
123}
124if ($i == 4) {
125    echo "unblocking source\n";
126    $so = socket_set_option($s, $level, MCAST_UNBLOCK_SOURCE, array(
127        "group"	=> $mcastaddr,
128        "interface" => $interface,
129        "source" => $sblock,
130    ));
131    var_dump($so);
132    $r = socket_sendto($sends1, $m = "mcast packet", strlen($m), 0, $mcastaddr, $port);
133    var_dump($r);
134}
135if ($i == 5) {
136    echo "leaving group\n";
137    $so = socket_set_option($s, $level, MCAST_LEAVE_GROUP, array(
138        "group"	=> $mcastaddr,
139        "interface" => $interface,
140    ));
141    var_dump($so);
142    $r = socket_sendto($sends1, $m = "ignored mcast packet", strlen($m), 0, $mcastaddr, $port);
143    var_dump($r);
144    $r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "::1", $port);
145    var_dump($r);
146}
147if ($i == 6) {
148    echo "joining source group\n";
149    $so = socket_set_option($s, $level, MCAST_JOIN_SOURCE_GROUP, array(
150        "group"	=> $mcastaddr,
151        "interface" => $interface,
152        "source" => $sblock,
153    ));
154    var_dump($so);
155    $r = socket_sendto($sends1, $m = "mcast packet from desired source", strlen($m), 0, $mcastaddr, $port);
156    var_dump($r);
157}
158if ($i == 7) {
159    echo "leaving source group\n";
160    $so = socket_set_option($s, $level, MCAST_LEAVE_SOURCE_GROUP, array(
161        "group"	=> $mcastaddr,
162        "interface" => $interface,
163        "source" => $sblock,
164    ));
165    var_dump($so);
166    $r = socket_sendto($sends1, $m = "ignored mcast packet", strlen($m), 0, $mcastaddr, $port);
167    var_dump($r);
168    $r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "::1", $port);
169    var_dump($r);
170}
171if ($i == 8) {
172    /*echo "joining source group\n";
173    $so = socket_set_option($s, $level, MCAST_JOIN_SOURCE_GROUP, array(
174        "group"	=> $mcastaddr,
175        "interface" => $interface,
176        "source" => $sblock,
177    ));
178    var_dump($so);*/
179    break;
180}
181
182}
183?>
184--EXPECTF--
185creating send socket
186object(Socket)#%d (0) {
187}
188creating receive socket
189object(Socket)#%d (0) {
190}
191bool(true)
192bool(true)
193int(14)
194int(14)
195string(14) "testing packet"
196string(%d) "%s"
197int(14)
1981> initial packet
199leaving group
200bool(true)
201int(20)
202int(14)
2032> unicast packet
204re-joining group
205bool(true)
206int(12)
2073> mcast packet
208blocking source
209bool(true)
210int(31)
211int(14)
2124> unicast packet
213unblocking source
214bool(true)
215int(12)
2165> mcast packet
217leaving group
218bool(true)
219int(20)
220int(14)
2216> unicast packet
222joining source group
223bool(true)
224int(32)
2257> mcast packet from desired source
226leaving source group
227bool(true)
228int(20)
229int(14)
2308> unicast packet
231