189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang/*
289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * Copyright (C) 2011 The Android Open Source Project
389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang *
489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * Licensed under the Apache License, Version 2.0 (the "License");
589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * you may not use this file except in compliance with the License.
689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * You may obtain a copy of the License at
789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang *
889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang *      http://www.apache.org/licenses/LICENSE-2.0
989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang *
1089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * Unless required by applicable law or agreed to in writing, software
1189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * distributed under the License is distributed on an "AS IS" BASIS,
1289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * See the License for the specific language governing permissions and
1489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * limitations under the License.
1589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang */
1689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangpackage com.android.tests.bandwidthenforcement;
1789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
1889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport android.app.IntentService;
1989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport android.content.Intent;
2089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport android.net.SntpClient;
2189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport android.os.Environment;
2289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport android.util.Log;
2389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
2489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.BufferedWriter;
2589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.ByteArrayOutputStream;
2689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.File;
2789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.FileWriter;
2889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.IOException;
2989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.InputStreamReader;
3089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.DatagramPacket;
3189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.DatagramSocket;
3289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.HttpURLConnection;
3389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.InetAddress;
3489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.URL;
3589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.util.Random;
3689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
3789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport libcore.io.Streams;
3889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
3989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang/*
4089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * Test Service that tries to connect to the web via different methods and outputs the results to
4189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * the log and a output file.
4289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang */
4389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangpublic class BandwidthEnforcementTestService extends IntentService {
4489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    private static final String TAG = "BandwidthEnforcementTestService";
4589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    private static final String OUTPUT_FILE = "BandwidthEnforcementTestServiceOutputFile";
4689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
4789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    public BandwidthEnforcementTestService() {
4889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        super(TAG);
4989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
5089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
5189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    @Override
5289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    protected void onHandleIntent(Intent intent) {
5389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        Log.d(TAG, "Trying to establish a connection.");
5489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        // Read output file path from intent.
5589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        String outputFile = intent.getStringExtra(OUTPUT_FILE);
5689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        dumpResult("testUrlConnection", testUrlConnection(), outputFile);
5789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        dumpResult("testUrlConnectionv6", testUrlConnectionv6(), outputFile);
5889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        dumpResult("testSntp", testSntp(), outputFile);
5989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        dumpResult("testDns", testDns(), outputFile);
6089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
6189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
6289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    public static void dumpResult(String tag, boolean result, String outputFile) {
6389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        Log.d(TAG, "Test output file: " + outputFile);
6489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        try {
6589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            if (outputFile != null){
6689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                File extStorage = Environment.getExternalStorageDirectory();
6789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                File outFile = new File(extStorage, outputFile);
6889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                FileWriter writer = new FileWriter(outFile, true);
6989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                BufferedWriter out = new BufferedWriter(writer);
7089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                if (result) {
7189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                    out.append(tag + ":fail\n");
7289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                } else {
7389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                    out.append(tag + ":pass\n");
7489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                }
7589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                out.close();
7689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            }
7789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            if (result) {
7889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                Log.e(TAG, tag + " FAILURE ====================");
7989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                Log.e(TAG, tag + " FAILURE was able to use data");
8089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                Log.e(TAG, tag + " FAILURE ====================");
8189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            } else {
8289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                Log.d(TAG, tag + " success; unable to use data");
8389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            }
8489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        } catch (IOException e) {
8589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            Log.e(TAG, "Could not write file " + e.getMessage());
8689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        }
8789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
8889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
8989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    /**
9089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * Tests a normal http url connection.
9189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * @return true if it was able to connect, false otherwise.
9289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     */
9389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    public static boolean testUrlConnection() {
9489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        try {
9589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            final HttpURLConnection conn = (HttpURLConnection) new URL("http://www.google.com/")
9689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            .openConnection();
9789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            try {
9889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                conn.connect();
9989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                final String content = Streams.readFully(
10089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                        new InputStreamReader(conn.getInputStream()));
10189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                if (content.contains("Google")) {
10289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                    return true;
10389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                }
10489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            } finally {
10589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                conn.disconnect();
10689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            }
10789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        } catch (IOException e) {
10889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            Log.d(TAG, "error: " + e);
10989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        }
11089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        return false;
11189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
11289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
11389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    /**
11489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * Tests a ipv6 http url connection.
11589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * @return true if it was able to connect, false otherwise.
11689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     */
11789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    public static boolean testUrlConnectionv6() {
11889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        try {
11989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            final HttpURLConnection conn = (HttpURLConnection) new URL("http://ipv6.google.com/")
12089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            .openConnection();
12189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            try {
12289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                conn.connect();
12389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                final String content = Streams.readFully(
12489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                        new InputStreamReader(conn.getInputStream()));
12589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                if (content.contains("Google")) {
12689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                    return true;
12789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                }
12889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            } finally {
12989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                conn.disconnect();
13089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            }
13189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        } catch (IOException e) {
13289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            Log.d(TAG, "error: " + e);
13389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        }
13489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        return false;
13589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
13689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
13789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    /**
13889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * Tests to connect via sntp.
13989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * @return true if it was able to connect, false otherwise.
14089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     */
14189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    public static boolean testSntp() {
14289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        final SntpClient client = new SntpClient();
14389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        if (client.requestTime("0.pool.ntp.org", 10000)) {
14489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            return true;
14589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        }
14689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        return false;
14789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
14889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
14989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    /**
15089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * Tests dns query.
15189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * @return true if it was able to connect, false otherwise.
15289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     */
15389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    public static boolean testDns() {
15489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        try {
15589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            final DatagramSocket socket = new DatagramSocket();
15689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            try {
15789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                socket.setSoTimeout(10000);
15889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
15989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                final byte[] query = buildDnsQuery("www", "android", "com");
16089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                final DatagramPacket queryPacket = new DatagramPacket(
16189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                        query, query.length, InetAddress.parseNumericAddress("8.8.8.8"), 53);
16289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                socket.send(queryPacket);
16389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
16489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                final byte[] reply = new byte[query.length];
16589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                final DatagramPacket replyPacket = new DatagramPacket(reply, reply.length);
16689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                socket.receive(replyPacket);
16789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                return true;
16889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
16989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            } finally {
17089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                socket.close();
17189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            }
17289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        } catch (IOException e) {
17389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            Log.d(TAG, "error: " + e);
17489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        }
17589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        return false;
17689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
17789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
17889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    /**
17989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * Helper method to build a dns query
18089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * @param query the dns strings of the server
18189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * @return the byte array of the dns query to send
18289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * @throws IOException
18389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     */
18489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    private static byte[] buildDnsQuery(String... query) throws IOException {
18589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        final Random random = new Random();
18689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        final ByteArrayOutputStream out = new ByteArrayOutputStream();
18789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
18889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        final byte[] id = new byte[2];
18989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        random.nextBytes(id);
19089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
19189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(id);
19289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(new byte[] { 0x01, 0x00 });
19389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(new byte[] { 0x00, 0x01 });
19489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(new byte[] { 0x00, 0x00 });
19589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(new byte[] { 0x00, 0x00 });
19689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(new byte[] { 0x00, 0x00 });
19789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
19889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        for (String phrase : query) {
19989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            final byte[] bytes = phrase.getBytes("US-ASCII");
20089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            out.write(bytes.length);
20189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            out.write(bytes);
20289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        }
20389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(0x00);
20489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
20589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(new byte[] { 0x00, 0x01 });
20689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(new byte[] { 0x00, 0x01 });
20789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
20889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        return out.toByteArray();
20989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
21089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang}
211