Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1dc2ff66 authored by Lorenzo Colitti's avatar Lorenzo Colitti Committed by Android (Google) Code Review
Browse files

Merge "RouteInfo changes." into jb-mr2-dev

parents 614edf58 45b9a5bb
Loading
Loading
Loading
Loading
+22 −1
Original line number Diff line number Diff line
@@ -92,6 +92,11 @@ public class LinkProperties implements Parcelable {

    public void setInterfaceName(String iface) {
        mIfaceName = iface;
        ArrayList<RouteInfo> newRoutes = new ArrayList<RouteInfo>(mRoutes.size());
        for (RouteInfo route : mRoutes) {
            newRoutes.add(routeWithInterface(route));
        }
        mRoutes = newRoutes;
    }

    public String getInterfaceName() {
@@ -130,9 +135,25 @@ public class LinkProperties implements Parcelable {
        mDomains = domains;
    }

    private RouteInfo routeWithInterface(RouteInfo route) {
        return new RouteInfo(
            route.getDestination(),
            route.getGateway(),
            mIfaceName);
    }

    public void addRoute(RouteInfo route) {
        if (route != null) mRoutes.add(route);
        if (route != null) {
            String routeIface = route.getInterface();
            if (routeIface != null && !routeIface.equals(mIfaceName)) {
                throw new IllegalStateException(
                   "Route added with non-matching interface: " + routeIface +
                   " vs. mIfaceName");
            }
            mRoutes.add(routeWithInterface(route));
        }
    }

    public Collection<RouteInfo> getRoutes() {
        return Collections.unmodifiableCollection(mRoutes);
    }
+59 −13
Original line number Diff line number Diff line
@@ -29,6 +29,17 @@ import java.util.Collection;
/**
 * A simple container for route information.
 *
 * In order to be used, a route must have a destination prefix and:
 *
 * - A gateway address (next-hop, for gatewayed routes), or
 * - An interface (for directly-connected routes), or
 * - Both a gateway and an interface.
 *
 * This class does not enforce these constraints because there is code that
 * uses RouteInfo objects to store directly-connected routes without interfaces.
 * Such objects cannot be used directly, but can be put into a LinkProperties
 * object which then specifies the interface.
 *
 * @hide
 */
public class RouteInfo implements Parcelable {
@@ -42,10 +53,30 @@ public class RouteInfo implements Parcelable {
     */
    private final InetAddress mGateway;

    /**
     * The interface for this route.
     */
    private final String mInterface;

    private final boolean mIsDefault;
    private final boolean mIsHost;

    public RouteInfo(LinkAddress destination, InetAddress gateway) {
    /**
     * Constructs a RouteInfo object.
     *
     * If @destination is null, then @gateway must be specified and the
     * constructed route is either the IPv4 default route <code>0.0.0.0</code>
     * if @gateway is an instance of {@link Inet4Address}, or the IPv6 default
     * route <code>::/0</code> if @gateway is an instance of
     * {@link Inet6Address}.
     *
     * @destination and @gateway may not both be null.
     *
     * @param destination the destination prefix
     * @param gateway the IP address to route packets through
     * @param iface the interface name to send packets on
     */
    public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
        if (destination == null) {
            if (gateway != null) {
                if (gateway instanceof Inet4Address) {
@@ -55,7 +86,8 @@ public class RouteInfo implements Parcelable {
                }
            } else {
                // no destination, no gateway. invalid.
                throw new RuntimeException("Invalid arguments passed in.");
                throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," +
                                                   destination);
            }
        }
        if (gateway == null) {
@@ -68,16 +100,21 @@ public class RouteInfo implements Parcelable {
        mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(),
                destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
        mGateway = gateway;
        mInterface = iface;
        mIsDefault = isDefault();
        mIsHost = isHost();
    }

    public RouteInfo(LinkAddress destination, InetAddress gateway) {
        this(destination, gateway, null);
    }

    public RouteInfo(InetAddress gateway) {
        this(null, gateway);
        this(null, gateway, null);
    }

    public RouteInfo(LinkAddress host) {
        this(host, null);
        this(host, null, null);
    }

    public static RouteInfo makeHostRoute(InetAddress host) {
@@ -119,6 +156,10 @@ public class RouteInfo implements Parcelable {
        return mGateway;
    }

    public String getInterface() {
        return mInterface;
    }

    public boolean isDefaultRoute() {
        return mIsDefault;
    }
@@ -153,6 +194,8 @@ public class RouteInfo implements Parcelable {
            dest.writeByte((byte) 1);
            dest.writeByteArray(mGateway.getAddress());
        }

        dest.writeString(mInterface);
    }

    @Override
@@ -171,14 +214,19 @@ public class RouteInfo implements Parcelable {
                target.getGateway() == null
                : mGateway.equals(target.getGateway());

        return sameDestination && sameAddress
        boolean sameInterface = (mInterface == null) ?
                target.getInterface() == null
                : mInterface.equals(target.getInterface());

        return sameDestination && sameAddress && sameInterface
            && mIsDefault == target.mIsDefault;
    }

    @Override
    public int hashCode() {
        return (mDestination == null ? 0 : mDestination.hashCode())
            + (mGateway == null ? 0 :mGateway.hashCode())
        return (mDestination == null ? 0 : mDestination.hashCode() * 41)
            + (mGateway == null ? 0 :mGateway.hashCode() * 47)
            + (mInterface == null ? 0 :mInterface.hashCode() * 67)
            + (mIsDefault ? 3 : 7);
    }

@@ -206,13 +254,15 @@ public class RouteInfo implements Parcelable {
                } catch (UnknownHostException e) {}
            }

            String iface = in.readString();

            LinkAddress dest = null;

            if (destAddr != null) {
                dest = new LinkAddress(destAddr, prefix);
            }

            return new RouteInfo(dest, gateway);
            return new RouteInfo(dest, gateway, iface);
        }

        public RouteInfo[] newArray(int size) {
@@ -220,13 +270,9 @@ public class RouteInfo implements Parcelable {
        }
    };

    private boolean matches(InetAddress destination) {
    protected boolean matches(InetAddress destination) {
        if (destination == null) return false;

        // if the destination is present and the route is default.
        // return true
        if (isDefault()) return true;

        // match the route destination and destination with prefix length
        InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
                mDestination.getNetworkPrefixLength());
+180 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.net;

import java.lang.reflect.Method;
import java.net.InetAddress;

import android.net.LinkAddress;
import android.net.RouteInfo;
import android.os.Parcel;

import junit.framework.TestCase;
import android.test.suitebuilder.annotation.SmallTest;

public class RouteInfoTest extends TestCase {

    private InetAddress Address(String addr) {
        return InetAddress.parseNumericAddress(addr);
    }

    private LinkAddress Prefix(String prefix) {
        String[] parts = prefix.split("/");
        return new LinkAddress(Address(parts[0]), Integer.parseInt(parts[1]));
    }

    @SmallTest
    public void testConstructor() {
        RouteInfo r;

        // Invalid input.
        try {
            r = new RouteInfo(null, null, "rmnet0");
            fail("Expected RuntimeException:  destination and gateway null");
        } catch(RuntimeException e) {}

        // Null destination is default route.
        r = new RouteInfo(null, Address("2001:db8::1"), null);
        assertEquals(Prefix("::/0"), r.getDestination());
        assertEquals(Address("2001:db8::1"), r.getGateway());
        assertNull(r.getInterface());

        r = new RouteInfo(null, Address("192.0.2.1"), "wlan0");
        assertEquals(Prefix("0.0.0.0/0"), r.getDestination());
        assertEquals(Address("192.0.2.1"), r.getGateway());
        assertEquals("wlan0", r.getInterface());

        // Null gateway sets gateway to unspecified address (why?).
        r = new RouteInfo(Prefix("2001:db8:beef:cafe::/48"), null, "lo");
        assertEquals(Prefix("2001:db8:beef::/48"), r.getDestination());
        assertEquals(Address("::"), r.getGateway());
        assertEquals("lo", r.getInterface());

        r = new RouteInfo(Prefix("192.0.2.5/24"), null);
        assertEquals(Prefix("192.0.2.0/24"), r.getDestination());
        assertEquals(Address("0.0.0.0"), r.getGateway());
        assertNull(r.getInterface());
    }

    public void testMatches() {
        class PatchedRouteInfo extends RouteInfo {
            public PatchedRouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
                super(destination, gateway, iface);
            }

            public boolean matches(InetAddress destination) {
                return super.matches(destination);
            }
        }

        RouteInfo r;

        r = new PatchedRouteInfo(Prefix("2001:db8:f00::ace:d00d/127"), null, "rmnet0");
        assertTrue(r.matches(Address("2001:db8:f00::ace:d00c")));
        assertTrue(r.matches(Address("2001:db8:f00::ace:d00d")));
        assertFalse(r.matches(Address("2001:db8:f00::ace:d00e")));
        assertFalse(r.matches(Address("2001:db8:f00::bad:d00d")));
        assertFalse(r.matches(Address("2001:4868:4860::8888")));

        r = new PatchedRouteInfo(Prefix("192.0.2.0/23"), null, "wlan0");
        assertTrue(r.matches(Address("192.0.2.43")));
        assertTrue(r.matches(Address("192.0.3.21")));
        assertFalse(r.matches(Address("192.0.0.21")));
        assertFalse(r.matches(Address("8.8.8.8")));

        RouteInfo ipv6Default = new PatchedRouteInfo(Prefix("::/0"), null, "rmnet0");
        assertTrue(ipv6Default.matches(Address("2001:db8::f00")));
        assertFalse(ipv6Default.matches(Address("192.0.2.1")));

        RouteInfo ipv4Default = new PatchedRouteInfo(Prefix("0.0.0.0/0"), null, "rmnet0");
        assertTrue(ipv4Default.matches(Address("255.255.255.255")));
        assertTrue(ipv4Default.matches(Address("192.0.2.1")));
        assertFalse(ipv4Default.matches(Address("2001:db8::f00")));
    }

    private void assertAreEqual(Object o1, Object o2) {
        assertTrue(o1.equals(o2));
        assertTrue(o2.equals(o1));
    }

    private void assertAreNotEqual(Object o1, Object o2) {
        assertFalse(o1.equals(o2));
        assertFalse(o2.equals(o1));
    }

    public void testEquals() {
        // IPv4
        RouteInfo r1 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
        RouteInfo r2 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
        assertAreEqual(r1, r2);

        RouteInfo r3 = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "wlan0");
        RouteInfo r4 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::2"), "wlan0");
        RouteInfo r5 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "rmnet0");
        assertAreNotEqual(r1, r3);
        assertAreNotEqual(r1, r4);
        assertAreNotEqual(r1, r5);

        // IPv6
        r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
        r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
        assertAreEqual(r1, r2);

        r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
        r4 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.2"), "wlan0");
        r5 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "rmnet0");
        assertAreNotEqual(r1, r3);
        assertAreNotEqual(r1, r4);
        assertAreNotEqual(r1, r5);

        // Interfaces (but not destinations or gateways) can be null.
        r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
        r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
        r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
        assertAreEqual(r1, r2);
        assertAreNotEqual(r1, r3);
    }

    public RouteInfo passThroughParcel(RouteInfo r) {
        Parcel p = Parcel.obtain();
        RouteInfo r2 = null;
        try {
            r.writeToParcel(p, 0);
            p.setDataPosition(0);
            r2 = RouteInfo.CREATOR.createFromParcel(p);
        } finally {
            p.recycle();
        }
        assertNotNull(r2);
        return r2;
    }

    public void assertParcelingIsLossless(RouteInfo r) {
      RouteInfo r2 = passThroughParcel(r);
      assertEquals(r, r2);
    }

    public void testParceling() {
        RouteInfo r;

        r = new RouteInfo(Prefix("::/0"), Address("2001:db8::"), null);
        assertParcelingIsLossless(r);

        r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
        assertParcelingIsLossless(r);
    }
}