blob: 68cbb88037b063da26a55ad97461e802cd58bfe3 [file] [log] [blame]
/*
* 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.compat.annotation.UnsupportedAppUsage;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Locale;
/**
* A class for creating a service discovery request for use with
* {@link WifiP2pManager#addServiceRequest} and {@link WifiP2pManager#removeServiceRequest}
*
* <p>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}.
*
* <p>For the purpose of creating a UPnP or Bonjour service request, use
* {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest} respectively.
*
* {@see WifiP2pManager}
* {@see WifiP2pUpnpServiceRequest}
* {@see WifiP2pDnsSdServiceRequest}
*/
public class WifiP2pServiceRequest implements Parcelable {
/**
* Service discovery protocol. It's defined in table63 in Wi-Fi Direct specification.
*/
private int mProtocolType;
/**
* The length of the service request TLV.
* The value is equal to 2 plus the number of octets in the
* query data field.
*/
private int mLength;
/**
* Service transaction ID.
* This is a nonzero value used to match the service request/response TLVs.
*/
private int mTransId;
/**
* The hex dump string of query data for the requested service information.
*
* e.g) DnsSd apple file sharing over tcp (dns name=_afpovertcp._tcp.local.)
* 0b5f6166706f766572746370c00c000c01
*/
private String mQuery;
/**
* This constructor is only used in newInstance().
*
* @param protocolType service discovery protocol.
* @param query The part of service specific query.
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
protected WifiP2pServiceRequest(int protocolType, String query) {
validateQuery(query);
mProtocolType = protocolType;
mQuery = query;
if (query != null) {
mLength = query.length()/2 + 2;
} else {
mLength = 2;
}
}
/**
* This constructor is only used in Parcelable.
*
* @param serviceType service discovery type.
* @param length the length of service discovery packet.
* @param transId the transaction id
* @param query The part of service specific query.
*/
private WifiP2pServiceRequest(int serviceType, int length,
int transId, String query) {
mProtocolType = serviceType;
mLength = length;
mTransId = transId;
mQuery = query;
}
/**
* Return transaction id.
*
* @return transaction id
* @hide
*/
public int getTransactionId() {
return mTransId;
}
/**
* Set transaction id.
*
* @param id
* @hide
*/
public void setTransactionId(int id) {
mTransId = id;
}
/**
* Return wpa_supplicant request string.
*
* The format is the hex dump of the following frame.
* <pre>
* _______________________________________________________________
* | Length (2) | Type (1) | Transaction ID (1) |
* | Query Data (variable) |
* </pre>
*
* @return wpa_supplicant request string.
* @hide
*/
public String getSupplicantQuery() {
StringBuffer sb = new StringBuffer();
// length is retained as little endian format.
sb.append(String.format(Locale.US, "%02x", (mLength) & 0xff));
sb.append(String.format(Locale.US, "%02x", (mLength >> 8) & 0xff));
sb.append(String.format(Locale.US, "%02x", mProtocolType));
sb.append(String.format(Locale.US, "%02x", mTransId));
if (mQuery != null) {
sb.append(mQuery);
}
return sb.toString();
}
/**
* Validate query.
*
* <p>If invalid, throw IllegalArgumentException.
* @param query The part of service specific query.
*/
private void validateQuery(String query) {
if (query == null) {
return;
}
int UNSIGNED_SHORT_MAX = 0xffff;
if (query.length()%2 == 1) {
throw new IllegalArgumentException(
"query size is invalid. query=" + query);
}
if (query.length()/2 > UNSIGNED_SHORT_MAX) {
throw new IllegalArgumentException(
"query size is too large. len=" + query.length());
}
// check whether query is hex string.
query = query.toLowerCase(Locale.ROOT);
char[] chars = query.toCharArray();
for (char c: chars) {
if (!((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f'))){
throw new IllegalArgumentException(
"query should be hex string. query=" + query);
}
}
}
/**
* Create a service discovery request.
*
* @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 queryData hex string that is vendor specific. Can be null.
* @return service discovery request.
*/
public static WifiP2pServiceRequest newInstance(int protocolType, String queryData) {
return new WifiP2pServiceRequest(protocolType, queryData);
}
/**
* Create a service discovery request.
*
* @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 protocolType ) {
return new WifiP2pServiceRequest(protocolType, null);
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof WifiP2pServiceRequest)) {
return false;
}
WifiP2pServiceRequest req = (WifiP2pServiceRequest)o;
/*
* Not compare transaction id.
* Transaction id may be changed on each service discovery operation.
*/
if ((req.mProtocolType != mProtocolType) ||
(req.mLength != mLength)) {
return false;
}
if (req.mQuery == null && mQuery == null) {
return true;
} else if (req.mQuery != null) {
return req.mQuery.equals(mQuery);
}
return false;
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + mProtocolType;
result = 31 * result + mLength;
result = 31 * result + (mQuery == null ? 0 : mQuery.hashCode());
return result;
}
/** Implement the Parcelable interface {@hide} */
public int describeContents() {
return 0;
}
/** Implement the Parcelable interface {@hide} */
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mProtocolType);
dest.writeInt(mLength);
dest.writeInt(mTransId);
dest.writeString(mQuery);
}
/** Implement the Parcelable interface {@hide} */
@UnsupportedAppUsage
public static final @android.annotation.NonNull Creator<WifiP2pServiceRequest> CREATOR =
new Creator<WifiP2pServiceRequest>() {
public WifiP2pServiceRequest createFromParcel(Parcel in) {
int servType = in.readInt();
int length = in.readInt();
int transId = in.readInt();
String query = in.readString();
return new WifiP2pServiceRequest(servType, length, transId, query);
}
public WifiP2pServiceRequest[] newArray(int size) {
return new WifiP2pServiceRequest[size];
}
};
}