Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6418238

REGRESSION: InetAddress.isReachable() throws ConnectException at high load

XMLWordPrintable

    • b85
    • x86
    • windows_xp

      FULL PRODUCT VERSION :
      java version "1.6.0-beta"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.6.0-beta-b59g)
      Java HotSpot(TM) Client VM (build 1.6.0-beta-b59g, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows XP [Version 5.1.2600]

      A DESCRIPTION OF THE PROBLEM :
      After about 3960 calls to java.net.InetAddress.isReachable() that has timed out I get the following exception. Running under 1.5.0_06 does not give this exception (if it is because it isn't thrown, or if it is because it doesn't occur is a different question).

      java.net.ConnectException: An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full
      at java.net.Inet6AddressImpl.isReachable0(Native Method)
      at java.net.Inet6AddressImpl.isReachable(Inet6AddressImpl.java:59)
      at java.net.InetAddress.isReachable(InetAddress.java:418)
      at java.net.InetAddress.isReachable(InetAddress.java:377)
      at com.myprog.NodeManager$AliveProber.run(NodeManager.java:316)

      The timeout has been set to 1 second (1000 ms) and varying the number of outstanding calls to isReachable() does not cause any major change in how many calls that are needed for the exception to occur.

      I intended to use this call to discover devices in a local network by looping through all IP addresses for the subnetwork when I hit this problem.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Code used to re-create the bug is executed in:
      network: 10.2.2.40
      subnetmask: 255.255.240.0


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      I would expect that this error only should occur if I have too many outstanding requests at a time and not after a certain number of requests.


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package com.teleca.monitor.server;

      import java.io.IOException;
      import java.net.Inet4Address;
      import java.net.Inet6Address;
      import java.net.InetAddress;
      import java.net.NetworkInterface;
      import java.net.SocketException;
      import java.net.UnknownHostException;
      import java.util.Enumeration;
      import java.util.Hashtable;
      import java.util.Vector;

      public class NodeManager
      {
      private final static int MAX_OUTSTANDING=8; // Tune for number of outstanding requests, tried values have been up to 256.

      static Hashtable<InetAddress, Object> aliveHosts = new Hashtable<InetAddress, Object>();
      static Object lockObj=new Object();
      static int calls=0;

      public NodeManager()
      {
      }

      /**
      * Get all nodes available on given network interface.
      * <p>
      * Notice that this utilizes ICMP PING and/or TCP/ECHO to detect nodes.
      * If the node is configured to not respond to PING and/or TCP/ECHO
      * requests it will not be detected.
      *
      * @param ni Interface to scan.
      * @return Array of InetAddress.
      */
      // public static InetAddress[] discoverNodes(NetworkInterface ni)
      // {
      // InetAddress[] iaa = null;
      // List<InterfaceAddress> ifl = ni.getInterfaceAddresses();
      // for (Iterator<InterfaceAddress> i = ifl.iterator(); i.hasNext();)
      // {
      // InterfaceAddress ifa = i.next();
      // short prefix = ifa.getNetworkPrefixLength();
      // InetAddress ina = ifa.getAddress();
      // iaa = discoverNodes(ina, prefix);
      // }
      // return iaa;
      // }

      /**
      * Get all nodes on a given network masked by given prefix.
      * <p>
      * Notice that this utilizes ICMP PING and/or TCP/ECHO to detect nodes.
      * If the node is configured to not respond to PING and/or TCP/ECHO
      * requests it will not be detected.
      *
      * @param ina Address to scan for nodes, masked by 'prefix' bits.
      * @param prefix Number of bits that are network prefix.
      * @return Array of InetAddress.
      */
      private static InetAddress[] discoverNodes(InetAddress ina, short prefix)
      {
      InetAddress[] iaa = null;

      if (ina instanceof Inet4Address && prefix > 0)
      {
      byte[] addr = ina.getAddress();
      System.out.println("prefix=" + prefix);
      System.out.println("addr.length=" + addr.length);
      System.out.print("addr=");
      for (int i = 0; i < addr.length; i++)
      {
      if (ina instanceof Inet4Address)
      {
      System.out.print(Integer.toString(addr[i] & 0xff) + ".");
      } else
      {
      System.out.print(Integer.toHexString(addr[i] & 0xff) + ":");
      }
      }
      System.out.print(" ; ");
      int nodebits = (addr.length * 8) - prefix;

      if (nodebits <= 0)
      {
      iaa = new InetAddress[1];
      iaa[0] = ina;
      } else
      {
      byte[] firstAddr = new byte[addr.length];
      int bitsLeft = prefix;
      int mask = 0;
      int maskByte = -1;

      for (int i = 0; i < addr.length; i++)
      {
      if (bitsLeft >= 8)
      {
      firstAddr[i] = addr[i];
      bitsLeft -= 8;
      } else
      {
      if (bitsLeft > 0)
      {
      maskByte = i;
      for (int j = 0; j < 8 && bitsLeft > 0; j++)
      {
      mask <<= 1;
      mask |= 1;
      bitsLeft--;
      }
      firstAddr[i] = (byte) ((addr[i] & ~mask) & 0xff);
      } else
      {
      if (maskByte == -1)
      {
      maskByte = i;
      }
      firstAddr[i] = 0;
      }
      }
      }

      firstAddr[addr.length - 1] |= 1;

      System.out.print("Mask[" + maskByte + "]=" + Integer.toHexString(mask & 0xff) + " ; ");
      System.out.print("~Mask[" + maskByte + "]=" + Integer.toString(~mask & 0xff) + " ; ");

      byte[] lastAddr = new byte[addr.length];
      if (maskByte >= 0)
      {
      for (int i = 0; i <= maskByte; i++)
      {
      lastAddr[i] = firstAddr[i];
      }

      lastAddr[maskByte] |= mask;

      for (int i = maskByte + 1; i < addr.length; i++)
      {
      lastAddr[i] |= 0xff;
      }
      lastAddr[addr.length - 1] &= 254;
      } else
      {
      for (int i = 0; i < addr.length; i++)
      {
      lastAddr[i] = firstAddr[i];
      }
      }

      if (ina instanceof Inet4Address)
      {
      for (int i = 0; i < addr.length; i++)
      {
      System.out.print(Integer.toString(firstAddr[i] & 0xff) + ".");
      }

      System.out.print(" - ");

      for (int i = 0; i < addr.length; i++)
      {
      System.out.print(Integer.toString(lastAddr[i] & 0xff) + ".");
      }

      System.out.println();
      Vector v1 = new Vector();
      // firstAddr=new byte []{10, 2, 2, 30};
      // lastAddr=new byte []{10, 2, 2, 50};
      probe(firstAddr, lastAddr, new byte[firstAddr.length], 0, v1);
      for (Enumeration e = v1.elements(); e.hasMoreElements();)
      {
      AliveProber ap = (AliveProber) e.nextElement();
      try
      {
      ap.join();
      } catch (InterruptedException e1)
      {
      // TODO Auto-generated catch block
      e1.printStackTrace();
      }
      }
      }

      if (ina instanceof Inet6Address)
      {
      System.out.print("firstAddr=");

      for (int i = 0; i < addr.length; i++)
      {
      System.out.print(Integer.toHexString(firstAddr[i] & 0xff) + ":");
      }
      System.out.print(" - ");

      System.out.print("lastAddr=");

      for (int i = 0; i < addr.length; i++)
      {
      System.out.print(Integer.toHexString(lastAddr[i] & 0xff) + ":");
      }
      System.out.println();
      }
      }
      int n = 0;
      for (Enumeration e = aliveHosts.keys(); e.hasMoreElements();)
      {
      InetAddress ia = (InetAddress) e.nextElement();
      System.out.println("ia[" + n + "]=" + ia + " ; " + ia.getCanonicalHostName());
      n++;
      }
      }

      return iaa;
      }

      private static void probe(byte[] firstAddr, byte[] lastAddr, byte[] curAddr, int level, Vector v1)
      {
      if (level == firstAddr.length)
      {
      AliveProber ap=new AliveProber(curAddr);
      v1.add(ap);
      } else
      {
      int start = (firstAddr[level] & 0xff);
      int end = (lastAddr[level] & 0xff);
      if ((level + 1) == firstAddr.length)
      {
      for (int i = 0; i < level; i++)
      {
      if (curAddr[i] != firstAddr[i])
      {
      start = 0;
      }
      if (curAddr[i] != lastAddr[i])
      {
      end = 255;
      }
      }
      }

      for (int i = start; i <= end; i++)
      {
      curAddr[level] = (byte) (i & 0xff);
      probe(firstAddr, lastAddr, curAddr, level + 1, v1);
      }
      }

      if (v1.size() >= MAX_OUTSTANDING)
      {
      for (Enumeration e = v1.elements(); e.hasMoreElements();)
      {
      AliveProber ap = (AliveProber) e.nextElement();
      if (!ap.isAlive())
      {
      v1.remove(ap);
      }
      }

      for (Enumeration e = v1.elements(); e.hasMoreElements() && v1.size() >= MAX_OUTSTANDING;)
      {
      AliveProber ap = (AliveProber) e.nextElement();
      try
      {
      ap.join();
      v1.remove(ap);
      } catch (InterruptedException e1)
      {
      // TODO Auto-generated catch block
      e1.printStackTrace();
      }
      }
      }
      }

      private static class AliveProber
      extends Thread
      {
      InetAddress ia = null;

      public AliveProber(byte[] addr)
      {
      if (addr.length != 4)
      {
      System.err.println("Not INET4 address!");
      new Throwable().printStackTrace();
      System.exit(9);
      } else
      {
      try
      {
      ia = InetAddress.getByAddress(addr);
      } catch (UnknownHostException e)
      {
      }
      }
      this.start();
      }

      public void run()
      {
      try
      {
      StringBuffer sb=new StringBuffer();
      calls++;

      if (ia.isReachable(1000))
      {
      sb.append("ia=" + ia);
      sb.append(" - Alive");
      aliveHosts.put(ia, "");
      } else
      {
      sb.append("ia=" + ia);
      sb.append(" - DEAD");
      }

      synchronized(lockObj)
      {
      System.out.println(sb.toString());
      }
      } catch (IOException e)
      {
      synchronized(lockObj)
      {
      System.err.println("calls="+calls+", "+e.getClass().getName() + ":" + e.getMessage() + ":" + ia);
      e.printStackTrace();
      System.exit(9);
      }
      }
      }
      }

      /**
      * @param args
      */
      public static void main(String[] args)
      {
      try
      {
      for (Enumeration<NetworkInterface> nie = NetworkInterface.getNetworkInterfaces(); nie.hasMoreElements();)
      {
      NetworkInterface ni = nie.nextElement();
      System.out.println("ni=" + ni.getName() + ":" + ni.getDisplayName());
      // discoverNodes(ni);
      discoverNodes(InetAddress.getByAddress(new byte[]{10,2,2,40}), (short)20);
      }
      } catch (SocketException e)
      {
      // TODO Auto-generated catch block
      e.printStackTrace();
      } catch (UnknownHostException e)
      {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }
      }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Currently this problem doesn't seem to occur when running Java 1.5.0_06, but the problem may as well not be visualized there.

      Release Regression From : 5.0u6
      The above release value was the last known release where this
      bug was known to work. Since then there has been a regression.

            jccollet Jean-Christophe Collet (Inactive)
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: