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