DnsPinger.java revision a7bc1135c270fd4a84ab7ad45b7194e9b580300e
1bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy/* 2bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * Copyright (C) 2011 The Android Open Source Project 3bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * 4bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * Licensed under the Apache License, Version 2.0 (the "License"); 5bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * you may not use this file except in compliance with the License. 6bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * You may obtain a copy of the License at 7bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * 8bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * http://www.apache.org/licenses/LICENSE-2.0 9bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * 10bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * Unless required by applicable law or agreed to in writing, software 11bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * distributed under the License is distributed on an "AS IS" BASIS, 12bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * See the License for the specific language governing permissions and 14bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * limitations under the License. 15bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy */ 16bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 17a7bc1135c270fd4a84ab7ad45b7194e9b580300eIsaac Levypackage android.net; 18bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 19bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport android.content.Context; 20bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport android.net.ConnectivityManager; 21bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport android.net.LinkProperties; 223541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levyimport android.net.NetworkUtils; 23bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport android.os.SystemClock; 243541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levyimport android.provider.Settings; 25bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport android.util.Slog; 26bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 27bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.net.DatagramPacket; 28bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.net.DatagramSocket; 29bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.net.InetAddress; 303ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levyimport java.net.NetworkInterface; 31bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.net.SocketTimeoutException; 32bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.util.Collection; 33bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.util.Random; 34bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 35bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy/** 36bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * Performs a simple DNS "ping" by sending a "server status" query packet to the 37bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * DNS server. As long as the server replies, we consider it a success. 38bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * <p> 39bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * We do not use a simple hostname lookup because that could be cached and the 40bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * API may not differentiate between a time out and a failure lookup (which we 41bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * really care about). 42bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * <p> 433541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy * TODO : More general API. Socket does not bind to specified connection type 44bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * TODO : Choice of DNS query location - current looks up www.android.com 45bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * 46bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * @hide 47bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy */ 48bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levypublic final class DnsPinger { 49bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private static final boolean V = true; 50bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 51bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy /** Number of bytes for the query */ 523ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy private static final int DNS_QUERY_BASE_SIZE = 32; 53bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 54bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy /** The DNS port */ 55bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private static final int DNS_PORT = 53; 56bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 57bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy /** Used to generate IDs */ 58bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private static Random sRandom = new Random(); 59bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 60bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private ConnectivityManager mConnectivityManager = null; 61bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private Context mContext; 62b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy private int mConnectionType; 633541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy private InetAddress mDefaultDns; 64bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 65bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private String TAG; 66bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 67b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy /** 683541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy * @param connectionType The connection type from {@link ConnectivityManager} 69b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy */ 70b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy public DnsPinger(String TAG, Context context, int connectionType) { 71bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy mContext = context; 72b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy mConnectionType = connectionType; 733541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy if (!ConnectivityManager.isNetworkTypeValid(connectionType)) { 743541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy Slog.e(TAG, "Invalid connectionType in constructor: " + connectionType); 753541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy } 76bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy this.TAG = TAG; 773541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy 783541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy mDefaultDns = getDefaultDns(); 79bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 80bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 81bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy /** 823541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy * @return The first DNS in the link properties of the specified connection 833541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy * type or the default system DNS if the link properties has null 843541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy * dns set. Should not be null. 85bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy */ 86bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy public InetAddress getDns() { 873ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy LinkProperties curLinkProps = getCurrentLinkProperties(); 883541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy if (curLinkProps == null) { 893541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy Slog.e(TAG, "getCurLinkProperties:: LP for type" + mConnectionType + " is null!"); 903541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy return mDefaultDns; 913541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy } 923541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy 933541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy Collection<InetAddress> dnses = curLinkProps.getDnses(); 943541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy if (dnses == null || dnses.size() == 0) { 953541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy Slog.v(TAG, "getDns::LinkProps has null dns - returning default"); 963541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy return mDefaultDns; 973541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy } 98bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 99bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return dnses.iterator().next(); 100bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 101bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 1023ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy private LinkProperties getCurrentLinkProperties() { 1033ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy if (mConnectivityManager == null) { 1043ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy mConnectivityManager = (ConnectivityManager) mContext.getSystemService( 1053ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy Context.CONNECTIVITY_SERVICE); 1063ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy } 1073ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy 1083ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy return mConnectivityManager.getLinkProperties(mConnectionType); 1093ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy } 1103ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy 1113541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy private InetAddress getDefaultDns() { 1123541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy String dns = Settings.Secure.getString(mContext.getContentResolver(), 1133541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy Settings.Secure.DEFAULT_DNS_SERVER); 1143541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy if (dns == null || dns.length() == 0) { 1153541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy dns = mContext.getResources().getString( 1163541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy com.android.internal.R.string.config_default_dns_server); 1173541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy } 1183541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy try { 1193541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy return NetworkUtils.numericToInetAddress(dns); 1203541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy } catch (IllegalArgumentException e) { 1213541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy Slog.w(TAG, "getDefaultDns::malformed default dns address"); 1223541ce04ddb1b559ac9e79b5067c93b910f22955Isaac Levy return null; 123b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy } 124b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy } 125b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy 126bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy /** 127bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * @return time to response. Negative value on error. 128bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy */ 129bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy public long pingDns(InetAddress dnsAddress, int timeout) { 130bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy DatagramSocket socket = null; 131bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy try { 132bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket = new DatagramSocket(); 133bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 134bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Set some socket properties 135bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket.setSoTimeout(timeout); 136bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 1373ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy // Try to bind but continue ping if bind fails 1383ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy try { 1393ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy socket.setNetworkInterface(NetworkInterface.getByName( 1403ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy getCurrentLinkProperties().getInterfaceName())); 1413ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy } catch (Exception e) { 1423ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy Slog.d(TAG,"pingDns::Error binding to socket", e); 1433ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy } 1443ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy 1453ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy byte[] buf = constructQuery(); 146bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 147bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Send the DNS query 148bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 149bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy DatagramPacket packet = new DatagramPacket(buf, 150bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf.length, dnsAddress, DNS_PORT); 151bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy long start = SystemClock.elapsedRealtime(); 152bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket.send(packet); 153bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 154bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Wait for reply (blocks for the above timeout) 155bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy DatagramPacket replyPacket = new DatagramPacket(buf, buf.length); 156bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket.receive(replyPacket); 157bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 158bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // If a timeout occurred, an exception would have been thrown. We 159bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // got a reply! 160bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return SystemClock.elapsedRealtime() - start; 161bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 162bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } catch (SocketTimeoutException e) { 163bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Squelch this exception. 164bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return -1; 165bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } catch (Exception e) { 166bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy if (V) { 167bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy Slog.v(TAG, "DnsPinger.pingDns got socket exception: ", e); 168bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 169bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return -2; 170bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } finally { 171bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy if (socket != null) { 172bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket.close(); 173bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 174bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 175bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 176bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 177bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 1783ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy /** 1793ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy * @return google.com DNS query packet 1803ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy */ 1813ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy private static byte[] constructQuery() { 1823ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy byte[] buf = new byte[DNS_QUERY_BASE_SIZE]; 183bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 184bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [0-1] bytes are an ID, generate random ID for this query 185bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[0] = (byte) sRandom.nextInt(256); 186bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[1] = (byte) sRandom.nextInt(256); 187bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 188bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [2-3] bytes are for flags. 1893ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy buf[2] = 0x01; // Recursion desired 190bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 1913ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy // [4-5] bytes are for number of queries (QCOUNT) 1923ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy buf[5] = 0x01; 193bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 194bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [6-7] [8-9] [10-11] are all counts of other fields we don't use 195bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 196bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [12-15] for www 197bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy writeString(buf, 12, "www"); 198bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 1993ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy // [16-22] for google 2003ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy writeString(buf, 16, "google"); 2013ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy 2023ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy // [23-26] for com 2033ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy writeString(buf, 23, "com"); 2043ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy 2053ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy // [27] is a null byte terminator byte for the url 206bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 2073ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy // [28-29] bytes are for QTYPE, set to 1 = A (host address) 2083ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy buf[29] = 0x01; 209bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 2103ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy // [30-31] bytes are for QCLASS, set to 1 = IN (internet) 2113ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy buf[31] = 0x01; 212bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 2133ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy return buf; 214bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 215bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 2163ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy /** 2173ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy * Writes the string's length and its contents to the buffer 2183ee9d05d971cbf0c720057aec54ffac289af40feIsaac Levy */ 219bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private static void writeString(byte[] buf, int startPos, String string) { 220bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy int pos = startPos; 221bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 222bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Write the length first 223bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[pos++] = (byte) string.length(); 224bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy for (int i = 0; i < string.length(); i++) { 225bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[pos++] = (byte) string.charAt(i); 226bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 227bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 228bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy} 229