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.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      */
     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      */
     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      */
    109     public int getTransactionId() {
    110         return mTransId;
    111     }
    112 
    113     /**
    114      * Set transaction id.
    115      *
    116      * @param id
    117      * @hide
    118      */
    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      */
    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      */
    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      */
    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      */
    210     public static WifiP2pServiceRequest newInstance(int protocolType ) {
    211         return new WifiP2pServiceRequest(protocolType, null);
    212     }
    213 
    214     @Override
    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
    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} */
    252     public int describeContents() {
    253         return 0;
    254     }
    255 
    256     /** Implement the Parcelable interface {@hide} */
    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