private DatagramChannel connectClient() throws IOException {
    final DatagramChannel client =
        address.isMulticastAddress()
            ? DatagramChannel.open(address.getAddress().length == 4 ? INET : INET6)
            : DatagramChannel.open();

    final InetSocketAddress hostAddress = new InetSocketAddress(port);
    client.configureBlocking(false);
    if (address.isMulticastAddress()) {
      client.setOption(SO_REUSEADDR, true);
      client.bind(hostAddress);
      if (networkInterface != null) {
        // This is probably not needed, because client socket doesn't send datagrams,
        // but since EVERYBODY on the internet configures this for any channels, and
        // I don't see any harm this config could make, I leave it here
        client.setOption(IP_MULTICAST_IF, networkInterface);
        client.join(address, networkInterface);
      } else {
        client.join(address, NetworkInterface.getByInetAddress(hostAddress.getAddress()));
      }
      if (LOG.isDebugEnabled()) LOG.debug("Connecting via multicast, group=" + address);
    } else {
      client.bind(hostAddress);
    }

    if (LOG.isDebugEnabled()) LOG.debug("Listening on port " + port);
    closeables.add(client);
    return client;
  }
  /** Block datagrams from given source if a memory to receive all datagrams. */
  void block(MembershipKeyImpl key, InetAddress source) throws IOException {
    assert key.channel() == this;
    assert key.sourceAddress() == null;

    synchronized (stateLock) {
      if (!key.isValid()) throw new IllegalStateException("key is no longer valid");
      if (source.isAnyLocalAddress())
        throw new IllegalArgumentException("Source address is a wildcard address");
      if (source.isMulticastAddress())
        throw new IllegalArgumentException("Source address is multicast address");
      if (source.getClass() != key.group().getClass())
        throw new IllegalArgumentException("Source address is different type to group");

      int n;
      if (key instanceof MembershipKeyImpl.Type6) {
        MembershipKeyImpl.Type6 key6 = (MembershipKeyImpl.Type6) key;
        n = Net.block6(fd, key6.groupAddress(), key6.index(), Net.inet6AsByteArray(source));
      } else {
        MembershipKeyImpl.Type4 key4 = (MembershipKeyImpl.Type4) key;
        n = Net.block4(fd, key4.groupAddress(), key4.interfaceAddress(), Net.inet4AsInt(source));
      }
      if (n == IOStatus.UNAVAILABLE) {
        // ancient kernel
        throw new UnsupportedOperationException();
      }
    }
  }
示例#3
0
  /** Publish a request message to the specified multicast group. */
  protected void publishRequest(String message) throws IOException, SocketException {

    groupAddr = InetAddress.getByName(request_group);
    interfaceAddr = InetAddress.getByName(request_interface_address);

    /* is it a multicast address? */
    if (groupAddr.isMulticastAddress()) {

      /* open the socket and join the multicast group */
      udpSocket = new MulticastSocket();
      udpSocket.setNetworkInterface(NetworkInterface.getByInetAddress(interfaceAddr));
      udpSocket.setInterface(interfaceAddr);
      udpSocket.joinGroup(groupAddr);

      /* Send request packet */
      DatagramPacket p =
          new DatagramPacket(message.getBytes(), message.getBytes().length, groupAddr, 7777);

      System.out.println("Sending request: " + new String(p.getData(), 0, p.getLength()));
      udpSocket.send(p);

    } else {
      System.err.println("Invalid multicast address: " + groupAddr.toString());
    }
  }
