• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.net.util;
18 
19 import static android.net.util.PacketReader.DEFAULT_RECV_BUF_SIZE;
20 import static android.system.OsConstants.AF_INET6;
21 import static android.system.OsConstants.IPPROTO_UDP;
22 import static android.system.OsConstants.SOCK_DGRAM;
23 import static android.system.OsConstants.SOCK_NONBLOCK;
24 import static android.system.OsConstants.SOL_SOCKET;
25 import static android.system.OsConstants.SO_SNDTIMEO;
26 
27 import static org.junit.Assert.assertEquals;
28 import static org.junit.Assert.assertFalse;
29 import static org.junit.Assert.assertTrue;
30 import static org.junit.Assert.fail;
31 
32 import android.os.Handler;
33 import android.os.HandlerThread;
34 import android.system.ErrnoException;
35 import android.system.Os;
36 import android.system.StructTimeval;
37 
38 import androidx.test.filters.SmallTest;
39 import androidx.test.runner.AndroidJUnit4;
40 
41 import org.junit.After;
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 
46 import java.io.FileDescriptor;
47 import java.net.DatagramPacket;
48 import java.net.DatagramSocket;
49 import java.net.Inet6Address;
50 import java.net.InetAddress;
51 import java.net.InetSocketAddress;
52 import java.net.SocketException;
53 import java.util.Arrays;
54 import java.util.concurrent.CountDownLatch;
55 import java.util.concurrent.TimeUnit;
56 
57 /**
58  * Tests for PacketReader.
59  *
60  * @hide
61  */
62 @RunWith(AndroidJUnit4.class)
63 @SmallTest
64 public class PacketReaderTest {
65     static final InetAddress LOOPBACK6 = Inet6Address.getLoopbackAddress();
66     static final StructTimeval TIMEO = StructTimeval.fromMillis(500);
67 
68     protected CountDownLatch mLatch;
69     protected FileDescriptor mLocalSocket;
70     protected InetSocketAddress mLocalSockName;
71     protected byte[] mLastRecvBuf;
72     protected boolean mStopped;
73     protected HandlerThread mHandlerThread;
74     protected PacketReader mReceiver;
75 
76     class UdpLoopbackReader extends PacketReader {
UdpLoopbackReader(Handler h)77         public UdpLoopbackReader(Handler h) {
78             super(h);
79         }
80 
81         @Override
createFd()82         protected FileDescriptor createFd() {
83             FileDescriptor s = null;
84             try {
85                 s = Os.socket(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
86                 Os.bind(s, LOOPBACK6, 0);
87                 mLocalSockName = (InetSocketAddress) Os.getsockname(s);
88                 Os.setsockoptTimeval(s, SOL_SOCKET, SO_SNDTIMEO, TIMEO);
89             } catch (ErrnoException|SocketException e) {
90                 closeFd(s);
91                 fail();
92                 return null;
93             }
94 
95             mLocalSocket = s;
96             return s;
97         }
98 
99         @Override
handlePacket(byte[] recvbuf, int length)100         protected void handlePacket(byte[] recvbuf, int length) {
101             mLastRecvBuf = Arrays.copyOf(recvbuf, length);
102             mLatch.countDown();
103         }
104 
105         @Override
onStart()106         protected void onStart() {
107             mStopped = false;
108             mLatch.countDown();
109         }
110 
111         @Override
onStop()112         protected void onStop() {
113             mStopped = true;
114             mLatch.countDown();
115         }
116     };
117 
118     @Before
setUp()119     public void setUp() {
120         resetLatch();
121         mLocalSocket = null;
122         mLocalSockName = null;
123         mLastRecvBuf = null;
124         mStopped = false;
125 
126         mHandlerThread = new HandlerThread(PacketReaderTest.class.getSimpleName());
127         mHandlerThread.start();
128     }
129 
130     @After
tearDown()131     public void tearDown() throws Exception {
132         if (mReceiver != null) {
133             mHandlerThread.getThreadHandler().post(() -> { mReceiver.stop(); });
134             waitForActivity();
135         }
136         mReceiver = null;
137         mHandlerThread.quit();
138         mHandlerThread = null;
139     }
140 
resetLatch()141     void resetLatch() { mLatch = new CountDownLatch(1); }
142 
waitForActivity()143     void waitForActivity() throws Exception {
144         try {
145             mLatch.await(1000, TimeUnit.MILLISECONDS);
146         } finally {
147             resetLatch();
148         }
149     }
150 
sendPacket(byte[] contents)151     void sendPacket(byte[] contents) throws Exception {
152         final DatagramSocket sender = new DatagramSocket();
153         sender.connect(mLocalSockName);
154         sender.send(new DatagramPacket(contents, contents.length));
155         sender.close();
156     }
157 
158     @Test
testBasicWorking()159     public void testBasicWorking() throws Exception {
160         final Handler h = mHandlerThread.getThreadHandler();
161         mReceiver = new UdpLoopbackReader(h);
162 
163         h.post(() -> { mReceiver.start(); });
164         waitForActivity();
165         assertTrue(mLocalSockName != null);
166         assertEquals(LOOPBACK6, mLocalSockName.getAddress());
167         assertTrue(0 < mLocalSockName.getPort());
168         assertTrue(mLocalSocket != null);
169         assertFalse(mStopped);
170 
171         final byte[] one = "one 1".getBytes("UTF-8");
172         sendPacket(one);
173         waitForActivity();
174         assertEquals(1, mReceiver.numPacketsReceived());
175         assertTrue(Arrays.equals(one, mLastRecvBuf));
176         assertFalse(mStopped);
177 
178         final byte[] two = "two 2".getBytes("UTF-8");
179         sendPacket(two);
180         waitForActivity();
181         assertEquals(2, mReceiver.numPacketsReceived());
182         assertTrue(Arrays.equals(two, mLastRecvBuf));
183         assertFalse(mStopped);
184 
185         mReceiver.stop();
186         waitForActivity();
187         assertEquals(2, mReceiver.numPacketsReceived());
188         assertTrue(Arrays.equals(two, mLastRecvBuf));
189         assertTrue(mStopped);
190         mReceiver = null;
191     }
192 
193     class NullPacketReader extends PacketReader {
NullPacketReader(Handler h, int recvbufsize)194         public NullPacketReader(Handler h, int recvbufsize) {
195             super(h, recvbufsize);
196         }
197 
198         @Override
createFd()199         public FileDescriptor createFd() { return null; }
200     }
201 
202     @Test
testMinimalRecvBufSize()203     public void testMinimalRecvBufSize() throws Exception {
204         final Handler h = mHandlerThread.getThreadHandler();
205 
206         for (int i : new int[]{-1, 0, 1, DEFAULT_RECV_BUF_SIZE-1}) {
207             final PacketReader b = new NullPacketReader(h, i);
208             assertEquals(DEFAULT_RECV_BUF_SIZE, b.recvBufSize());
209         }
210     }
211 }
212