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