示例#4
0
  public static String[] getNetworkParams(NetworkInterface nic) {
    List<InterfaceAddress> addrs = nic.getInterfaceAddresses();
    if (addrs == null || addrs.size() == 0) {
      return null;
    }
    InterfaceAddress addr = null;
    for (InterfaceAddress iaddr : addrs) {
      InetAddress inet = iaddr.getAddress();
      if (!inet.isLinkLocalAddress()
          && !inet.isLoopbackAddress()
          && !inet.isMulticastAddress()
          && inet.getAddress().length == 4) {
        addr = iaddr;
        break;
      }
    }
    if (addr == null) {
      return null;
    }
    String[] result = new String[3];
    result[0] = addr.getAddress().getHostAddress();
    try {
      byte[] mac = nic.getHardwareAddress();
      result[1] = byte2Mac(mac);
    } catch (Exception e) {
    }

    result[2] = prefix2Netmask(addr.getNetworkPrefixLength());
    return result;
  }
  /**
   * Joins a multicast group. Its behavior may be affected by {@code setInterface} or {@code
   * setNetworkInterface}.
   *
   * <p>If there is a security manager, this method first calls its {@code checkMulticast} method
   * with the {@code mcastaddr} argument as its argument.
   *
   * @param mcastaddr is the multicast address to join
   * @exception IOException if there is an error joining or when the address is not a multicast
   *     address.
   * @exception SecurityException if a security manager exists and its {@code checkMulticast} method
   *     doesn't allow the join.
   * @see SecurityManager#checkMulticast(InetAddress)
   */
  public void joinGroup(InetAddress mcastaddr) throws IOException {
    if (isClosed()) {
      throw new SocketException("Socket is closed");
    }

    checkAddress(mcastaddr, "joinGroup");
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
      security.checkMulticast(mcastaddr);
    }

    if (!mcastaddr.isMulticastAddress()) {
      throw new SocketException("Not a multicast address");
    }

    /**
     * required for some platforms where it's not possible to join a group without setting the
     * interface first.
     */
    NetworkInterface defaultInterface = NetworkInterface.getDefault();

    if (!interfaceSet && defaultInterface != null) {
      setNetworkInterface(defaultInterface);
    }

    getImpl().join(mcastaddr);
  }
  // TODO: needs to be InetAddress[]
  public InetAddress resolvePublishHostAddresses(String publishHosts[]) throws IOException {
    if (publishHosts == null) {
      if (GLOBAL_NETWORK_PUBLISHHOST_SETTING.exists(settings)
          || GLOBAL_NETWORK_HOST_SETTING.exists(settings)) {
        // if we have settings use them (we have a fallback to GLOBAL_NETWORK_HOST_SETTING inline
        publishHosts =
            GLOBAL_NETWORK_PUBLISHHOST_SETTING.get(settings).toArray(Strings.EMPTY_ARRAY);
      } else {
        // next check any registered custom resolvers
        for (CustomNameResolver customNameResolver : customNameResolvers) {
          InetAddress addresses[] = customNameResolver.resolveDefault();
          if (addresses != null) {
            return addresses[0];
          }
        }
        // we know it's not here. get the defaults
        publishHosts =
            GLOBAL_NETWORK_PUBLISHHOST_SETTING.get(settings).toArray(Strings.EMPTY_ARRAY);
      }
    }

    InetAddress addresses[] = resolveInetAddresses(publishHosts);
    // TODO: allow publishing multiple addresses
    // for now... the hack begins

    // 1. single wildcard address, probably set by network.host: expand to all interface addresses.
    if (addresses.length == 1 && addresses[0].isAnyLocalAddress()) {
      HashSet<InetAddress> all = new HashSet<>(Arrays.asList(NetworkUtils.getAllAddresses()));
      addresses = all.toArray(new InetAddress[all.size()]);
    }

    // 2. try to deal with some (mis)configuration
    for (InetAddress address : addresses) {
      // check if its multicast: flat out mistake
      if (address.isMulticastAddress()) {
        throw new IllegalArgumentException(
            "publish address: {"
                + NetworkAddress.format(address)
                + "} is invalid: multicast address");
      }
      // check if its a wildcard address: this is only ok if its the only address!
      // (if it was a single wildcard address, it was replaced by step 1 above)
      if (address.isAnyLocalAddress()) {
        throw new IllegalArgumentException(
            "publish address: {"
                + NetworkAddress.format(address)
                + "} is wildcard, but multiple addresses specified: this makes no sense");
      }
    }

    // 3. if we end out with multiple publish addresses, select by preference.
    // don't warn the user, or they will get confused by bind_host vs publish_host etc.
    if (addresses.length > 1) {
      List<InetAddress> sorted = new ArrayList<>(Arrays.asList(addresses));
      NetworkUtils.sortAddresses(sorted);
      addresses = new InetAddress[] {sorted.get(0)};
    }
    return addresses[0];
  }
  public int send(ByteBuffer src, SocketAddress target) throws IOException {
    if (src == null) throw new NullPointerException();

    synchronized (writeLock) {
      ensureOpen();
      InetSocketAddress isa = Net.checkAddress(target);
      InetAddress ia = isa.getAddress();
      if (ia == null) throw new IOException("Target address not resolved");
      synchronized (stateLock) {
        if (!isConnected()) {
          if (target == null) throw new NullPointerException();
          SecurityManager sm = System.getSecurityManager();
          if (sm != null) {
            if (ia.isMulticastAddress()) {
              sm.checkMulticast(ia);
            } else {
              sm.checkConnect(ia.getHostAddress(), isa.getPort());
            }
          }
        } else { // Connected case; Check address then write
          if (!target.equals(remoteAddress)) {
            throw new IllegalArgumentException("Connected address not equal to target address");
          }
          return write(src);
        }
      }

      int n = 0;
      try {
        begin();
        if (!isOpen()) return 0;
        writerThread = NativeThread.current();
        do {
          n = send(fd, src, isa);
        } while ((n == IOStatus.INTERRUPTED) && isOpen());

        synchronized (stateLock) {
          if (isOpen() && (localAddress == null)) {
            localAddress = Net.localAddress(fd);
          }
        }
        return IOStatus.normalize(n);
      } finally {
        writerThread = 0;
        end((n > 0) || (n == IOStatus.UNAVAILABLE));
        assert IOStatus.check(n);
      }
    }
  }
