Home | History | Annotate | Download | only in nsd
      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 */
     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 */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    175     public WifiP2pDevice getSrcDevice() {
    176         return mDevice;
    177     }
    178 
    179     /** @hide */
    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      */
    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      */
    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
    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
    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 
    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
    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} */
    334     public int describeContents() {
    335         return 0;
    336     }
    337 
    338     /** Implement the Parcelable interface {@hide} */
    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 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