diff --git a/router/java/src/net/i2p/router/transport/udp/MTU.java b/router/java/src/net/i2p/router/transport/udp/MTU.java new file mode 100644 index 0000000000000000000000000000000000000000..22001b13fa7ca0e5f275b39b7a582ff5b06696bf --- /dev/null +++ b/router/java/src/net/i2p/router/transport/udp/MTU.java @@ -0,0 +1,84 @@ +package net.i2p.router.transport.udp; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; + +import net.i2p.util.VersionComparator; + +/** + * Get the MTU for the network interface of an address. + * Not available until Java 6 / Android API 9. + * @since 0.9.2 + */ +abstract class MTU { + + private static final boolean hasMTU = + (new VersionComparator()).compare(System.getProperty("java.version"), "1.6") >= 0; + + /** + * The MTU for the socket interface, if available. + * Not available for Java 5. + * @param ia null ok + * @return 0 if Java 5, or if not bound to an address; + * limited to range MIN_MTU to LARGE_MTU. + */ + public static int getMTU(InetAddress ia) { + if (ia == null || !hasMTU) + return 0; + Enumeration<NetworkInterface> ifcs; + try { + ifcs = NetworkInterface.getNetworkInterfaces(); + } catch (SocketException se) { + return 0; + } + if (ifcs != null) { + while (ifcs.hasMoreElements()) { + NetworkInterface ifc = ifcs.nextElement(); + for(Enumeration<InetAddress> addrs = ifc.getInetAddresses(); addrs.hasMoreElements();) { + InetAddress addr = addrs.nextElement(); + if (ia.equals(addr)) { + try { + // testing + //return ifc.getMTU(); + return rectify(ifc.getMTU()); + } catch (SocketException se) { + // ignore + } catch (Throwable t) { + // NoSuchMethodException or NoSuchMethodError if we somehow got the + // version detection wrong or the JVM doesn't support it + return 0; + } + } + } + } + } + return 0; + } + + /** + * @return min of PeerState.MIN_MTU, max of PeerState.LARGE_MTU, + * rectifyed so rv % 16 == 12 + */ + public static int rectify(int mtu) { + int rv = mtu; + int mod = rv % 16; + if (mod > 12) + rv -= mod - 12; + else if (mod < 12) + rv -= mod + 4; + return Math.max(PeerState.MIN_MTU, Math.min(PeerState.LARGE_MTU, rv)); + } + +/**** + public static void main(String args[]) { + try { + InetAddress test = InetAddress.getByName(args[0]); + System.out.println("MTU is " + getMTU(test)); + } catch (Exception e) { + e.printStackTrace(); + } + } +****/ +} diff --git a/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java b/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java index 9531335b42a19172d0c2a0cbc966f21994c40979..2723c3ac791ec63179d75f7df532fb1ebb739c39 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java @@ -154,4 +154,15 @@ class UDPEndpoint { return null; return _receiver.receiveNext(); } + + /** + * The MTU for the socket interface, if available. + * Not available for Java 5. + * @return 0 if Java 5, or if bound to an address; + * limited to range MIN_MTU to LARGE_MTU. + * @since 0.9.2 + */ + public int getMTU() { + return MTU.getMTU(_bindAddress); + } }