RouteInfo.java revision 59b1a4ede7032c1b4d897e13dd4ede09b5e14743
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            if (gateway != null) {
50                if (gateway instanceof Inet4Address) {
51                    destination = new LinkAddress(Inet4Address.ANY, 0);
52                } else {
53                    destination = new LinkAddress(Inet6Address.ANY, 0);
54                }
55            } else {
56                // no destination, no gateway. invalid.
57                throw new RuntimeException("Invalid arguments passed in.");
58            }
59        }
60        if (gateway == null) {
61            if (destination.getAddress() instanceof Inet4Address) {
62                gateway = Inet4Address.ANY;
63            } else {
64                gateway = Inet6Address.ANY;
65            }
66        }
67        mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(),
68                destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
69        mGateway = gateway;
70        mIsDefault = isDefault();
71    }
72
73    public RouteInfo(InetAddress gateway) {
74        this(null, gateway);
75    }
76
77    public static RouteInfo makeHostRoute(InetAddress host) {
78        return makeHostRoute(host, null);
79    }
80
81    public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway) {
82        if (host == null) return null;
83
84        if (host instanceof Inet4Address) {
85            return new RouteInfo(new LinkAddress(host, 32), gateway);
86        } else {
87            return new RouteInfo(new LinkAddress(host, 128), gateway);
88        }
89    }
90
91    private boolean isDefault() {
92        boolean val = false;
93        if (mGateway != null) {
94            if (mGateway instanceof Inet4Address) {
95                val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0);
96            } else {
97                val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0);
98            }
99        }
100        return val;
101    }
102
103    public LinkAddress getDestination() {
104        return mDestination;
105    }
106
107    public InetAddress getGateway() {
108        return mGateway;
109    }
110
111    public boolean isDefaultRoute() {
112        return mIsDefault;
113    }
114
115    public String toString() {
116        String val = "";
117        if (mDestination != null) val = mDestination.toString();
118        if (mGateway != null) val += " -> " + mGateway.getHostAddress();
119        return val;
120    }
121
122    public int describeContents() {
123        return 0;
124    }
125
126    public void writeToParcel(Parcel dest, int flags) {
127        if (mDestination == null) {
128            dest.writeByte((byte) 0);
129        } else {
130            dest.writeByte((byte) 1);
131            dest.writeByteArray(mDestination.getAddress().getAddress());
132            dest.writeInt(mDestination.getNetworkPrefixLength());
133        }
134
135        if (mGateway == null) {
136            dest.writeByte((byte) 0);
137        } else {
138            dest.writeByte((byte) 1);
139            dest.writeByteArray(mGateway.getAddress());
140        }
141    }
142
143    public static final Creator<RouteInfo> CREATOR =
144        new Creator<RouteInfo>() {
145        public RouteInfo createFromParcel(Parcel in) {
146            InetAddress destAddr = null;
147            int prefix = 0;
148            InetAddress gateway = null;
149
150            if (in.readByte() == 1) {
151                byte[] addr = in.createByteArray();
152                prefix = in.readInt();
153
154                try {
155                    destAddr = InetAddress.getByAddress(addr);
156                } catch (UnknownHostException e) {}
157            }
158
159            if (in.readByte() == 1) {
160                byte[] addr = in.createByteArray();
161
162                try {
163                    gateway = InetAddress.getByAddress(addr);
164                } catch (UnknownHostException e) {}
165            }
166
167            LinkAddress dest = null;
168
169            if (destAddr != null) {
170                dest = new LinkAddress(destAddr, prefix);
171            }
172
173            return new RouteInfo(dest, gateway);
174        }
175
176        public RouteInfo[] newArray(int size) {
177            return new RouteInfo[size];
178        }
179    };
180
181    private boolean matches(InetAddress destination) {
182        if (destination == null) return false;
183
184        // if the destination is present and the route is default.
185        // return true
186        if (isDefault()) return true;
187
188        // match the route destination and destination with prefix length
189        InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
190                mDestination.getNetworkPrefixLength());
191
192        return mDestination.getAddress().equals(dstNet);
193    }
194
195    /**
196     * Find the route from a Collection of routes that best matches a given address.
197     * May return null if no routes are applicable.
198     * @param routes a Collection of RouteInfos to chose from
199     * @param dest the InetAddress your trying to get to
200     * @return the RouteInfo from the Collection that best fits the given address
201     */
202    public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
203        if ((routes == null) || (dest == null)) return null;
204
205        RouteInfo bestRoute = null;
206        // pick a longest prefix match under same address type
207        for (RouteInfo route : routes) {
208            if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) {
209                if ((bestRoute != null) &&
210                        (bestRoute.mDestination.getNetworkPrefixLength() >=
211                        route.mDestination.getNetworkPrefixLength())) {
212                    continue;
213                }
214                if (route.matches(dest)) bestRoute = route;
215            }
216        }
217        return bestRoute;
218    }
219}
220