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