@Override public <T> DatagramChannel setOption(SocketOption<T> name, T value) throws IOException { if (name == null) throw new NullPointerException(); if (!supportedOptions().contains(name)) throw new UnsupportedOperationException("'" + name + "' not supported"); synchronized (stateLock) { ensureOpen(); if (name == StandardSocketOptions.IP_TOS) { // IPv4 only; no-op for IPv6 if (family == StandardProtocolFamily.INET) { Net.setSocketOption(fd, family, name, value); } return this; } if (name == StandardSocketOptions.IP_MULTICAST_TTL || name == StandardSocketOptions.IP_MULTICAST_LOOP) { // options are protocol dependent Net.setSocketOption(fd, family, name, value); return this; } if (name == StandardSocketOptions.IP_MULTICAST_IF) { if (value == null) throw new IllegalArgumentException("Cannot set IP_MULTICAST_IF to 'null'"); NetworkInterface interf = (NetworkInterface) value; if (family == StandardProtocolFamily.INET6) { int index = interf.getIndex(); if (index == -1) throw new IOException("Network interface cannot be identified"); Net.setInterface6(fd, index); } 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 targetAddress = Net.inet4AsInt(target); Net.setInterface4(fd, targetAddress); } return this; } // remaining options don't need any special handling Net.setSocketOption(fd, Net.UNSPEC, name, value); return this; } }
/** 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; } }