示例#8
0
 private synchronized void addLocalAddress(InetAddress addr) {
   int addrtype;
   if (addr.isLoopbackAddress()) {
     addrtype = HOSTMAP_LOOPBACK;
   } else if (addr.isLinkLocalAddress()) {
     addrtype = HOSTMAP_LINKLOCAL;
   } else if (addr.isSiteLocalAddress()) {
     addrtype = HOSTMAP_SITELOCAL;
   } else if (addr.isMulticastAddress()) {
     addrtype = HOSTMAP_MULTICAST;
   } else {
     addrtype = HOSTMAP_GLOBAL;
   }
   if (addr.getAddress().length == 4) {
     addrtype |= HOSTMAP_IPV4;
   } else {
     addrtype |= HOSTMAP_IPV6;
   }
   String addrAsString = addr.getHostAddress();
   fLocalHostAddresses.put(addrAsString, Integer.valueOf(addrtype | HOSTMAP_ADDR));
   if (0 == (addrtype & (HOSTMAP_LINKLOCAL | HOSTMAP_SITELOCAL | HOSTMAP_MULTICAST))) {
     // Don't do DNS Reverse Loopkup's for non-routable addresses.
     // They won't be known to the Name Server anyway, and they
     // make startup _much_ slower.
     String addrAsNameCan = addr.getCanonicalHostName().toLowerCase();
     // query the name after the canonical name, it will re-use
     // cached canonical name (if the name was not explicitly set)
     String addrAsName = addr.getHostName().toLowerCase();
     if (!addrAsNameCan.equals(addrAsString)) {
       // We must check if we really got a name, since InetAddress.getHostName()
       // returns the original address in case it thinks the name is spoofed!
       if (0 == (addrtype & HOSTMAP_LOOPBACK)) {
         // Not loopback --> found a Canonical Name.
         fLocalHostAddresses.put(
             addrAsNameCan, Integer.valueOf(addrtype | HOSTMAP_NAME | HOSTMAP_CANONICALNAME));
         // override the address as canonical-address
         fLocalHostAddresses.put(
             addrAsString, Integer.valueOf(addrtype | HOSTMAP_ADDR | HOSTMAP_CANONICALADDR));
       } else {
         // Loopback --> add the found name as non-canonical.
         fLocalHostAddresses.put(addrAsNameCan, Integer.valueOf(addrtype | HOSTMAP_NAME));
       }
     }
     if (!addrAsName.equals(addrAsString) && !addrAsName.equals(addrAsNameCan)) {
       // don't override the canonical name by the name.
       fLocalHostAddresses.put(addrAsName, Integer.valueOf(addrtype | HOSTMAP_NAME));
     }
   }
 }
