From 8bf825f48fde77cb2feb8720aac17093581bb085 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Sat, 14 Apr 2012 14:05:19 -0700 Subject: Open p2p pre-association service discovery API This allows applications to filter out the devices by the services supported for the purpose of establishing a connection. so, a game app can connect to devices that support the game, and a media streaming app can filter and connect only to the available media display devices Change-Id: Ia792e292d2ca771beeb4ca3b007a047527c19229 --- wifi/java/android/net/wifi/p2p/WifiP2pManager.java | 161 ++++++----- .../wifi/p2p/nsd/WifiP2pBonjourServiceInfo.java | 223 --------------- .../wifi/p2p/nsd/WifiP2pBonjourServiceRequest.java | 102 ------- .../p2p/nsd/WifiP2pBonjourServiceResponse.java | 313 --------------------- .../net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java | 229 +++++++++++++++ .../wifi/p2p/nsd/WifiP2pDnsSdServiceRequest.java | 107 +++++++ .../wifi/p2p/nsd/WifiP2pDnsSdServiceResponse.java | 313 +++++++++++++++++++++ .../net/wifi/p2p/nsd/WifiP2pServiceInfo.java | 11 +- .../net/wifi/p2p/nsd/WifiP2pServiceRequest.java | 82 +++--- .../net/wifi/p2p/nsd/WifiP2pServiceResponse.java | 4 +- .../net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java | 9 +- .../wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java | 10 +- 12 files changed, 800 insertions(+), 764 deletions(-) delete mode 100644 wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceInfo.java delete mode 100644 wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceRequest.java delete mode 100644 wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceResponse.java create mode 100644 wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java create mode 100644 wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceRequest.java create mode 100644 wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceResponse.java (limited to 'wifi/java/android') diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java index 35f37a8..df14bb9 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java @@ -22,8 +22,8 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.nsd.DnsSdTxtRecord; -import android.net.wifi.p2p.nsd.WifiP2pBonjourServiceInfo; -import android.net.wifi.p2p.nsd.WifiP2pBonjourServiceResponse; +import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo; +import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceResponse; import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; import android.net.wifi.p2p.nsd.WifiP2pServiceRequest; import android.net.wifi.p2p.nsd.WifiP2pServiceResponse; @@ -56,21 +56,20 @@ import java.util.List; * callbacks provided by the application. The application needs to do an initialization with * {@link #initialize} before doing any p2p operation. * - *

Application actions {@link #discoverPeers}, {@link #connect}, {@link #cancelConnect}, - * {@link #createGroup} and {@link #removeGroup} need a {@link ActionListener} instance for - * receiving callbacks {@link ActionListener#onSuccess} or {@link ActionListener#onFailure}. - * Action callbacks indicate whether the initiation of the action was a success or a failure. + *

Most application calls need a {@link ActionListener} instance for receiving callbacks + * {@link ActionListener#onSuccess} or {@link ActionListener#onFailure}. Action callbacks + * indicate whether the initiation of the action was a success or a failure. * Upon failure, the reason of failure can be one of {@link #ERROR}, {@link #P2P_UNSUPPORTED} * or {@link #BUSY}. * *

An application can initiate discovery of peers with {@link #discoverPeers}. An initiated * discovery request from an application stays active until the device starts connecting to a peer - * or forms a p2p group. The {@link ActionListener} callbacks provide feedback on whether the - * discovery initiation was successful or failure. Additionally, applications can listen - * to {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent action to know when the peer list changes. + * ,forms a p2p group or there is an explicit {@link #stopPeerDiscovery}. + * Applications can listen to {@link #WIFI_P2P_DISCOVERY_CHANGED_ACTION} to know if a peer-to-peer + * discovery is running or stopped. Additionally, {@link #WIFI_P2P_PEERS_CHANGED_ACTION} indicates + * if the peer list has changed. * - *

When the peer list change intent {@link #WIFI_P2P_PEERS_CHANGED_ACTION} is received - * or when an application needs to fetch the current list of peers, it can request the list + *

When an application needs to fetch the current list of peers, it can request the list * of peers with {@link #requestPeers}. When the peer list is available * {@link PeerListListener#onPeersAvailable} is called with the device list. * @@ -78,7 +77,7 @@ import java.util.List; * {@link WifiP2pConfig} for details on setting up the configuration. For communication with legacy * Wi-Fi devices that do not support p2p, an app can create a group using {@link #createGroup} * which creates an access point whose details can be fetched with {@link #requestGroupInfo}. -* + * *

After a successful group formation through {@link #createGroup} or through {@link #connect}, * use {@link #requestConnectionInfo} to fetch the connection details. The connection info * {@link WifiP2pInfo} contains the address of the group owner @@ -86,8 +85,36 @@ import java.util.List; * if the current device is a p2p group owner. A p2p client can thus communicate with * the p2p group owner through a socket connection. * - *

Android has no platform support for service discovery yet, so applications could - * run a service discovery protocol to discover services on the peer-to-peer netework. + *

With peer discovery using {@link #discoverPeers}, an application discovers the neighboring + * peers, but has no good way to figure out which peer to establish a connection with. For example, + * if a game application is interested in finding all the neighboring peers that are also running + * the same game, it has no way to find out until after the connection is setup. Pre-association + * service discovery is meant to address this issue of filtering the peers based on the running + * services. + * + *

With pre-association service discovery, an application can advertise a service for a + * application on a peer device prior to a connection setup between the devices. + * Currently, DNS based service discovery (Bonjour) and Upnp are the higher layer protocols + * supported. Get Bonjour resources at dns-sd.org and Upnp resources at upnp.org + * As an example, a video application can discover a Upnp capable media renderer + * prior to setting up a Wi-fi p2p connection with the device. + * + *

An application can advertise a Upnp or a Bonjour service with a call to + * {@link #addLocalService}. After a local service is added, + * the framework automatically responds to a peer application discovering the service prior + * to establishing a p2p connection. A call to {@link #removeLocalService} removes a local + * service and {@link #clearLocalServices} can be used to clear all local services. + * + *

An application that is looking for peer devices that support certain services + * can do so with a call to {@link #discoverServices}. Prior to initiating the discovery, + * application can add service discovery request with a call to {@link #addServiceRequest}, + * remove a service discovery request with a call to {@link #removeServiceRequest} or clear + * all requests with a call to {@link #clearServiceRequests}. When no service requests remain, + * a previously running service discovery will stop. + * + * The application is notified of a result of service discovery request through listener callbacks + * set through {@link #setDnsSdResponseListeners} for Bonjour or + * {@link #setUpnpServiceResponseListener} for Upnp. * *

Note: * Registering an application handler with {@link #initialize} requires the permissions @@ -443,30 +470,28 @@ public class WifiP2pManager { /** * Interface for callback invocation when service discovery response other than - * UPnP or Bonjour is received - * @hide + * Upnp or Bonjour is received */ public interface ServiceResponseListener { /** * The requested service response is available. * - * @param serviceType service type. see the service type of - * {@link WifiP2pServiceInfo} + * @param protocolType protocol type. currently only + * {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}. * @param responseData service discovery response data based on the requested * service protocol type. The format depends on the service type. * @param srcDevice source device. */ - public void onServiceAvailable(int serviceType, + public void onServiceAvailable(int protocolType, byte[] responseData, WifiP2pDevice srcDevice); } /** * Interface for callback invocation when Bonjour service discovery response * is received - * @hide */ - public interface BonjourServiceResponseListener { + public interface DnsSdServiceResponseListener { /** * The requested Bonjour service response is available. @@ -479,7 +504,7 @@ public class WifiP2pManager { * e.g) "_ipp._tcp.local." * @param srcDevice source device. */ - public void onBonjourServiceAvailable(String instanceName, + public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice srcDevice); } @@ -487,9 +512,8 @@ public class WifiP2pManager { /** * Interface for callback invocation when Bonjour TXT record is available * for a service - * @hide */ - public interface BonjourTxtRecordListener { + public interface DnsSdTxtRecordListener { /** * The requested Bonjour service response is available. * @@ -501,7 +525,7 @@ public class WifiP2pManager { * @param record txt record. * @param srcDevice source device. */ - public void onBonjourTxtRecordAvailable(String fullDomainName, + public void onDnsSdTxtRecordAvailable(String fullDomainName, DnsSdTxtRecord record, WifiP2pDevice srcDevice); } @@ -509,7 +533,6 @@ public class WifiP2pManager { /** * Interface for callback invocation when upnp service discovery response * is received - * @hide * */ public interface UpnpServiceResponseListener { @@ -542,8 +565,8 @@ public class WifiP2pManager { private final static int INVALID_LISTENER_KEY = 0; private ChannelListener mChannelListener; private ServiceResponseListener mServRspListener; - private BonjourServiceResponseListener mBonjourServRspListener; - private BonjourTxtRecordListener mBonjourTxtListener; + private DnsSdServiceResponseListener mDnsSdServRspListener; + private DnsSdTxtRecordListener mDnsSdTxtListener; private UpnpServiceResponseListener mUpnpServRspListener; private HashMap mListenerMap = new HashMap(); private Object mListenerMapLock = new Object(); @@ -632,8 +655,8 @@ public class WifiP2pManager { } private void handleServiceResponse(WifiP2pServiceResponse resp) { - if (resp instanceof WifiP2pBonjourServiceResponse) { - handleBonjourServiceResponse((WifiP2pBonjourServiceResponse)resp); + if (resp instanceof WifiP2pDnsSdServiceResponse) { + handleDnsSdServiceResponse((WifiP2pDnsSdServiceResponse)resp); } else if (resp instanceof WifiP2pUpnpServiceResponse) { if (mUpnpServRspListener != null) { handleUpnpServiceResponse((WifiP2pUpnpServiceResponse)resp); @@ -651,17 +674,17 @@ public class WifiP2pManager { resp.getSrcDevice()); } - private void handleBonjourServiceResponse(WifiP2pBonjourServiceResponse resp) { - if (resp.getDnsType() == WifiP2pBonjourServiceInfo.DNS_TYPE_PTR) { - if (mBonjourServRspListener != null) { - mBonjourServRspListener.onBonjourServiceAvailable( + private void handleDnsSdServiceResponse(WifiP2pDnsSdServiceResponse resp) { + if (resp.getDnsType() == WifiP2pDnsSdServiceInfo.DNS_TYPE_PTR) { + if (mDnsSdServRspListener != null) { + mDnsSdServRspListener.onDnsSdServiceAvailable( resp.getInstanceName(), resp.getDnsQueryName(), resp.getSrcDevice()); } - } else if (resp.getDnsType() == WifiP2pBonjourServiceInfo.DNS_TYPE_TXT) { - if (mBonjourTxtListener != null) { - mBonjourTxtListener.onBonjourTxtRecordAvailable( + } else if (resp.getDnsType() == WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT) { + if (mDnsSdTxtListener != null) { + mDnsSdTxtListener.onDnsSdTxtRecordAvailable( resp.getDnsQueryName(), resp.getTxtRecord(), resp.getSrcDevice()); @@ -749,10 +772,16 @@ public class WifiP2pManager { c.mAsyncChannel.sendMessage(DISCOVER_PEERS, 0, c.putListener(listener)); } - /** - * TODO: Add more documentation before opening up - * Cancel peer discovery - * @hide + /** + * Stop an ongoing peer discovery + * + *

The function call immediately returns after sending a stop request + * to the framework. The application is notified of a success or failure to initiate + * stop through listener callbacks {@link ActionListener#onSuccess} or + * {@link ActionListener#onFailure}. + * + * @param c is the channel created at {@link #initialize} + * @param listener for callbacks on success or failure. Can be null. */ public void stopPeerDiscovery(Channel c, ActionListener listener) { checkChannel(c); @@ -843,27 +872,25 @@ public class WifiP2pManager { } /** - * Register a local service of service discovery. + * Register a local service for service discovery. If a local service is registered, + * the framework automatically responds to a service discovery request from a peer. * *

The function call immediately returns after sending a request to add a local * service to the framework. The application is notified of a success or failure to * add service through listener callbacks {@link ActionListener#onSuccess} or * {@link ActionListener#onFailure}. * - *

The service information is set through the subclass of {@link WifiP2pServiceInfo}.
- * e.g ) {@link WifiP2pUpnpServiceInfo#newInstance} or - * {@link WifiP2pBonjourServiceInfo#newInstance} + *

The service information is set through {@link WifiP2pServiceInfo}.
+ * or its subclass calls {@link WifiP2pUpnpServiceInfo#newInstance} or + * {@link WifiP2pDnsSdServiceInfo#newInstance} for a Upnp or Bonjour service + * respectively * - *

If a local service is added, the framework responds the appropriate service discovery - * request automatically. - * - *

These service information will be clear when p2p is disabled or call + *

The service information can be cleared with calls to * {@link #removeLocalService} or {@link #clearLocalServices}. * * @param c is the channel created at {@link #initialize} * @param servInfo is a local service information. * @param listener for callbacks on success or failure. Can be null. - * @hide */ public void addLocalService(Channel c, WifiP2pServiceInfo servInfo, ActionListener listener) { checkChannel(c); @@ -872,7 +899,7 @@ public class WifiP2pManager { } /** - * Unregister a specified local service of service discovery. + * Remove a registered local service added with {@link #addLocalService} * *

The function call immediately returns after sending a request to remove a * local service to the framework. The application is notified of a success or failure to @@ -882,7 +909,6 @@ public class WifiP2pManager { * @param c is the channel created at {@link #initialize} * @param servInfo is the local service information. * @param listener for callbacks on success or failure. Can be null. - * @hide */ public void removeLocalService(Channel c, WifiP2pServiceInfo servInfo, ActionListener listener) { @@ -901,7 +927,6 @@ public class WifiP2pManager { * * @param c is the channel created at {@link #initialize} * @param listener for callbacks on success or failure. Can be null. - * @hide */ public void clearLocalServices(Channel c, ActionListener listener) { checkChannel(c); @@ -910,12 +935,14 @@ public class WifiP2pManager { /** * Register a callback to be invoked on receiving service discovery response. + * Used only for vendor specific protocol right now. For Bonjour or Upnp, use + * {@link #setDnsSdResponseListeners} or {@link #setUpnpServiceResponseListener} + * respectively. * *

see {@link #discoverServices} for the detail. * * @param c is the channel created at {@link #initialize} * @param listener for callbacks on receiving service discovery response. - * @hide */ public void setServiceResponseListener(Channel c, ServiceResponseListener listener) { @@ -930,15 +957,14 @@ public class WifiP2pManager { *

see {@link #discoverServices} for the detail. * * @param c - * @param servlistener is for listening to a Bonjour service response - * @param txtListener is for listening to a Bonjour TXT record - * @hide + * @param servListener is for listening to a Bonjour service response + * @param txtListener is for listening to a Bonjour TXT record response */ - public void setBonjourResponseListeners(Channel c, - BonjourServiceResponseListener servListener, BonjourTxtRecordListener txtListener) { + public void setDnsSdResponseListeners(Channel c, + DnsSdServiceResponseListener servListener, DnsSdTxtRecordListener txtListener) { checkChannel(c); - c.mBonjourServRspListener = servListener; - c.mBonjourTxtListener = txtListener; + c.mDnsSdServRspListener = servListener; + c.mDnsSdTxtListener = txtListener; } /** @@ -949,7 +975,6 @@ public class WifiP2pManager { * * @param c is the channel created at {@link #initialize} * @param listener for callbacks on receiving service discovery response. - * @hide */ public void setUpnpServiceResponseListener(Channel c, UpnpServiceResponseListener listener) { @@ -971,11 +996,10 @@ public class WifiP2pManager { * *

The application is notified of the response against the service discovery request * through listener callbacks registered by {@link #setServiceResponseListener} or - * {@link #setBonjourServiceResponseListener}, or {@link #setUpnpServiceResponseListener}. + * {@link #setDnsSdResponseListeners}, or {@link #setUpnpServiceResponseListener}. * * @param c is the channel created at {@link #initialize} * @param listener for callbacks on success or failure. Can be null. - * @hide */ public void discoverServices(Channel c, ActionListener listener) { checkChannel(c); @@ -993,14 +1017,13 @@ public class WifiP2pManager { *

After service discovery request is added, you can initiate service discovery by * {@link #discoverServices}. * - *

These information will be clear when wifi p2p is disabled or + *

The added service requests can be cleared with calls to * {@link #removeServiceRequest(Channel, WifiP2pServiceRequest, ActionListener)} or - * {@link #clearServiceRequests(Channel, ActionListener)} is called. + * {@link #clearServiceRequests(Channel, ActionListener)}. * * @param c is the channel created at {@link #initialize} * @param req is the service discovery request. * @param listener for callbacks on success or failure. Can be null. - * @hide */ public void addServiceRequest(Channel c, WifiP2pServiceRequest req, ActionListener listener) { @@ -1011,7 +1034,7 @@ public class WifiP2pManager { } /** - * Remove a specified service discovery request. + * Remove a specified service discovery request added with {@link #addServiceRequest} * *

The function call immediately returns after sending a request to remove service * discovery request to the framework. The application is notified of a success or failure to @@ -1021,7 +1044,6 @@ public class WifiP2pManager { * @param c is the channel created at {@link #initialize} * @param req is the service discovery request. * @param listener for callbacks on success or failure. Can be null. - * @hide */ public void removeServiceRequest(Channel c, WifiP2pServiceRequest req, ActionListener listener) { @@ -1041,7 +1063,6 @@ public class WifiP2pManager { * * @param c is the channel created at {@link #initialize} * @param listener for callbacks on success or failure. Can be null. - * @hide */ public void clearServiceRequests(Channel c, ActionListener listener) { checkChannel(c); diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceInfo.java deleted file mode 100644 index ed278d5..0000000 --- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceInfo.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.wifi.p2p.nsd; - -import android.net.nsd.DnsSdTxtRecord; -import android.text.TextUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * A class for Bonjour service information. - * @hide - */ -public class WifiP2pBonjourServiceInfo extends WifiP2pServiceInfo { - - /** - * Bonjour version 1. - * @hide - */ - public static final int VERSION_1 = 0x01; - - /** - * Pointer record. - * @hide - */ - public static final int DNS_TYPE_PTR = 12; - - /** - * Text record. - * @hide - */ - public static final int DNS_TYPE_TXT = 16; - - /** - * virtual memory packet. - * see E.3 of the Wi-Fi Direct technical specification for the detail.
- * Key: domain name Value: pointer address.
- */ - private final static Map sVmPacket; - - static { - sVmPacket = new HashMap(); - sVmPacket.put("_tcp.local.", "c00c"); - sVmPacket.put("local.", "c011"); - sVmPacket.put("_udp.local.", "c01c"); - } - - /** - * This constructor is only used in newInstance(). - * - * @param queryList - */ - private WifiP2pBonjourServiceInfo(List queryList) { - super(queryList); - } - - /** - * Create Bonjour service information object. - * - * @param instanceName instance name.
- * e.g) "MyPrinter" - * @param registrationType registration type.
- * e.g) "_ipp._tcp.local." - * @param txtRecord text record. - * @return Bonjour service information object - */ - public static WifiP2pBonjourServiceInfo newInstance(String instanceName, - String registrationType, DnsSdTxtRecord txtRecord) { - if (TextUtils.isEmpty(instanceName) || TextUtils.isEmpty(registrationType)) { - throw new IllegalArgumentException( - "instance name or registration type cannot be empty"); - } - - if (txtRecord == null) { - txtRecord = new DnsSdTxtRecord(); - } - - ArrayList queries = new ArrayList(); - queries.add(createPtrServiceQuery(instanceName, registrationType)); - queries.add(createTxtServiceQuery(instanceName, registrationType, txtRecord)); - - return new WifiP2pBonjourServiceInfo(queries); - } - - /** - * Create wpa_supplicant service query for PTR record. - * - * @param instanceName instance name.
- * e.g) "MyPrinter" - * @param registrationType registration type.
- * e.g) "_ipp._tcp.local." - * @return wpa_supplicant service query. - */ - private static String createPtrServiceQuery(String instanceName, - String registrationType) { - - StringBuffer sb = new StringBuffer(); - sb.append("bonjour "); - sb.append(createRequest(registrationType, DNS_TYPE_PTR, VERSION_1)); - sb.append(" "); - - byte[] data = instanceName.getBytes(); - sb.append(String.format("%02x", data.length)); - sb.append(WifiP2pServiceInfo.bin2HexStr(data)); - // This is the start point of this response. - // Therefore, it indicates the request domain name. - sb.append("c027"); - return sb.toString(); - } - - /** - * Create wpa_supplicant service query for TXT record. - * - * @param instanceName instance name.
- * e.g) "MyPrinter" - * @param registrationType registration type.
- * e.g) "_ipp._tcp.local." - * @param txtRecord TXT record.
- * @return wpa_supplicant service query. - */ - public static String createTxtServiceQuery(String instanceName, - String registrationType, - DnsSdTxtRecord txtRecord) { - - - StringBuffer sb = new StringBuffer(); - sb.append("bonjour "); - - sb.append(createRequest((instanceName + "." + registrationType), - DNS_TYPE_TXT, VERSION_1)); - sb.append(" "); - byte[] rawData = txtRecord.getRawData(); - if (rawData.length == 0) { - sb.append("00"); - } else { - sb.append(bin2HexStr(rawData)); - } - return sb.toString(); - } - - /** - * Create bonjour service discovery request. - * - * @param dnsName dns name - * @param dnsType dns type - * @param version version number - * @hide - */ - static String createRequest(String dnsName, int dnsType, int version) { - StringBuffer sb = new StringBuffer(); - - /* - * The request format is as follows. - * ________________________________________________ - * | Encoded and Compressed dns name (variable) | - * ________________________________________________ - * | Type (2) | Version (1) | - */ - if (dnsType == WifiP2pBonjourServiceInfo.DNS_TYPE_TXT) { - dnsName = dnsName.toLowerCase(); - } - sb.append(compressDnsName(dnsName)); - sb.append(String.format("%04x", dnsType)); - sb.append(String.format("%02x", version)); - - return sb.toString(); - } - - /** - * Compress DNS data. - * - * see E.3 of the Wi-Fi Direct technical specification for the detail. - * - * @param dnsName dns name - * @return compressed dns name - */ - private static String compressDnsName(String dnsName) { - StringBuffer sb = new StringBuffer(); - - // The domain name is replaced with a pointer to a prior - // occurrence of the same name in virtual memory packet. - while (true) { - String data = sVmPacket.get(dnsName); - if (data != null) { - sb.append(data); - break; - } - int i = dnsName.indexOf('.'); - if (i == -1) { - if (dnsName.length() > 0) { - sb.append(String.format("%02x", dnsName.length())); - sb.append(WifiP2pServiceInfo.bin2HexStr(dnsName.getBytes())); - } - // for a sequence of labels ending in a zero octet - sb.append("00"); - break; - } - - String name = dnsName.substring(0, i); - dnsName = dnsName.substring(i + 1); - sb.append(String.format("%02x", name.length())); - sb.append(WifiP2pServiceInfo.bin2HexStr(name.getBytes())); - } - return sb.toString(); - } -} diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceRequest.java deleted file mode 100644 index d1635f1..0000000 --- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceRequest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.wifi.p2p.nsd; - - -/** - * A class for a request of bonjour service discovery. - * @hide - */ -public class WifiP2pBonjourServiceRequest extends WifiP2pServiceRequest { - - /** - * This constructor is only used in newInstance(). - * - * @param query The part of service specific query. - * @hide - */ - private WifiP2pBonjourServiceRequest(String query) { - super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, query); - } - - /** - * This constructor is only used in newInstance(). - * @hide - */ - private WifiP2pBonjourServiceRequest() { - super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, null); - } - - private WifiP2pBonjourServiceRequest(String registrationType, int dnsType, int version) { - super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, WifiP2pBonjourServiceInfo.createRequest( - registrationType, - WifiP2pBonjourServiceInfo.DNS_TYPE_PTR, - WifiP2pBonjourServiceInfo.VERSION_1)); - } - - /** - * Create a service discovery request to search all Bonjour services. - * - * @return service request for Bonjour. - */ - public static WifiP2pBonjourServiceRequest newInstance() { - return new WifiP2pBonjourServiceRequest(); - } - - /** - * Create a service discovery request to resolve the instance name with the specified - * registration type. - * - * @param registrationType registration type. Cannot be null
- * e.g)
- * "_afpovertcp._tcp.local."(Apple File Sharing over TCP)
- * "_ipp._tcp.local." (IP Printing over TCP)
- * @return service request for Bonjour. - */ - public static WifiP2pBonjourServiceRequest newInstance(String registrationType) { - if (registrationType == null) { - throw new IllegalArgumentException("registration type cannot be null"); - } - return new WifiP2pBonjourServiceRequest(registrationType, - WifiP2pBonjourServiceInfo.DNS_TYPE_PTR, - WifiP2pBonjourServiceInfo.VERSION_1); - } - - /** - * Create a service discovery request to get the TXT data from the specified - * service. - * - * @param instanceName instance name. Cannot be null.
- * "MyPrinter" - * @param registrationType registration type. Cannot be null.
- * e.g)
- * "_afpovertcp._tcp.local."(Apple File Sharing over TCP)
- * "_ipp._tcp.local." (IP Printing over TCP)
- * @return service request for Bonjour. - */ - public static WifiP2pBonjourServiceRequest newInstance(String instanceName, - String registrationType) { - if (instanceName == null || registrationType == null) { - throw new IllegalArgumentException( - "instance name or registration type cannot be null"); - } - String fullDomainName = instanceName + "." + registrationType; - return new WifiP2pBonjourServiceRequest(fullDomainName, - WifiP2pBonjourServiceInfo.DNS_TYPE_TXT, - WifiP2pBonjourServiceInfo.VERSION_1); - } -} diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceResponse.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceResponse.java deleted file mode 100644 index c511569..0000000 --- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceResponse.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.wifi.p2p.nsd; - -import android.net.nsd.DnsSdTxtRecord; -import android.net.wifi.p2p.WifiP2pDevice; - -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -/** - * A class for a response of bonjour service discovery. - * - * @hide - */ -public class WifiP2pBonjourServiceResponse extends WifiP2pServiceResponse { - - /** - * DNS query name. - * e.g) - * for PTR - * "_ipp._tcp.local." - * for TXT - * "MyPrinter._ipp._tcp.local." - */ - private String mDnsQueryName; - - /** - * Service instance name. - * e.g) "MyPrinter" - * This field is only used when the dns type equals to - * {@link WifiP2pBonjourServiceInfo#DNS_TYPE_PTR}. - */ - private String mInstanceName; - - /** - * DNS Type. - * Should be {@link WifiP2pBonjourServiceInfo#DNS_TYPE_PTR} or - * {@link WifiP2pBonjourServiceInfo#DNS_TYPE_TXT}. - */ - private int mDnsType; - - /** - * Bonjour version number. - * Should be {@link WifiP2pBonjourServiceInfo#VERSION_1}. - */ - private int mVersion; - - /** - * Txt record. - * This field is only used when the dns type equals to - * {@link WifiP2pBonjourServiceInfo#DNS_TYPE_TXT}. - */ - private DnsSdTxtRecord mTxtRecord; - - /** - * Virtual memory packet. - * see E.3 of the Wi-Fi Direct technical specification for the detail.
- * The spec can be obtained from wi-fi.org - * Key: pointer Value: domain name.
- */ - private final static Map sVmpack; - - static { - sVmpack = new HashMap(); - sVmpack.put(0x0c, "_tcp.local."); - sVmpack.put(0x11, "local."); - sVmpack.put(0x1c, "_udp.local."); - } - - /** - * Returns query DNS name. - * @return DNS name. - */ - public String getDnsQueryName() { - return mDnsQueryName; - } - - /** - * Return query DNS type. - * @return DNS type. - */ - public int getDnsType() { - return mDnsType; - } - - /** - * Return bonjour version number. - * @return version number. - */ - public int getVersion() { - return mVersion; - } - - /** - * Return instance name. - * @return - */ - public String getInstanceName() { - return mInstanceName; - } - - /** - * Return TXT record data. - * @return TXT record data. - */ - public DnsSdTxtRecord getTxtRecord() { - return mTxtRecord; - } - - @Override - public String toString() { - StringBuffer sbuf = new StringBuffer(); - sbuf.append("serviceType:Bonjour(").append(mServiceType).append(")"); - sbuf.append(" status:").append(Status.toString(mStatus)); - sbuf.append(" srcAddr:").append(mDevice.deviceAddress); - sbuf.append(" version:").append(String.format("%02x", mVersion)); - sbuf.append(" dnsName:").append(mDnsQueryName); - if (mTxtRecord != null) { - sbuf.append(" TxtRecord:").append(mTxtRecord); - } - if (mInstanceName != null) { - sbuf.append(" InsName:").append(mInstanceName); - } - return sbuf.toString(); - } - - /** - * This is only used in framework. - * @param status status code. - * @param dev source device. - * @param data RDATA. - * @hide - */ - protected WifiP2pBonjourServiceResponse(int status, - int tranId, WifiP2pDevice dev, byte[] data) { - super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, - status, tranId, dev, data); - if (!parse()) { - throw new IllegalArgumentException("Malformed bonjour service response"); - } - } - - /** - * Parse Bonjour service discovery response. - * - * @return {@code true} if the operation succeeded - */ - private boolean parse() { - /* - * The data format from Wi-Fi Direct spec is as follows. - * ________________________________________________ - * | encoded and compressed dns name (variable) | - * ________________________________________________ - * | dnstype(2byte) | version(1byte) | - * ________________________________________________ - * | RDATA (variable) | - */ - if (mData == null) { - // the empty is OK. - return true; - } - - DataInputStream dis = new DataInputStream(new ByteArrayInputStream(mData)); - - mDnsQueryName = readDnsName(dis); - if (mDnsQueryName == null) { - return false; - } - - try { - mDnsType = dis.readUnsignedShort(); - mVersion = dis.readUnsignedByte(); - } catch (IOException e) { - e.printStackTrace(); - return false; - } - - if (mDnsType == WifiP2pBonjourServiceInfo.DNS_TYPE_PTR) { - String rData = readDnsName(dis); - if (rData == null) { - return false; - } - if (rData.length() <= mDnsQueryName.length()) { - return false; - } - - mInstanceName = rData.substring(0, - rData.length() - mDnsQueryName.length() -1); - } else if (mDnsType == WifiP2pBonjourServiceInfo.DNS_TYPE_TXT) { - mTxtRecord = readTxtData(dis); - if (mTxtRecord == null) { - return false; - } - } else { - return false; - } - - return true; - } - - /** - * Read dns name. - * - * @param dis data input stream. - * @return dns name - */ - private String readDnsName(DataInputStream dis) { - StringBuffer sb = new StringBuffer(); - - // copy virtual memory packet. - HashMap vmpack = new HashMap(sVmpack); - if (mDnsQueryName != null) { - vmpack.put(0x27, mDnsQueryName); - } - try { - while (true) { - int i = dis.readUnsignedByte(); - if (i == 0x00) { - return sb.toString(); - } else if (i == 0xc0) { - // refer to pointer. - String ref = vmpack.get(dis.readUnsignedByte()); - if (ref == null) { - //invalid. - return null; - } - sb.append(ref); - return sb.toString(); - } else { - byte[] data = new byte[i]; - dis.readFully(data); - sb.append(new String(data)); - sb.append("."); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - return null; - } - - /** - * Read TXT record data. - * - * @param dis - * @return TXT record data - */ - private DnsSdTxtRecord readTxtData(DataInputStream dis) { - DnsSdTxtRecord txtRecord = new DnsSdTxtRecord(); - try { - while (dis.available() > 0) { - int len = dis.readUnsignedByte(); - if (len == 0) { - break; - } - byte[] data = new byte[len]; - dis.readFully(data); - String[] keyVal = new String(data).split("="); - if (keyVal.length != 2) { - return null; - } - txtRecord.set(keyVal[0], keyVal[1]); - } - return txtRecord; - } catch (IOException e) { - e.printStackTrace(); - } - return null; - } - - /** - * Creates Bonjour service response. - * This is only called from WifiP2pServiceResponse - * - * @param status status code. - * @param dev source device. - * @param data Bonjour response data. - * @return Bonjour service response data. - * @hide - */ - static WifiP2pBonjourServiceResponse newInstance(int status, - int transId, WifiP2pDevice dev, byte[] data) { - if (status != WifiP2pServiceResponse.Status.SUCCESS) { - return new WifiP2pBonjourServiceResponse(status, - transId, dev, null); - } - try { - return new WifiP2pBonjourServiceResponse(status, - transId, dev, data); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } - return null; - } -} diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java new file mode 100644 index 0000000..54b7ac4 --- /dev/null +++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.p2p.nsd; + +import android.net.nsd.DnsSdTxtRecord; +import android.text.TextUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A class for storing Bonjour service information that is advertised + * over a Wi-Fi peer-to-peer setup. + * + * {@see android.net.wifi.p2p.WifiP2pManager#addLocalService} + * {@see android.net.wifi.p2p.WifiP2pManager#removeLocalService} + * {@see WifiP2pServiceInfo} + * {@see WifiP2pUpnpServiceInfo} + */ +public class WifiP2pDnsSdServiceInfo extends WifiP2pServiceInfo { + + /** + * Bonjour version 1. + * @hide + */ + public static final int VERSION_1 = 0x01; + + /** + * Pointer record. + * @hide + */ + public static final int DNS_TYPE_PTR = 12; + + /** + * Text record. + * @hide + */ + public static final int DNS_TYPE_TXT = 16; + + /** + * virtual memory packet. + * see E.3 of the Wi-Fi Direct technical specification for the detail.
+ * Key: domain name Value: pointer address.
+ */ + private final static Map sVmPacket; + + static { + sVmPacket = new HashMap(); + sVmPacket.put("_tcp.local.", "c00c"); + sVmPacket.put("local.", "c011"); + sVmPacket.put("_udp.local.", "c01c"); + } + + /** + * This constructor is only used in newInstance(). + * + * @param queryList + */ + private WifiP2pDnsSdServiceInfo(List queryList) { + super(queryList); + } + + /** + * Create a Bonjour service information object. + * + * @param instanceName instance name.
+ * e.g) "MyPrinter" + * @param serviceType service type.
+ * e.g) "_ipp._tcp" + * @param txtRecord TXT record as defined at + * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt + * @return Bonjour service information object + */ + public static WifiP2pDnsSdServiceInfo newInstance(String instanceName, + String serviceType, DnsSdTxtRecord txtRecord) { + if (TextUtils.isEmpty(instanceName) || TextUtils.isEmpty(serviceType)) { + throw new IllegalArgumentException( + "instance name or service type cannot be empty"); + } + + if (txtRecord == null) { + txtRecord = new DnsSdTxtRecord(); + } + + ArrayList queries = new ArrayList(); + queries.add(createPtrServiceQuery(instanceName, serviceType)); + queries.add(createTxtServiceQuery(instanceName, serviceType, txtRecord)); + + return new WifiP2pDnsSdServiceInfo(queries); + } + + /** + * Create wpa_supplicant service query for PTR record. + * + * @param instanceName instance name.
+ * e.g) "MyPrinter" + * @param serviceType service type.
+ * e.g) "_ipp._tcp" + * @return wpa_supplicant service query. + */ + private static String createPtrServiceQuery(String instanceName, + String serviceType) { + + StringBuffer sb = new StringBuffer(); + sb.append("bonjour "); + sb.append(createRequest(serviceType + ".local.", DNS_TYPE_PTR, VERSION_1)); + sb.append(" "); + + byte[] data = instanceName.getBytes(); + sb.append(String.format("%02x", data.length)); + sb.append(WifiP2pServiceInfo.bin2HexStr(data)); + // This is the start point of this response. + // Therefore, it indicates the request domain name. + sb.append("c027"); + return sb.toString(); + } + + /** + * Create wpa_supplicant service query for TXT record. + * + * @param instanceName instance name.
+ * e.g) "MyPrinter" + * @param serviceType service type.
+ * e.g) "_ipp._tcp" + * @param txtRecord TXT record.
+ * @return wpa_supplicant service query. + */ + private static String createTxtServiceQuery(String instanceName, + String serviceType, + DnsSdTxtRecord txtRecord) { + + + StringBuffer sb = new StringBuffer(); + sb.append("bonjour "); + + sb.append(createRequest((instanceName + "." + serviceType + ".local."), + DNS_TYPE_TXT, VERSION_1)); + sb.append(" "); + byte[] rawData = txtRecord.getRawData(); + if (rawData.length == 0) { + sb.append("00"); + } else { + sb.append(bin2HexStr(rawData)); + } + return sb.toString(); + } + + /** + * Create bonjour service discovery request. + * + * @param dnsName dns name + * @param dnsType dns type + * @param version version number + * @hide + */ + static String createRequest(String dnsName, int dnsType, int version) { + StringBuffer sb = new StringBuffer(); + + /* + * The request format is as follows. + * ________________________________________________ + * | Encoded and Compressed dns name (variable) | + * ________________________________________________ + * | Type (2) | Version (1) | + */ + if (dnsType == WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT) { + dnsName = dnsName.toLowerCase(); + } + sb.append(compressDnsName(dnsName)); + sb.append(String.format("%04x", dnsType)); + sb.append(String.format("%02x", version)); + + return sb.toString(); + } + + /** + * Compress DNS data. + * + * see E.3 of the Wi-Fi Direct technical specification for the detail. + * + * @param dnsName dns name + * @return compressed dns name + */ + private static String compressDnsName(String dnsName) { + StringBuffer sb = new StringBuffer(); + + // The domain name is replaced with a pointer to a prior + // occurrence of the same name in virtual memory packet. + while (true) { + String data = sVmPacket.get(dnsName); + if (data != null) { + sb.append(data); + break; + } + int i = dnsName.indexOf('.'); + if (i == -1) { + if (dnsName.length() > 0) { + sb.append(String.format("%02x", dnsName.length())); + sb.append(WifiP2pServiceInfo.bin2HexStr(dnsName.getBytes())); + } + // for a sequence of labels ending in a zero octet + sb.append("00"); + break; + } + + String name = dnsName.substring(0, i); + dnsName = dnsName.substring(i + 1); + sb.append(String.format("%02x", name.length())); + sb.append(WifiP2pServiceInfo.bin2HexStr(name.getBytes())); + } + return sb.toString(); + } +} diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceRequest.java new file mode 100644 index 0000000..d5415e0 --- /dev/null +++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceRequest.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.p2p.nsd; + +import android.net.wifi.p2p.WifiP2pManager; + +/** + * A class for creating a Bonjour service discovery request for use with + * {@link WifiP2pManager#addServiceRequest} and {@link WifiP2pManager#removeServiceRequest} + * + * {@see WifiP2pManager} + * {@see WifiP2pServiceRequest} + * {@see WifiP2pUpnpServiceRequest} + */ +public class WifiP2pDnsSdServiceRequest extends WifiP2pServiceRequest { + + /** + * This constructor is only used in newInstance(). + * + * @param query The part of service specific query. + * @hide + */ + private WifiP2pDnsSdServiceRequest(String query) { + super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, query); + } + + /** + * This constructor is only used in newInstance(). + * @hide + */ + private WifiP2pDnsSdServiceRequest() { + super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, null); + } + + private WifiP2pDnsSdServiceRequest(String dnsQuery, int dnsType, int version) { + super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, WifiP2pDnsSdServiceInfo.createRequest( + dnsQuery, + dnsType, + version)); + } + + /** + * Create a service discovery request to search all Bonjour services. + * + * @return service request for Bonjour. + */ + public static WifiP2pDnsSdServiceRequest newInstance() { + return new WifiP2pDnsSdServiceRequest(); + } + + /** + * Create a service discovery to search for Bonjour services with the specified + * service type. + * + * @param serviceType service type. Cannot be null
+ * "_afpovertcp._tcp."(Apple File Sharing over TCP)
+ * "_ipp._tcp" (IP Printing over TCP)
+ * "_http._tcp" (http service) + * @return service request for DnsSd. + */ + public static WifiP2pDnsSdServiceRequest newInstance(String serviceType) { + if (serviceType == null) { + throw new IllegalArgumentException("service type cannot be null"); + } + return new WifiP2pDnsSdServiceRequest(serviceType + ".local.", + WifiP2pDnsSdServiceInfo.DNS_TYPE_PTR, + WifiP2pDnsSdServiceInfo.VERSION_1); + } + + /** + * Create a service discovery request to get the TXT data from the specified + * Bonjour service. + * + * @param instanceName instance name. Cannot be null.
+ * "MyPrinter" + * @param serviceType service type. Cannot be null.
+ * e.g)
+ * "_afpovertcp._tcp"(Apple File Sharing over TCP)
+ * "_ipp._tcp" (IP Printing over TCP)
+ * @return service request for Bonjour. + */ + public static WifiP2pDnsSdServiceRequest newInstance(String instanceName, + String serviceType) { + if (instanceName == null || serviceType == null) { + throw new IllegalArgumentException( + "instance name or service type cannot be null"); + } + String fullDomainName = instanceName + "." + serviceType + ".local."; + return new WifiP2pDnsSdServiceRequest(fullDomainName, + WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT, + WifiP2pDnsSdServiceInfo.VERSION_1); + } +} diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceResponse.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceResponse.java new file mode 100644 index 0000000..c053c8a --- /dev/null +++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceResponse.java @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.p2p.nsd; + +import android.net.nsd.DnsSdTxtRecord; +import android.net.wifi.p2p.WifiP2pDevice; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * A class for a response of bonjour service discovery. + * + * @hide + */ +public class WifiP2pDnsSdServiceResponse extends WifiP2pServiceResponse { + + /** + * DNS query name. + * e.g) + * for PTR + * "_ipp._tcp.local." + * for TXT + * "MyPrinter._ipp._tcp.local." + */ + private String mDnsQueryName; + + /** + * Service instance name. + * e.g) "MyPrinter" + * This field is only used when the dns type equals to + * {@link WifiP2pDnsSdServiceInfo#DNS_TYPE_PTR}. + */ + private String mInstanceName; + + /** + * DNS Type. + * Should be {@link WifiP2pDnsSdServiceInfo#DNS_TYPE_PTR} or + * {@link WifiP2pDnsSdServiceInfo#DNS_TYPE_TXT}. + */ + private int mDnsType; + + /** + * DnsSd version number. + * Should be {@link WifiP2pDnsSdServiceInfo#VERSION_1}. + */ + private int mVersion; + + /** + * Txt record. + * This field is only used when the dns type equals to + * {@link WifiP2pDnsSdServiceInfo#DNS_TYPE_TXT}. + */ + private DnsSdTxtRecord mTxtRecord; + + /** + * Virtual memory packet. + * see E.3 of the Wi-Fi Direct technical specification for the detail.
+ * The spec can be obtained from wi-fi.org + * Key: pointer Value: domain name.
+ */ + private final static Map sVmpack; + + static { + sVmpack = new HashMap(); + sVmpack.put(0x0c, "_tcp.local."); + sVmpack.put(0x11, "local."); + sVmpack.put(0x1c, "_udp.local."); + } + + /** + * Returns query DNS name. + * @return DNS name. + */ + public String getDnsQueryName() { + return mDnsQueryName; + } + + /** + * Return query DNS type. + * @return DNS type. + */ + public int getDnsType() { + return mDnsType; + } + + /** + * Return bonjour version number. + * @return version number. + */ + public int getVersion() { + return mVersion; + } + + /** + * Return instance name. + * @return + */ + public String getInstanceName() { + return mInstanceName; + } + + /** + * Return TXT record data. + * @return TXT record data. + */ + public DnsSdTxtRecord getTxtRecord() { + return mTxtRecord; + } + + @Override + public String toString() { + StringBuffer sbuf = new StringBuffer(); + sbuf.append("serviceType:DnsSd(").append(mServiceType).append(")"); + sbuf.append(" status:").append(Status.toString(mStatus)); + sbuf.append(" srcAddr:").append(mDevice.deviceAddress); + sbuf.append(" version:").append(String.format("%02x", mVersion)); + sbuf.append(" dnsName:").append(mDnsQueryName); + if (mTxtRecord != null) { + sbuf.append(" TxtRecord:").append(mTxtRecord); + } + if (mInstanceName != null) { + sbuf.append(" InsName:").append(mInstanceName); + } + return sbuf.toString(); + } + + /** + * This is only used in framework. + * @param status status code. + * @param dev source device. + * @param data RDATA. + * @hide + */ + protected WifiP2pDnsSdServiceResponse(int status, + int tranId, WifiP2pDevice dev, byte[] data) { + super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, + status, tranId, dev, data); + if (!parse()) { + throw new IllegalArgumentException("Malformed bonjour service response"); + } + } + + /** + * Parse DnsSd service discovery response. + * + * @return {@code true} if the operation succeeded + */ + private boolean parse() { + /* + * The data format from Wi-Fi Direct spec is as follows. + * ________________________________________________ + * | encoded and compressed dns name (variable) | + * ________________________________________________ + * | dnstype(2byte) | version(1byte) | + * ________________________________________________ + * | RDATA (variable) | + */ + if (mData == null) { + // the empty is OK. + return true; + } + + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(mData)); + + mDnsQueryName = readDnsName(dis); + if (mDnsQueryName == null) { + return false; + } + + try { + mDnsType = dis.readUnsignedShort(); + mVersion = dis.readUnsignedByte(); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + + if (mDnsType == WifiP2pDnsSdServiceInfo.DNS_TYPE_PTR) { + String rData = readDnsName(dis); + if (rData == null) { + return false; + } + if (rData.length() <= mDnsQueryName.length()) { + return false; + } + + mInstanceName = rData.substring(0, + rData.length() - mDnsQueryName.length() -1); + } else if (mDnsType == WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT) { + mTxtRecord = readTxtData(dis); + if (mTxtRecord == null) { + return false; + } + } else { + return false; + } + + return true; + } + + /** + * Read dns name. + * + * @param dis data input stream. + * @return dns name + */ + private String readDnsName(DataInputStream dis) { + StringBuffer sb = new StringBuffer(); + + // copy virtual memory packet. + HashMap vmpack = new HashMap(sVmpack); + if (mDnsQueryName != null) { + vmpack.put(0x27, mDnsQueryName); + } + try { + while (true) { + int i = dis.readUnsignedByte(); + if (i == 0x00) { + return sb.toString(); + } else if (i == 0xc0) { + // refer to pointer. + String ref = vmpack.get(dis.readUnsignedByte()); + if (ref == null) { + //invalid. + return null; + } + sb.append(ref); + return sb.toString(); + } else { + byte[] data = new byte[i]; + dis.readFully(data); + sb.append(new String(data)); + sb.append("."); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + /** + * Read TXT record data. + * + * @param dis + * @return TXT record data + */ + private DnsSdTxtRecord readTxtData(DataInputStream dis) { + DnsSdTxtRecord txtRecord = new DnsSdTxtRecord(); + try { + while (dis.available() > 0) { + int len = dis.readUnsignedByte(); + if (len == 0) { + break; + } + byte[] data = new byte[len]; + dis.readFully(data); + String[] keyVal = new String(data).split("="); + if (keyVal.length != 2) { + return null; + } + txtRecord.set(keyVal[0], keyVal[1]); + } + return txtRecord; + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + /** + * Creates DnsSd service response. + * This is only called from WifiP2pServiceResponse + * + * @param status status code. + * @param dev source device. + * @param data DnsSd response data. + * @return DnsSd service response data. + * @hide + */ + static WifiP2pDnsSdServiceResponse newInstance(int status, + int transId, WifiP2pDevice dev, byte[] data) { + if (status != WifiP2pServiceResponse.Status.SUCCESS) { + return new WifiP2pDnsSdServiceResponse(status, + transId, dev, null); + } + try { + return new WifiP2pDnsSdServiceResponse(status, + transId, dev, data); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java index aed5616..b931475 100644 --- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java +++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java @@ -23,13 +23,11 @@ import java.util.ArrayList; import java.util.List; /** - * The class for service information. - * - *

Currently UPnP and Bonjour are only supported. + * A class for storing service information that is advertised + * over a Wi-Fi peer-to-peer setup * * @see WifiP2pUpnpServiceInfo - * @see WifiP2pBonjourServiceInfo - * @hide + * @see WifiP2pDnsSdServiceInfo */ public class WifiP2pServiceInfo implements Parcelable { @@ -39,7 +37,7 @@ public class WifiP2pServiceInfo implements Parcelable { public static final int SERVICE_TYPE_ALL = 0; /** - * Bonjour protocol. + * DNS based service discovery protocol. */ public static final int SERVICE_TYPE_BONJOUR = 1; @@ -50,6 +48,7 @@ public class WifiP2pServiceInfo implements Parcelable { /** * WS-Discovery protocol + * @hide */ public static final int SERVICE_TYPE_WS_DISCOVERY = 3; diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java index e41d9aa..c7f0e5f 100644 --- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java +++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java @@ -21,24 +21,26 @@ import android.os.Parcel; import android.os.Parcelable; /** - * A class for a request of service discovery. + * A class for creating a service discovery request for use with + * {@link WifiP2pManager#addServiceRequest} and {@link WifiP2pManager#removeServiceRequest} * - *

This class is used when you create customized service discovery request. - * e.g) vendor specific request/ws discovery etc. + *

This class is used to create service discovery request for custom + * vendor specific service discovery protocol {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC} + * or to search all service protocols {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL}. * - *

If you want to create UPnP or Bonjour service request, then you had better - * use {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pBonjourServiceRequest}. + *

For the purpose of creating a UPnP or Bonjour service request, use + * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest} respectively. * - * @see WifiP2pUpnpServiceRequest - * @see WifiP2pBonjourServiceRequest - * @hide + * {@see WifiP2pManager} + * {@see WifiP2pUpnpServiceRequest} + * {@see WifiP2pDnsSdServiceRequest} */ public class WifiP2pServiceRequest implements Parcelable { /** - * Service type. It's defined in table63 in Wi-Fi Direct specification. + * Service discovery protocol. It's defined in table63 in Wi-Fi Direct specification. */ - private int mServiceType; + private int mProtocolType; /** * The length of the service request TLV. @@ -56,7 +58,7 @@ public class WifiP2pServiceRequest implements Parcelable { /** * The hex dump string of query data for the requested service information. * - * e.g) Bonjour apple file sharing over tcp (dns name=_afpovertcp._tcp.local.) + * e.g) DnsSd apple file sharing over tcp (dns name=_afpovertcp._tcp.local.) * 0b5f6166706f766572746370c00c000c01 */ private String mQuery; @@ -64,14 +66,14 @@ public class WifiP2pServiceRequest implements Parcelable { /** * This constructor is only used in newInstance(). * - * @param serviceType service discovery type. + * @param protocolType service discovery protocol. * @param query The part of service specific query. * @hide */ - protected WifiP2pServiceRequest(int serviceType, String query) { + protected WifiP2pServiceRequest(int protocolType, String query) { validateQuery(query); - mServiceType = serviceType; + mProtocolType = protocolType; mQuery = query; if (query != null) { mLength = query.length()/2 + 2; @@ -90,7 +92,7 @@ public class WifiP2pServiceRequest implements Parcelable { */ private WifiP2pServiceRequest(int serviceType, int length, int transId, String query) { - mServiceType = serviceType; + mProtocolType = serviceType; mLength = length; mTransId = transId; mQuery = query; @@ -134,7 +136,7 @@ public class WifiP2pServiceRequest implements Parcelable { // length is retained as little endian format. sb.append(String.format("%02x", (mLength) & 0xff)); sb.append(String.format("%02x", (mLength >> 8) & 0xff)); - sb.append(String.format("%02x", mServiceType)); + sb.append(String.format("%02x", mProtocolType)); sb.append(String.format("%02x", mTransId)); if (mQuery != null) { sb.append(mQuery); @@ -177,42 +179,34 @@ public class WifiP2pServiceRequest implements Parcelable { } /** - * Create service discovery request. - * - *

The created instance is set to framework by - * {@link WifiP2pManager#addLocalService}. + * Create a service discovery request. * - * @param serviceType service type.
- * e.g) {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL}, - * {@link WifiP2pServiceInfo#SERVICE_TYPE_WS_DISCOVERY}, - * {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}. - * If you want to use UPnP or Bonjour, you create the request by - * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pBonjourServiceRequest} + * @param protocolType can be {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL} + * or {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}. + * In order to create a UPnP or Bonjour service request, use + * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest} + * respectively * - * @param query hex string. if null, all specified services are requested. + * @param queryData hex string that is vendor specific. Can be null. * @return service discovery request. */ - public static WifiP2pServiceRequest newInstance(int serviceType, String query) { - return new WifiP2pServiceRequest(serviceType, query); + public static WifiP2pServiceRequest newInstance(int protocolType, String queryData) { + return new WifiP2pServiceRequest(protocolType, queryData); } /** - * Create all service discovery request. - * - *

The created instance is set to framework by - * {@link WifiP2pManager#addLocalService}. + * Create a service discovery request. * - * @param serviceType service type.
- * e.g) {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL}, - * {@link WifiP2pServiceInfo#SERVICE_TYPE_WS_DISCOVERY}, - * {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}. - * If you want to use UPnP or Bonjour, you create the request by - * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pBonjourServiceRequest} + * @param protocolType can be {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL} + * or {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}. + * In order to create a UPnP or Bonjour service request, use + * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest} + * respectively * * @return service discovery request. */ - public static WifiP2pServiceRequest newInstance(int serviceType) { - return new WifiP2pServiceRequest(serviceType, null); + public static WifiP2pServiceRequest newInstance(int protocolType ) { + return new WifiP2pServiceRequest(protocolType, null); } @Override @@ -230,7 +224,7 @@ public class WifiP2pServiceRequest implements Parcelable { * Not compare transaction id. * Transaction id may be changed on each service discovery operation. */ - if ((req.mServiceType != mServiceType) || + if ((req.mProtocolType != mProtocolType) || (req.mLength != mLength)) { return false; } @@ -246,7 +240,7 @@ public class WifiP2pServiceRequest implements Parcelable { @Override public int hashCode() { int result = 17; - result = 31 * result + mServiceType; + result = 31 * result + mProtocolType; result = 31 * result + mLength; result = 31 * result + (mQuery == null ? 0 : mQuery.hashCode()); return result; @@ -259,7 +253,7 @@ public class WifiP2pServiceRequest implements Parcelable { /** Implement the Parcelable interface {@hide} */ public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mServiceType); + dest.writeInt(mProtocolType); dest.writeInt(mLength); dest.writeInt(mTransId); dest.writeString(mQuery); diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java index 0855eae..ac31663 100644 --- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java +++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java @@ -246,7 +246,7 @@ public class WifiP2pServiceResponse implements Parcelable { WifiP2pServiceResponse resp; if (type == WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR) { - resp = WifiP2pBonjourServiceResponse.newInstance(status, + resp = WifiP2pDnsSdServiceResponse.newInstance(status, transId, dev, data); } else if (type == WifiP2pServiceInfo.SERVICE_TYPE_UPNP) { resp = WifiP2pUpnpServiceResponse.newInstance(status, @@ -373,7 +373,7 @@ public class WifiP2pServiceResponse implements Parcelable { in.readByteArray(data); } if (type == WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR) { - return WifiP2pBonjourServiceResponse.newInstance(status, + return WifiP2pDnsSdServiceResponse.newInstance(status, transId, dev, data); } else if (type == WifiP2pServiceInfo.SERVICE_TYPE_UPNP) { return WifiP2pUpnpServiceResponse.newInstance(status, diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java index 4d40e81..40a0d61 100644 --- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java +++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java @@ -21,8 +21,13 @@ import java.util.List; import java.util.UUID; /** - * The class for UPnP service information. - * @hide + * A class for storing Upnp service information that is advertised + * over a Wi-Fi peer-to-peer setup. + * + * {@see android.net.wifi.p2p.WifiP2pManager#addLocalService} + * {@see android.net.wifi.p2p.WifiP2pManager#removeLocalService} + * {@see WifiP2pServiceInfo} + * {@see WifiP2pDnsSdServiceInfo} */ public class WifiP2pUpnpServiceInfo extends WifiP2pServiceInfo { diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java index b97637a..b5cf144 100644 --- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java +++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java @@ -16,9 +16,15 @@ package android.net.wifi.p2p.nsd; +import android.net.wifi.p2p.WifiP2pManager; + /** - * The class for a request of upnp service discovery. - * @hide + * A class for creating a Upnp service discovery request for use with + * {@link WifiP2pManager#addServiceRequest} and {@link WifiP2pManager#removeServiceRequest} + * + * {@see WifiP2pManager} + * {@see WifiP2pServiceRequest} + * {@see WifiP2pDnsSdServiceRequest} */ public class WifiP2pUpnpServiceRequest extends WifiP2pServiceRequest { -- cgit v1.1