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