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 android.net.util;
18
19import static android.system.OsConstants.*;
20
21import android.system.ErrnoException;
22import android.system.Os;
23import android.system.StructTimeval;
24
25import libcore.io.IoBridge;
26
27import java.io.FileDescriptor;
28import java.io.FileInputStream;
29import java.io.IOException;
30import java.net.DatagramPacket;
31import java.net.DatagramSocket;
32import java.net.Inet6Address;
33import java.net.InetAddress;
34import java.net.InetSocketAddress;
35import java.net.SocketException;
36import java.util.Arrays;
37import java.util.concurrent.CountDownLatch;
38import java.util.concurrent.TimeUnit;
39
40import junit.framework.TestCase;
41
42
43/**
44 * Tests for BlockingSocketReader.
45 *
46 * @hide
47 */
48public class BlockingSocketReaderTest extends TestCase {
49    static final InetAddress LOOPBACK6 = Inet6Address.getLoopbackAddress();
50    static final StructTimeval TIMEO = StructTimeval.fromMillis(500);
51
52    protected CountDownLatch mLatch;
53    protected FileDescriptor mLocalSocket;
54    protected InetSocketAddress mLocalSockName;
55    protected byte[] mLastRecvBuf;
56    protected boolean mExited;
57    protected BlockingSocketReader mReceiver;
58
59    @Override
60    public void setUp() {
61        resetLatch();
62        mLocalSocket = null;
63        mLocalSockName = null;
64        mLastRecvBuf = null;
65        mExited = false;
66
67        mReceiver = new BlockingSocketReader() {
68            @Override
69            protected FileDescriptor createSocket() {
70                FileDescriptor s = null;
71                try {
72                    s = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
73                    Os.bind(s, LOOPBACK6, 0);
74                    mLocalSockName = (InetSocketAddress) Os.getsockname(s);
75                    Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO);
76                } catch (ErrnoException|SocketException e) {
77                    closeSocket(s);
78                    fail();
79                    return null;
80                }
81
82                mLocalSocket = s;
83                return s;
84            }
85
86            @Override
87            protected void handlePacket(byte[] recvbuf, int length) {
88                mLastRecvBuf = Arrays.copyOf(recvbuf, length);
89                mLatch.countDown();
90            }
91
92            @Override
93            protected void onExit() {
94                mExited = true;
95                mLatch.countDown();
96            }
97        };
98    }
99
100    @Override
101    public void tearDown() {
102        if (mReceiver != null) mReceiver.stop();
103        mReceiver = null;
104    }
105
106    void resetLatch() { mLatch = new CountDownLatch(1); }
107
108    void waitForActivity() throws Exception {
109        assertTrue(mLatch.await(500, TimeUnit.MILLISECONDS));
110        resetLatch();
111    }
112
113    void sendPacket(byte[] contents) throws Exception {
114        final DatagramSocket sender = new DatagramSocket();
115        sender.connect(mLocalSockName);
116        sender.send(new DatagramPacket(contents, contents.length));
117        sender.close();
118    }
119
120    public void testBasicWorking() throws Exception {
121        assertTrue(mReceiver.start());
122        assertTrue(mLocalSockName != null);
123        assertEquals(LOOPBACK6, mLocalSockName.getAddress());
124        assertTrue(0 < mLocalSockName.getPort());
125        assertTrue(mLocalSocket != null);
126        assertFalse(mExited);
127
128        final byte[] one = "one 1".getBytes("UTF-8");
129        sendPacket(one);
130        waitForActivity();
131        assertEquals(1, mReceiver.numPacketsReceived());
132        assertTrue(Arrays.equals(one, mLastRecvBuf));
133        assertFalse(mExited);
134
135        final byte[] two = "two 2".getBytes("UTF-8");
136        sendPacket(two);
137        waitForActivity();
138        assertEquals(2, mReceiver.numPacketsReceived());
139        assertTrue(Arrays.equals(two, mLastRecvBuf));
140        assertFalse(mExited);
141
142        mReceiver.stop();
143        waitForActivity();
144        assertEquals(2, mReceiver.numPacketsReceived());
145        assertTrue(Arrays.equals(two, mLastRecvBuf));
146        assertTrue(mExited);
147    }
148}
149