1--TEST--
2Multicast support: IPv4 receive options
3--SKIPIF--
4<?php
5if (!extension_loaded('sockets')) {
6    die('skip sockets extension not available.');
7}
8if (getenv('SKIP_ONLINE_TESTS')) die('skip online test');
9$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
10$br = socket_bind($s, '0.0.0.0', 0);
11$so = @socket_set_option($s, IPPROTO_IP, MCAST_JOIN_GROUP, array(
12    "group"	=> '224.0.0.23',
13    "interface" => 'lo',
14));
15if ($so === false) {
16    die('skip interface \'lo\' is unavailable.');
17}
18if (!defined("MCAST_BLOCK_SOURCE")) {
19    die('skip source operations are unavailable');
20}
21--FILE--
22<?php
23include __DIR__."/mcast_helpers.php.inc";
24$domain = AF_INET;
25$level = IPPROTO_IP;
26$interface = "lo";
27$mcastaddr = '224.0.0.23';
28$sblock = "127.0.0.1";
29
30echo "creating send socket bound to 127.0.0.1\n";
31$sends1 = socket_create($domain, SOCK_DGRAM, SOL_UDP);
32$br = socket_bind($sends1, '127.0.0.1');
33var_dump($br);
34
35echo "creating unbound socket and hoping the routing table causes an interface other than lo to be used for sending messages to $mcastaddr\n";
36$sends2 = socket_create($domain, SOCK_DGRAM, SOL_UDP);
37var_dump($br);
38
39echo "creating receive socket\n";
40$s = socket_create($domain, SOCK_DGRAM, SOL_UDP);
41var_dump($s);
42$br = socket_bind($s, '0.0.0.0', 0);
43socket_getsockname($s, $unused, $port);
44var_dump($br);
45
46$so = socket_set_option($s, $level, MCAST_JOIN_GROUP, array(
47    "group"	=> $mcastaddr,
48    "interface" => $interface,
49));
50var_dump($so);
51
52$r = socket_sendto($sends1, $m = "initial packet", strlen($m), 0, $mcastaddr, $port);
53var_dump($r);
54
55$i = 0;
56checktimeout($s, 500);
57while (($str = socket_read($s, 3000)) !== FALSE) {
58    $i++;
59    echo "$i> ", $str, "\n";
60
61if ($i == 1) {
62    echo "leaving group\n";
63    $so = socket_set_option($s, $level, MCAST_LEAVE_GROUP, array(
64        "group"	=> $mcastaddr,
65        "interface" => $interface,
66    ));
67    var_dump($so);
68    $r = socket_sendto($sends1, $m = "ignored mcast packet", strlen($m), 0, $mcastaddr, $port);
69    var_dump($r);
70    $r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "127.0.0.1", $port);
71    var_dump($r);
72}
73if ($i == 2) {
74    echo "re-joining group\n";
75    $so = socket_set_option($s, $level, MCAST_JOIN_GROUP, array(
76        "group"	=> $mcastaddr,
77        "interface" => $interface,
78    ));
79    var_dump($so);
80    $r = socket_sendto($sends2, $m = "ignored mcast packet (different interface)", strlen($m), 0, $mcastaddr, $port);
81    var_dump($r);
82    $r = socket_sendto($sends1, $m = "mcast packet", strlen($m), 0, $mcastaddr, $port);
83    var_dump($r);
84}
85if ($i == 3) {
86    echo "blocking source\n";
87    $so = socket_set_option($s, $level, MCAST_BLOCK_SOURCE, array(
88        "group"	=> $mcastaddr,
89        "interface" => $interface,
90        "source" => $sblock,
91    ));
92    var_dump($so);
93    $r = socket_sendto($sends1, $m = "ignored packet (blocked source)", strlen($m), 0, $mcastaddr, $port);
94    var_dump($r);
95    $r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "127.0.0.1", $port);
96    var_dump($r);
97}
98if ($i == 4) {
99    echo "unblocking source\n";
100    $so = socket_set_option($s, $level, MCAST_UNBLOCK_SOURCE, array(
101        "group"	=> $mcastaddr,
102        "interface" => $interface,
103        "source" => $sblock,
104    ));
105    var_dump($so);
106    $r = socket_sendto($sends1, $m = "mcast packet from 127.0.0.1", strlen($m), 0, $mcastaddr, $port);
107    var_dump($r);
108}
109if ($i == 5) {
110    echo "leaving group\n";
111    $so = socket_set_option($s, $level, MCAST_LEAVE_GROUP, array(
112        "group"	=> $mcastaddr,
113        "interface" => $interface,
114    ));
115    var_dump($so);
116    $r = socket_sendto($sends1, $m = "ignored mcast packet", strlen($m), 0, $mcastaddr, $port);
117    var_dump($r);
118    $r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "127.0.0.1", $port);
119    var_dump($r);
120}
121if ($i == 6) {
122    echo "joining source group\n";
123    $so = socket_set_option($s, $level, MCAST_JOIN_SOURCE_GROUP, array(
124        "group"	=> $mcastaddr,
125        "interface" => $interface,
126        "source" => $sblock,
127    ));
128    var_dump($so);
129    $r = socket_sendto($sends1, $m = "mcast packet from 127.0.0.1", strlen($m), 0, $mcastaddr, $port);
130    var_dump($r);
131}
132if ($i == 7) {
133    echo "leaving source group\n";
134    $so = socket_set_option($s, $level, MCAST_LEAVE_SOURCE_GROUP, array(
135        "group"	=> $mcastaddr,
136        "interface" => $interface,
137        "source" => $sblock,
138    ));
139    var_dump($so);
140    $r = socket_sendto($sends1, $m = "ignored mcast packet", strlen($m), 0, $mcastaddr, $port);
141    var_dump($r);
142    $r = socket_sendto($sends1, $m = "unicast packet", strlen($m), 0, "127.0.0.1", $port);
143    var_dump($r);
144}
145if ($i == 8) {
146/*	echo "rjsg\n";
147    $so = socket_set_option($s, $level, MCAST_JOIN_GROUP, array(
148        "group"	=> $mcastaddr,
149        "interface" => $interface,
150    ));
151    var_dump($so);*/
152    break;
153}
154
155}
156?>
157--EXPECTF--
158creating send socket bound to 127.0.0.1
159bool(true)
160creating unbound socket and hoping the routing table causes an interface other than lo to be used for sending messages to 224.0.0.23
161bool(true)
162creating receive socket
163object(Socket)#%d (0) {
164}
165bool(true)
166bool(true)
167int(14)
1681> initial packet
169leaving group
170bool(true)
171int(20)
172int(14)
1732> unicast packet
174re-joining group
175bool(true)
176int(42)
177int(12)
1783> mcast packet
179blocking source
180bool(true)
181int(31)
182int(14)
1834> unicast packet
184unblocking source
185bool(true)
186int(27)
1875> mcast packet from 127.0.0.1
188leaving group
189bool(true)
190int(20)
191int(14)
1926> unicast packet
193joining source group
194bool(true)
195int(27)
1967> mcast packet from 127.0.0.1
197leaving source group
198bool(true)
199int(20)
200int(14)
2018> unicast packet
202