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.WifiP2pDevice; 20 import android.os.Parcel; 21 import android.os.Parcelable; 22 23 import java.io.ByteArrayInputStream; 24 import java.io.DataInputStream; 25 import java.io.IOException; 26 import java.util.ArrayList; 27 import java.util.Arrays; 28 import java.util.List; 29 30 /** 31 * The class for a response of service discovery. 32 * 33 * @hide 34 */ 35 public class WifiP2pServiceResponse implements Parcelable { 36 37 private static int MAX_BUF_SIZE = 1024; 38 39 /** 40 * Service type. It's defined in table63 in Wi-Fi Direct specification. 41 */ 42 protected int mServiceType; 43 44 /** 45 * Status code of service discovery response. 46 * It's defined in table65 in Wi-Fi Direct specification. 47 * @see Status 48 */ 49 protected int mStatus; 50 51 /** 52 * Service transaction ID. 53 * This is a nonzero value used to match the service request/response TLVs. 54 */ 55 protected int mTransId; 56 57 /** 58 * Source device. 59 */ 60 protected WifiP2pDevice mDevice; 61 62 /** 63 * Service discovery response data based on the requested on 64 * the service protocol type. The protocol format depends on the service type. 65 */ 66 protected byte[] mData; 67 68 69 /** 70 * The status code of service discovery response. 71 * Currently 4 status codes are defined and the status codes from 4 to 255 72 * are reserved. 73 * 74 * See Wi-Fi Direct specification for the detail. 75 */ 76 public static class Status { 77 /** success */ 78 public static final int SUCCESS = 0; 79 80 /** the service protocol type is not available */ 81 public static final int SERVICE_PROTOCOL_NOT_AVAILABLE = 1; 82 83 /** the requested information is not available */ 84 public static final int REQUESTED_INFORMATION_NOT_AVAILABLE = 2; 85 86 /** bad request */ 87 public static final int BAD_REQUEST = 3; 88 89 /** @hide */ toString(int status)90 public static String toString(int status) { 91 switch(status) { 92 case SUCCESS: 93 return "SUCCESS"; 94 case SERVICE_PROTOCOL_NOT_AVAILABLE: 95 return "SERVICE_PROTOCOL_NOT_AVAILABLE"; 96 case REQUESTED_INFORMATION_NOT_AVAILABLE: 97 return "REQUESTED_INFORMATION_NOT_AVAILABLE"; 98 case BAD_REQUEST: 99 return "BAD_REQUEST"; 100 default: 101 return "UNKNOWN"; 102 } 103 } 104 105 /** not used */ Status()106 private Status() {} 107 } 108 109 /** 110 * Hidden constructor. This is only used in framework. 111 * 112 * @param serviceType service discovery type. 113 * @param status status code. 114 * @param transId transaction id. 115 * @param device source device. 116 * @param data query data. 117 */ WifiP2pServiceResponse(int serviceType, int status, int transId, WifiP2pDevice device, byte[] data)118 protected WifiP2pServiceResponse(int serviceType, int status, int transId, 119 WifiP2pDevice device, byte[] data) { 120 mServiceType = serviceType; 121 mStatus = status; 122 mTransId = transId; 123 mDevice = device; 124 mData = data; 125 } 126 127 /** 128 * Return the service type of service discovery response. 129 * 130 * @return service discovery type.<br> 131 * e.g) {@link WifiP2pServiceInfo#SERVICE_TYPE_BONJOUR} 132 */ getServiceType()133 public int getServiceType() { 134 return mServiceType; 135 } 136 137 /** 138 * Return the status code of service discovery response. 139 * 140 * @return status code. 141 * @see Status 142 */ getStatus()143 public int getStatus() { 144 return mStatus; 145 } 146 147 /** 148 * Return the transaction id of service discovery response. 149 * 150 * @return transaction id. 151 * @hide 152 */ getTransactionId()153 public int getTransactionId() { 154 return mTransId; 155 } 156 157 /** 158 * Return response data. 159 * 160 * <pre>Data format depends on service type 161 * 162 * @return a query or response data. 163 */ getRawData()164 public byte[] getRawData() { 165 return mData; 166 } 167 168 /** 169 * Returns the source device of service discovery response. 170 * 171 * <pre>This is valid only when service discovery response. 172 * 173 * @return the source device of service discovery response. 174 */ getSrcDevice()175 public WifiP2pDevice getSrcDevice() { 176 return mDevice; 177 } 178 179 /** @hide */ setSrcDevice(WifiP2pDevice dev)180 public void setSrcDevice(WifiP2pDevice dev) { 181 if (dev == null) return; 182 this.mDevice = dev; 183 } 184 185 186 /** 187 * Create the list of WifiP2pServiceResponse instance from supplicant event. 188 * 189 * @param srcAddr source address of the service response 190 * @param tlvsBin byte array containing the binary tlvs data 191 * @return if parse failed, return null 192 * @hide 193 */ newInstance(String srcAddr, byte[] tlvsBin)194 public static List<WifiP2pServiceResponse> newInstance(String srcAddr, byte[] tlvsBin) { 195 //updateIndicator not used, and not passed up from supplicant 196 197 List<WifiP2pServiceResponse> respList = new ArrayList<WifiP2pServiceResponse>(); 198 WifiP2pDevice dev = new WifiP2pDevice(); 199 dev.deviceAddress = srcAddr; 200 if (tlvsBin == null) { 201 return null; 202 } 203 204 205 DataInputStream dis = new DataInputStream(new ByteArrayInputStream(tlvsBin)); 206 try { 207 while (dis.available() > 0) { 208 /* 209 * Service discovery header is as follows. 210 * ______________________________________________________________ 211 * | Length(2byte) | Type(1byte) | TransId(1byte)}| 212 * ______________________________________________________________ 213 * | status(1byte) | vendor specific(variable) | 214 */ 215 // The length equals to 3 plus the number of octets in the vendor 216 // specific content field. And this is little endian. 217 int length = (dis.readUnsignedByte() + 218 (dis.readUnsignedByte() << 8)) - 3; 219 int type = dis.readUnsignedByte(); 220 int transId = dis.readUnsignedByte(); 221 int status = dis.readUnsignedByte(); 222 if (length < 0) { 223 return null; 224 } 225 if (length == 0) { 226 if (status == Status.SUCCESS) { 227 respList.add(new WifiP2pServiceResponse(type, status, 228 transId, dev, null)); 229 } 230 continue; 231 } 232 if (length > MAX_BUF_SIZE) { 233 dis.skip(length); 234 continue; 235 } 236 byte[] data = new byte[length]; 237 dis.readFully(data); 238 239 WifiP2pServiceResponse resp; 240 if (type == WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR) { 241 resp = WifiP2pDnsSdServiceResponse.newInstance(status, 242 transId, dev, data); 243 } else if (type == WifiP2pServiceInfo.SERVICE_TYPE_UPNP) { 244 resp = WifiP2pUpnpServiceResponse.newInstance(status, 245 transId, dev, data); 246 } else { 247 resp = new WifiP2pServiceResponse(type, status, transId, dev, data); 248 } 249 if (resp != null && resp.getStatus() == Status.SUCCESS) { 250 respList.add(resp); 251 } 252 } 253 return respList; 254 } catch (IOException e) { 255 e.printStackTrace(); 256 } 257 258 if (respList.size() > 0) { 259 return respList; 260 } 261 return null; 262 } 263 264 /** 265 * Converts hex string to byte array. 266 * 267 * @param hex hex string. if invalid, return null. 268 * @return binary data. 269 */ hexStr2Bin(String hex)270 private static byte[] hexStr2Bin(String hex) { 271 int sz = hex.length()/2; 272 byte[] b = new byte[hex.length()/2]; 273 274 for (int i=0;i<sz;i++) { 275 try { 276 b[i] = (byte)Integer.parseInt(hex.substring(i*2, i*2+2), 16); 277 } catch (Exception e) { 278 e.printStackTrace(); 279 return null; 280 } 281 } 282 return b; 283 } 284 285 @Override toString()286 public String toString() { 287 StringBuffer sbuf = new StringBuffer(); 288 sbuf.append("serviceType:").append(mServiceType); 289 sbuf.append(" status:").append(Status.toString(mStatus)); 290 sbuf.append(" srcAddr:").append(mDevice.deviceAddress); 291 sbuf.append(" data:").append(Arrays.toString(mData)); 292 return sbuf.toString(); 293 } 294 295 @Override equals(Object o)296 public boolean equals(Object o) { 297 if (o == this) { 298 return true; 299 } 300 if (!(o instanceof WifiP2pServiceResponse)) { 301 return false; 302 } 303 304 WifiP2pServiceResponse req = (WifiP2pServiceResponse)o; 305 306 return (req.mServiceType == mServiceType) && 307 (req.mStatus == mStatus) && 308 equals(req.mDevice.deviceAddress, mDevice.deviceAddress) && 309 Arrays.equals(req.mData, mData); 310 } 311 equals(Object a, Object b)312 private boolean equals(Object a, Object b) { 313 if (a == null && b == null) { 314 return true; 315 } else if (a != null) { 316 return a.equals(b); 317 } 318 return false; 319 } 320 321 @Override hashCode()322 public int hashCode() { 323 int result = 17; 324 result = 31 * result + mServiceType; 325 result = 31 * result + mStatus; 326 result = 31 * result + mTransId; 327 result = 31 * result + (mDevice.deviceAddress == null ? 328 0 : mDevice.deviceAddress.hashCode()); 329 result = 31 * result + (mData == null ? 0 : Arrays.hashCode(mData)); 330 return result; 331 } 332 333 /** Implement the Parcelable interface {@hide} */ describeContents()334 public int describeContents() { 335 return 0; 336 } 337 338 /** Implement the Parcelable interface {@hide} */ writeToParcel(Parcel dest, int flags)339 public void writeToParcel(Parcel dest, int flags) { 340 dest.writeInt(mServiceType); 341 dest.writeInt(mStatus); 342 dest.writeInt(mTransId); 343 dest.writeParcelable(mDevice, flags); 344 if (mData == null || mData.length == 0) { 345 dest.writeInt(0); 346 } else { 347 dest.writeInt(mData.length); 348 dest.writeByteArray(mData); 349 } 350 } 351 352 /** Implement the Parcelable interface {@hide} */ 353 public static final @android.annotation.NonNull Creator<WifiP2pServiceResponse> CREATOR = 354 new Creator<WifiP2pServiceResponse>() { 355 public WifiP2pServiceResponse createFromParcel(Parcel in) { 356 357 int type = in.readInt(); 358 int status = in.readInt(); 359 int transId = in.readInt(); 360 WifiP2pDevice dev = (WifiP2pDevice)in.readParcelable(null); 361 int len = in.readInt(); 362 byte[] data = null; 363 if (len > 0) { 364 data = new byte[len]; 365 in.readByteArray(data); 366 } 367 if (type == WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR) { 368 return WifiP2pDnsSdServiceResponse.newInstance(status, 369 transId, dev, data); 370 } else if (type == WifiP2pServiceInfo.SERVICE_TYPE_UPNP) { 371 return WifiP2pUpnpServiceResponse.newInstance(status, 372 transId, dev, data); 373 } 374 return new WifiP2pServiceResponse(type, status, transId, dev, data); 375 } 376 377 public WifiP2pServiceResponse[] newArray(int size) { 378 return new WifiP2pServiceResponse[size]; 379 } 380 }; 381 } 382