1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package libcore.java.nio.channels;
18
19import junit.framework.TestCase;
20
21import java.io.IOException;
22import java.net.Inet4Address;
23import java.net.Inet6Address;
24import java.net.InetAddress;
25import java.net.InetSocketAddress;
26import java.net.NetworkInterface;
27import java.net.StandardProtocolFamily;
28import java.net.StandardSocketOptions;
29import java.net.UnknownHostException;
30import java.nio.ByteBuffer;
31import java.nio.channels.DatagramChannel;
32import java.nio.channels.MembershipKey;
33
34public class MembershipKeyTest extends TestCase {
35
36    private MembershipKey key;
37    private final int PORT = 5000;
38    private final String TEST_MESSAGE = "hello";
39    private DatagramChannel client;
40    private InetAddress sourceAddress = Inet4Address.LOOPBACK;
41    private final static InetAddress MULTICAST_ADDRESS = getMulticastAddress();
42    private final static NetworkInterface NETWORK_INTERFACE = getNetworkInterface();
43
44    private void init(boolean withSource) throws Exception {
45        client = DatagramChannel.open(StandardProtocolFamily.INET)
46                .bind(new InetSocketAddress(Inet4Address.ANY, PORT));
47        client.configureBlocking(false);
48
49        if (withSource) {
50            key = client.join(MULTICAST_ADDRESS, NETWORK_INTERFACE, sourceAddress);
51        } else {
52            key = client.join(MULTICAST_ADDRESS, NETWORK_INTERFACE);
53        }
54    }
55
56    @Override
57    public void tearDown() throws IOException {
58        client.close();
59        key = null;
60    }
61
62    public void test_isValid_OnChannelCloseWithJoinWithoutSource() throws Exception {
63        init(false);
64        check_isValid();
65    }
66
67    public void test_isValid_OnChannelCloseWithJoinWithSource() throws Exception {
68        init(true);
69        check_isValid();
70    }
71
72    private void check_isValid() throws IOException {
73        assertTrue(key.isValid());
74        client.close();
75        assertFalse(key.isValid());
76    }
77
78    public void test_isValid_OnDropJoinWithoutSource() throws Exception {
79        init(false);
80        check_isValid_OnDrop();
81    }
82
83    public void test_isValid_OnDropJoinWithSource() throws Exception {
84        init(true);
85        check_isValid_OnDrop();
86    }
87
88    private void check_isValid_OnDrop() {
89        assertTrue(key.isValid());
90        key.drop();
91        assertFalse(key.isValid());
92    }
93
94    public void test_dropWithJoinWithoutSource() throws Exception {
95        init(false);
96        check_drop();
97    }
98
99    public void test_dropWithJoinWithSource() throws Exception {
100        init(true);
101        check_drop();
102    }
103
104    private void check_drop() throws IOException {
105        key.drop();
106        try(DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) {
107            assertEquals(TEST_MESSAGE.length(), dc
108                    .bind(new InetSocketAddress(Inet4Address.LOOPBACK, 0))
109                    .send(ByteBuffer.wrap(TEST_MESSAGE.getBytes()),
110                            new InetSocketAddress(MULTICAST_ADDRESS, PORT)));
111        }
112
113        ByteBuffer buffer = ByteBuffer.allocate(1048);
114        client.receive(buffer);
115        buffer.flip();
116        assertEquals(0, buffer.limit());
117    }
118
119    public void test_networkInterface() throws Exception {
120        init(false);
121        assertEquals(NETWORK_INTERFACE, key.networkInterface());
122        client.close();
123        assertEquals(NETWORK_INTERFACE, key.networkInterface());
124    }
125
126    public void test_sourceAddressWithJoinWithSource() throws Exception {
127        init(true);
128        assertEquals(sourceAddress, key.sourceAddress());
129    }
130
131    public void test_sourceAddressWithJoinWithoutSource() throws Exception {
132        init(false);
133        assertNull(key.sourceAddress());
134    }
135
136    public void test_groupWithJoinWithSource() throws Exception {
137        init(true);
138        assertEquals(MULTICAST_ADDRESS, key.group());
139    }
140
141    public void test_groupWithoutJoinWIthSource() throws Exception {
142        init(false);
143        assertEquals(MULTICAST_ADDRESS, key.group());
144    }
145
146    public void test_channelWithJoinWithSource() throws Exception {
147        init(true);
148        assertEquals(client, key.channel());
149        key.drop();
150        assertEquals(client, key.channel());
151    }
152
153    public void test_channelWithJoinWithoutSource() throws Exception {
154        init(false);
155        assertEquals(client, key.channel());
156        key.drop();
157        assertEquals(client, key.channel());
158    }
159
160    public void test_blockWithJoinWithSource() throws Exception {
161        init(true);
162        try {
163            key.block(sourceAddress);
164            fail();
165        } catch (IllegalStateException expected) {}
166    }
167
168    public void test_blockWithJoinWithoutSource() throws Exception {
169        init(false);
170        key.block(sourceAddress);
171
172        try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) {
173            assertEquals(TEST_MESSAGE.length(), dc
174                    .bind(new InetSocketAddress(Inet4Address.LOOPBACK, 0))
175                    .send(ByteBuffer.wrap(TEST_MESSAGE.getBytes()),
176                            new InetSocketAddress(MULTICAST_ADDRESS, PORT)));
177        }
178
179        ByteBuffer buffer = ByteBuffer.allocate(1048);
180        client.receive(buffer);
181        buffer.flip();
182        assertEquals(0, buffer.limit());
183    }
184
185    public void test_block_Exception () throws Exception {
186        init(false);
187
188        // Blocking a multicast channel
189        try {
190            key.block(Inet4Address.getByName("224.0.0.10"));
191            fail();
192        } catch (IllegalArgumentException expected) {}
193
194        // Different address type than the group
195        try {
196            key.block(Inet6Address.LOOPBACK);
197            fail();
198        } catch (IllegalArgumentException expected) {}
199
200        key.drop();
201        try {
202            key.block(sourceAddress);
203            fail();
204        } catch (IllegalStateException expected) {}
205    }
206
207    public void test_unblockWithJoinWithSource() throws Exception {
208        init(true);
209        try {
210            key.unblock(Inet4Address.getByName("127.0.0.2"));
211            fail();
212        } catch (IllegalStateException expected) {}
213    }
214
215    public void test_unblockWithJoinWithoutSource() throws Exception {
216        init(false);
217
218        key.block(sourceAddress);
219        key.unblock(sourceAddress);
220
221        try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) {
222            assertEquals(TEST_MESSAGE.length(), dc
223                    .bind(new InetSocketAddress(Inet4Address.LOOPBACK, 0))
224                    .setOption(StandardSocketOptions.IP_MULTICAST_LOOP, true /* enable loop */)
225                    .send(ByteBuffer.wrap(TEST_MESSAGE.getBytes()),
226                            new InetSocketAddress(MULTICAST_ADDRESS, PORT)));
227        }
228
229        ByteBuffer buffer = ByteBuffer.allocate(1048);
230        client.receive(buffer);
231        buffer.flip();
232        int limits = buffer.limit();
233        byte bytes[] = new byte[limits];
234        buffer.get(bytes, 0, limits);
235        String receivedMessage = new String(bytes);
236        assertEquals(TEST_MESSAGE, receivedMessage);
237    }
238
239    public void test_unblock_Exception() throws Exception {
240        init(false);
241        try {
242            key.unblock(sourceAddress);
243            fail();
244        } catch (IllegalStateException expected) {}
245
246        key.drop();
247
248        try {
249            key.unblock(sourceAddress);
250            fail();
251        } catch (IllegalStateException expected) {}
252    }
253
254    private static InetAddress getMulticastAddress() {
255        try {
256            return InetAddress.getByName("239.255.0.1");
257        } catch (UnknownHostException exception) {
258            throw new RuntimeException(exception);
259        }
260    }
261
262    private static NetworkInterface getNetworkInterface() {
263        try {
264            return NetworkInterface.getByName("lo");
265        } catch (Exception e) {
266            throw new RuntimeException(e);
267        }
268    }
269}
270