RouteInfo.java revision be2b058ec1e11e1d33b6d03230c21e5d2d7ac40c
1/*
2 * Copyright (C) 2011 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
17package android.net;
18
19import android.os.Parcel;
20import android.os.Parcelable;
21
22import java.net.UnknownHostException;
23import java.net.InetAddress;
24import java.net.Inet4Address;
25import java.net.Inet6Address;
26
27import java.util.Collection;
28
29/**
30 * A simple container for route information.
31 *
32 * @hide
33 */
34public class RouteInfo implements Parcelable {
35    /**
36     * The IP destination address for this route.
37     */
38    private final LinkAddress mDestination;
39
40    /**
41     * The gateway address for this route.
42     */
43    private final InetAddress mGateway;
44
45    private final boolean mIsDefault;
46
47    public RouteInfo(LinkAddress destination, InetAddress gateway) {
48        if (destination == null) {
49            try {
50                if (gateway != null) {
51                    if (gateway instanceof Inet4Address) {
52                        destination = new LinkAddress(Inet4Address.ANY, 0);
53                    } else {
54                        destination = new LinkAddress(Inet6Address.ANY, 0);
55                    }
56                } else {
57                    // no destination, no gateway. invalid.
58                    throw new RuntimeException("Invalid arguments passed in.");
59                }
60            } catch (Exception e) {}
61        }
62        if (gateway == null) {
63            if (destination.getAddress() instanceof Inet4Address) {
64                gateway = Inet4Address.ANY;
65            } else {
66                gateway = Inet6Address.ANY;
67            }
68        }
69        mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(),
70                destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
71        mGateway = gateway;
72        mIsDefault = isDefault();
73    }
74
75    public RouteInfo(InetAddress gateway) {
76        this(null, gateway);
77    }
78
79    private boolean isDefault() {
80        boolean val = false;
81        if (mGateway != null) {
82            if (mGateway instanceof Inet4Address) {
83                val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0);
84            } else {
85                val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0);
86            }
87        }
88        return val;
89    }
90
91    public LinkAddress getDestination() {
92        return mDestination;
93    }
94
95    public InetAddress getGateway() {
96        return mGateway;
97    }
98
99    public boolean isDefaultRoute() {
100        return mIsDefault;
101    }
102
103    public String toString() {
104        String val = "";
105        if (mDestination != null) val = mDestination.toString();
106        if (mGateway != null) val += " -> " + mGateway.getHostAddress();
107        return val;
108    }
109
110    public int describeContents() {
111        return 0;
112    }
113
114    public void writeToParcel(Parcel dest, int flags) {
115        if (mDestination == null) {
116            dest.writeByte((byte) 0);
117        } else {
118            dest.writeByte((byte) 1);
119            dest.writeByteArray(mDestination.getAddress().getAddress());
120            dest.writeInt(mDestination.getNetworkPrefixLength());
121        }
122
123        if (mGateway == null) {
124            dest.writeByte((byte) 0);
125        } else {
126            dest.writeByte((byte) 1);
127            dest.writeByteArray(mGateway.getAddress());
128        }
129    }
130
131    @Override
132    public boolean equals(Object obj) {
133        if (this == obj) return true;
134
135        if (!(obj instanceof RouteInfo)) return false;
136
137        RouteInfo target = (RouteInfo) obj;
138
139        boolean sameDestination = ( mDestination == null) ?
140                target.getDestination() == null
141                : mDestination.equals(target.getDestination());
142
143        boolean sameAddress = (mGateway == null) ?
144                target.getGateway() == null
145                : mGateway.equals(target.getGateway());
146
147        return sameDestination && sameAddress
148            && mIsDefault == target.mIsDefault;
149    }
150
151    @Override
152    public int hashCode() {
153        return (mDestination == null ? 0 : mDestination.hashCode())
154            + (mGateway == null ? 0 :mGateway.hashCode())
155            + (mIsDefault ? 3 : 7);
156    }
157
158    public static final Creator<RouteInfo> CREATOR =
159        new Creator<RouteInfo>() {
160        public RouteInfo createFromParcel(Parcel in) {
161            InetAddress destAddr = null;
162            int prefix = 0;
163            InetAddress gateway = null;
164
165            if (in.readByte() == 1) {
166                byte[] addr = in.createByteArray();
167                prefix = in.readInt();
168
169                try {
170                    destAddr = InetAddress.getByAddress(addr);
171                } catch (UnknownHostException e) {}
172            }
173
174            if (in.readByte() == 1) {
175                byte[] addr = in.createByteArray();
176
177                try {
178                    gateway = InetAddress.getByAddress(addr);
179                } catch (UnknownHostException e) {}
180            }
181
182            LinkAddress dest = null;
183
184            if (destAddr != null) {
185                dest = new LinkAddress(destAddr, prefix);
186            }
187
188            return new RouteInfo(dest, gateway);
189        }
190
191        public RouteInfo[] newArray(int size) {
192            return new RouteInfo[size];
193        }
194    };
195
196    private boolean matches(InetAddress destination) {
197        if (destination == null) return false;
198
199        // if the destination is present and the route is default.
200        // return true
201        if (isDefault()) return true;
202
203        // match the route destination and destination with prefix length
204        InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
205                mDestination.getNetworkPrefixLength());
206
207        return mDestination.getAddress().equals(dstNet);
208    }
209
210    /**
211     * Find the route from a Collection of routes that best matches a given address.
212     * May return null if no routes are applicable.
213     * @param routes a Collection of RouteInfos to chose from
214     * @param dest the InetAddress your trying to get to
215     * @return the RouteInfo from the Collection that best fits the given address
216     */
217    public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
218        if ((routes == null) || (dest == null)) return null;
219
220        RouteInfo bestRoute = null;
221        // pick a longest prefix match under same address type
222        for (RouteInfo route : routes) {
223            if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) {
224                if ((bestRoute != null) &&
225                        (bestRoute.mDestination.getNetworkPrefixLength() >=
226                        route.mDestination.getNetworkPrefixLength())) {
227                    continue;
228                }
229                if (route.matches(dest)) bestRoute = route;
230            }
231        }
232        return bestRoute;
233    }
234}
235