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?>
50--FILE--
51<?php
52include __DIR__."/mcast_helpers.php.inc";
53$domain = AF_INET6;
54$level = IPPROTO_IPV6;
55$interface = 0;
56$mcastaddr = 'ff01::114';
57$sblock = "?";
58
59echo "creating send socket\n";
60$sends1 = socket_create($domain, SOCK_DGRAM, SOL_UDP) or die("err");
61var_dump($sends1);
62
63echo "creating receive socket\n";
64$s = socket_create($domain, SOCK_DGRAM, SOL_UDP) or die("err");
65var_dump($s);
66$br = socket_bind($s, '::0', 0) or die("err");
67var_dump($br);
68socket_getsockname($s, $unused, $port);
69
70$so = socket_set_option($s, $level, MCAST_JOIN_GROUP, array(
71    "group"	=> $mcastaddr,
72    "interface" => $interface,
73)) or die("err");
74var_dump($so);
75
76$r = socket_sendto($sends1, $m = "testing packet", strlen($m), 0, $mcastaddr, $port);
77var_dump($r);
78checktimeout($s, 500);
79$r = socket_recvfrom($s, $str, 2000, 0, $from, $fromPort);
80var_dump($r, $str, $from);
81$sblock = $from;
82
83$r = socket_sendto($sends1, $m = "initial packet", strlen($m), 0, $mcastaddr, $port);
84var_dump($r);
85
86$i = 0;
87checktimeout($s, 500);
88while (($str = socket_read($s, 3000)) !== FALSE) {
89    $i++;
90    echo "$i> ", $str, "\n";
91
92if ($i == 1) {
93    echo "leaving group\n";
94    $so = socket_set_option($s, $level, MCAST_LEAVE_GROUP, array(
95        "group"	=> $mcastaddr,
96        "interface" => $interface,
97    ));
98    var_dump($so);
99    $r = socket_sendto($sends1, $m = "ignored mcast packet", strlen($m), 0, $mcastaddr, $port);
100    var_dump($r);
101    $r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "::1", $port);
102    var_dump($r);
103}
104if ($i == 2) {
105    echo "re-joining group\n";
106    $so = socket_set_option($s, $level, MCAST_JOIN_GROUP, array(
107        "group"	=> $mcastaddr,
108        "interface" => $interface,
109    ));
110    var_dump($so);
111    $r = socket_sendto($sends1, $m = "mcast packet", strlen($m), 0, $mcastaddr, $port);
112    var_dump($r);
113}
114if ($i == 3) {
115    echo "blocking source\n";
116    $so = socket_set_option($s, $level, MCAST_BLOCK_SOURCE, array(
117        "group"	=> $mcastaddr,
118        "interface" => $interface,
119        "source" => $sblock,
120    ));
121    var_dump($so);
122    $r = socket_sendto($sends1, $m = "ignored packet (blocked source)", strlen($m), 0, $mcastaddr, $port);
123    var_dump($r);
124    $r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "::1", $port);
125    var_dump($r);
126}
127if ($i == 4) {
128    echo "unblocking source\n";
129    $so = socket_set_option($s, $level, MCAST_UNBLOCK_SOURCE, array(
130        "group"	=> $mcastaddr,
131        "interface" => $interface,
132        "source" => $sblock,
133    ));
134    var_dump($so);
135    $r = socket_sendto($sends1, $m = "mcast packet", strlen($m), 0, $mcastaddr, $port);
136    var_dump($r);
137}
138if ($i == 5) {
139    echo "leaving group\n";
140    $so = socket_set_option($s, $level, MCAST_LEAVE_GROUP, array(
141        "group"	=> $mcastaddr,
142        "interface" => $interface,
143    ));
144    var_dump($so);
145    $r = socket_sendto($sends1, $m = "ignored mcast packet", strlen($m), 0, $mcastaddr, $port);
146    var_dump($r);
147    $r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "::1", $port);
148    var_dump($r);
149}
150if ($i == 6) {
151    echo "joining source group\n";
152    $so = socket_set_option($s, $level, MCAST_JOIN_SOURCE_GROUP, array(
153        "group"	=> $mcastaddr,
154        "interface" => $interface,
155        "source" => $sblock,
156    ));
157    var_dump($so);
158    $r = socket_sendto($sends1, $m = "mcast packet from desired source", strlen($m), 0, $mcastaddr, $port);
159    var_dump($r);
160}
161if ($i == 7) {
162    echo "leaving source group\n";
163    $so = socket_set_option($s, $level, MCAST_LEAVE_SOURCE_GROUP, array(
164        "group"	=> $mcastaddr,
165        "interface" => $interface,
166        "source" => $sblock,
167    ));
168    var_dump($so);
169    $r = socket_sendto($sends1, $m = "ignored mcast packet", strlen($m), 0, $mcastaddr, $port);
170    var_dump($r);
171    $r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "::1", $port);
172    var_dump($r);
173}
174if ($i == 8) {
175    /*echo "joining source group\n";
176    $so = socket_set_option($s, $level, MCAST_JOIN_SOURCE_GROUP, array(
177        "group"	=> $mcastaddr,
178        "interface" => $interface,
179        "source" => $sblock,
180    ));
181    var_dump($so);*/
182    break;
183}
184
185}
186?>
187--EXPECTF--
188creating send socket
189object(Socket)#%d (0) {
190}
191creating receive socket
192object(Socket)#%d (0) {
193}
194bool(true)
195bool(true)
196int(14)
197int(14)
198string(14) "testing packet"
199string(%d) "%s"
200int(14)
2011> initial packet
202leaving group
203bool(true)
204int(20)
205int(14)
2062> unicast packet
207re-joining group
208bool(true)
209int(12)
2103> mcast packet
211blocking source
212bool(true)
213int(31)
214int(14)
2154> unicast packet
216unblocking source
217bool(true)
218int(12)
2195> mcast packet
220leaving group
221bool(true)
222int(20)
223int(14)
2246> unicast packet
225joining source group
226bool(true)
227int(32)
2287> mcast packet from desired source
229leaving source group
230bool(true)
231int(20)
232int(14)
2338> unicast packet
234