Home | History | Annotate | Download | only in lowpan
      1 /*
      2  * Copyright (C) 2017 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.lowpan;
     18 
     19 import android.annotation.NonNull;
     20 import android.icu.text.StringPrep;
     21 import android.icu.text.StringPrepParseException;
     22 import android.os.Parcel;
     23 import android.os.Parcelable;
     24 import android.util.Log;
     25 import com.android.internal.util.HexDump;
     26 import java.nio.charset.StandardCharsets;
     27 import java.util.Arrays;
     28 import java.util.Objects;
     29 
     30 /**
     31  * Describes an instance of a LoWPAN network.
     32  *
     33  * @hide
     34  */
     35 // @SystemApi
     36 public class LowpanIdentity implements Parcelable {
     37     private static final String TAG = LowpanIdentity.class.getSimpleName();
     38 
     39     // Constants
     40     public static final int UNSPECIFIED_CHANNEL = -1;
     41     public static final int UNSPECIFIED_PANID = 0xFFFFFFFF;
     42     // Builder
     43 
     44     /** @hide */
     45     // @SystemApi
     46     public static class Builder {
     47         private static final StringPrep stringPrep =
     48                 StringPrep.getInstance(StringPrep.RFC3920_RESOURCEPREP);
     49 
     50         final LowpanIdentity mIdentity = new LowpanIdentity();
     51 
     52         private static String escape(@NonNull byte[] bytes) {
     53             StringBuffer sb = new StringBuffer();
     54             for (byte b : bytes) {
     55                 if (b >= 32 && b <= 126) {
     56                     sb.append((char) b);
     57                 } else {
     58                     sb.append(String.format("\\0x%02x", b & 0xFF));
     59                 }
     60             }
     61             return sb.toString();
     62         }
     63 
     64         public Builder setLowpanIdentity(@NonNull LowpanIdentity x) {
     65             Objects.requireNonNull(x);
     66             setRawName(x.getRawName());
     67             setXpanid(x.getXpanid());
     68             setPanid(x.getPanid());
     69             setChannel(x.getChannel());
     70             setType(x.getType());
     71             return this;
     72         }
     73 
     74         public Builder setName(@NonNull String name) {
     75             Objects.requireNonNull(name);
     76             try {
     77                 mIdentity.mName = stringPrep.prepare(name, StringPrep.DEFAULT);
     78                 mIdentity.mRawName = mIdentity.mName.getBytes(StandardCharsets.UTF_8);
     79                 mIdentity.mIsNameValid = true;
     80             } catch (StringPrepParseException x) {
     81                 Log.w(TAG, x.toString());
     82                 setRawName(name.getBytes(StandardCharsets.UTF_8));
     83             }
     84             return this;
     85         }
     86 
     87         public Builder setRawName(@NonNull byte[] name) {
     88             Objects.requireNonNull(name);
     89             mIdentity.mRawName = name.clone();
     90             mIdentity.mName = new String(name, StandardCharsets.UTF_8);
     91             try {
     92                 String nameCheck = stringPrep.prepare(mIdentity.mName, StringPrep.DEFAULT);
     93                 mIdentity.mIsNameValid =
     94                         Arrays.equals(nameCheck.getBytes(StandardCharsets.UTF_8), name);
     95             } catch (StringPrepParseException x) {
     96                 Log.w(TAG, x.toString());
     97                 mIdentity.mIsNameValid = false;
     98             }
     99 
    100             // Non-normal names must be rendered differently to avoid confusion.
    101             if (!mIdentity.mIsNameValid) {
    102                 mIdentity.mName = "" + escape(name) + "";
    103             }
    104 
    105             return this;
    106         }
    107 
    108         public Builder setXpanid(byte x[]) {
    109             mIdentity.mXpanid = (x != null ? x.clone() : null);
    110             return this;
    111         }
    112 
    113         public Builder setPanid(int x) {
    114             mIdentity.mPanid = x;
    115             return this;
    116         }
    117 
    118         public Builder setType(@NonNull String x) {
    119             mIdentity.mType = x;
    120             return this;
    121         }
    122 
    123         public Builder setChannel(int x) {
    124             mIdentity.mChannel = x;
    125             return this;
    126         }
    127 
    128         public LowpanIdentity build() {
    129             return mIdentity;
    130         }
    131     }
    132 
    133     LowpanIdentity() {}
    134 
    135     // Instance Variables
    136 
    137     private String mName = "";
    138     private boolean mIsNameValid = true;
    139     private byte[] mRawName = new byte[0];
    140     private String mType = "";
    141     private byte[] mXpanid = new byte[0];
    142     private int mPanid = UNSPECIFIED_PANID;
    143     private int mChannel = UNSPECIFIED_CHANNEL;
    144 
    145     // Public Getters
    146 
    147     public String getName() {
    148         return mName;
    149     }
    150 
    151     public boolean isNameValid() {
    152         return mIsNameValid;
    153     }
    154 
    155     public byte[] getRawName() {
    156         return mRawName.clone();
    157     }
    158 
    159     public byte[] getXpanid() {
    160         return mXpanid.clone();
    161     }
    162 
    163     public int getPanid() {
    164         return mPanid;
    165     }
    166 
    167     public String getType() {
    168         return mType;
    169     }
    170 
    171     public int getChannel() {
    172         return mChannel;
    173     }
    174 
    175     @Override
    176     public String toString() {
    177         StringBuffer sb = new StringBuffer();
    178 
    179         sb.append("Name:").append(getName());
    180 
    181         if (mType.length() > 0) {
    182             sb.append(", Type:").append(mType);
    183         }
    184 
    185         if (mXpanid.length > 0) {
    186             sb.append(", XPANID:").append(HexDump.toHexString(mXpanid));
    187         }
    188 
    189         if (mPanid != UNSPECIFIED_PANID) {
    190             sb.append(", PANID:").append(String.format("0x%04X", mPanid));
    191         }
    192 
    193         if (mChannel != UNSPECIFIED_CHANNEL) {
    194             sb.append(", Channel:").append(mChannel);
    195         }
    196 
    197         return sb.toString();
    198     }
    199 
    200     @Override
    201     public boolean equals(Object obj) {
    202         if (!(obj instanceof LowpanIdentity)) {
    203             return false;
    204         }
    205         LowpanIdentity rhs = (LowpanIdentity) obj;
    206         return Arrays.equals(mRawName, rhs.mRawName)
    207                 && Arrays.equals(mXpanid, rhs.mXpanid)
    208                 && mType.equals(rhs.mType)
    209                 && mPanid == rhs.mPanid
    210                 && mChannel == rhs.mChannel;
    211     }
    212 
    213     @Override
    214     public int hashCode() {
    215         return Objects.hash(
    216                 Arrays.hashCode(mRawName), mType, Arrays.hashCode(mXpanid), mPanid, mChannel);
    217     }
    218 
    219     /** Implement the Parcelable interface. */
    220     @Override
    221     public int describeContents() {
    222         return 0;
    223     }
    224 
    225     /** Implement the Parcelable interface. */
    226     @Override
    227     public void writeToParcel(Parcel dest, int flags) {
    228         dest.writeByteArray(mRawName);
    229         dest.writeString(mType);
    230         dest.writeByteArray(mXpanid);
    231         dest.writeInt(mPanid);
    232         dest.writeInt(mChannel);
    233     }
    234 
    235     /** Implement the Parcelable interface. */
    236     public static final Creator<LowpanIdentity> CREATOR =
    237             new Creator<LowpanIdentity>() {
    238 
    239                 public LowpanIdentity createFromParcel(Parcel in) {
    240                     Builder builder = new Builder();
    241 
    242                     builder.setRawName(in.createByteArray());
    243                     builder.setType(in.readString());
    244                     builder.setXpanid(in.createByteArray());
    245                     builder.setPanid(in.readInt());
    246                     builder.setChannel(in.readInt());
    247 
    248                     return builder.build();
    249                 }
    250 
    251                 public LowpanIdentity[] newArray(int size) {
    252                     return new LowpanIdentity[size];
    253                 }
    254             };
    255 }
    256