示例#9
0
  /**
   * Leave a multicast group. Its behavior may be affected by <code>setInterface</code> or <code>
   * setNetworkInterface</code>.
   *
   * <p>If there is a security manager, this method first calls its <code>checkMulticast</code>
   * method with the <code>mcastaddr</code> argument as its argument.
   *
   * @param mcastaddr is the multicast address to leave
   * @exception IOException if there is an error leaving or when the address is not a multicast
   *     address.
   * @exception SecurityException if a security manager exists and its <code>checkMulticast</code>
   *     method doesn't allow the operation.
   * @see SecurityManager#checkMulticast(InetAddress)
   */
  public void leaveGroup(InetAddress mcastaddr) throws IOException {
    if (isClosed()) {
      throw new SocketException("Socket is closed");
    }

    SecurityManager security = System.getSecurityManager();
    if (security != null) {
      security.checkMulticast(mcastaddr);
    }

    if (!mcastaddr.isMulticastAddress()) {
      throw new SocketException("Not a multicast address");
    }

    getImpl().leave(mcastaddr);
  }
示例#10
0
    /**
     * Initialise the listener, including opening a multicast socket and joining the specified
     * group.
     *
     * @throws IOException if the socket cannot be opened.
     * @throws SocketException if there is a problem setting the interface or joining the multicast
     *     group.
     */
    public void init() throws IOException, SocketException {

      String request_interface_address = InetAddress.getLocalHost().getHostAddress();

      groupListenRequestAddr = InetAddress.getByName(request_group);
      interfaceListenRequestAddr = InetAddress.getByName(request_interface_address);

      /* is it a multicast address? */
      if (groupListenRequestAddr.isMulticastAddress()) {
        udpListenRequestSocket = new MulticastSocket(request_port);
        udpListenRequestSocket.setInterface(interfaceListenRequestAddr);
        udpListenRequestSocket.joinGroup(groupListenRequestAddr);

      } else {
        System.err.println("Not a valid multicast address!");
      }
    }
