121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff/*
221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff * Copyright (C) 2012 The Android Open Source Project
321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff *
421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff * Licensed under the Apache License, Version 2.0 (the "License");
521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff * you may not use this file except in compliance with the License.
621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff * You may obtain a copy of the License at
721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff *
821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff *      http://www.apache.org/licenses/LICENSE-2.0
921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff *
1021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff * Unless required by applicable law or agreed to in writing, software
1121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff * distributed under the License is distributed on an "AS IS" BASIS,
1221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff * See the License for the specific language governing permissions and
1421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff * limitations under the License.
1521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff */
1621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
1721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriffpackage android.net.wifi.p2p.nsd;
1821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
1921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriffimport android.net.nsd.DnsSdTxtRecord;
2021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriffimport android.text.TextUtils;
2121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
2221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriffimport java.util.ArrayList;
2321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriffimport java.util.HashMap;
2421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriffimport java.util.List;
25fea17de7aaa5729d3111102b2734b158403d2780Jeff Sharkeyimport java.util.Locale;
2621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriffimport java.util.Map;
2721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
2821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff/**
298bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff * A class for storing Bonjour service information that is advertised
308bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff * over a Wi-Fi peer-to-peer setup.
318bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff *
328bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff * {@see android.net.wifi.p2p.WifiP2pManager#addLocalService}
338bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff * {@see android.net.wifi.p2p.WifiP2pManager#removeLocalService}
348bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff * {@see WifiP2pServiceInfo}
358bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff * {@see WifiP2pUpnpServiceInfo}
3621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff */
378bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriffpublic class WifiP2pDnsSdServiceInfo extends WifiP2pServiceInfo {
3821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
3921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    /**
4021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * Bonjour version 1.
4121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @hide
4221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     */
4321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    public static final int VERSION_1 = 0x01;
4421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
4521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    /**
4621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * Pointer record.
4721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @hide
4821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     */
4921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    public static final int DNS_TYPE_PTR = 12;
5021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
5121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    /**
5221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * Text record.
5321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @hide
5421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     */
5521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    public static final int DNS_TYPE_TXT = 16;
5621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
5721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    /**
5821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * virtual memory packet.
5921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * see E.3 of the Wi-Fi Direct technical specification for the detail.<br>
6021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * Key: domain name Value: pointer address.<br>
6121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     */
6221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    private final static Map<String, String> sVmPacket;
6321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
6421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    static {
6521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        sVmPacket = new HashMap<String, String>();
6621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        sVmPacket.put("_tcp.local.", "c00c");
6721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        sVmPacket.put("local.", "c011");
6821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        sVmPacket.put("_udp.local.", "c01c");
6921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    }
7021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
7121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    /**
7221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * This constructor is only used in newInstance().
7321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     *
7421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @param queryList
7521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     */
768bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff    private WifiP2pDnsSdServiceInfo(List<String> queryList) {
7721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        super(queryList);
7821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    }
7921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
8021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    /**
818bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff     * Create a Bonjour service information object.
8221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     *
8321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @param instanceName instance name.<br>
8421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     *  e.g) "MyPrinter"
858bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff     * @param serviceType service type.<br>
868bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff     *  e.g) "_ipp._tcp"
87527ba07b637cedf206fec0d3b0cf92141700a23cIrfan Sheriff     * @param txtMap TXT record with key/value pair in a map confirming to format defined at
888bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff     * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt
8921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @return Bonjour service information object
9021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     */
918bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff    public static WifiP2pDnsSdServiceInfo newInstance(String instanceName,
92527ba07b637cedf206fec0d3b0cf92141700a23cIrfan Sheriff            String serviceType, Map<String, String> txtMap) {
938bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff        if (TextUtils.isEmpty(instanceName) || TextUtils.isEmpty(serviceType)) {
9421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff            throw new IllegalArgumentException(
958bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff                    "instance name or service type cannot be empty");
9621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        }
9721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
98527ba07b637cedf206fec0d3b0cf92141700a23cIrfan Sheriff        DnsSdTxtRecord txtRecord = new DnsSdTxtRecord();
99527ba07b637cedf206fec0d3b0cf92141700a23cIrfan Sheriff        if (txtMap != null) {
100527ba07b637cedf206fec0d3b0cf92141700a23cIrfan Sheriff            for (String key : txtMap.keySet()) {
101527ba07b637cedf206fec0d3b0cf92141700a23cIrfan Sheriff                txtRecord.set(key, txtMap.get(key));
102527ba07b637cedf206fec0d3b0cf92141700a23cIrfan Sheriff            }
10321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        }
10421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
10521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        ArrayList<String> queries = new ArrayList<String>();
1068bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff        queries.add(createPtrServiceQuery(instanceName, serviceType));
1078bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff        queries.add(createTxtServiceQuery(instanceName, serviceType, txtRecord));
10821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
1098bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff        return new WifiP2pDnsSdServiceInfo(queries);
11021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    }
11121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
11221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    /**
11321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * Create wpa_supplicant service query for PTR record.
11421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     *
11521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @param instanceName instance name.<br>
11621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     *  e.g) "MyPrinter"
1178bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff     * @param serviceType service type.<br>
1188bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff     *  e.g) "_ipp._tcp"
11921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @return wpa_supplicant service query.
12021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     */
12121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    private static String createPtrServiceQuery(String instanceName,
1228bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff            String serviceType) {
12321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
12421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        StringBuffer sb = new StringBuffer();
12521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        sb.append("bonjour ");
1268bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff        sb.append(createRequest(serviceType + ".local.", DNS_TYPE_PTR, VERSION_1));
12721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        sb.append(" ");
12821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
12921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        byte[] data = instanceName.getBytes();
130fea17de7aaa5729d3111102b2734b158403d2780Jeff Sharkey        sb.append(String.format(Locale.US, "%02x", data.length));
13121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        sb.append(WifiP2pServiceInfo.bin2HexStr(data));
13221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        // This is the start point of this response.
13321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        // Therefore, it indicates the request domain name.
13421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        sb.append("c027");
13521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        return sb.toString();
13621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    }
13721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
13821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    /**
13921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * Create wpa_supplicant service query for TXT record.
14021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     *
14121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @param instanceName instance name.<br>
14221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     *  e.g) "MyPrinter"
1438bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff     * @param serviceType service type.<br>
1448bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff     *  e.g) "_ipp._tcp"
14521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @param txtRecord TXT record.<br>
14621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @return wpa_supplicant service query.
14721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     */
1488bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff    private static String createTxtServiceQuery(String instanceName,
1498bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff            String serviceType,
15021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff            DnsSdTxtRecord txtRecord) {
15121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
15221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
15321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        StringBuffer sb = new StringBuffer();
15421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        sb.append("bonjour ");
15521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
1568bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff        sb.append(createRequest((instanceName + "." + serviceType + ".local."),
15721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff                DNS_TYPE_TXT, VERSION_1));
15821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        sb.append(" ");
15921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        byte[] rawData = txtRecord.getRawData();
16021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        if (rawData.length == 0) {
16121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff            sb.append("00");
16221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        } else {
16321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff            sb.append(bin2HexStr(rawData));
16421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        }
16521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        return sb.toString();
16621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    }
16721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
16821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    /**
16921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * Create bonjour service discovery request.
17021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     *
17121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @param dnsName dns name
17221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @param dnsType dns type
17321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @param version version number
17421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @hide
17521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     */
17621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    static String createRequest(String dnsName, int dnsType, int version) {
17721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        StringBuffer sb = new StringBuffer();
17821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
17921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        /*
18021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff         * The request format is as follows.
18121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff         * ________________________________________________
18221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff         * |  Encoded and Compressed dns name (variable)  |
18321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff         * ________________________________________________
18421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff         * |   Type (2)           | Version (1) |
18521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff         */
1868bf825f48fde77cb2feb8720aac17093581bb085Irfan Sheriff        if (dnsType == WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT) {
187ee00b353a4070a9ddbdf67fa715dc84e7282f7c2Elliott Hughes            dnsName = dnsName.toLowerCase(Locale.ROOT); // TODO: is this right?
18821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        }
18921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        sb.append(compressDnsName(dnsName));
190fea17de7aaa5729d3111102b2734b158403d2780Jeff Sharkey        sb.append(String.format(Locale.US, "%04x", dnsType));
191fea17de7aaa5729d3111102b2734b158403d2780Jeff Sharkey        sb.append(String.format(Locale.US, "%02x", version));
19221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
19321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        return sb.toString();
19421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    }
19521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
19621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    /**
19721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * Compress DNS data.
19821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     *
19921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * see E.3 of the Wi-Fi Direct technical specification for the detail.
20021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     *
20121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @param dnsName dns name
20221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     * @return compressed dns name
20321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff     */
20421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    private static String compressDnsName(String dnsName) {
20521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        StringBuffer sb = new StringBuffer();
20621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
20721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        // The domain name is replaced with a pointer to a prior
20821ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        // occurrence of the same name in virtual memory packet.
20921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        while (true) {
21021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff            String data = sVmPacket.get(dnsName);
21121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff            if (data != null) {
21221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff                sb.append(data);
21321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff                break;
21421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff            }
21521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff            int i = dnsName.indexOf('.');
21621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff            if (i == -1) {
21721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff                if (dnsName.length() > 0) {
218fea17de7aaa5729d3111102b2734b158403d2780Jeff Sharkey                    sb.append(String.format(Locale.US, "%02x", dnsName.length()));
21921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff                    sb.append(WifiP2pServiceInfo.bin2HexStr(dnsName.getBytes()));
22021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff                }
22121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff                // for a sequence of labels ending in a zero octet
22221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff                sb.append("00");
22321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff                break;
22421ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff            }
22521ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff
22621ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff            String name = dnsName.substring(0, i);
22721ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff            dnsName = dnsName.substring(i + 1);
228fea17de7aaa5729d3111102b2734b158403d2780Jeff Sharkey            sb.append(String.format(Locale.US, "%02x", name.length()));
22921ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff            sb.append(WifiP2pServiceInfo.bin2HexStr(name.getBytes()));
23021ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        }
23121ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff        return sb.toString();
23221ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff    }
23321ba8153325e010224c6bc75a0acdc98b6ca82e8Irfan Sheriff}
234