1/*
2 * Copyright (C) 2011 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 */
16package com.android.tests.bandwidthenforcement;
17
18import android.app.IntentService;
19import android.content.Intent;
20import android.net.SntpClient;
21import android.os.Environment;
22import android.util.Log;
23
24import java.io.BufferedWriter;
25import java.io.ByteArrayOutputStream;
26import java.io.File;
27import java.io.FileWriter;
28import java.io.IOException;
29import java.io.InputStreamReader;
30import java.net.DatagramPacket;
31import java.net.DatagramSocket;
32import java.net.HttpURLConnection;
33import java.net.InetAddress;
34import java.net.URL;
35import java.util.Random;
36
37import libcore.io.Streams;
38
39/*
40 * Test Service that tries to connect to the web via different methods and outputs the results to
41 * the log and a output file.
42 */
43public class BandwidthEnforcementTestService extends IntentService {
44    private static final String TAG = "BandwidthEnforcementTestService";
45    private static final String OUTPUT_FILE = "BandwidthEnforcementTestServiceOutputFile";
46
47    public BandwidthEnforcementTestService() {
48        super(TAG);
49    }
50
51    @Override
52    protected void onHandleIntent(Intent intent) {
53        Log.d(TAG, "Trying to establish a connection.");
54        // Read output file path from intent.
55        String outputFile = intent.getStringExtra(OUTPUT_FILE);
56        dumpResult("testUrlConnection", testUrlConnection(), outputFile);
57        dumpResult("testUrlConnectionv6", testUrlConnectionv6(), outputFile);
58        dumpResult("testSntp", testSntp(), outputFile);
59        dumpResult("testDns", testDns(), outputFile);
60    }
61
62    public static void dumpResult(String tag, boolean result, String outputFile) {
63        Log.d(TAG, "Test output file: " + outputFile);
64        try {
65            if (outputFile != null){
66                File extStorage = Environment.getExternalStorageDirectory();
67                File outFile = new File(extStorage, outputFile);
68                FileWriter writer = new FileWriter(outFile, true);
69                BufferedWriter out = new BufferedWriter(writer);
70                if (result) {
71                    out.append(tag + ":fail\n");
72                } else {
73                    out.append(tag + ":pass\n");
74                }
75                out.close();
76            }
77            if (result) {
78                Log.e(TAG, tag + " FAILURE ====================");
79                Log.e(TAG, tag + " FAILURE was able to use data");
80                Log.e(TAG, tag + " FAILURE ====================");
81            } else {
82                Log.d(TAG, tag + " success; unable to use data");
83            }
84        } catch (IOException e) {
85            Log.e(TAG, "Could not write file " + e.getMessage());
86        }
87    }
88
89    /**
90     * Tests a normal http url connection.
91     * @return true if it was able to connect, false otherwise.
92     */
93    public static boolean testUrlConnection() {
94        try {
95            final HttpURLConnection conn = (HttpURLConnection) new URL("http://www.google.com/")
96            .openConnection();
97            try {
98                conn.connect();
99                final String content = Streams.readFully(
100                        new InputStreamReader(conn.getInputStream()));
101                if (content.contains("Google")) {
102                    return true;
103                }
104            } finally {
105                conn.disconnect();
106            }
107        } catch (IOException e) {
108            Log.d(TAG, "error: " + e);
109        }
110        return false;
111    }
112
113    /**
114     * Tests a ipv6 http url connection.
115     * @return true if it was able to connect, false otherwise.
116     */
117    public static boolean testUrlConnectionv6() {
118        try {
119            final HttpURLConnection conn = (HttpURLConnection) new URL("http://ipv6.google.com/")
120            .openConnection();
121            try {
122                conn.connect();
123                final String content = Streams.readFully(
124                        new InputStreamReader(conn.getInputStream()));
125                if (content.contains("Google")) {
126                    return true;
127                }
128            } finally {
129                conn.disconnect();
130            }
131        } catch (IOException e) {
132            Log.d(TAG, "error: " + e);
133        }
134        return false;
135    }
136
137    /**
138     * Tests to connect via sntp.
139     * @return true if it was able to connect, false otherwise.
140     */
141    public static boolean testSntp() {
142        final SntpClient client = new SntpClient();
143        if (client.requestTime("0.pool.ntp.org", 10000)) {
144            return true;
145        }
146        return false;
147    }
148
149    /**
150     * Tests dns query.
151     * @return true if it was able to connect, false otherwise.
152     */
153    public static boolean testDns() {
154        try {
155            final DatagramSocket socket = new DatagramSocket();
156            try {
157                socket.setSoTimeout(10000);
158
159                final byte[] query = buildDnsQuery("www", "android", "com");
160                final DatagramPacket queryPacket = new DatagramPacket(
161                        query, query.length, InetAddress.parseNumericAddress("8.8.8.8"), 53);
162                socket.send(queryPacket);
163
164                final byte[] reply = new byte[query.length];
165                final DatagramPacket replyPacket = new DatagramPacket(reply, reply.length);
166                socket.receive(replyPacket);
167                return true;
168
169            } finally {
170                socket.close();
171            }
172        } catch (IOException e) {
173            Log.d(TAG, "error: " + e);
174        }
175        return false;
176    }
177
178    /**
179     * Helper method to build a dns query
180     * @param query the dns strings of the server
181     * @return the byte array of the dns query to send
182     * @throws IOException
183     */
184    private static byte[] buildDnsQuery(String... query) throws IOException {
185        final Random random = new Random();
186        final ByteArrayOutputStream out = new ByteArrayOutputStream();
187
188        final byte[] id = new byte[2];
189        random.nextBytes(id);
190
191        out.write(id);
192        out.write(new byte[] { 0x01, 0x00 });
193        out.write(new byte[] { 0x00, 0x01 });
194        out.write(new byte[] { 0x00, 0x00 });
195        out.write(new byte[] { 0x00, 0x00 });
196        out.write(new byte[] { 0x00, 0x00 });
197
198        for (String phrase : query) {
199            final byte[] bytes = phrase.getBytes("US-ASCII");
200            out.write(bytes.length);
201            out.write(bytes);
202        }
203        out.write(0x00);
204
205        out.write(new byte[] { 0x00, 0x01 });
206        out.write(new byte[] { 0x00, 0x01 });
207
208        return out.toByteArray();
209    }
210}
211