示例#11
0
  public static void main(String[] args) {
    if (args.length == 0 || args == null) {
      System.out.println("Didn't enter argument!, Please enter like this.");
      System.out.println("ex. java IPCharateristics args[0] args[1] ...");
      return;
    }
    try {
      InetAddress address = InetAddress.getByName(args[0]);

      if (address.isAnyLocalAddress()) {
        System.out.println(address + " is a wildcard address.");
      }
      if (address.isLoopbackAddress()) {
        System.out.println(address + " is a loopback address.");
      }
      if (address.isLinkLocalAddress()) {
        System.out.println(address + " is a link-local address.");
      }
      if (address.isSiteLocalAddress()) {
        System.out.println(address + " is a site-local address");
      } else {
        System.out.println(address + " is a global address");
      }

      if (address.isMulticastAddress()) {
        if (address.isMCGlobal()) {
          System.out.println(address + " is a global multicast address.");
        } else if (address.isMCOrgLocal()) {
          System.out.println(address + " is an organization wide multicast address.");
        } else if (address.isMCSiteLocal()) {
          System.out.println(address + " is a site wide multicast address.");
        } else if (address.isMCLinkLocal()) {
          System.out.println(address + " is a subnet wide multicast address.");
        } else if (address.isMCNodeLocal()) {
          System.out.println(address + " is an interface-local multicast address.");
        } else {
          System.out.println(address + " is an unknown multicast address type.");
        }
      } else {
        System.out.println(address + " is a unicast address.");
      }
    } catch (UnknownHostException ex) {
      System.out.println("Could not resolve " + args[0]);
    }
  }
  private Pair<String, Integer> validateUrl(String url) throws IllegalArgumentException {
    try {
      URI uri = new URI(url);
      if (!uri.getScheme().equalsIgnoreCase("http") && !uri.getScheme().equalsIgnoreCase("https")) {
        throw new IllegalArgumentException("Unsupported scheme for url");
      }
      int port = uri.getPort();
      if (!(port == 80 || port == 443 || port == -1)) {
        throw new IllegalArgumentException("Only ports 80 and 443 are allowed");
      }

      if (port == -1 && uri.getScheme().equalsIgnoreCase("https")) {
        port = 443;
      } else if (port == -1 && uri.getScheme().equalsIgnoreCase("http")) {
        port = 80;
      }

      String host = uri.getHost();
      try {
        InetAddress hostAddr = InetAddress.getByName(host);
        if (hostAddr.isAnyLocalAddress()
            || hostAddr.isLinkLocalAddress()
            || hostAddr.isLoopbackAddress()
            || hostAddr.isMulticastAddress()) {
          throw new IllegalArgumentException("Illegal host specified in url");
        }
        if (hostAddr instanceof Inet6Address) {
          throw new IllegalArgumentException(
              "IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")");
        }
        return new Pair<String, Integer>(host, port);
      } catch (UnknownHostException uhe) {
        throw new IllegalArgumentException("Unable to resolve " + host);
      }
    } catch (IllegalArgumentException iae) {
      s_logger.warn("Failed uri validation check: " + iae.getMessage());
      throw iae;
    } catch (URISyntaxException use) {
      s_logger.warn("Failed uri syntax check: " + use.getMessage());
      throw new IllegalArgumentException(use.getMessage());
    }
  }
  /**
   * {@collect.stats} {@description.open} Connects this socket to a remote socket address (IP
   * address + port number). Binds socket if not already bound.
   *
   * <p>{@description.close}
   *
   * @param addr The remote address.
   * @param port The remote port
   * @throws SocketException if binding the socket fails.
   */
  private synchronized void connectInternal(InetAddress address, int port) throws SocketException {
    if (port < 0 || port > 0xFFFF) {
      throw new IllegalArgumentException("connect: " + port);
    }
    if (address == null) {
      throw new IllegalArgumentException("connect: null address");
    }
    checkAddress(address, "connect");
    if (isClosed()) return;
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
      if (address.isMulticastAddress()) {
        security.checkMulticast(address);
      } else {
        security.checkConnect(address.getHostAddress(), port);
        security.checkAccept(address.getHostAddress(), port);
      }
    }

    if (!isBound()) bind(new InetSocketAddress(0));

    // old impls do not support connect/disconnect
    if (oldImpl) {
      connectState = ST_CONNECTED_NO_IMPL;
    } else {
      try {
        getImpl().connect(address, port);

        // socket is now connected by the impl
        connectState = ST_CONNECTED;
      } catch (SocketException se) {

        // connection will be emulated by DatagramSocket
        connectState = ST_CONNECTED_NO_IMPL;
      }
    }

    connectedAddress = address;
    connectedPort = port;
  }
  /**
   * Resolves {@code bindHosts} to a list of internet addresses. The list will not contain duplicate
   * addresses.
   *
   * @param bindHosts list of hosts to bind to. this may contain special pseudo-hostnames such as
   *     _local_ (see the documentation). if it is null, it will be populated based on global
   *     default settings.
   * @return unique set of internet addresses
   */
  public InetAddress[] resolveBindHostAddresses(String bindHosts[]) throws IOException {
    // first check settings
    if (bindHosts == null) {
      if (GLOBAL_NETWORK_BINDHOST_SETTING.exists(settings)
          || GLOBAL_NETWORK_HOST_SETTING.exists(settings)) {
        // if we have settings use them (we have a fallback to GLOBAL_NETWORK_HOST_SETTING inline
        bindHosts = GLOBAL_NETWORK_BINDHOST_SETTING.get(settings).toArray(Strings.EMPTY_ARRAY);
      } else {
        // next check any registered custom resolvers
        for (CustomNameResolver customNameResolver : customNameResolvers) {
          InetAddress addresses[] = customNameResolver.resolveDefault();
          if (addresses != null) {
            return addresses;
          }
        }
        // we know it's not here. get the defaults
        bindHosts = GLOBAL_NETWORK_BINDHOST_SETTING.get(settings).toArray(Strings.EMPTY_ARRAY);
      }
    }

    InetAddress addresses[] = resolveInetAddresses(bindHosts);

    // try to deal with some (mis)configuration
    for (InetAddress address : addresses) {
      // check if its multicast: flat out mistake
      if (address.isMulticastAddress()) {
        throw new IllegalArgumentException(
            "bind address: {" + NetworkAddress.format(address) + "} is invalid: multicast address");
      }
      // check if its a wildcard address: this is only ok if its the only address!
      if (address.isAnyLocalAddress() && addresses.length > 1) {
        throw new IllegalArgumentException(
            "bind address: {"
                + NetworkAddress.format(address)
                + "} is wildcard, but multiple addresses specified: this makes no sense");
      }
    }
    return addresses;
  }
