@Override
  public DatagramChannel bind(SocketAddress local) throws IOException {
    synchronized (readLock) {
      synchronized (writeLock) {
        synchronized (stateLock) {
          ensureOpen();
          if (localAddress != null) throw new AlreadyBoundException();
          InetSocketAddress isa;
          if (local == null) {
            // only Inet4Address allowed with IPv4 socket
            if (family == StandardProtocolFamily.INET) {
              isa = new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 0);
            } else {
              isa = new InetSocketAddress(0);
            }
          } else {
            isa = Net.checkAddress(local);

            // only Inet4Address allowed with IPv4 socket
            if (family == StandardProtocolFamily.INET) {
              InetAddress addr = isa.getAddress();
              if (!(addr instanceof Inet4Address)) throw new UnsupportedAddressTypeException();
            }
          }
          SecurityManager sm = System.getSecurityManager();
          if (sm != null) {
            sm.checkListen(isa.getPort());
          }
          Net.bind(family, fd, isa.getAddress(), isa.getPort());
          localAddress = Net.localAddress(fd);
        }
      }
    }
    return this;
  }
  public DatagramChannel connect(SocketAddress sa) throws IOException {
    int localPort = 0;

    synchronized (readLock) {
      synchronized (writeLock) {
        synchronized (stateLock) {
          ensureOpenAndUnconnected();
          InetSocketAddress isa = Net.checkAddress(sa);
          SecurityManager sm = System.getSecurityManager();
          if (sm != null) sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
          int n = Net.connect(family, fd, isa.getAddress(), isa.getPort());
          if (n <= 0) throw new Error(); // Can't happen

          // Connection succeeded; disallow further invocation
          state = ST_CONNECTED;
          remoteAddress = sa;
          sender = isa;
          cachedSenderInetAddress = isa.getAddress();
          cachedSenderPort = isa.getPort();

          // set or refresh local address
          localAddress = Net.localAddress(fd);
        }
      }
    }
    return this;
  }
  /** 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();
      }
    }
  }
 public DatagramChannelImpl(SelectorProvider sp, FileDescriptor fd) throws IOException {
   super(sp);
   this.family =
       Net.isIPv6Available() ? StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
   this.fd = fd;
   this.fdVal = IOUtil.fdVal(fd);
   this.state = ST_UNCONNECTED;
   this.localAddress = Net.localAddress(fd);
 }
 public void bind(SocketAddress local) throws IOException {
   synchronized (readLock) {
     synchronized (writeLock) {
       synchronized (stateLock) {
         ensureOpenAndUnconnected();
         if (localAddress != null) throw new AlreadyBoundException();
         InetSocketAddress isa = Net.checkAddress(local);
         Net.bind(fd, isa.getAddress(), isa.getPort());
         localAddress = Net.localAddress(fd);
       }
     }
   }
 }
 public DatagramChannelImpl(SelectorProvider sp) throws IOException {
   super(sp);
   ResourceManager.beforeUdpCreate();
   try {
     this.family =
         Net.isIPv6Available() ? StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
     this.fd = Net.socket(family, false);
     this.fdVal = IOUtil.fdVal(fd);
     this.state = ST_UNCONNECTED;
   } catch (IOException ioe) {
     ResourceManager.afterUdpClose();
     throw ioe;
   }
 }
  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);
      }
    }
  }
  @Override
  public DatagramChannel connect(SocketAddress sa) throws IOException {
    int localPort = 0;

    synchronized (readLock) {
      synchronized (writeLock) {
        synchronized (stateLock) {
          ensureOpenAndUnconnected();
          InetSocketAddress isa = Net.checkAddress(sa);
          SecurityManager sm = System.getSecurityManager();
          if (sm != null) sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
          int n = Net.connect(family, fd, isa.getAddress(), isa.getPort());
          if (n <= 0) throw new Error(); // Can't happen

          // Connection succeeded; disallow further invocation
          state = ST_CONNECTED;
          remoteAddress = isa;
          sender = isa;
          cachedSenderInetAddress = isa.getAddress();
          cachedSenderPort = isa.getPort();

          // set or refresh local address
          localAddress = Net.localAddress(fd);

          // flush any packets already received.
          boolean blocking = false;
          synchronized (blockingLock()) {
            try {
              blocking = isBlocking();
              // remainder of each packet thrown away
              ByteBuffer tmpBuf = ByteBuffer.allocate(1);
              if (blocking) {
                configureBlocking(false);
              }
              do {
                tmpBuf.clear();
              } while (receive(tmpBuf) != null);
            } finally {
              if (blocking) {
                configureBlocking(true);
              }
            }
          }
        }
      }
    }
    return this;
  }
  private long read0(ByteBuffer[] bufs) throws IOException {
    if (bufs == null) throw new NullPointerException();
    synchronized (readLock) {
      if (!ensureReadOpen()) return -1;
      long n = 0;
      try {
        begin();
        synchronized (stateLock) {
          if (!isOpen()) return 0;
          readerThread = NativeThread.current();
        }

        for (; ; ) {
          n = Net.read(fd, bufs);
          if ((n == IOStatus.INTERRUPTED) && isOpen()) continue;
          return IOStatus.normalize(n);
        }
      } finally {
        readerCleanup();
        end(n > 0 || (n == IOStatus.UNAVAILABLE));
        synchronized (stateLock) {
          if ((n <= 0) && (!isInputOpen)) return IOStatus.EOF;
        }
        assert IOStatus.check(n);
      }
    }
  }
 public long write0(ByteBuffer[] bufs) throws IOException {
   if (bufs == null) throw new NullPointerException();
   synchronized (writeLock) {
     ensureWriteOpen();
     long n = 0;
     try {
       begin();
       synchronized (stateLock) {
         if (!isOpen()) return 0;
         writerThread = NativeThread.current();
       }
       for (; ; ) {
         n = Net.write(fd, bufs);
         if ((n == IOStatus.INTERRUPTED) && isOpen()) continue;
         return IOStatus.normalize(n);
       }
     } finally {
       writerCleanup();
       end((n > 0) || (n == IOStatus.UNAVAILABLE));
       synchronized (stateLock) {
         if ((n <= 0) && (!isOutputOpen)) throw new AsynchronousCloseException();
       }
       assert IOStatus.check(n);
     }
   }
 }
 public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family) throws IOException {
   super(sp);
   if ((family != StandardProtocolFamily.INET) && (family != StandardProtocolFamily.INET6)) {
     if (family == null) throw new NullPointerException("'family' is null");
     else throw new UnsupportedOperationException("Protocol family not supported");
   }
   if (family == StandardProtocolFamily.INET6) {
     if (!Net.isIPv6Available()) {
       throw new UnsupportedOperationException("IPv6 not available");
     }
   }
   this.family = family;
   this.fd = Net.socket(family, false);
   this.fdVal = IOUtil.fdVal(fd);
   this.state = ST_UNCONNECTED;
 }
  public boolean connect(SocketAddress sa) throws IOException {
    int trafficClass = 0; // ## Pick up from options
    int localPort = 0;

    synchronized (readLock) {
      synchronized (writeLock) {
        ensureOpenAndUnconnected();
        InetSocketAddress isa = Net.checkAddress(sa);
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
        synchronized (blockingLock()) {
          int n = 0;
          try {
            try {
              begin();
              synchronized (stateLock) {
                if (!isOpen()) {
                  return false;
                }
                readerThread = NativeThread.current();
              }
              for (; ; ) {
                InetAddress ia = isa.getAddress();
                if (ia.isAnyLocalAddress()) ia = InetAddress.getLocalHost();
                n = connectImpl(ia, isa.getPort(), trafficClass);
                if ((n == IOStatus.INTERRUPTED) && isOpen()) continue;
                break;
              }
            } finally {
              readerCleanup();
              end((n > 0) || (n == IOStatus.UNAVAILABLE));
              assert IOStatus.check(n);
            }
          } catch (IOException x) {
            // If an exception was thrown, close the channel after
            // invoking end() so as to avoid bogus
            // AsynchronousCloseExceptions
            close();
            throw x;
          }
          synchronized (stateLock) {
            remoteAddress = isa;
            if (n > 0) {

              // Connection succeeded; disallow further
              // invocation
              state = ST_CONNECTED;
              return true;
            }
            // If nonblocking and no exception then connection
            // pending; disallow another invocation
            if (!isBlocking()) state = ST_PENDING;
            else assert false;
          }
        }
        return false;
      }
    }
  }
 @Override
 public SocketAddress getLocalAddress() throws IOException {
   synchronized (stateLock) {
     if (!isOpen()) throw new ClosedChannelException();
     // Perform security check before returning address
     return Net.getRevealedLocalAddress(localAddress);
   }
 }
  @Override
  <A> Future<Void> implConnect(
      SocketAddress remote, A attachment, CompletionHandler<Void, ? super A> handler) {
    if (!isOpen()) {
      Throwable exc = new ClosedChannelException();
      if (handler == null) return CompletedFuture.withFailure(exc);
      Invoker.invoke(this, handler, attachment, null, exc);
      return null;
    }

    InetSocketAddress isa = Net.checkAddress(remote);

    // permission check
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());

    // check and update state
    // ConnectEx requires the socket to be bound to a local address
    IOException bindException = null;
    synchronized (stateLock) {
      if (state == ST_CONNECTED) throw new AlreadyConnectedException();
      if (state == ST_PENDING) throw new ConnectionPendingException();
      if (localAddress == null) {
        try {
          bind(new InetSocketAddress(0));
        } catch (IOException x) {
          bindException = x;
        }
      }
      if (bindException == null) state = ST_PENDING;
    }

    // handle bind failure
    if (bindException != null) {
      try {
        close();
      } catch (IOException ignore) {
      }
      if (handler == null) return CompletedFuture.withFailure(bindException);
      Invoker.invoke(this, handler, attachment, null, bindException);
      return null;
    }

    // setup task
    PendingFuture<Void, A> result = new PendingFuture<Void, A>(this, handler, attachment);
    ConnectTask task = new ConnectTask<A>(isa, result);
    result.setContext(task);

    // initiate I/O
    if (Iocp.supportsThreadAgnosticIo()) {
      task.run();
    } else {
      Invoker.invokeOnThreadInThreadPool(this, task);
    }
    return result;
  }
  @Override
  @SuppressWarnings("unchecked")
  public <T> T getOption(SocketOption<T> name) 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
          || name == StandardSocketOptions.IP_MULTICAST_TTL
          || name == StandardSocketOptions.IP_MULTICAST_LOOP) {
        return (T) Net.getSocketOption(fd, family, name);
      }

      if (name == StandardSocketOptions.IP_MULTICAST_IF) {
        if (family == StandardProtocolFamily.INET) {
          int address = Net.getInterface4(fd);
          if (address == 0) return null; // default interface

          InetAddress ia = Net.inet4FromInt(address);
          NetworkInterface ni = NetworkInterface.getByInetAddress(ia);
          if (ni == null) throw new IOException("Unable to map address to interface");
          return (T) ni;
        } else {
          int index = Net.getInterface6(fd);
          if (index == 0) return null; // default interface

          NetworkInterface ni = NetworkInterface.getByIndex(index);
          if (ni == null) throw new IOException("Unable to map index to interface");
          return (T) ni;
        }
      }

      if (name == StandardSocketOptions.SO_REUSEADDR && reuseAddressEmulated) {
        return (T) Boolean.valueOf(isReuseAddress);
      }

      // no special handling
      return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
    }
  }
 public SocketAddress localAddress() {
   synchronized (stateLock) {
     if (state == ST_CONNECTED
         && (localAddress == null
             || ((InetSocketAddress) localAddress).getAddress().isAnyLocalAddress())) {
       // Socket was not bound before connecting or
       // Socket was bound with an "anyLocalAddress"
       localAddress = Net.localAddress(fd);
     }
     return localAddress;
   }
 }
  /** Unblock given source. */
  void unblock(MembershipKeyImpl key, InetAddress source) {
    assert key.channel() == this;
    assert key.sourceAddress() == null;

    synchronized (stateLock) {
      if (!key.isValid()) throw new IllegalStateException("key is no longer valid");

      try {
        if (key instanceof MembershipKeyImpl.Type6) {
          MembershipKeyImpl.Type6 key6 = (MembershipKeyImpl.Type6) key;
          Net.unblock6(fd, key6.groupAddress(), key6.index(), Net.inet6AsByteArray(source));
        } else {
          MembershipKeyImpl.Type4 key4 = (MembershipKeyImpl.Type4) key;
          Net.unblock4(fd, key4.groupAddress(), key4.interfaceAddress(), Net.inet4AsInt(source));
        }
      } catch (IOException ioe) {
        // should not happen
        throw new AssertionError(ioe);
      }
    }
  }
  // package-private
  void drop(MembershipKeyImpl key) {
    assert key.channel() == this;

    synchronized (stateLock) {
      if (!key.isValid()) return;

      try {
        if (key instanceof MembershipKeyImpl.Type6) {
          MembershipKeyImpl.Type6 key6 = (MembershipKeyImpl.Type6) key;
          Net.drop6(fd, key6.groupAddress(), key6.index(), key6.source());
        } else {
          MembershipKeyImpl.Type4 key4 = (MembershipKeyImpl.Type4) key;
          Net.drop4(fd, key4.groupAddress(), key4.interfaceAddress(), key4.source());
        }
      } catch (IOException ioe) {
        // should not happen
        throw new AssertionError(ioe);
      }

      key.invalidate();
      registry.remove(key);
    }
  }
  @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;
    }
  }
  public DatagramChannel disconnect() throws IOException {
    synchronized (readLock) {
      synchronized (writeLock) {
        synchronized (stateLock) {
          if (!isConnected() || !isOpen()) return this;
          InetSocketAddress isa = (InetSocketAddress) remoteAddress;
          SecurityManager sm = System.getSecurityManager();
          if (sm != null) sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
          disconnect0(fd);
          remoteAddress = null;
          state = ST_UNCONNECTED;

          // refresh local address
          localAddress = Net.localAddress(fd);
        }
      }
    }
    return this;
  }
  // package-private
  int poll(int events, long timeout) throws IOException {
    assert Thread.holdsLock(blockingLock()) && !isBlocking();

    synchronized (readLock) {
      int n = 0;
      try {
        begin();
        synchronized (stateLock) {
          if (!isOpen()) return 0;
          readerThread = NativeThread.current();
        }
        n = Net.poll(fd, events, timeout);
      } finally {
        readerThread = 0;
        end(n > 0);
      }
      return n;
    }
  }
    /** Task to initiate a connection. */
    @Override
    public void run() {
      long overlapped = 0L;
      Throwable exc = null;
      try {
        begin();

        // synchronize on result to allow this thread handle the case
        // where the connection is established immediately.
        synchronized (result) {
          overlapped = ioCache.add(result);
          // initiate the connection
          int n =
              connect0(
                  handle, Net.isIPv6Available(), remote.getAddress(), remote.getPort(), overlapped);
          if (n == IOStatus.UNAVAILABLE) {
            // connection is pending
            return;
          }

          // connection established immediately
          afterConnect();
          result.setResult(null);
        }
      } catch (Throwable x) {
        if (overlapped != 0L) ioCache.remove(overlapped);
        exc = x;
      } finally {
        end();
      }

      if (exc != null) {
        closeChannel();
        result.setFailure(toIOException(exc));
      }
      Invoker.invoke(result);
    }
  public int read(ByteBuffer buf) throws IOException {

    if (buf == null) throw new NullPointerException();

    synchronized (readLock) {
      if (!ensureReadOpen()) return -1;
      int n = 0;
      try {

        // Set up the interruption machinery; see
        // AbstractInterruptibleChannel for details
        //
        begin();

        synchronized (stateLock) {
          if (!isOpen()) {
            // Either the current thread is already interrupted, so
            // begin() closed the channel, or another thread closed the
            // channel since we checked it a few bytecodes ago.  In
            // either case the value returned here is irrelevant since
            // the invocation of end() in the finally block will throw
            // an appropriate exception.
            //
            return 0;
          }

          // Save this thread so that it can be signalled on those
          // platforms that require it
          //
          readerThread = NativeThread.current();
        }

        // Between the previous test of isOpen() and the return of the
        // IOUtil.read invocation below, this channel might be closed
        // or this thread might be interrupted.  We rely upon the
        // implicit synchronization point in the kernel read() call to
        // make sure that the right thing happens.  In either case the
        // implCloseSelectableChannel method is ultimately invoked in
        // some other thread, so there are three possibilities:
        //
        //   - implCloseSelectableChannel() invokes nd.preClose()
        //     before this thread invokes read(), in which case the
        //     read returns immediately with either EOF or an error,
        //     the latter of which will cause an IOException to be
        //     thrown.
        //
        //   - implCloseSelectableChannel() invokes nd.preClose() after
        //     this thread is blocked in read().  On some operating
        //     systems (e.g., Solaris and Windows) this causes the read
        //     to return immediately with either EOF or an error
        //     indication.
        //
        //   - implCloseSelectableChannel() invokes nd.preClose() after
        //     this thread is blocked in read() but the operating
        //     system (e.g., Linux) doesn't support preemptive close,
        //     so implCloseSelectableChannel() proceeds to signal this
        //     thread, thereby causing the read to return immediately
        //     with IOStatus.INTERRUPTED.
        //
        // In all three cases the invocation of end() in the finally
        // clause will notice that the channel has been closed and
        // throw an appropriate exception (AsynchronousCloseException
        // or ClosedByInterruptException) if necessary.
        //
        // *There is A fourth possibility. implCloseSelectableChannel()
        // invokes nd.preClose(), signals reader/writer thred and quickly
        // moves on to nd.close() in kill(), which does a real close.
        // Then a third thread accepts a new connection, opens file or
        // whatever that causes the released "fd" to be recycled. All
        // above happens just between our last isOpen() check and the
        // next kernel read reached, with the recycled "fd". The solution
        // is to postpone the real kill() if there is a reader or/and
        // writer thread(s) over there "waiting", leave the cleanup/kill
        // to the reader or writer thread. (the preClose() still happens
        // so the connection gets cut off as usual).
        //
        // For socket channels there is the additional wrinkle that
        // asynchronous shutdown works much like asynchronous close,
        // except that the channel is shutdown rather than completely
        // closed.  This is analogous to the first two cases above,
        // except that the shutdown operation plays the role of
        // nd.preClose().
        for (; ; ) {
          n = Net.read(fd, buf);
          if ((n == IOStatus.INTERRUPTED) && isOpen()) {
            // The system call was interrupted but the channel
            // is still open, so retry
            continue;
          }
          return IOStatus.normalize(n);
        }

      } finally {
        readerCleanup(); // Clear reader thread
        // The end method, which is defined in our superclass
        // AbstractInterruptibleChannel, resets the interruption
        // machinery.  If its argument is true then it returns
        // normally; otherwise it checks the interrupt and open state
        // of this channel and throws an appropriate exception if
        // necessary.
        //
        // So, if we actually managed to do any I/O in the above try
        // block then we pass true to the end method.  We also pass
        // true if the channel was in non-blocking mode when the I/O
        // operation was initiated but no data could be transferred;
        // this prevents spurious exceptions from being thrown in the
        // rare event that a channel is closed or a thread is
        // interrupted at the exact moment that a non-blocking I/O
        // request is made.
        //
        end(n > 0 || (n == IOStatus.UNAVAILABLE));

        // Extra case for socket channels: Asynchronous shutdown
        //
        synchronized (stateLock) {
          if ((n <= 0) && (!isInputOpen)) return IOStatus.EOF;
        }

        assert IOStatus.check(n);
      }
    }
  }
 // Constructor for normal connecting sockets
 //
 SocketChannelImpl(SelectorProvider sp) throws IOException {
   super(sp);
   this.fd = Net.socket(true);
   this.state = ST_UNCONNECTED;
 }
  /** 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;
    }
  }