1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.wifi.p2p.nsd; 18 19 import android.annotation.UnsupportedAppUsage; 20 import android.net.wifi.p2p.WifiP2pManager; 21 import android.os.Build; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 25 import java.util.Locale; 26 27 /** 28 * A class for creating a service discovery request for use with 29 * {@link WifiP2pManager#addServiceRequest} and {@link WifiP2pManager#removeServiceRequest} 30 * 31 * <p>This class is used to create service discovery request for custom 32 * vendor specific service discovery protocol {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC} 33 * or to search all service protocols {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL}. 34 * 35 * <p>For the purpose of creating a UPnP or Bonjour service request, use 36 * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest} respectively. 37 * 38 * {@see WifiP2pManager} 39 * {@see WifiP2pUpnpServiceRequest} 40 * {@see WifiP2pDnsSdServiceRequest} 41 */ 42 public class WifiP2pServiceRequest implements Parcelable { 43 44 /** 45 * Service discovery protocol. It's defined in table63 in Wi-Fi Direct specification. 46 */ 47 private int mProtocolType; 48 49 /** 50 * The length of the service request TLV. 51 * The value is equal to 2 plus the number of octets in the 52 * query data field. 53 */ 54 private int mLength; 55 56 /** 57 * Service transaction ID. 58 * This is a nonzero value used to match the service request/response TLVs. 59 */ 60 private int mTransId; 61 62 /** 63 * The hex dump string of query data for the requested service information. 64 * 65 * e.g) DnsSd apple file sharing over tcp (dns name=_afpovertcp._tcp.local.) 66 * 0b5f6166706f766572746370c00c000c01 67 */ 68 private String mQuery; 69 70 /** 71 * This constructor is only used in newInstance(). 72 * 73 * @param protocolType service discovery protocol. 74 * @param query The part of service specific query. 75 * @hide 76 */ 77 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) WifiP2pServiceRequest(int protocolType, String query)78 protected WifiP2pServiceRequest(int protocolType, String query) { 79 validateQuery(query); 80 81 mProtocolType = protocolType; 82 mQuery = query; 83 if (query != null) { 84 mLength = query.length()/2 + 2; 85 } else { 86 mLength = 2; 87 } 88 } 89 90 /** 91 * This constructor is only used in Parcelable. 92 * 93 * @param serviceType service discovery type. 94 * @param length the length of service discovery packet. 95 * @param transId the transaction id 96 * @param query The part of service specific query. 97 */ WifiP2pServiceRequest(int serviceType, int length, int transId, String query)98 private WifiP2pServiceRequest(int serviceType, int length, 99 int transId, String query) { 100 mProtocolType = serviceType; 101 mLength = length; 102 mTransId = transId; 103 mQuery = query; 104 } 105 106 /** 107 * Return transaction id. 108 * 109 * @return transaction id 110 * @hide 111 */ getTransactionId()112 public int getTransactionId() { 113 return mTransId; 114 } 115 116 /** 117 * Set transaction id. 118 * 119 * @param id 120 * @hide 121 */ setTransactionId(int id)122 public void setTransactionId(int id) { 123 mTransId = id; 124 } 125 126 /** 127 * Return wpa_supplicant request string. 128 * 129 * The format is the hex dump of the following frame. 130 * <pre> 131 * _______________________________________________________________ 132 * | Length (2) | Type (1) | Transaction ID (1) | 133 * | Query Data (variable) | 134 * </pre> 135 * 136 * @return wpa_supplicant request string. 137 * @hide 138 */ getSupplicantQuery()139 public String getSupplicantQuery() { 140 StringBuffer sb = new StringBuffer(); 141 // length is retained as little endian format. 142 sb.append(String.format(Locale.US, "%02x", (mLength) & 0xff)); 143 sb.append(String.format(Locale.US, "%02x", (mLength >> 8) & 0xff)); 144 sb.append(String.format(Locale.US, "%02x", mProtocolType)); 145 sb.append(String.format(Locale.US, "%02x", mTransId)); 146 if (mQuery != null) { 147 sb.append(mQuery); 148 } 149 150 return sb.toString(); 151 } 152 153 /** 154 * Validate query. 155 * 156 * <p>If invalid, throw IllegalArgumentException. 157 * @param query The part of service specific query. 158 */ validateQuery(String query)159 private void validateQuery(String query) { 160 if (query == null) { 161 return; 162 } 163 164 int UNSIGNED_SHORT_MAX = 0xffff; 165 if (query.length()%2 == 1) { 166 throw new IllegalArgumentException( 167 "query size is invalid. query=" + query); 168 } 169 if (query.length()/2 > UNSIGNED_SHORT_MAX) { 170 throw new IllegalArgumentException( 171 "query size is too large. len=" + query.length()); 172 } 173 174 // check whether query is hex string. 175 query = query.toLowerCase(Locale.ROOT); 176 char[] chars = query.toCharArray(); 177 for (char c: chars) { 178 if (!((c >= '0' && c <= '9') || 179 (c >= 'a' && c <= 'f'))){ 180 throw new IllegalArgumentException( 181 "query should be hex string. query=" + query); 182 } 183 } 184 } 185 186 /** 187 * Create a service discovery request. 188 * 189 * @param protocolType can be {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL} 190 * or {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}. 191 * In order to create a UPnP or Bonjour service request, use 192 * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest} 193 * respectively 194 * 195 * @param queryData hex string that is vendor specific. Can be null. 196 * @return service discovery request. 197 */ newInstance(int protocolType, String queryData)198 public static WifiP2pServiceRequest newInstance(int protocolType, String queryData) { 199 return new WifiP2pServiceRequest(protocolType, queryData); 200 } 201 202 /** 203 * Create a service discovery request. 204 * 205 * @param protocolType can be {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL} 206 * or {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}. 207 * In order to create a UPnP or Bonjour service request, use 208 * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest} 209 * respectively 210 * 211 * @return service discovery request. 212 */ newInstance(int protocolType )213 public static WifiP2pServiceRequest newInstance(int protocolType ) { 214 return new WifiP2pServiceRequest(protocolType, null); 215 } 216 217 @Override equals(Object o)218 public boolean equals(Object o) { 219 if (o == this) { 220 return true; 221 } 222 if (!(o instanceof WifiP2pServiceRequest)) { 223 return false; 224 } 225 226 WifiP2pServiceRequest req = (WifiP2pServiceRequest)o; 227 228 /* 229 * Not compare transaction id. 230 * Transaction id may be changed on each service discovery operation. 231 */ 232 if ((req.mProtocolType != mProtocolType) || 233 (req.mLength != mLength)) { 234 return false; 235 } 236 237 if (req.mQuery == null && mQuery == null) { 238 return true; 239 } else if (req.mQuery != null) { 240 return req.mQuery.equals(mQuery); 241 } 242 return false; 243 } 244 245 @Override hashCode()246 public int hashCode() { 247 int result = 17; 248 result = 31 * result + mProtocolType; 249 result = 31 * result + mLength; 250 result = 31 * result + (mQuery == null ? 0 : mQuery.hashCode()); 251 return result; 252 } 253 254 /** Implement the Parcelable interface {@hide} */ describeContents()255 public int describeContents() { 256 return 0; 257 } 258 259 /** Implement the Parcelable interface {@hide} */ writeToParcel(Parcel dest, int flags)260 public void writeToParcel(Parcel dest, int flags) { 261 dest.writeInt(mProtocolType); 262 dest.writeInt(mLength); 263 dest.writeInt(mTransId); 264 dest.writeString(mQuery); 265 } 266 267 /** Implement the Parcelable interface {@hide} */ 268 @UnsupportedAppUsage 269 public static final @android.annotation.NonNull Creator<WifiP2pServiceRequest> CREATOR = 270 new Creator<WifiP2pServiceRequest>() { 271 public WifiP2pServiceRequest createFromParcel(Parcel in) { 272 int servType = in.readInt(); 273 int length = in.readInt(); 274 int transId = in.readInt(); 275 String query = in.readString(); 276 return new WifiP2pServiceRequest(servType, length, transId, query); 277 } 278 279 public WifiP2pServiceRequest[] newArray(int size) { 280 return new WifiP2pServiceRequest[size]; 281 } 282 }; 283 } 284