示例#15
0
 private static boolean shouldInclude(
     InetAddress ia,
     boolean includeSiteLocal,
     boolean includeLoopbackAndWildcard,
     boolean includeIPv6) {
   return (!ia.isLinkLocalAddress())
       && // 169.254.x.x
       (!ia.isMulticastAddress())
       && (includeLoopbackAndWildcard || ((!ia.isAnyLocalAddress()) && (!ia.isLoopbackAddress())))
       && (includeSiteLocal
           || ((!ia.isSiteLocalAddress())
               &&
               // disallow fc00::/8 and fd00::/8 (Unique local addresses RFC 4193)
               // not recognized as local by InetAddress
               (ia.getAddress().length != 16 || (ia.getAddress()[0] & 0xfe) != 0xfc)))
       &&
       // Hamachi 5/8 allocated to RIPE (30 November 2010)
       // Removed from TransportImpl.isPubliclyRoutable()
       // Check moved to here, for now, but will eventually need to
       // remove it from here also.
       // (includeLocal ||
       // (!ia.getHostAddress().startsWith("5."))) &&
       (includeIPv6 || (ia instanceof Inet4Address));
 }
  private String validateUrl(String url) {
    try {
      URI uri = new URI(url);
      if ((uri.getScheme() == null)
          || (!uri.getScheme().equalsIgnoreCase("http")
              && !uri.getScheme().equalsIgnoreCase("https")
              && !uri.getScheme().equalsIgnoreCase("file"))) {
        throw new IllegalArgumentException("Unsupported scheme for url: " + url);
      }

      int port = uri.getPort();
      if (!(port == 80 || port == 443 || port == -1)) {
        throw new IllegalArgumentException("Only ports 80 and 443 are allowed");
      }
      String host = uri.getHost();
      try {
        InetAddress hostAddr = InetAddress.getByName(host);
        if (hostAddr.isAnyLocalAddress()
            || hostAddr.isLinkLocalAddress()
            || hostAddr.isLoopbackAddress()
            || hostAddr.isMulticastAddress()) {
          throw new IllegalArgumentException("Illegal host specified in url");
        }
        if (hostAddr instanceof Inet6Address) {
          throw new IllegalArgumentException(
              "IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")");
        }
      } catch (UnknownHostException uhe) {
        throw new IllegalArgumentException("Unable to resolve " + host);
      }

      return uri.toString();
    } catch (URISyntaxException e) {
      throw new IllegalArgumentException("Invalid URL " + url);
    }
  }
示例#17
0
 private static boolean isGoodV6Address(InetAddress address) {
   return address instanceof Inet6Address
       && !address.isAnyLocalAddress()
       && !address.isLoopbackAddress()
       && !address.isMulticastAddress();
 }
示例#18
0
  public static boolean isValidIp(long addr) {
    InetAddress ip = getAddressFromLong(addr);

    return !ip.isLoopbackAddress() && !ip.isMulticastAddress();
  }
