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