jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
changeset 1152 29d6145d1097
parent 2 90ce3da70b43
child 1247 b4c26443dee5
equal deleted inserted replaced
1151:4070cecdb99d 1152:29d6145d1097
    29 import java.io.IOException;
    29 import java.io.IOException;
    30 import java.net.*;
    30 import java.net.*;
    31 import java.nio.ByteBuffer;
    31 import java.nio.ByteBuffer;
    32 import java.nio.channels.*;
    32 import java.nio.channels.*;
    33 import java.nio.channels.spi.*;
    33 import java.nio.channels.spi.*;
    34 import java.lang.ref.SoftReference;
    34 import java.util.*;
    35 
    35 
    36 
    36 
    37 /**
    37 /**
    38  * An implementation of DatagramChannels.
    38  * An implementation of DatagramChannels.
    39  */
    39  */
    45 
    45 
    46     // Used to make native read and write calls
    46     // Used to make native read and write calls
    47     private static NativeDispatcher nd = new DatagramDispatcher();
    47     private static NativeDispatcher nd = new DatagramDispatcher();
    48 
    48 
    49     // Our file descriptor
    49     // Our file descriptor
    50     FileDescriptor fd = null;
    50     private final FileDescriptor fd;
    51 
    51 
    52     // fd value needed for dev/poll. This value will remain valid
    52     // fd value needed for dev/poll. This value will remain valid
    53     // even after the value in the file descriptor object has been set to -1
    53     // even after the value in the file descriptor object has been set to -1
    54     int fdVal;
    54     private final int fdVal;
       
    55 
       
    56     // The protocol family of the socket
       
    57     private final ProtocolFamily family;
    55 
    58 
    56     // IDs of native threads doing reads and writes, for signalling
    59     // IDs of native threads doing reads and writes, for signalling
    57     private volatile long readerThread = 0;
    60     private volatile long readerThread = 0;
    58     private volatile long writerThread = 0;
    61     private volatile long writerThread = 0;
    59 
    62 
    60     // Cached InetAddress and port for unconnected DatagramChannels
    63     // Cached InetAddress and port for unconnected DatagramChannels
    61     // used by receive0
    64     // used by receive0
    62     private InetAddress cachedSenderInetAddress = null;
    65     private InetAddress cachedSenderInetAddress;
    63     private int cachedSenderPort = 0;
    66     private int cachedSenderPort;
    64 
    67 
    65     // Lock held by current reading or connecting thread
    68     // Lock held by current reading or connecting thread
    66     private final Object readLock = new Object();
    69     private final Object readLock = new Object();
    67 
    70 
    68     // Lock held by current writing or connecting thread
    71     // Lock held by current writing or connecting thread
    74 
    77 
    75     // -- The following fields are protected by stateLock
    78     // -- The following fields are protected by stateLock
    76 
    79 
    77     // State (does not necessarily increase monotonically)
    80     // State (does not necessarily increase monotonically)
    78     private static final int ST_UNINITIALIZED = -1;
    81     private static final int ST_UNINITIALIZED = -1;
    79     private static int ST_UNCONNECTED = 0;
    82     private static final int ST_UNCONNECTED = 0;
    80     private static int ST_CONNECTED = 1;
    83     private static final int ST_CONNECTED = 1;
    81     private static final int ST_KILLED = 2;
    84     private static final int ST_KILLED = 2;
    82     private int state = ST_UNINITIALIZED;
    85     private int state = ST_UNINITIALIZED;
    83 
    86 
    84     // Binding
    87     // Binding
    85     private SocketAddress localAddress = null;
    88     private SocketAddress localAddress;
    86     SocketAddress remoteAddress = null;
    89     private SocketAddress remoteAddress;
    87 
       
    88     // Options
       
    89     private SocketOpts.IP options = null;
       
    90 
    90 
    91     // Our socket adaptor, if any
    91     // Our socket adaptor, if any
    92     private DatagramSocket socket = null;
    92     private DatagramSocket socket;
       
    93 
       
    94     // Multicast support
       
    95     private MembershipRegistry registry;
    93 
    96 
    94     // -- End of fields protected by stateLock
    97     // -- End of fields protected by stateLock
    95 
    98 
    96 
    99 
    97     public DatagramChannelImpl(SelectorProvider sp)
   100     public DatagramChannelImpl(SelectorProvider sp)
    98         throws IOException
   101         throws IOException
    99     {
   102     {
   100         super(sp);
   103         super(sp);
   101         this.fd = Net.socket(false);
   104         this.family = Net.isIPv6Available() ?
       
   105             StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
       
   106         this.fd = Net.socket(family, false);
   102         this.fdVal = IOUtil.fdVal(fd);
   107         this.fdVal = IOUtil.fdVal(fd);
   103         this.state = ST_UNCONNECTED;
   108         this.state = ST_UNCONNECTED;
   104     }
   109     }
   105 
   110 
       
   111     public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family) {
       
   112         super(sp);
       
   113         if ((family != StandardProtocolFamily.INET) &&
       
   114             (family != StandardProtocolFamily.INET6)) {
       
   115             throw new UnsupportedOperationException("Protocol family not supported");
       
   116         }
       
   117         if (family == StandardProtocolFamily.INET6) {
       
   118             if (!Net.isIPv6Available()) {
       
   119                 throw new UnsupportedOperationException("IPv6 not available");
       
   120             }
       
   121         }
       
   122         this.family = family;
       
   123         this.fd = Net.socket(family, false);
       
   124         this.fdVal = IOUtil.fdVal(fd);
       
   125         this.state = ST_UNCONNECTED;
       
   126     }
       
   127 
   106     public DatagramChannelImpl(SelectorProvider sp, FileDescriptor fd)
   128     public DatagramChannelImpl(SelectorProvider sp, FileDescriptor fd)
   107         throws IOException
   129         throws IOException
   108     {
   130     {
   109         super(sp);
   131         super(sp);
       
   132         this.family = Net.isIPv6Available() ?
       
   133             StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
   110         this.fd = fd;
   134         this.fd = fd;
   111         this.fdVal = IOUtil.fdVal(fd);
   135         this.fdVal = IOUtil.fdVal(fd);
   112         this.state = ST_UNCONNECTED;
   136         this.state = ST_UNCONNECTED;
       
   137         this.localAddress = Net.localAddress(fd);
   113     }
   138     }
   114 
   139 
   115     public DatagramSocket socket() {
   140     public DatagramSocket socket() {
   116         synchronized (stateLock) {
   141         synchronized (stateLock) {
   117             if (socket == null)
   142             if (socket == null)
   118                 socket = DatagramSocketAdaptor.create(this);
   143                 socket = DatagramSocketAdaptor.create(this);
   119             return socket;
   144             return socket;
   120         }
   145         }
       
   146     }
       
   147 
       
   148     @Override
       
   149     public SocketAddress getLocalAddress() throws IOException {
       
   150         synchronized (stateLock) {
       
   151             if (!isOpen())
       
   152                 return null;
       
   153             return localAddress;
       
   154         }
       
   155     }
       
   156 
       
   157     @Override
       
   158     public SocketAddress getConnectedAddress() throws IOException {
       
   159         synchronized (stateLock) {
       
   160             if (!isOpen())
       
   161                 return null;
       
   162             return remoteAddress;
       
   163         }
       
   164     }
       
   165 
       
   166     @Override
       
   167     public DatagramChannel setOption(SocketOption name, Object value)
       
   168         throws IOException
       
   169     {
       
   170         if (name == null)
       
   171             throw new NullPointerException();
       
   172         if (!options().contains(name))
       
   173             throw new IllegalArgumentException("Invalid option name");
       
   174 
       
   175         synchronized (stateLock) {
       
   176             ensureOpen();
       
   177 
       
   178             if (name == StandardSocketOption.IP_TOS) {
       
   179                 // IPv4 only; no-op for IPv6
       
   180                 if (family == StandardProtocolFamily.INET) {
       
   181                     Net.setSocketOption(fd, family, name, value);
       
   182                 }
       
   183                 return this;
       
   184             }
       
   185 
       
   186             if (name == StandardSocketOption.IP_MULTICAST_TTL ||
       
   187                 name == StandardSocketOption.IP_MULTICAST_LOOP)
       
   188             {
       
   189                 // options are protocol dependent
       
   190                 Net.setSocketOption(fd, family, name, value);
       
   191                 return this;
       
   192             }
       
   193 
       
   194             if (name == StandardSocketOption.IP_MULTICAST_IF) {
       
   195                 if (value == null)
       
   196                     throw new IllegalArgumentException("Cannot set IP_MULTICAST_IF to 'null'");
       
   197                 NetworkInterface interf = (NetworkInterface)value;
       
   198                 if (family == StandardProtocolFamily.INET6) {
       
   199                     int index = interf.getIndex();
       
   200                     if (index == -1)
       
   201                         throw new IOException("Network interface cannot be identified");
       
   202                     Net.setInterface6(fd, index);
       
   203                 } else {
       
   204                     // need IPv4 address to identify interface
       
   205                     Inet4Address target = Net.anyInet4Address(interf);
       
   206                     if (target == null)
       
   207                         throw new IOException("Network interface not configured for IPv4");
       
   208                     int targetAddress = Net.inet4AsInt(target);
       
   209                     Net.setInterface4(fd, targetAddress);
       
   210                 }
       
   211                 return this;
       
   212             }
       
   213 
       
   214             // remaining options don't need any special handling
       
   215             Net.setSocketOption(fd, Net.UNSPEC, name, value);
       
   216             return this;
       
   217         }
       
   218     }
       
   219 
       
   220     @Override
       
   221     @SuppressWarnings("unchecked")
       
   222     public <T> T getOption(SocketOption<T> name)
       
   223         throws IOException
       
   224     {
       
   225         if (name == null)
       
   226             throw new NullPointerException();
       
   227         if (!options().contains(name))
       
   228             throw new IllegalArgumentException("Invalid option name");
       
   229 
       
   230         synchronized (stateLock) {
       
   231             ensureOpen();
       
   232 
       
   233             if (name == StandardSocketOption.IP_TOS) {
       
   234                 // IPv4 only; always return 0 on IPv6
       
   235                 if (family == StandardProtocolFamily.INET) {
       
   236                     return (T) Net.getSocketOption(fd, family, name);
       
   237                 } else {
       
   238                     return (T) Integer.valueOf(0);
       
   239                 }
       
   240             }
       
   241 
       
   242             if (name == StandardSocketOption.IP_MULTICAST_TTL ||
       
   243                 name == StandardSocketOption.IP_MULTICAST_LOOP)
       
   244             {
       
   245                 return (T) Net.getSocketOption(fd, family, name);
       
   246             }
       
   247 
       
   248             if (name == StandardSocketOption.IP_MULTICAST_IF) {
       
   249                 if (family == StandardProtocolFamily.INET) {
       
   250                     int address = Net.getInterface4(fd);
       
   251                     if (address == 0)
       
   252                         return null;    // default interface
       
   253 
       
   254                     InetAddress ia = Net.inet4FromInt(address);
       
   255                     NetworkInterface ni = NetworkInterface.getByInetAddress(ia);
       
   256                     if (ni == null)
       
   257                         throw new IOException("Unable to map address to interface");
       
   258                     return (T) ni;
       
   259                 } else {
       
   260                     int index = Net.getInterface6(fd);
       
   261                     if (index == 0)
       
   262                         return null;    // default interface
       
   263 
       
   264                     NetworkInterface ni = NetworkInterface.getByIndex(index);
       
   265                     if (ni == null)
       
   266                         throw new IOException("Unable to map index to interface");
       
   267                     return (T) ni;
       
   268                 }
       
   269             }
       
   270 
       
   271             // no special handling
       
   272             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
       
   273         }
       
   274     }
       
   275 
       
   276     private static class LazyInitialization {
       
   277         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
       
   278 
       
   279         private static Set<SocketOption<?>> defaultOptions() {
       
   280             HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(8);
       
   281             set.add(StandardSocketOption.SO_SNDBUF);
       
   282             set.add(StandardSocketOption.SO_RCVBUF);
       
   283             set.add(StandardSocketOption.SO_REUSEADDR);
       
   284             set.add(StandardSocketOption.SO_BROADCAST);
       
   285             set.add(StandardSocketOption.IP_TOS);
       
   286             set.add(StandardSocketOption.IP_MULTICAST_IF);
       
   287             set.add(StandardSocketOption.IP_MULTICAST_TTL);
       
   288             set.add(StandardSocketOption.IP_MULTICAST_LOOP);
       
   289             return Collections.unmodifiableSet(set);
       
   290         }
       
   291     }
       
   292 
       
   293     @Override
       
   294     public final Set<SocketOption<?>> options() {
       
   295         return LazyInitialization.defaultOptions;
   121     }
   296     }
   122 
   297 
   123     private void ensureOpen() throws ClosedChannelException {
   298     private void ensureOpen() throws ClosedChannelException {
   124         if (!isOpen())
   299         if (!isOpen())
   125             throw new ClosedChannelException();
   300             throw new ClosedChannelException();
   133         if (dst == null)
   308         if (dst == null)
   134             throw new NullPointerException();
   309             throw new NullPointerException();
   135         synchronized (readLock) {
   310         synchronized (readLock) {
   136             ensureOpen();
   311             ensureOpen();
   137             // If socket is not bound then behave as if nothing received
   312             // If socket is not bound then behave as if nothing received
   138             if (!isBound())             // ## NotYetBoundException ??
   313             // Will be fixed by 6621699
       
   314             if (localAddress() == null) {
   139                 return null;
   315                 return null;
       
   316             }
   140             int n = 0;
   317             int n = 0;
   141             ByteBuffer bb = null;
   318             ByteBuffer bb = null;
   142             try {
   319             try {
   143                 begin();
   320                 begin();
   144                 if (!isOpen())
   321                 if (!isOpen())
   265                     return 0;
   442                     return 0;
   266                 writerThread = NativeThread.current();
   443                 writerThread = NativeThread.current();
   267                 do {
   444                 do {
   268                     n = send(fd, src, target);
   445                     n = send(fd, src, target);
   269                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
   446                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
       
   447 
       
   448                 synchronized (stateLock) {
       
   449                     if (isOpen() && (localAddress == null)) {
       
   450                         localAddress = Net.localAddress(fd);
       
   451                     }
       
   452                 }
   270                 return IOStatus.normalize(n);
   453                 return IOStatus.normalize(n);
   271             } finally {
   454             } finally {
   272                 writerThread = 0;
   455                 writerThread = 0;
   273                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
   456                 end((n > 0) || (n == IOStatus.UNAVAILABLE));
   274                 assert IOStatus.check(n);
   457                 assert IOStatus.check(n);
   314         int pos = bb.position();
   497         int pos = bb.position();
   315         int lim = bb.limit();
   498         int lim = bb.limit();
   316         assert (pos <= lim);
   499         assert (pos <= lim);
   317         int rem = (pos <= lim ? lim - pos : 0);
   500         int rem = (pos <= lim ? lim - pos : 0);
   318 
   501 
   319         int written = send0(fd, ((DirectBuffer)bb).address() + pos,
   502         boolean preferIPv6 = (family != StandardProtocolFamily.INET);
       
   503         int written = send0(preferIPv6, fd, ((DirectBuffer)bb).address() + pos,
   320                             rem, target);
   504                             rem, target);
   321         if (written > 0)
   505         if (written > 0)
   322             bb.position(pos + written);
   506             bb.position(pos + written);
   323         return written;
   507         return written;
   324     }
   508     }
   451 
   635 
   452     protected void implConfigureBlocking(boolean block) throws IOException {
   636     protected void implConfigureBlocking(boolean block) throws IOException {
   453         IOUtil.configureBlocking(fd, block);
   637         IOUtil.configureBlocking(fd, block);
   454     }
   638     }
   455 
   639 
   456     public SocketOpts options() {
       
   457         synchronized (stateLock) {
       
   458             if (options == null) {
       
   459                 SocketOptsImpl.Dispatcher d
       
   460                     = new SocketOptsImpl.Dispatcher() {
       
   461                             int getInt(int opt) throws IOException {
       
   462                                 return Net.getIntOption(fd, opt);
       
   463                             }
       
   464                             void setInt(int opt, int arg)
       
   465                                 throws IOException
       
   466                             {
       
   467                                 Net.setIntOption(fd, opt, arg);
       
   468                             }
       
   469                         };
       
   470                 options = new SocketOptsImpl.IP(d);
       
   471             }
       
   472             return options;
       
   473         }
       
   474     }
       
   475 
       
   476     public boolean isBound() {
       
   477         return Net.localPortNumber(fd) != 0;
       
   478     }
       
   479 
       
   480     public SocketAddress localAddress() {
   640     public SocketAddress localAddress() {
   481         synchronized (stateLock) {
   641         synchronized (stateLock) {
   482             if (isConnected() && (localAddress == null)) {
       
   483                 // Socket was not bound before connecting,
       
   484                 // so ask what the address turned out to be
       
   485                 localAddress = Net.localAddress(fd);
       
   486             }
       
   487             SecurityManager sm = System.getSecurityManager();
       
   488             if (sm != null) {
       
   489                 InetSocketAddress isa = (InetSocketAddress)localAddress;
       
   490                 sm.checkConnect(isa.getAddress().getHostAddress(), -1);
       
   491             }
       
   492             return localAddress;
   642             return localAddress;
   493         }
   643         }
   494     }
   644     }
   495 
   645 
   496     public SocketAddress remoteAddress() {
   646     public SocketAddress remoteAddress() {
   497         synchronized (stateLock) {
   647         synchronized (stateLock) {
   498             return remoteAddress;
   648             return remoteAddress;
   499         }
   649         }
   500     }
   650     }
   501 
   651 
   502     public void bind(SocketAddress local) throws IOException {
   652     @Override
       
   653     public DatagramChannel bind(SocketAddress local) throws IOException {
   503         synchronized (readLock) {
   654         synchronized (readLock) {
   504             synchronized (writeLock) {
   655             synchronized (writeLock) {
   505                 synchronized (stateLock) {
   656                 synchronized (stateLock) {
   506                     ensureOpen();
   657                     ensureOpen();
   507                     if (isBound())
   658                     if (localAddress != null)
   508                         throw new AlreadyBoundException();
   659                         throw new AlreadyBoundException();
   509                     InetSocketAddress isa = Net.checkAddress(local);
   660                     InetSocketAddress isa;
       
   661                     if (local == null) {
       
   662                         isa = new InetSocketAddress(0);
       
   663                     } else {
       
   664                         isa = Net.checkAddress(local);
       
   665 
       
   666                         // only Inet4Address allowed with IPv4 socket
       
   667                         if (family == StandardProtocolFamily.INET) {
       
   668                             InetAddress addr = isa.getAddress();
       
   669                             if (!(addr instanceof Inet4Address))
       
   670                                 throw new UnsupportedAddressTypeException();
       
   671                         }
       
   672                     }
   510                     SecurityManager sm = System.getSecurityManager();
   673                     SecurityManager sm = System.getSecurityManager();
   511                     if (sm != null)
   674                     if (sm != null) {
   512                         sm.checkListen(isa.getPort());
   675                         sm.checkListen(isa.getPort());
   513                     Net.bind(fd, isa.getAddress(), isa.getPort());
   676                     }
       
   677                     Net.bind(family, fd, isa.getAddress(), isa.getPort());
   514                     localAddress = Net.localAddress(fd);
   678                     localAddress = Net.localAddress(fd);
   515                 }
   679                 }
   516             }
   680             }
   517         }
   681         }
       
   682         return this;
   518     }
   683     }
   519 
   684 
   520     public boolean isConnected() {
   685     public boolean isConnected() {
   521         synchronized (stateLock) {
   686         synchronized (stateLock) {
   522             return (state == ST_CONNECTED);
   687             return (state == ST_CONNECTED);
   531                 throw new IllegalStateException("Connect already invoked");
   696                 throw new IllegalStateException("Connect already invoked");
   532         }
   697         }
   533     }
   698     }
   534 
   699 
   535     public DatagramChannel connect(SocketAddress sa) throws IOException {
   700     public DatagramChannel connect(SocketAddress sa) throws IOException {
   536         int trafficClass = 0;
       
   537         int localPort = 0;
   701         int localPort = 0;
   538 
   702 
   539         synchronized(readLock) {
   703         synchronized(readLock) {
   540             synchronized(writeLock) {
   704             synchronized(writeLock) {
   541                 synchronized (stateLock) {
   705                 synchronized (stateLock) {
   543                     InetSocketAddress isa = Net.checkAddress(sa);
   707                     InetSocketAddress isa = Net.checkAddress(sa);
   544                     SecurityManager sm = System.getSecurityManager();
   708                     SecurityManager sm = System.getSecurityManager();
   545                     if (sm != null)
   709                     if (sm != null)
   546                         sm.checkConnect(isa.getAddress().getHostAddress(),
   710                         sm.checkConnect(isa.getAddress().getHostAddress(),
   547                                         isa.getPort());
   711                                         isa.getPort());
   548                     int n = Net.connect(fd,
   712                     int n = Net.connect(family,
       
   713                                         fd,
   549                                         isa.getAddress(),
   714                                         isa.getAddress(),
   550                                         isa.getPort(),
   715                                         isa.getPort());
   551                                         trafficClass);
       
   552                     if (n <= 0)
   716                     if (n <= 0)
   553                         throw new Error();      // Can't happen
   717                         throw new Error();      // Can't happen
   554 
   718 
   555                     // Connection succeeded; disallow further invocation
   719                     // Connection succeeded; disallow further invocation
   556                     state = ST_CONNECTED;
   720                     state = ST_CONNECTED;
   557                     remoteAddress = sa;
   721                     remoteAddress = sa;
   558                     sender = isa;
   722                     sender = isa;
   559                     cachedSenderInetAddress = isa.getAddress();
   723                     cachedSenderInetAddress = isa.getAddress();
   560                     cachedSenderPort = isa.getPort();
   724                     cachedSenderPort = isa.getPort();
       
   725 
       
   726                     // Socket was not bound before connecting,
       
   727                     if (localAddress == null) {
       
   728                         localAddress = Net.localAddress(fd);
       
   729                     }
   561                 }
   730                 }
   562             }
   731             }
   563         }
   732         }
   564         return this;
   733         return this;
   565     }
   734     }
   582             }
   751             }
   583         }
   752         }
   584         return this;
   753         return this;
   585     }
   754     }
   586 
   755 
       
   756     /**
       
   757      * Joins channel's socket to the given group/interface and
       
   758      * optional source address.
       
   759      */
       
   760     private MembershipKey innerJoin(InetAddress group,
       
   761                                     NetworkInterface interf,
       
   762                                     InetAddress source)
       
   763         throws IOException
       
   764     {
       
   765         if (!group.isMulticastAddress())
       
   766             throw new IllegalArgumentException("Group not a multicast address");
       
   767 
       
   768         // check multicast address is compatible with this socket
       
   769         if (!(group instanceof Inet4Address)) {
       
   770             if (family == StandardProtocolFamily.INET)
       
   771                 throw new IllegalArgumentException("Group is not IPv4 address");
       
   772             if (!(group instanceof Inet6Address))
       
   773                 throw new IllegalArgumentException("Address type not supported");
       
   774         }
       
   775 
       
   776         // check source address
       
   777         if (source != null) {
       
   778             if (source.isAnyLocalAddress())
       
   779                 throw new IllegalArgumentException("Source address is a wildcard address");
       
   780             if (source.isMulticastAddress())
       
   781                 throw new IllegalArgumentException("Source address is multicast address");
       
   782             if (source.getClass() != group.getClass())
       
   783                 throw new IllegalArgumentException("Source address is different type to group");
       
   784         }
       
   785 
       
   786         SecurityManager sm = System.getSecurityManager();
       
   787         if (sm != null)
       
   788             sm.checkMulticast(group);
       
   789 
       
   790         synchronized (stateLock) {
       
   791             if (!isOpen())
       
   792                 throw new ClosedChannelException();
       
   793 
       
   794             // check the registry to see if we are already a member of the group
       
   795             if (registry == null) {
       
   796                 registry = new MembershipRegistry();
       
   797             } else {
       
   798                 // return existing membership key
       
   799                 MembershipKey key = registry.checkMembership(group, interf, source);
       
   800                 if (key != null)
       
   801                     return key;
       
   802             }
       
   803 
       
   804             MembershipKeyImpl key;
       
   805             if (family == StandardProtocolFamily.INET6) {
       
   806                 int index = interf.getIndex();
       
   807                 if (index == -1)
       
   808                     throw new IOException("Network interface cannot be identified");
       
   809 
       
   810                 // need multicast and source address as byte arrays
       
   811                 byte[] groupAddress = Net.inet6AsByteArray(group);
       
   812                 byte[] sourceAddress = (source == null) ? null :
       
   813                     Net.inet6AsByteArray(source);
       
   814 
       
   815                 // join the group
       
   816                 int n = Net.join6(fd, groupAddress, index, sourceAddress);
       
   817                 if (n == IOStatus.UNAVAILABLE)
       
   818                     throw new UnsupportedOperationException();
       
   819 
       
   820                 key = new MembershipKeyImpl.Type6(this, group, interf, source,
       
   821                                                   groupAddress, index, sourceAddress);
       
   822 
       
   823             } else {
       
   824                 // need IPv4 address to identify interface
       
   825                 Inet4Address target = Net.anyInet4Address(interf);
       
   826                 if (target == null)
       
   827                     throw new IOException("Network interface not configured for IPv4");
       
   828 
       
   829                 int groupAddress = Net.inet4AsInt(group);
       
   830                 int targetAddress = Net.inet4AsInt(target);
       
   831                 int sourceAddress = (source == null) ? 0 : Net.inet4AsInt(source);
       
   832 
       
   833                 // join the group
       
   834                 int n = Net.join4(fd, groupAddress, targetAddress, sourceAddress);
       
   835                 if (n == IOStatus.UNAVAILABLE)
       
   836                     throw new UnsupportedOperationException();
       
   837 
       
   838                 key = new MembershipKeyImpl.Type4(this, group, interf, source,
       
   839                                                   groupAddress, targetAddress, sourceAddress);
       
   840             }
       
   841 
       
   842             registry.add(key);
       
   843             return key;
       
   844         }
       
   845     }
       
   846 
       
   847     @Override
       
   848     public MembershipKey join(InetAddress group,
       
   849                               NetworkInterface interf)
       
   850         throws IOException
       
   851     {
       
   852         return innerJoin(group, interf, null);
       
   853     }
       
   854 
       
   855     @Override
       
   856     public MembershipKey join(InetAddress group,
       
   857                               NetworkInterface interf,
       
   858                               InetAddress source)
       
   859         throws IOException
       
   860     {
       
   861         if (source == null)
       
   862             throw new NullPointerException("source address is null");
       
   863         return innerJoin(group, interf, source);
       
   864     }
       
   865 
       
   866     // package-private
       
   867     void drop(MembershipKeyImpl key)
       
   868         throws IOException
       
   869     {
       
   870         assert key.getChannel() == this;
       
   871 
       
   872         synchronized (stateLock) {
       
   873             if (!key.isValid())
       
   874                 return;
       
   875 
       
   876             if (family == StandardProtocolFamily.INET6) {
       
   877                 MembershipKeyImpl.Type6 key6 =
       
   878                     (MembershipKeyImpl.Type6)key;
       
   879                 Net.drop6(fd, key6.group(), key6.index(), key6.source());
       
   880             } else {
       
   881                 MembershipKeyImpl.Type4 key4 =
       
   882                     (MembershipKeyImpl.Type4)key;
       
   883                 Net.drop4(fd, key4.group(), key4.interfaceAddress(), key4.source());
       
   884             }
       
   885 
       
   886             key.invalidate();
       
   887             registry.remove(key);
       
   888         }
       
   889     }
       
   890 
       
   891     /**
       
   892      * Block datagrams from given source if a memory to receive all
       
   893      * datagrams.
       
   894      */
       
   895     void block(MembershipKeyImpl key, InetAddress source)
       
   896         throws IOException
       
   897     {
       
   898         assert key.getChannel() == this;
       
   899         assert key.getSourceAddress() == null;
       
   900 
       
   901         synchronized (stateLock) {
       
   902             if (!key.isValid())
       
   903                 throw new IllegalStateException("key is no longer valid");
       
   904             if (source.isAnyLocalAddress())
       
   905                 throw new IllegalArgumentException("Source address is a wildcard address");
       
   906             if (source.isMulticastAddress())
       
   907                 throw new IllegalArgumentException("Source address is multicast address");
       
   908             if (source.getClass() != key.getGroup().getClass())
       
   909                 throw new IllegalArgumentException("Source address is different type to group");
       
   910 
       
   911             int n;
       
   912             if (family == StandardProtocolFamily.INET6) {
       
   913                  MembershipKeyImpl.Type6 key6 =
       
   914                     (MembershipKeyImpl.Type6)key;
       
   915                 n = Net.block6(fd, key6.group(), key6.index(),
       
   916                                Net.inet6AsByteArray(source));
       
   917             } else {
       
   918                 MembershipKeyImpl.Type4 key4 =
       
   919                     (MembershipKeyImpl.Type4)key;
       
   920                 n = Net.block4(fd, key4.group(), key4.interfaceAddress(),
       
   921                                Net.inet4AsInt(source));
       
   922             }
       
   923             if (n == IOStatus.UNAVAILABLE) {
       
   924                 // ancient kernel
       
   925                 throw new UnsupportedOperationException();
       
   926             }
       
   927         }
       
   928     }
       
   929 
       
   930     /**
       
   931      * Unblock given source.
       
   932      */
       
   933     void unblock(MembershipKeyImpl key, InetAddress source)
       
   934         throws IOException
       
   935     {
       
   936         assert key.getChannel() == this;
       
   937         assert key.getSourceAddress() == null;
       
   938 
       
   939         synchronized (stateLock) {
       
   940             if (!key.isValid())
       
   941                 throw new IllegalStateException("key is no longer valid");
       
   942 
       
   943             if (family == StandardProtocolFamily.INET6) {
       
   944                 MembershipKeyImpl.Type6 key6 =
       
   945                     (MembershipKeyImpl.Type6)key;
       
   946                 Net.unblock6(fd, key6.group(), key6.index(),
       
   947                              Net.inet6AsByteArray(source));
       
   948             } else {
       
   949                 MembershipKeyImpl.Type4 key4 =
       
   950                     (MembershipKeyImpl.Type4)key;
       
   951                 Net.unblock4(fd, key4.group(), key4.interfaceAddress(),
       
   952                              Net.inet4AsInt(source));
       
   953             }
       
   954         }
       
   955     }
       
   956 
   587     protected void implCloseSelectableChannel() throws IOException {
   957     protected void implCloseSelectableChannel() throws IOException {
   588         synchronized (stateLock) {
   958         synchronized (stateLock) {
   589             nd.preClose(fd);
   959             nd.preClose(fd);
       
   960 
       
   961             // if member of mulitcast group then invalidate all keys
       
   962             if (registry != null)
       
   963                 registry.invalidateAll();
       
   964 
   590             long th;
   965             long th;
   591             if ((th = readerThread) != 0)
   966             if ((th = readerThread) != 0)
   592                 NativeThread.signal(th);
   967                 NativeThread.signal(th);
   593             if ((th = writerThread) != 0)
   968             if ((th = writerThread) != 0)
   594                 NativeThread.signal(th);
   969                 NativeThread.signal(th);
   693 
  1068 
   694     private native int receive0(FileDescriptor fd, long address, int len,
  1069     private native int receive0(FileDescriptor fd, long address, int len,
   695                                 boolean connected)
  1070                                 boolean connected)
   696         throws IOException;
  1071         throws IOException;
   697 
  1072 
   698     private native int send0(FileDescriptor fd, long address, int len,
  1073     private native int send0(boolean preferIPv6, FileDescriptor fd, long address, int len,
   699                      SocketAddress sa)
  1074                              SocketAddress sa)
   700         throws IOException;
  1075         throws IOException;
   701 
  1076 
   702     static {
  1077     static {
   703         Util.load();
  1078         Util.load();
   704         initIDs();
  1079         initIDs();