示例#19
0
  /** (thread entry-point) */
  private void multicastReceiverThreadMain() {
    while (_enabled) {
      MulticastSocket socket = null;

      try {
        synchronized (_lock) {
          // clear flag regardless
          _recycleReceiver = false;
        }

        socket = createMulticastSocket(s_receiveSocketlabel, s_interface, MDNS_PORT);

        synchronized (_lock) {
          // make sure not flagged since reset
          if (_recycleReceiver) {
            Stream.safeClose(socket);
            continue;
          }

          _receiveSocket = socket;
        }

        while (_enabled) {
          DatagramPacket dp = UDPPacketRecycleQueue.instance().getReadyToUsePacket();

          // ('returnPacket' will be called in 'catch' or later after use in thread-pool)

          try {
            socket.receive(dp);

          } catch (Exception exc) {
            UDPPacketRecycleQueue.instance().returnPacket(dp);

            throw exc;
          }

          InetAddress recvAddr = dp.getAddress();

          if (recvAddr.isMulticastAddress()) {
            s_multicastInData.addAndGet(dp.getLength());
            s_multicastInOps.incrementAndGet();
          } else {
            s_unicastInData.addAndGet(dp.getLength());
            s_unicastInOps.incrementAndGet();
          }

          // check whether it's external i.e. completely different IP address
          // (local multicasting would almost always be reliable)

          MulticastSocket otherLocal = _sendSocket;
          boolean isLocal = (otherLocal != null && recvAddr.equals(otherLocal.getLocalAddress()));

          // update counter which is used to detect silence
          if (!isLocal) _lastExternalMulticastPacket = System.nanoTime();

          enqueueForProcessing(dp, s_receiveSocketlabel);
        } // (inner while)

      } catch (Exception exc) {
        // (timeouts and general IO problems)

        // clean up regardless
        Stream.safeClose(socket);

        synchronized (_lock) {
          if (!_enabled) break;

          if (_recycleReceiver)
            _logger.info(s_receiveSocketlabel + " was gracefully closed. Will reinitialise...");
          else
            _logger.warn(
                s_receiveSocketlabel
                    + " receive failed; this may be a transitional condition. Will reinitialise... message was '"
                    + exc.toString()
                    + "'");

          // set flag
          _recycleSender = true;
          // "signal" other thread
          Stream.safeClose(_sendSocket);

          // stagger retry
          Threads.waitOnSync(_lock, 333);
        }
      }
    } // (outer while)

    _logger.info("This thread has run to completion.");
  } // (method)
  /** Joins channel's socket to the given group/interface and optional source address. */
  private MembershipKey innerJoin(InetAddress group, NetworkInterface interf, InetAddress source)
      throws IOException {
    if (!group.isMulticastAddress())
      throw new IllegalArgumentException("Group not a multicast address");

    // check multicast address is compatible with this socket
    if (group instanceof Inet4Address) {
      if (family == StandardProtocolFamily.INET6 && !Net.canIPv6SocketJoinIPv4Group())
        throw new IllegalArgumentException("IPv6 socket cannot join IPv4 multicast group");
    } else if (group instanceof Inet6Address) {
      if (family != StandardProtocolFamily.INET6)
        throw new IllegalArgumentException("Only IPv6 sockets can join IPv6 multicast group");
    } else {
      throw new IllegalArgumentException("Address type not supported");
    }

    // check source address
    if (source != null) {
      if (source.isAnyLocalAddress())
        throw new IllegalArgumentException("Source address is a wildcard address");
      if (source.isMulticastAddress())
        throw new IllegalArgumentException("Source address is multicast address");
      if (source.getClass() != group.getClass())
        throw new IllegalArgumentException("Source address is different type to group");
    }

    SecurityManager sm = System.getSecurityManager();
    if (sm != null) sm.checkMulticast(group);

    synchronized (stateLock) {
      if (!isOpen()) throw new ClosedChannelException();

      // check the registry to see if we are already a member of the group
      if (registry == null) {
        registry = new MembershipRegistry();
      } else {
        // return existing membership key
        MembershipKey key = registry.checkMembership(group, interf, source);
        if (key != null) return key;
      }

      MembershipKeyImpl key;
      if ((family == StandardProtocolFamily.INET6)
          && ((group instanceof Inet6Address) || Net.canJoin6WithIPv4Group())) {
        int index = interf.getIndex();
        if (index == -1) throw new IOException("Network interface cannot be identified");

        // need multicast and source address as byte arrays
        byte[] groupAddress = Net.inet6AsByteArray(group);
        byte[] sourceAddress = (source == null) ? null : Net.inet6AsByteArray(source);

        // join the group
        int n = Net.join6(fd, groupAddress, index, sourceAddress);
        if (n == IOStatus.UNAVAILABLE) throw new UnsupportedOperationException();

        key =
            new MembershipKeyImpl.Type6(
                this, group, interf, source, groupAddress, index, sourceAddress);

      } else {
        // need IPv4 address to identify interface
        Inet4Address target = Net.anyInet4Address(interf);
        if (target == null) throw new IOException("Network interface not configured for IPv4");

        int groupAddress = Net.inet4AsInt(group);
        int targetAddress = Net.inet4AsInt(target);
        int sourceAddress = (source == null) ? 0 : Net.inet4AsInt(source);

        // join the group
        int n = Net.join4(fd, groupAddress, targetAddress, sourceAddress);
        if (n == IOStatus.UNAVAILABLE) throw new UnsupportedOperationException();

        key =
            new MembershipKeyImpl.Type4(
                this, group, interf, source, groupAddress, targetAddress, sourceAddress);
      }

      registry.add(key);
      return key;
    }
  }