1ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline/*
2ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline * Copyright (C) 2016 The Android Open Source Project
3ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline *
4ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline * Licensed under the Apache License, Version 2.0 (the "License");
5ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline * you may not use this file except in compliance with the License.
6ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline * You may obtain a copy of the License at
7ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline *
8ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline *      http://www.apache.org/licenses/LICENSE-2.0
9ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline *
10ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline * Unless required by applicable law or agreed to in writing, software
11ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline * distributed under the License is distributed on an "AS IS" BASIS,
12ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline * See the License for the specific language governing permissions and
14ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline * limitations under the License.
15ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline */
16ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
17ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klinepackage android.net.util;
18ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
1984714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klineimport static android.net.util.PacketReader.DEFAULT_RECV_BUF_SIZE;
20ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport static android.system.OsConstants.*;
214a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport static org.junit.Assert.assertEquals;
224a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport static org.junit.Assert.assertFalse;
234a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport static org.junit.Assert.assertTrue;
244a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport static org.junit.Assert.fail;
25ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
26f840e07f821cb17c9ae1e6583a28eff548b90892Erik Klineimport android.os.Handler;
27f840e07f821cb17c9ae1e6583a28eff548b90892Erik Klineimport android.os.HandlerThread;
284a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport android.support.test.filters.SmallTest;
294a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport android.support.test.runner.AndroidJUnit4;
30ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport android.system.ErrnoException;
31ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport android.system.Os;
32ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport android.system.StructTimeval;
33ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
34ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport java.io.FileDescriptor;
35ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport java.io.FileInputStream;
36ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport java.io.IOException;
37f840e07f821cb17c9ae1e6583a28eff548b90892Erik Klineimport java.io.UncheckedIOException;
38ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport java.net.DatagramPacket;
39ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport java.net.DatagramSocket;
40ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport java.net.Inet6Address;
41ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport java.net.InetAddress;
42ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport java.net.InetSocketAddress;
43ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport java.net.SocketException;
44ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport java.util.Arrays;
45ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport java.util.concurrent.CountDownLatch;
46ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Klineimport java.util.concurrent.TimeUnit;
47ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
484a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport org.junit.runner.RunWith;
494a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport org.junit.After;
504a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport org.junit.Before;
514a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport org.junit.Test;
52ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
534a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichiimport libcore.io.IoBridge;
54ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
55ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline/**
5684714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline * Tests for PacketReader.
57ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline *
58ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline * @hide
59ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline */
604a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi@RunWith(AndroidJUnit4.class)
614a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi@SmallTest
6284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Klinepublic class PacketReaderTest {
63ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    static final InetAddress LOOPBACK6 = Inet6Address.getLoopbackAddress();
64ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    static final StructTimeval TIMEO = StructTimeval.fromMillis(500);
65ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
66ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    protected CountDownLatch mLatch;
67ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    protected FileDescriptor mLocalSocket;
68ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    protected InetSocketAddress mLocalSockName;
69ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    protected byte[] mLastRecvBuf;
70f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline    protected boolean mStopped;
71f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline    protected HandlerThread mHandlerThread;
7284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline    protected PacketReader mReceiver;
73ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
7484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline    class UdpLoopbackReader extends PacketReader {
75f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        public UdpLoopbackReader(Handler h) {
76f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            super(h);
77f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        }
78f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline
79f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        @Override
80f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        protected FileDescriptor createFd() {
81f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            FileDescriptor s = null;
82f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            try {
83f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline                s = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
84f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline                Os.bind(s, LOOPBACK6, 0);
85f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline                mLocalSockName = (InetSocketAddress) Os.getsockname(s);
86f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline                Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO);
87f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            } catch (ErrnoException|SocketException e) {
88f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline                closeFd(s);
89f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline                fail();
90f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline                return null;
91f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            }
92f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline
93f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            mLocalSocket = s;
94f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            return s;
95f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        }
96f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline
97f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        @Override
98f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        protected void handlePacket(byte[] recvbuf, int length) {
99f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            mLastRecvBuf = Arrays.copyOf(recvbuf, length);
100f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            mLatch.countDown();
101f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        }
102f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline
103f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        @Override
104f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        protected void onStart() {
105f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            mStopped = false;
106f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            mLatch.countDown();
107f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        }
108f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline
109f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        @Override
110f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        protected void onStop() {
111f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            mStopped = true;
112f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            mLatch.countDown();
113f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        }
114f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline    };
115f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline
1164a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @Before
117ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    public void setUp() {
118ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        resetLatch();
119ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        mLocalSocket = null;
120ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        mLocalSockName = null;
121ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        mLastRecvBuf = null;
122f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        mStopped = false;
123ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
12484714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline        mHandlerThread = new HandlerThread(PacketReaderTest.class.getSimpleName());
125f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        mHandlerThread.start();
126ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    }
127ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
1284a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @After
129f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline    public void tearDown() throws Exception {
130f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        if (mReceiver != null) {
131f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            mHandlerThread.getThreadHandler().post(() -> { mReceiver.stop(); });
132f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            waitForActivity();
133f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        }
134ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        mReceiver = null;
135f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        mHandlerThread.quit();
136f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        mHandlerThread = null;
137ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    }
138ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
139ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    void resetLatch() { mLatch = new CountDownLatch(1); }
140ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
141ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    void waitForActivity() throws Exception {
142f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        try {
143f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            mLatch.await(1000, TimeUnit.MILLISECONDS);
144f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        } finally {
145f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            resetLatch();
146f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        }
147ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    }
148ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
149ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    void sendPacket(byte[] contents) throws Exception {
150ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        final DatagramSocket sender = new DatagramSocket();
151ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        sender.connect(mLocalSockName);
152ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        sender.send(new DatagramPacket(contents, contents.length));
153ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        sender.close();
154ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    }
155ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
1564a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @Test
157ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    public void testBasicWorking() throws Exception {
158f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        final Handler h = mHandlerThread.getThreadHandler();
159f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        mReceiver = new UdpLoopbackReader(h);
160f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline
161f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        h.post(() -> { mReceiver.start(); });
162f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        waitForActivity();
163ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        assertTrue(mLocalSockName != null);
164ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        assertEquals(LOOPBACK6, mLocalSockName.getAddress());
165ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        assertTrue(0 < mLocalSockName.getPort());
166ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        assertTrue(mLocalSocket != null);
167f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        assertFalse(mStopped);
168ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
169ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        final byte[] one = "one 1".getBytes("UTF-8");
170ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        sendPacket(one);
171ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        waitForActivity();
172ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        assertEquals(1, mReceiver.numPacketsReceived());
173ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        assertTrue(Arrays.equals(one, mLastRecvBuf));
174f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        assertFalse(mStopped);
175ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
176ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        final byte[] two = "two 2".getBytes("UTF-8");
177ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        sendPacket(two);
178ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        waitForActivity();
179ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        assertEquals(2, mReceiver.numPacketsReceived());
180ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        assertTrue(Arrays.equals(two, mLastRecvBuf));
181f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        assertFalse(mStopped);
182ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline
183ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        mReceiver.stop();
184ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        waitForActivity();
185ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        assertEquals(2, mReceiver.numPacketsReceived());
186ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline        assertTrue(Arrays.equals(two, mLastRecvBuf));
187f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        assertTrue(mStopped);
188f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        mReceiver = null;
189f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline    }
190f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline
19184714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline    class NullPacketReader extends PacketReader {
19284714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline        public NullPacketReader(Handler h, int recvbufsize) {
193f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            super(h, recvbufsize);
194f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        }
195f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline
196f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        @Override
197f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        public FileDescriptor createFd() { return null; }
198f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline    }
199f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline
2004a0c5d7ef7144280fe8a209a871bbd4ef90d6368Hugo Benichi    @Test
201f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline    public void testMinimalRecvBufSize() throws Exception {
202f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        final Handler h = mHandlerThread.getThreadHandler();
203f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline
204f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        for (int i : new int[]{-1, 0, 1, DEFAULT_RECV_BUF_SIZE-1}) {
20584714bffa1a58fe1f6a114ae015f8e38be46f32dErik Kline            final PacketReader b = new NullPacketReader(h, i);
206f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline            assertEquals(DEFAULT_RECV_BUF_SIZE, b.recvBufSize());
207f840e07f821cb17c9ae1e6583a28eff548b90892Erik Kline        }
208ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline    }
209ade3a8ccb0acc1ba1ee29e5668b5e78670f26002Erik Kline}
210