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      * <pre>The format is as follows.
    190      * P2P-SERV-DISC-RESP &lt;address&gt; &lt;update indicator&gt; &lt;response data&gt;
    191      * e.g) P2P-SERV-DISC-RESP 02:03:7f:11:62:da 1 0300000101
    192      *
    193      * @param supplicantEvent wpa_supplicant event string.
    194      * @return if parse failed, return null
    195      * @hide
    196      */
    197     public static List<WifiP2pServiceResponse> newInstance(String supplicantEvent) {
    198 
    199         List<WifiP2pServiceResponse> respList = new ArrayList<WifiP2pServiceResponse>();
    200         String[] args = supplicantEvent.split(" ");
    201         if (args.length != 4) {
    202             return null;
    203         }
    204         WifiP2pDevice dev = new WifiP2pDevice();
    205         String srcAddr = args[1];
    206         dev.deviceAddress = srcAddr;
    207         //String updateIndicator = args[2];//not used.
    208         byte[] bin = hexStr2Bin(args[3]);
    209         if (bin == null) {
    210             return null;
    211         }
    212 
    213         DataInputStream dis = new DataInputStream(new ByteArrayInputStream(bin));
    214         try {
    215             while (dis.available() > 0) {
    216                 /*
    217                  * Service discovery header is as follows.
    218                  * ______________________________________________________________
    219                  * |           Length(2byte)     | Type(1byte) | TransId(1byte)}|
    220                  * ______________________________________________________________
    221                  * | status(1byte)  |            vendor specific(variable)      |
    222                  */
    223                 // The length equals to 3 plus the number of octets in the vendor
    224                 // specific content field. And this is little endian.
    225                 int length = (dis.readUnsignedByte() +
    226                         (dis.readUnsignedByte() << 8)) - 3;
    227                 int type = dis.readUnsignedByte();
    228                 int transId = dis.readUnsignedByte();
    229                 int status = dis.readUnsignedByte();
    230                 if (length < 0) {
    231                     return null;
    232                 }
    233                 if (length == 0) {
    234                     if (status == Status.SUCCESS) {
    235                         respList.add(new WifiP2pServiceResponse(type, status,
    236                             transId, dev, null));
    237                     }
    238                     continue;
    239                 }
    240                 if (length > MAX_BUF_SIZE) {
    241                     dis.skip(length);
    242                     continue;
    243                 }
    244                 byte[] data = new byte[length];
    245                 dis.readFully(data);
    246 
    247                 WifiP2pServiceResponse resp;
    248                 if (type ==  WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR) {
    249                     resp = WifiP2pDnsSdServiceResponse.newInstance(status,
    250                             transId, dev, data);
    251                 } else if (type == WifiP2pServiceInfo.SERVICE_TYPE_UPNP) {
    252                     resp = WifiP2pUpnpServiceResponse.newInstance(status,
    253                             transId, dev, data);
    254                 } else {
    255                     resp = new WifiP2pServiceResponse(type, status, transId, dev, data);
    256                 }
    257                 if (resp != null && resp.getStatus() == Status.SUCCESS) {
    258                     respList.add(resp);
    259                 }
    260             }
    261             return respList;
    262         } catch (IOException e) {
    263             e.printStackTrace();
    264         }
    265 
    266         if (respList.size() > 0) {
    267             return respList;
    268         }
    269         return null;
    270     }
    271 
    272     /**
    273      * Converts hex string to byte array.
    274      *
    275      * @param hex hex string. if invalid, return null.
    276      * @return binary data.
    277      */
    278     private static byte[] hexStr2Bin(String hex) {
    279         int sz = hex.length()/2;
    280         byte[] b = new byte[hex.length()/2];
    281 
    282         for (int i=0;i<sz;i++) {
    283             try {
    284                 b[i] = (byte)Integer.parseInt(hex.substring(i*2, i*2+2), 16);
    285             } catch (Exception e) {
    286                 e.printStackTrace();
    287                 return null;
    288             }
    289         }
    290         return b;
    291     }
    292 
    293     @Override
    294     public String toString() {
    295         StringBuffer sbuf = new StringBuffer();
    296         sbuf.append("serviceType:").append(mServiceType);
    297         sbuf.append(" status:").append(Status.toString(mStatus));
    298         sbuf.append(" srcAddr:").append(mDevice.deviceAddress);
    299         sbuf.append(" data:").append(mData);
    300         return sbuf.toString();
    301     }
    302 
    303     @Override
    304     public boolean equals(Object o) {
    305         if (o == this) {
    306             return true;
    307         }
    308         if (!(o instanceof WifiP2pServiceResponse)) {
    309             return false;
    310         }
    311 
    312         WifiP2pServiceResponse req = (WifiP2pServiceResponse)o;
    313 
    314         return (req.mServiceType == mServiceType) &&
    315             (req.mStatus == mStatus) &&
    316                 equals(req.mDevice.deviceAddress, mDevice.deviceAddress) &&
    317                 Arrays.equals(req.mData, mData);
    318     }
    319 
    320     private boolean equals(Object a, Object b) {
    321         if (a == null && b == null) {
    322             return true;
    323         } else if (a != null) {
    324             return a.equals(b);
    325         }
    326         return false;
    327     }
    328 
    329     @Override
    330     public int hashCode() {
    331         int result = 17;
    332         result = 31 * result + mServiceType;
    333         result = 31 * result + mStatus;
    334         result = 31 * result + mTransId;
    335         result = 31 * result + (mDevice.deviceAddress == null ?
    336                 0 : mDevice.deviceAddress.hashCode());
    337         result = 31 * result + (mData == null ? 0 : mData.hashCode());
    338         return result;
    339     }
    340 
    341     /** Implement the Parcelable interface {@hide} */
    342     public int describeContents() {
    343         return 0;
    344     }
    345 
    346     /** Implement the Parcelable interface {@hide} */
    347     public void writeToParcel(Parcel dest, int flags) {
    348         dest.writeInt(mServiceType);
    349         dest.writeInt(mStatus);
    350         dest.writeInt(mTransId);
    351         dest.writeParcelable(mDevice, flags);
    352         if (mData == null || mData.length == 0) {
    353             dest.writeInt(0);
    354         } else {
    355             dest.writeInt(mData.length);
    356             dest.writeByteArray(mData);
    357         }
    358     }
    359 
    360     /** Implement the Parcelable interface {@hide} */
    361     public static final Creator<WifiP2pServiceResponse> CREATOR =
    362         new Creator<WifiP2pServiceResponse>() {
    363             public WifiP2pServiceResponse createFromParcel(Parcel in) {
    364 
    365                 int type = in.readInt();
    366                 int status = in.readInt();
    367                 int transId = in.readInt();
    368                 WifiP2pDevice dev = (WifiP2pDevice)in.readParcelable(null);
    369                 int len = in.readInt();
    370                 byte[] data = null;
    371                 if (len > 0) {
    372                     data = new byte[len];
    373                     in.readByteArray(data);
    374                 }
    375                 if (type ==  WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR) {
    376                     return WifiP2pDnsSdServiceResponse.newInstance(status,
    377                             transId, dev, data);
    378                 } else if (type == WifiP2pServiceInfo.SERVICE_TYPE_UPNP) {
    379                     return WifiP2pUpnpServiceResponse.newInstance(status,
    380                             transId, dev, data);
    381                 }
    382                 return new WifiP2pServiceResponse(type, status, transId, dev, data);
    383             }
    384 
    385             public WifiP2pServiceResponse[] newArray(int size) {
    386                 return new WifiP2pServiceResponse[size];
    387             }
    388         };
    389 }
    390