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