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;
19dfdd82e84fcd102ab9b4d2233d195a013914c2aeKurt Marcinkiewiczimport android.content.Context;
2089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport android.content.Intent;
21dfdd82e84fcd102ab9b4d2233d195a013914c2aeKurt Marcinkiewiczimport android.net.ConnectivityManager;
22dfdd82e84fcd102ab9b4d2233d195a013914c2aeKurt Marcinkiewiczimport android.net.Network;
2389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport android.net.SntpClient;
2489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport android.os.Environment;
2589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport android.util.Log;
2689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
2789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.BufferedWriter;
2889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.ByteArrayOutputStream;
2989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.File;
3089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.FileWriter;
3189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.IOException;
3289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.io.InputStreamReader;
3389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.DatagramPacket;
3489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.DatagramSocket;
3589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.HttpURLConnection;
3689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.InetAddress;
3789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.net.URL;
3889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport java.util.Random;
3989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
4089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangimport libcore.io.Streams;
4189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
4289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang/*
4389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * Test Service that tries to connect to the web via different methods and outputs the results to
4489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang * the log and a output file.
4589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang */
4689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuangpublic class BandwidthEnforcementTestService extends IntentService {
4789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    private static final String TAG = "BandwidthEnforcementTestService";
4889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    private static final String OUTPUT_FILE = "BandwidthEnforcementTestServiceOutputFile";
4989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
5089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    public BandwidthEnforcementTestService() {
5189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        super(TAG);
5289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
5389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
5489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    @Override
5589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    protected void onHandleIntent(Intent intent) {
5689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        Log.d(TAG, "Trying to establish a connection.");
5789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        // Read output file path from intent.
5889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        String outputFile = intent.getStringExtra(OUTPUT_FILE);
5989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        dumpResult("testUrlConnection", testUrlConnection(), outputFile);
6089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        dumpResult("testUrlConnectionv6", testUrlConnectionv6(), outputFile);
61dfdd82e84fcd102ab9b4d2233d195a013914c2aeKurt Marcinkiewicz        dumpResult("testSntp", testSntp(getApplicationContext()), outputFile);
6289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        dumpResult("testDns", testDns(), outputFile);
6389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
6489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
6589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    public static void dumpResult(String tag, boolean result, String outputFile) {
6689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        Log.d(TAG, "Test output file: " + outputFile);
6789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        try {
6889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            if (outputFile != null){
6989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                File extStorage = Environment.getExternalStorageDirectory();
7089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                File outFile = new File(extStorage, outputFile);
7189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                FileWriter writer = new FileWriter(outFile, true);
7289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                BufferedWriter out = new BufferedWriter(writer);
7389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                if (result) {
7489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                    out.append(tag + ":fail\n");
7589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                } else {
7689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                    out.append(tag + ":pass\n");
7789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                }
7889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                out.close();
7989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            }
8089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            if (result) {
8189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                Log.e(TAG, tag + " FAILURE ====================");
8289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                Log.e(TAG, tag + " FAILURE was able to use data");
8389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                Log.e(TAG, tag + " FAILURE ====================");
8489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            } else {
8589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                Log.d(TAG, tag + " success; unable to use data");
8689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            }
8789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        } catch (IOException e) {
8889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            Log.e(TAG, "Could not write file " + e.getMessage());
8989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        }
9089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
9189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
9289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    /**
9389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * Tests a normal http url connection.
9489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * @return true if it was able to connect, false otherwise.
9589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     */
9689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    public static boolean testUrlConnection() {
9789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        try {
9889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            final HttpURLConnection conn = (HttpURLConnection) new URL("http://www.google.com/")
9989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            .openConnection();
10089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            try {
10189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                conn.connect();
10289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                final String content = Streams.readFully(
10389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                        new InputStreamReader(conn.getInputStream()));
10489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                if (content.contains("Google")) {
10589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                    return true;
10689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                }
10789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            } finally {
10889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                conn.disconnect();
10989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            }
11089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        } catch (IOException e) {
11189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            Log.d(TAG, "error: " + e);
11289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        }
11389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        return false;
11489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
11589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
11689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    /**
11789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * Tests a ipv6 http url connection.
11889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * @return true if it was able to connect, false otherwise.
11989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     */
12089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    public static boolean testUrlConnectionv6() {
12189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        try {
12289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            final HttpURLConnection conn = (HttpURLConnection) new URL("http://ipv6.google.com/")
12389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            .openConnection();
12489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            try {
12589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                conn.connect();
12689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                final String content = Streams.readFully(
12789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                        new InputStreamReader(conn.getInputStream()));
12889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                if (content.contains("Google")) {
12989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                    return true;
13089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                }
13189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            } finally {
13289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                conn.disconnect();
13389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            }
13489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        } catch (IOException e) {
13589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            Log.d(TAG, "error: " + e);
13689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        }
13789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        return false;
13889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
13989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
14089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    /**
14189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * Tests to connect via sntp.
14289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * @return true if it was able to connect, false otherwise.
14389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     */
144dfdd82e84fcd102ab9b4d2233d195a013914c2aeKurt Marcinkiewicz    public static boolean testSntp(Context context) {
14589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        final SntpClient client = new SntpClient();
146dfdd82e84fcd102ab9b4d2233d195a013914c2aeKurt Marcinkiewicz        final ConnectivityManager mCM = context.getSystemService(ConnectivityManager.class);
147dfdd82e84fcd102ab9b4d2233d195a013914c2aeKurt Marcinkiewicz        final Network network = mCM.getActiveNetwork();
148dfdd82e84fcd102ab9b4d2233d195a013914c2aeKurt Marcinkiewicz
149dfdd82e84fcd102ab9b4d2233d195a013914c2aeKurt Marcinkiewicz        if (client.requestTime("0.pool.ntp.org", 10000, network)) {
15089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            return true;
15189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        }
15289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        return false;
15389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
15489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
15589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    /**
15689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * Tests dns query.
15789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * @return true if it was able to connect, false otherwise.
15889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     */
15989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    public static boolean testDns() {
16089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        try {
16189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            final DatagramSocket socket = new DatagramSocket();
16289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            try {
16389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                socket.setSoTimeout(10000);
16489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
16589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                final byte[] query = buildDnsQuery("www", "android", "com");
16689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                final DatagramPacket queryPacket = new DatagramPacket(
16789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                        query, query.length, InetAddress.parseNumericAddress("8.8.8.8"), 53);
16889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                socket.send(queryPacket);
16989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
17089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                final byte[] reply = new byte[query.length];
17189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                final DatagramPacket replyPacket = new DatagramPacket(reply, reply.length);
17289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                socket.receive(replyPacket);
17389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                return true;
17489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
17589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            } finally {
17689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang                socket.close();
17789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            }
17889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        } catch (IOException e) {
17989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            Log.d(TAG, "error: " + e);
18089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        }
18189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        return false;
18289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
18389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
18489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    /**
18589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * Helper method to build a dns query
18689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * @param query the dns strings of the server
18789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * @return the byte array of the dns query to send
18889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     * @throws IOException
18989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang     */
19089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    private static byte[] buildDnsQuery(String... query) throws IOException {
19189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        final Random random = new Random();
19289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        final ByteArrayOutputStream out = new ByteArrayOutputStream();
19389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
19489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        final byte[] id = new byte[2];
19589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        random.nextBytes(id);
19689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
19789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(id);
19889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(new byte[] { 0x01, 0x00 });
19989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(new byte[] { 0x00, 0x01 });
20089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(new byte[] { 0x00, 0x00 });
20189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(new byte[] { 0x00, 0x00 });
20289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(new byte[] { 0x00, 0x00 });
20389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
20489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        for (String phrase : query) {
20589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            final byte[] bytes = phrase.getBytes("US-ASCII");
20689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            out.write(bytes.length);
20789355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang            out.write(bytes);
20889355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        }
20989355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(0x00);
21089355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
21189355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(new byte[] { 0x00, 0x01 });
21289355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        out.write(new byte[] { 0x00, 0x01 });
21389355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang
21489355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang        return out.toByteArray();
21589355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang    }
21689355b4cfd87e4ed6facf588bfca20fe2503dd71Tsu Chiang Chuang}
217