1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.  Oracle designates this
9 * particular file as subject to the "Classpath" exception as provided
10 * by Oracle in the LICENSE file that accompanied this code.
11 *
12 * This code is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 * version 2 for more details (a copy is included in the LICENSE file that
16 * accompanied this code).
17 *
18 * You should have received a copy of the GNU General Public License version
19 * 2 along with this work; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23 * or visit www.oracle.com if you need additional information or have any
24 * questions.
25 */
26
27package sun.nio.ch;
28
29import java.io.FileDescriptor;
30import java.io.IOException;
31import java.net.DatagramSocket;
32import java.net.Inet4Address;
33import java.net.Inet6Address;
34import java.net.InetAddress;
35import java.net.InetSocketAddress;
36import java.net.NetworkInterface;
37import java.net.PortUnreachableException;
38import java.net.ProtocolFamily;
39import java.net.SocketAddress;
40import java.net.SocketOption;
41import java.net.StandardProtocolFamily;
42import java.net.StandardSocketOptions;
43import java.nio.ByteBuffer;
44import java.nio.channels.AlreadyBoundException;
45import java.nio.channels.ClosedChannelException;
46import java.nio.channels.DatagramChannel;
47import java.nio.channels.MembershipKey;
48import java.nio.channels.NotYetConnectedException;
49import java.nio.channels.SelectionKey;
50import java.nio.channels.UnsupportedAddressTypeException;
51import java.nio.channels.spi.SelectorProvider;
52import java.util.Collections;
53import java.util.HashSet;
54import java.util.Set;
55
56import dalvik.system.BlockGuard;
57import dalvik.system.CloseGuard;
58import sun.net.ExtendedOptionsImpl;
59import sun.net.ResourceManager;
60
61/**
62 * An implementation of DatagramChannels.
63 */
64
65class DatagramChannelImpl
66    extends DatagramChannel
67    implements SelChImpl
68{
69
70    // Used to make native read and write calls
71    private static NativeDispatcher nd = new DatagramDispatcher();
72
73    // Our file descriptor
74    // Android-changed: Make the fd package visible so that we can expose it through DatagramSocketAdaptor.
75    final FileDescriptor fd;
76
77    // fd value needed for dev/poll. This value will remain valid
78    // even after the value in the file descriptor object has been set to -1
79    private final int fdVal;
80
81    // The protocol family of the socket
82    private final ProtocolFamily family;
83
84    // IDs of native threads doing reads and writes, for signalling
85    private volatile long readerThread = 0;
86    private volatile long writerThread = 0;
87
88    // Cached InetAddress and port for unconnected DatagramChannels
89    // used by receive0
90    private InetAddress cachedSenderInetAddress;
91    private int cachedSenderPort;
92
93    // Lock held by current reading or connecting thread
94    private final Object readLock = new Object();
95
96    // Lock held by current writing or connecting thread
97    private final Object writeLock = new Object();
98
99    // Lock held by any thread that modifies the state fields declared below
100    // DO NOT invoke a blocking I/O operation while holding this lock!
101    private final Object stateLock = new Object();
102
103    // -- The following fields are protected by stateLock
104
105    // State (does not necessarily increase monotonically)
106    private static final int ST_UNINITIALIZED = -1;
107    private static final int ST_UNCONNECTED = 0;
108    private static final int ST_CONNECTED = 1;
109    private static final int ST_KILLED = 2;
110    private int state = ST_UNINITIALIZED;
111
112    // Binding
113    private InetSocketAddress localAddress;
114    private InetSocketAddress remoteAddress;
115
116    // Our socket adaptor, if any
117    private DatagramSocket socket;
118
119    // Multicast support
120    private MembershipRegistry registry;
121
122    // set true when socket is bound and SO_REUSEADDRESS is emulated
123    private boolean reuseAddressEmulated;
124
125    // set true/false when socket is already bound and SO_REUSEADDR is emulated
126    private boolean isReuseAddress;
127
128    // -- End of fields protected by stateLock
129
130    // Android-changed: Add CloseGuard support.
131    private final CloseGuard guard = CloseGuard.get();
132
133    public DatagramChannelImpl(SelectorProvider sp)
134        throws IOException
135    {
136        super(sp);
137        ResourceManager.beforeUdpCreate();
138        try {
139            this.family = Net.isIPv6Available() ?
140                StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
141            this.fd = Net.socket(family, false);
142            this.fdVal = IOUtil.fdVal(fd);
143            this.state = ST_UNCONNECTED;
144            // Android-changed: Add CloseGuard support.
145            // Net#socket will set |fd| if it succeeds.
146            if (fd != null && fd.valid()) {
147                guard.open("close");
148            }
149        } catch (IOException ioe) {
150            ResourceManager.afterUdpClose();
151            throw ioe;
152        }
153    }
154
155    public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family)
156        throws IOException
157    {
158        super(sp);
159        if ((family != StandardProtocolFamily.INET) &&
160            (family != StandardProtocolFamily.INET6))
161        {
162            if (family == null)
163                throw new NullPointerException("'family' is null");
164            else
165                throw new UnsupportedOperationException("Protocol family not supported");
166        }
167        if (family == StandardProtocolFamily.INET6) {
168            if (!Net.isIPv6Available()) {
169                throw new UnsupportedOperationException("IPv6 not available");
170            }
171        }
172        this.family = family;
173        this.fd = Net.socket(family, false);
174        this.fdVal = IOUtil.fdVal(fd);
175        this.state = ST_UNCONNECTED;
176        // Android-changed: Add CloseGuard support.
177        // Net#socket will set |fd| if it succeeds.
178        if (fd != null && fd.valid()) {
179            guard.open("close");
180        }
181    }
182
183    public DatagramChannelImpl(SelectorProvider sp, FileDescriptor fd)
184        throws IOException
185    {
186        super(sp);
187        this.family = Net.isIPv6Available() ?
188            StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
189        this.fd = fd;
190        this.fdVal = IOUtil.fdVal(fd);
191        this.state = ST_UNCONNECTED;
192        this.localAddress = Net.localAddress(fd);
193        // Android-changed: Add CloseGuard support.
194        if (fd != null && fd.valid()) {
195            guard.open("close");
196        }
197    }
198
199    public DatagramSocket socket() {
200        synchronized (stateLock) {
201            if (socket == null)
202                socket = DatagramSocketAdaptor.create(this);
203            return socket;
204        }
205    }
206
207    @Override
208    public SocketAddress getLocalAddress() throws IOException {
209        synchronized (stateLock) {
210            if (!isOpen())
211                throw new ClosedChannelException();
212            // Perform security check before returning address
213            return Net.getRevealedLocalAddress(localAddress);
214        }
215    }
216
217    @Override
218    public SocketAddress getRemoteAddress() throws IOException {
219        synchronized (stateLock) {
220            if (!isOpen())
221                throw new ClosedChannelException();
222            return remoteAddress;
223        }
224    }
225
226    @Override
227    public <T> DatagramChannel setOption(SocketOption<T> name, T value)
228        throws IOException
229    {
230        if (name == null)
231            throw new NullPointerException();
232        if (!supportedOptions().contains(name))
233            throw new UnsupportedOperationException("'" + name + "' not supported");
234
235        synchronized (stateLock) {
236            ensureOpen();
237
238            if (name == StandardSocketOptions.IP_TOS ||
239                name == StandardSocketOptions.IP_MULTICAST_TTL ||
240                name == StandardSocketOptions.IP_MULTICAST_LOOP)
241            {
242                // options are protocol dependent
243                Net.setSocketOption(fd, family, name, value);
244                return this;
245            }
246
247            if (name == StandardSocketOptions.IP_MULTICAST_IF) {
248                if (value == null)
249                    throw new IllegalArgumentException("Cannot set IP_MULTICAST_IF to 'null'");
250                NetworkInterface interf = (NetworkInterface)value;
251                if (family == StandardProtocolFamily.INET6) {
252                    int index = interf.getIndex();
253                    if (index == -1)
254                        throw new IOException("Network interface cannot be identified");
255                    Net.setInterface6(fd, index);
256                } else {
257                    // need IPv4 address to identify interface
258                    Inet4Address target = Net.anyInet4Address(interf);
259                    if (target == null)
260                        throw new IOException("Network interface not configured for IPv4");
261                    int targetAddress = Net.inet4AsInt(target);
262                    Net.setInterface4(fd, targetAddress);
263                }
264                return this;
265            }
266            if (name == StandardSocketOptions.SO_REUSEADDR &&
267                    Net.useExclusiveBind() && localAddress != null)
268            {
269                reuseAddressEmulated = true;
270                this.isReuseAddress = (Boolean)value;
271            }
272
273            // remaining options don't need any special handling
274            Net.setSocketOption(fd, Net.UNSPEC, name, value);
275            return this;
276        }
277    }
278
279    @Override
280    @SuppressWarnings("unchecked")
281    public <T> T getOption(SocketOption<T> name)
282        throws IOException
283    {
284        if (name == null)
285            throw new NullPointerException();
286        if (!supportedOptions().contains(name))
287            throw new UnsupportedOperationException("'" + name + "' not supported");
288
289        synchronized (stateLock) {
290            ensureOpen();
291
292            if (name == StandardSocketOptions.IP_TOS ||
293                name == StandardSocketOptions.IP_MULTICAST_TTL ||
294                name == StandardSocketOptions.IP_MULTICAST_LOOP)
295            {
296                return (T) Net.getSocketOption(fd, family, name);
297            }
298
299            if (name == StandardSocketOptions.IP_MULTICAST_IF) {
300                if (family == StandardProtocolFamily.INET) {
301                    int address = Net.getInterface4(fd);
302                    if (address == 0)
303                        return null;    // default interface
304
305                    InetAddress ia = Net.inet4FromInt(address);
306                    NetworkInterface ni = NetworkInterface.getByInetAddress(ia);
307                    if (ni == null)
308                        throw new IOException("Unable to map address to interface");
309                    return (T) ni;
310                } else {
311                    int index = Net.getInterface6(fd);
312                    if (index == 0)
313                        return null;    // default interface
314
315                    NetworkInterface ni = NetworkInterface.getByIndex(index);
316                    if (ni == null)
317                        throw new IOException("Unable to map index to interface");
318                    return (T) ni;
319                }
320            }
321
322            if (name == StandardSocketOptions.SO_REUSEADDR &&
323                    reuseAddressEmulated)
324            {
325                return (T)Boolean.valueOf(isReuseAddress);
326            }
327
328            // no special handling
329            return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
330        }
331    }
332
333    private static class DefaultOptionsHolder {
334        static final Set<SocketOption<?>> defaultOptions = defaultOptions();
335
336        private static Set<SocketOption<?>> defaultOptions() {
337            HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(8);
338            set.add(StandardSocketOptions.SO_SNDBUF);
339            set.add(StandardSocketOptions.SO_RCVBUF);
340            set.add(StandardSocketOptions.SO_REUSEADDR);
341            set.add(StandardSocketOptions.SO_BROADCAST);
342            set.add(StandardSocketOptions.IP_TOS);
343            set.add(StandardSocketOptions.IP_MULTICAST_IF);
344            set.add(StandardSocketOptions.IP_MULTICAST_TTL);
345            set.add(StandardSocketOptions.IP_MULTICAST_LOOP);
346            if (ExtendedOptionsImpl.flowSupported()) {
347                set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA);
348            }
349            return Collections.unmodifiableSet(set);
350        }
351    }
352
353    @Override
354    public final Set<SocketOption<?>> supportedOptions() {
355        return DefaultOptionsHolder.defaultOptions;
356    }
357
358    private void ensureOpen() throws ClosedChannelException {
359        if (!isOpen())
360            throw new ClosedChannelException();
361    }
362
363    private SocketAddress sender;       // Set by receive0 (## ugh)
364
365    public SocketAddress receive(ByteBuffer dst) throws IOException {
366        if (dst.isReadOnly())
367            throw new IllegalArgumentException("Read-only buffer");
368        if (dst == null)
369            throw new NullPointerException();
370        // Android-changed: Do not attempt to bind to 0 (or 0.0.0.0) if there hasn't been
371        // an explicit call to bind() yet. Fail fast and return null.
372        if (localAddress == null)
373            return null;
374        synchronized (readLock) {
375            ensureOpen();
376            // Socket was not bound before attempting receive
377            // if (localAddress() == null)
378            //     bind(null);
379            int n = 0;
380            ByteBuffer bb = null;
381            try {
382                begin();
383                if (!isOpen())
384                    return null;
385                SecurityManager security = System.getSecurityManager();
386                readerThread = NativeThread.current();
387                if (isConnected() || (security == null)) {
388                    do {
389                        n = receive(fd, dst);
390                    } while ((n == IOStatus.INTERRUPTED) && isOpen());
391                    if (n == IOStatus.UNAVAILABLE)
392                        return null;
393                } else {
394                    bb = Util.getTemporaryDirectBuffer(dst.remaining());
395                    for (;;) {
396                        do {
397                            n = receive(fd, bb);
398                        } while ((n == IOStatus.INTERRUPTED) && isOpen());
399                        if (n == IOStatus.UNAVAILABLE)
400                            return null;
401                        InetSocketAddress isa = (InetSocketAddress)sender;
402                        try {
403                            security.checkAccept(
404                                isa.getAddress().getHostAddress(),
405                                isa.getPort());
406                        } catch (SecurityException se) {
407                            // Ignore packet
408                            bb.clear();
409                            n = 0;
410                            continue;
411                        }
412                        bb.flip();
413                        dst.put(bb);
414                        break;
415                    }
416                }
417                return sender;
418            } finally {
419                if (bb != null)
420                    Util.releaseTemporaryDirectBuffer(bb);
421                readerThread = 0;
422                end((n > 0) || (n == IOStatus.UNAVAILABLE));
423                assert IOStatus.check(n);
424            }
425        }
426    }
427
428    private int receive(FileDescriptor fd, ByteBuffer dst)
429        throws IOException
430    {
431        int pos = dst.position();
432        int lim = dst.limit();
433        assert (pos <= lim);
434        int rem = (pos <= lim ? lim - pos : 0);
435        if (dst instanceof DirectBuffer && rem > 0)
436            return receiveIntoNativeBuffer(fd, dst, rem, pos);
437
438        // Substitute a native buffer. If the supplied buffer is empty
439        // we must instead use a nonempty buffer, otherwise the call
440        // will not block waiting for a datagram on some platforms.
441        int newSize = Math.max(rem, 1);
442        ByteBuffer bb = Util.getTemporaryDirectBuffer(newSize);
443        try {
444            BlockGuard.getThreadPolicy().onNetwork();
445
446            int n = receiveIntoNativeBuffer(fd, bb, newSize, 0);
447            bb.flip();
448            if (n > 0 && rem > 0)
449                dst.put(bb);
450            return n;
451        } finally {
452            Util.releaseTemporaryDirectBuffer(bb);
453        }
454    }
455
456    private int receiveIntoNativeBuffer(FileDescriptor fd, ByteBuffer bb,
457                                        int rem, int pos)
458        throws IOException
459    {
460        int n = receive0(fd, ((DirectBuffer)bb).address() + pos, rem,
461                         isConnected());
462        if (n > 0)
463            bb.position(pos + n);
464        return n;
465    }
466
467    public int send(ByteBuffer src, SocketAddress target)
468        throws IOException
469    {
470        if (src == null)
471            throw new NullPointerException();
472
473        synchronized (writeLock) {
474            ensureOpen();
475            InetSocketAddress isa = Net.checkAddress(target);
476            InetAddress ia = isa.getAddress();
477            if (ia == null)
478                throw new IOException("Target address not resolved");
479            synchronized (stateLock) {
480                if (!isConnected()) {
481                    if (target == null)
482                        throw new NullPointerException();
483                    SecurityManager sm = System.getSecurityManager();
484                    if (sm != null) {
485                        if (ia.isMulticastAddress()) {
486                            sm.checkMulticast(ia);
487                        } else {
488                            sm.checkConnect(ia.getHostAddress(),
489                                            isa.getPort());
490                        }
491                    }
492                } else { // Connected case; Check address then write
493                    if (!target.equals(remoteAddress)) {
494                        throw new IllegalArgumentException(
495                            "Connected address not equal to target address");
496                    }
497                    return write(src);
498                }
499            }
500
501            int n = 0;
502            try {
503                begin();
504                if (!isOpen())
505                    return 0;
506                writerThread = NativeThread.current();
507                BlockGuard.getThreadPolicy().onNetwork();
508
509                do {
510                    n = send(fd, src, isa);
511                } while ((n == IOStatus.INTERRUPTED) && isOpen());
512
513                synchronized (stateLock) {
514                    if (isOpen() && (localAddress == null)) {
515                        localAddress = Net.localAddress(fd);
516                    }
517                }
518                return IOStatus.normalize(n);
519            } finally {
520                writerThread = 0;
521                end((n > 0) || (n == IOStatus.UNAVAILABLE));
522                assert IOStatus.check(n);
523            }
524        }
525    }
526
527    private int send(FileDescriptor fd, ByteBuffer src, InetSocketAddress target)
528        throws IOException
529    {
530        if (src instanceof DirectBuffer)
531            return sendFromNativeBuffer(fd, src, target);
532
533        // Substitute a native buffer
534        int pos = src.position();
535        int lim = src.limit();
536        assert (pos <= lim);
537        int rem = (pos <= lim ? lim - pos : 0);
538
539        ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
540        try {
541            bb.put(src);
542            bb.flip();
543            // Do not update src until we see how many bytes were written
544            src.position(pos);
545
546            int n = sendFromNativeBuffer(fd, bb, target);
547            if (n > 0) {
548                // now update src
549                src.position(pos + n);
550            }
551            return n;
552        } finally {
553            Util.releaseTemporaryDirectBuffer(bb);
554        }
555    }
556
557    private int sendFromNativeBuffer(FileDescriptor fd, ByteBuffer bb,
558                                     InetSocketAddress target)
559        throws IOException
560    {
561        int pos = bb.position();
562        int lim = bb.limit();
563        assert (pos <= lim);
564        int rem = (pos <= lim ? lim - pos : 0);
565
566        boolean preferIPv6 = (family != StandardProtocolFamily.INET);
567        int written;
568        try {
569            written = send0(preferIPv6, fd, ((DirectBuffer)bb).address() + pos,
570                            rem, target.getAddress(), target.getPort());
571        } catch (PortUnreachableException pue) {
572            if (isConnected())
573                throw pue;
574            written = rem;
575        }
576        if (written > 0)
577            bb.position(pos + written);
578        return written;
579    }
580
581    public int read(ByteBuffer buf) throws IOException {
582        if (buf == null)
583            throw new NullPointerException();
584        synchronized (readLock) {
585            synchronized (stateLock) {
586                ensureOpen();
587                if (!isConnected())
588                    throw new NotYetConnectedException();
589            }
590            int n = 0;
591            try {
592                begin();
593                if (!isOpen())
594                    return 0;
595                readerThread = NativeThread.current();
596                do {
597                    n = IOUtil.read(fd, buf, -1, nd);
598                } while ((n == IOStatus.INTERRUPTED) && isOpen());
599                return IOStatus.normalize(n);
600            } finally {
601                readerThread = 0;
602                end((n > 0) || (n == IOStatus.UNAVAILABLE));
603                assert IOStatus.check(n);
604            }
605        }
606    }
607
608    public long read(ByteBuffer[] dsts, int offset, int length)
609        throws IOException
610    {
611        if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
612            throw new IndexOutOfBoundsException();
613        synchronized (readLock) {
614            synchronized (stateLock) {
615                ensureOpen();
616                if (!isConnected())
617                    throw new NotYetConnectedException();
618            }
619            long n = 0;
620            try {
621                begin();
622                if (!isOpen())
623                    return 0;
624                readerThread = NativeThread.current();
625                do {
626                    n = IOUtil.read(fd, dsts, offset, length, nd);
627                } while ((n == IOStatus.INTERRUPTED) && isOpen());
628                return IOStatus.normalize(n);
629            } finally {
630                readerThread = 0;
631                end((n > 0) || (n == IOStatus.UNAVAILABLE));
632                assert IOStatus.check(n);
633            }
634        }
635    }
636
637    public int write(ByteBuffer buf) throws IOException {
638        if (buf == null)
639            throw new NullPointerException();
640        synchronized (writeLock) {
641            synchronized (stateLock) {
642                ensureOpen();
643                if (!isConnected())
644                    throw new NotYetConnectedException();
645            }
646            int n = 0;
647            try {
648                begin();
649                if (!isOpen())
650                    return 0;
651                writerThread = NativeThread.current();
652                do {
653                    n = IOUtil.write(fd, buf, -1, nd);
654                } while ((n == IOStatus.INTERRUPTED) && isOpen());
655                return IOStatus.normalize(n);
656            } finally {
657                writerThread = 0;
658                end((n > 0) || (n == IOStatus.UNAVAILABLE));
659                assert IOStatus.check(n);
660            }
661        }
662    }
663
664    public long write(ByteBuffer[] srcs, int offset, int length)
665        throws IOException
666    {
667        if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
668            throw new IndexOutOfBoundsException();
669        synchronized (writeLock) {
670            synchronized (stateLock) {
671                ensureOpen();
672                if (!isConnected())
673                    throw new NotYetConnectedException();
674            }
675            long n = 0;
676            try {
677                begin();
678                if (!isOpen())
679                    return 0;
680                writerThread = NativeThread.current();
681                do {
682                    n = IOUtil.write(fd, srcs, offset, length, nd);
683                } while ((n == IOStatus.INTERRUPTED) && isOpen());
684                return IOStatus.normalize(n);
685            } finally {
686                writerThread = 0;
687                end((n > 0) || (n == IOStatus.UNAVAILABLE));
688                assert IOStatus.check(n);
689            }
690        }
691    }
692
693    protected void implConfigureBlocking(boolean block) throws IOException {
694        IOUtil.configureBlocking(fd, block);
695    }
696
697    public SocketAddress localAddress() {
698        synchronized (stateLock) {
699            return localAddress;
700        }
701    }
702
703    public SocketAddress remoteAddress() {
704        synchronized (stateLock) {
705            return remoteAddress;
706        }
707    }
708
709    @Override
710    public DatagramChannel bind(SocketAddress local) throws IOException {
711        synchronized (readLock) {
712            synchronized (writeLock) {
713                synchronized (stateLock) {
714                    ensureOpen();
715                    if (localAddress != null)
716                        throw new AlreadyBoundException();
717                    InetSocketAddress isa;
718                    if (local == null) {
719                        // only Inet4Address allowed with IPv4 socket
720                        if (family == StandardProtocolFamily.INET) {
721                            isa = new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 0);
722                        } else {
723                            isa = new InetSocketAddress(0);
724                        }
725                    } else {
726                        isa = Net.checkAddress(local);
727
728                        // only Inet4Address allowed with IPv4 socket
729                        if (family == StandardProtocolFamily.INET) {
730                            InetAddress addr = isa.getAddress();
731                            if (!(addr instanceof Inet4Address))
732                                throw new UnsupportedAddressTypeException();
733                        }
734                    }
735                    SecurityManager sm = System.getSecurityManager();
736                    if (sm != null) {
737                        sm.checkListen(isa.getPort());
738                    }
739                    Net.bind(family, fd, isa.getAddress(), isa.getPort());
740                    localAddress = Net.localAddress(fd);
741                }
742            }
743        }
744        return this;
745    }
746
747    public boolean isConnected() {
748        synchronized (stateLock) {
749            return (state == ST_CONNECTED);
750        }
751    }
752
753    void ensureOpenAndUnconnected() throws IOException { // package-private
754        synchronized (stateLock) {
755            if (!isOpen())
756                throw new ClosedChannelException();
757            if (state != ST_UNCONNECTED)
758                throw new IllegalStateException("Connect already invoked");
759        }
760    }
761
762    @Override
763    public DatagramChannel connect(SocketAddress sa) throws IOException {
764        int localPort = 0;
765
766        synchronized(readLock) {
767            synchronized(writeLock) {
768                synchronized (stateLock) {
769                    ensureOpenAndUnconnected();
770                    InetSocketAddress isa = Net.checkAddress(sa);
771                    SecurityManager sm = System.getSecurityManager();
772                    if (sm != null)
773                        sm.checkConnect(isa.getAddress().getHostAddress(),
774                                        isa.getPort());
775                    int n = Net.connect(family,
776                                        fd,
777                                        isa.getAddress(),
778                                        isa.getPort());
779                    if (n <= 0)
780                        throw new Error();      // Can't happen
781
782                    // Connection succeeded; disallow further invocation
783                    state = ST_CONNECTED;
784                    remoteAddress = isa;
785                    sender = isa;
786                    cachedSenderInetAddress = isa.getAddress();
787                    cachedSenderPort = isa.getPort();
788
789                    // set or refresh local address
790                    localAddress = Net.localAddress(fd);
791
792                    // flush any packets already received.
793                    boolean blocking = false;
794                    synchronized (blockingLock()) {
795                        try {
796                            blocking = isBlocking();
797                            // remainder of each packet thrown away
798                            ByteBuffer tmpBuf = ByteBuffer.allocate(1);
799                            if (blocking) {
800                                configureBlocking(false);
801                            }
802                            do {
803                                tmpBuf.clear();
804                            } while (receive(tmpBuf) != null);
805                        } finally {
806                            if (blocking) {
807                                configureBlocking(true);
808                            }
809                        }
810                    }
811                }
812            }
813        }
814        return this;
815    }
816
817    public DatagramChannel disconnect() throws IOException {
818        synchronized(readLock) {
819            synchronized(writeLock) {
820                synchronized (stateLock) {
821                    if (!isConnected() || !isOpen())
822                        return this;
823                    InetSocketAddress isa = remoteAddress;
824                    SecurityManager sm = System.getSecurityManager();
825                    if (sm != null)
826                        sm.checkConnect(isa.getAddress().getHostAddress(),
827                                        isa.getPort());
828                    boolean isIPv6 = (family == StandardProtocolFamily.INET6);
829                    disconnect0(fd, isIPv6);
830                    remoteAddress = null;
831                    state = ST_UNCONNECTED;
832
833                    // refresh local address
834                    localAddress = Net.localAddress(fd);
835                }
836            }
837        }
838        return this;
839    }
840
841    /**
842     * Joins channel's socket to the given group/interface and
843     * optional source address.
844     */
845    private MembershipKey innerJoin(InetAddress group,
846                                    NetworkInterface interf,
847                                    InetAddress source)
848        throws IOException
849    {
850        if (!group.isMulticastAddress())
851            throw new IllegalArgumentException("Group not a multicast address");
852
853        // check multicast address is compatible with this socket
854        if (group instanceof Inet4Address) {
855            if (family == StandardProtocolFamily.INET6 && !Net.canIPv6SocketJoinIPv4Group())
856                throw new IllegalArgumentException("IPv6 socket cannot join IPv4 multicast group");
857        } else if (group instanceof Inet6Address) {
858            if (family != StandardProtocolFamily.INET6)
859                throw new IllegalArgumentException("Only IPv6 sockets can join IPv6 multicast group");
860        } else {
861            throw new IllegalArgumentException("Address type not supported");
862        }
863
864        // check source address
865        if (source != null) {
866            if (source.isAnyLocalAddress())
867                throw new IllegalArgumentException("Source address is a wildcard address");
868            if (source.isMulticastAddress())
869                throw new IllegalArgumentException("Source address is multicast address");
870            if (source.getClass() != group.getClass())
871                throw new IllegalArgumentException("Source address is different type to group");
872        }
873
874        SecurityManager sm = System.getSecurityManager();
875        if (sm != null)
876            sm.checkMulticast(group);
877
878        synchronized (stateLock) {
879            if (!isOpen())
880                throw new ClosedChannelException();
881
882            // check the registry to see if we are already a member of the group
883            if (registry == null) {
884                registry = new MembershipRegistry();
885            } else {
886                // return existing membership key
887                MembershipKey key = registry.checkMembership(group, interf, source);
888                if (key != null)
889                    return key;
890            }
891
892            MembershipKeyImpl key;
893            if ((family == StandardProtocolFamily.INET6) &&
894                ((group instanceof Inet6Address) || Net.canJoin6WithIPv4Group()))
895            {
896                int index = interf.getIndex();
897                if (index == -1)
898                    throw new IOException("Network interface cannot be identified");
899
900                // need multicast and source address as byte arrays
901                byte[] groupAddress = Net.inet6AsByteArray(group);
902                byte[] sourceAddress = (source == null) ? null :
903                    Net.inet6AsByteArray(source);
904
905                // join the group
906                int n = Net.join6(fd, groupAddress, index, sourceAddress);
907                if (n == IOStatus.UNAVAILABLE)
908                    throw new UnsupportedOperationException();
909
910                key = new MembershipKeyImpl.Type6(this, group, interf, source,
911                                                  groupAddress, index, sourceAddress);
912
913            } else {
914                // need IPv4 address to identify interface
915                Inet4Address target = Net.anyInet4Address(interf);
916                if (target == null)
917                    throw new IOException("Network interface not configured for IPv4");
918
919                int groupAddress = Net.inet4AsInt(group);
920                int targetAddress = Net.inet4AsInt(target);
921                int sourceAddress = (source == null) ? 0 : Net.inet4AsInt(source);
922
923                // join the group
924                int n = Net.join4(fd, groupAddress, targetAddress, sourceAddress);
925                if (n == IOStatus.UNAVAILABLE)
926                    throw new UnsupportedOperationException();
927
928                key = new MembershipKeyImpl.Type4(this, group, interf, source,
929                                                  groupAddress, targetAddress, sourceAddress);
930            }
931
932            registry.add(key);
933            return key;
934        }
935    }
936
937    @Override
938    public MembershipKey join(InetAddress group,
939                              NetworkInterface interf)
940        throws IOException
941    {
942        return innerJoin(group, interf, null);
943    }
944
945    @Override
946    public MembershipKey join(InetAddress group,
947                              NetworkInterface interf,
948                              InetAddress source)
949        throws IOException
950    {
951        if (source == null)
952            throw new NullPointerException("source address is null");
953        return innerJoin(group, interf, source);
954    }
955
956    // package-private
957    void drop(MembershipKeyImpl key) {
958        assert key.channel() == this;
959
960        synchronized (stateLock) {
961            if (!key.isValid())
962                return;
963
964            try {
965                if (key instanceof MembershipKeyImpl.Type6) {
966                    MembershipKeyImpl.Type6 key6 =
967                        (MembershipKeyImpl.Type6)key;
968                    Net.drop6(fd, key6.groupAddress(), key6.index(), key6.source());
969                } else {
970                    MembershipKeyImpl.Type4 key4 = (MembershipKeyImpl.Type4)key;
971                    Net.drop4(fd, key4.groupAddress(), key4.interfaceAddress(),
972                        key4.source());
973                }
974            } catch (IOException ioe) {
975                // should not happen
976                throw new AssertionError(ioe);
977            }
978
979            key.invalidate();
980            registry.remove(key);
981        }
982    }
983
984    /**
985     * Block datagrams from given source if a memory to receive all
986     * datagrams.
987     */
988    void block(MembershipKeyImpl key, InetAddress source)
989        throws IOException
990    {
991        assert key.channel() == this;
992        assert key.sourceAddress() == null;
993
994        synchronized (stateLock) {
995            if (!key.isValid())
996                throw new IllegalStateException("key is no longer valid");
997            if (source.isAnyLocalAddress())
998                throw new IllegalArgumentException("Source address is a wildcard address");
999            if (source.isMulticastAddress())
1000                throw new IllegalArgumentException("Source address is multicast address");
1001            if (source.getClass() != key.group().getClass())
1002                throw new IllegalArgumentException("Source address is different type to group");
1003
1004            int n;
1005            if (key instanceof MembershipKeyImpl.Type6) {
1006                 MembershipKeyImpl.Type6 key6 =
1007                    (MembershipKeyImpl.Type6)key;
1008                n = Net.block6(fd, key6.groupAddress(), key6.index(),
1009                               Net.inet6AsByteArray(source));
1010            } else {
1011                MembershipKeyImpl.Type4 key4 =
1012                    (MembershipKeyImpl.Type4)key;
1013                n = Net.block4(fd, key4.groupAddress(), key4.interfaceAddress(),
1014                               Net.inet4AsInt(source));
1015            }
1016            if (n == IOStatus.UNAVAILABLE) {
1017                // ancient kernel
1018                throw new UnsupportedOperationException();
1019            }
1020        }
1021    }
1022
1023    /**
1024     * Unblock given source.
1025     */
1026    void unblock(MembershipKeyImpl key, InetAddress source) {
1027        assert key.channel() == this;
1028        assert key.sourceAddress() == null;
1029
1030        synchronized (stateLock) {
1031            if (!key.isValid())
1032                throw new IllegalStateException("key is no longer valid");
1033
1034            try {
1035                if (key instanceof MembershipKeyImpl.Type6) {
1036                    MembershipKeyImpl.Type6 key6 =
1037                        (MembershipKeyImpl.Type6)key;
1038                    Net.unblock6(fd, key6.groupAddress(), key6.index(),
1039                                 Net.inet6AsByteArray(source));
1040                } else {
1041                    MembershipKeyImpl.Type4 key4 =
1042                        (MembershipKeyImpl.Type4)key;
1043                    Net.unblock4(fd, key4.groupAddress(), key4.interfaceAddress(),
1044                                 Net.inet4AsInt(source));
1045                }
1046            } catch (IOException ioe) {
1047                // should not happen
1048                throw new AssertionError(ioe);
1049            }
1050        }
1051    }
1052
1053    protected void implCloseSelectableChannel() throws IOException {
1054        synchronized (stateLock) {
1055            // Android-changed: Add CloseGuard support.
1056            guard.close();
1057            if (state != ST_KILLED)
1058                nd.preClose(fd);
1059            ResourceManager.afterUdpClose();
1060
1061            // if member of mulitcast group then invalidate all keys
1062            if (registry != null)
1063                registry.invalidateAll();
1064
1065            long th;
1066            if ((th = readerThread) != 0)
1067                NativeThread.signal(th);
1068            if ((th = writerThread) != 0)
1069                NativeThread.signal(th);
1070            if (!isRegistered())
1071                kill();
1072        }
1073    }
1074
1075    public void kill() throws IOException {
1076        synchronized (stateLock) {
1077            if (state == ST_KILLED)
1078                return;
1079            if (state == ST_UNINITIALIZED) {
1080                state = ST_KILLED;
1081                return;
1082            }
1083            assert !isOpen() && !isRegistered();
1084            nd.close(fd);
1085            state = ST_KILLED;
1086        }
1087    }
1088
1089    protected void finalize() throws Throwable {
1090        try {
1091            // Android-changed: Add CloseGuard support.
1092            if (guard != null) {
1093                guard.warnIfOpen();
1094            }
1095            // fd is null if constructor threw exception
1096            if (fd != null)
1097                close();
1098        } finally {
1099            super.finalize();
1100        }
1101    }
1102
1103    /**
1104     * Translates native poll revent set into a ready operation set
1105     */
1106    public boolean translateReadyOps(int ops, int initialOps,
1107                                     SelectionKeyImpl sk) {
1108        int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
1109        int oldOps = sk.nioReadyOps();
1110        int newOps = initialOps;
1111
1112        if ((ops & Net.POLLNVAL) != 0) {
1113            // This should only happen if this channel is pre-closed while a
1114            // selection operation is in progress
1115            // ## Throw an error if this channel has not been pre-closed
1116            return false;
1117        }
1118
1119        if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
1120            newOps = intOps;
1121            sk.nioReadyOps(newOps);
1122            return (newOps & ~oldOps) != 0;
1123        }
1124
1125        if (((ops & Net.POLLIN) != 0) &&
1126            ((intOps & SelectionKey.OP_READ) != 0))
1127            newOps |= SelectionKey.OP_READ;
1128
1129        if (((ops & Net.POLLOUT) != 0) &&
1130            ((intOps & SelectionKey.OP_WRITE) != 0))
1131            newOps |= SelectionKey.OP_WRITE;
1132
1133        sk.nioReadyOps(newOps);
1134        return (newOps & ~oldOps) != 0;
1135    }
1136
1137    public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
1138        return translateReadyOps(ops, sk.nioReadyOps(), sk);
1139    }
1140
1141    public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
1142        return translateReadyOps(ops, 0, sk);
1143    }
1144
1145    // package-private
1146    int poll(int events, long timeout) throws IOException {
1147        assert Thread.holdsLock(blockingLock()) && !isBlocking();
1148
1149        synchronized (readLock) {
1150            int n = 0;
1151            try {
1152                begin();
1153                synchronized (stateLock) {
1154                    if (!isOpen())
1155                        return 0;
1156                    readerThread = NativeThread.current();
1157                }
1158                n = Net.poll(fd, events, timeout);
1159            } finally {
1160                readerThread = 0;
1161                end(n > 0);
1162            }
1163            return n;
1164        }
1165    }
1166
1167    /**
1168     * Translates an interest operation set into a native poll event set
1169     */
1170    public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
1171        int newOps = 0;
1172
1173        if ((ops & SelectionKey.OP_READ) != 0)
1174            newOps |= Net.POLLIN;
1175        if ((ops & SelectionKey.OP_WRITE) != 0)
1176            newOps |= Net.POLLOUT;
1177        if ((ops & SelectionKey.OP_CONNECT) != 0)
1178            newOps |= Net.POLLIN;
1179        sk.selector.putEventOps(sk, newOps);
1180    }
1181
1182    public FileDescriptor getFD() {
1183        return fd;
1184    }
1185
1186    public int getFDVal() {
1187        return fdVal;
1188    }
1189
1190
1191    // -- Native methods --
1192
1193    private static native void initIDs();
1194
1195    private static native void disconnect0(FileDescriptor fd, boolean isIPv6)
1196        throws IOException;
1197
1198    private native int receive0(FileDescriptor fd, long address, int len,
1199                                boolean connected)
1200        throws IOException;
1201
1202    private native int send0(boolean preferIPv6, FileDescriptor fd, long address,
1203                             int len, InetAddress addr, int port)
1204        throws IOException;
1205
1206    static {
1207        initIDs();
1208    }
1209
1210}
1211