1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 * Copyright (c) 2000, 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 dalvik.system.BlockGuard;
30
31import java.io.*;
32import java.net.*;
33import jdk.net.*;
34import java.nio.channels.*;
35import java.util.*;
36import java.security.AccessController;
37import java.security.PrivilegedAction;
38import sun.net.ExtendedOptionsImpl;
39
40
41public class Net {
42
43    private Net() { }
44
45    // unspecified protocol family
46    static final ProtocolFamily UNSPEC = new ProtocolFamily() {
47        public String name() {
48            return "UNSPEC";
49        }
50    };
51
52    // set to true if exclusive binding is on for Windows
53    private static final boolean exclusiveBind;
54
55    // set to true if the fast tcp loopback should be enabled on Windows
56    private static final boolean fastLoopback;
57
58    // -- Miscellaneous utilities --
59
60    private static volatile boolean checkedIPv6 = false;
61    private static volatile boolean isIPv6Available;
62
63    /**
64     * Tells whether dual-IPv4/IPv6 sockets should be used.
65     */
66    static boolean isIPv6Available() {
67        if (!checkedIPv6) {
68            isIPv6Available = isIPv6Available0();
69            checkedIPv6 = true;
70        }
71        return isIPv6Available;
72    }
73
74    /**
75     * Returns true if exclusive binding is on
76     */
77    static boolean useExclusiveBind() {
78        return exclusiveBind;
79    }
80
81    /**
82     * Tells whether IPv6 sockets can join IPv4 multicast groups
83     */
84    static boolean canIPv6SocketJoinIPv4Group() {
85        return canIPv6SocketJoinIPv4Group0();
86    }
87
88    /**
89     * Tells whether {@link #join6} can be used to join an IPv4
90     * multicast group (IPv4 group as IPv4-mapped IPv6 address)
91     */
92    static boolean canJoin6WithIPv4Group() {
93        return canJoin6WithIPv4Group0();
94    }
95
96    public static InetSocketAddress checkAddress(SocketAddress sa) {
97        if (sa == null)
98            // BEGIN Android-changed
99            //throw new NullPointerException();
100            throw new IllegalArgumentException("sa == null");
101            // END Android-changed
102
103        if (!(sa instanceof InetSocketAddress))
104            throw new UnsupportedAddressTypeException(); // ## needs arg
105        InetSocketAddress isa = (InetSocketAddress)sa;
106        if (isa.isUnresolved())
107            throw new UnresolvedAddressException(); // ## needs arg
108        InetAddress addr = isa.getAddress();
109        if (!(addr instanceof Inet4Address || addr instanceof Inet6Address))
110            throw new IllegalArgumentException("Invalid address type");
111        return isa;
112    }
113
114    static InetSocketAddress asInetSocketAddress(SocketAddress sa) {
115        if (!(sa instanceof InetSocketAddress))
116            throw new UnsupportedAddressTypeException();
117        return (InetSocketAddress)sa;
118    }
119
120    static void translateToSocketException(Exception x)
121        throws SocketException
122    {
123        if (x instanceof SocketException)
124            throw (SocketException)x;
125        Exception nx = x;
126        if (x instanceof ClosedChannelException)
127            nx = new SocketException("Socket is closed");
128        else if (x instanceof NotYetConnectedException)
129            nx = new SocketException("Socket is not connected");
130        else if (x instanceof AlreadyBoundException)
131            nx = new SocketException("Already bound");
132        else if (x instanceof NotYetBoundException)
133            nx = new SocketException("Socket is not bound yet");
134        else if (x instanceof UnsupportedAddressTypeException)
135            nx = new SocketException("Unsupported address type");
136        else if (x instanceof UnresolvedAddressException) {
137            nx = new SocketException("Unresolved address");
138        } else if (x instanceof AlreadyConnectedException) {
139            // Android-added.
140            nx = new SocketException("Already connected");
141        }
142        if (nx != x)
143            nx.initCause(x);
144
145        if (nx instanceof SocketException)
146            throw (SocketException)nx;
147        else if (nx instanceof RuntimeException)
148            throw (RuntimeException)nx;
149        else
150            throw new Error("Untranslated exception", nx);
151    }
152
153    static void translateException(Exception x,
154                                   boolean unknownHostForUnresolved)
155        throws IOException
156    {
157        if (x instanceof IOException)
158            throw (IOException)x;
159        // Throw UnknownHostException from here since it cannot
160        // be thrown as a SocketException
161        if (unknownHostForUnresolved &&
162            (x instanceof UnresolvedAddressException))
163        {
164             throw new UnknownHostException();
165        }
166        translateToSocketException(x);
167    }
168
169    static void translateException(Exception x)
170        throws IOException
171    {
172        translateException(x, false);
173    }
174
175    /**
176     * Returns the local address after performing a SecurityManager#checkConnect.
177     */
178    static InetSocketAddress getRevealedLocalAddress(InetSocketAddress addr) {
179        SecurityManager sm = System.getSecurityManager();
180        if (addr == null || sm == null)
181            return addr;
182
183        try{
184            sm.checkConnect(addr.getAddress().getHostAddress(), -1);
185            // Security check passed
186        } catch (SecurityException e) {
187            // Return loopback address only if security check fails
188            addr = getLoopbackAddress(addr.getPort());
189        }
190        return addr;
191    }
192
193    static String getRevealedLocalAddressAsString(InetSocketAddress addr) {
194        return System.getSecurityManager() == null ? addr.toString() :
195                getLoopbackAddress(addr.getPort()).toString();
196    }
197
198    private static InetSocketAddress getLoopbackAddress(int port) {
199        return new InetSocketAddress(InetAddress.getLoopbackAddress(),
200                                     port);
201    }
202
203    /**
204     * Returns any IPv4 address of the given network interface, or
205     * null if the interface does not have any IPv4 addresses.
206     */
207    static Inet4Address anyInet4Address(final NetworkInterface interf) {
208        return AccessController.doPrivileged(new PrivilegedAction<Inet4Address>() {
209            public Inet4Address run() {
210                Enumeration<InetAddress> addrs = interf.getInetAddresses();
211                while (addrs.hasMoreElements()) {
212                    InetAddress addr = addrs.nextElement();
213                    if (addr instanceof Inet4Address) {
214                        return (Inet4Address)addr;
215                    }
216                }
217                return null;
218            }
219        });
220    }
221
222    /**
223     * Returns an IPv4 address as an int.
224     */
225    static int inet4AsInt(InetAddress ia) {
226        if (ia instanceof Inet4Address) {
227            byte[] addr = ia.getAddress();
228            int address  = addr[3] & 0xFF;
229            address |= ((addr[2] << 8) & 0xFF00);
230            address |= ((addr[1] << 16) & 0xFF0000);
231            address |= ((addr[0] << 24) & 0xFF000000);
232            return address;
233        }
234        throw new AssertionError("Should not reach here");
235    }
236
237    /**
238     * Returns an InetAddress from the given IPv4 address
239     * represented as an int.
240     */
241    static InetAddress inet4FromInt(int address) {
242        byte[] addr = new byte[4];
243        addr[0] = (byte) ((address >>> 24) & 0xFF);
244        addr[1] = (byte) ((address >>> 16) & 0xFF);
245        addr[2] = (byte) ((address >>> 8) & 0xFF);
246        addr[3] = (byte) (address & 0xFF);
247        try {
248            return InetAddress.getByAddress(addr);
249        } catch (UnknownHostException uhe) {
250            throw new AssertionError("Should not reach here");
251        }
252    }
253
254    /**
255     * Returns an IPv6 address as a byte array
256     */
257    static byte[] inet6AsByteArray(InetAddress ia) {
258        if (ia instanceof Inet6Address) {
259            return ia.getAddress();
260        }
261
262        // need to construct IPv4-mapped address
263        if (ia instanceof Inet4Address) {
264            byte[] ip4address = ia.getAddress();
265            byte[] address = new byte[16];
266            address[10] = (byte)0xff;
267            address[11] = (byte)0xff;
268            address[12] = ip4address[0];
269            address[13] = ip4address[1];
270            address[14] = ip4address[2];
271            address[15] = ip4address[3];
272            return address;
273        }
274
275        throw new AssertionError("Should not reach here");
276    }
277
278    // -- Socket options
279
280    static void setSocketOption(FileDescriptor fd, ProtocolFamily family,
281                                SocketOption<?> name, Object value)
282        throws IOException
283    {
284        if (value == null)
285            throw new IllegalArgumentException("Invalid option value");
286
287        // only simple values supported by this method
288        Class<?> type = name.type();
289
290        if (type == SocketFlow.class) {
291            SecurityManager sm = System.getSecurityManager();
292            if (sm != null) {
293                sm.checkPermission(new NetworkPermission("setOption.SO_FLOW_SLA"));
294            }
295            ExtendedOptionsImpl.setFlowOption(fd, (SocketFlow)value);
296            return;
297        }
298
299        if (type != Integer.class && type != Boolean.class)
300            throw new AssertionError("Should not reach here");
301
302        // special handling
303        if (name == StandardSocketOptions.SO_RCVBUF ||
304            name == StandardSocketOptions.SO_SNDBUF)
305        {
306            int i = ((Integer)value).intValue();
307            if (i < 0)
308                throw new IllegalArgumentException("Invalid send/receive buffer size");
309        }
310        if (name == StandardSocketOptions.SO_LINGER) {
311            int i = ((Integer)value).intValue();
312            if (i < 0)
313                value = Integer.valueOf(-1);
314            if (i > 65535)
315                value = Integer.valueOf(65535);
316        }
317        if (name == StandardSocketOptions.IP_TOS) {
318            int i = ((Integer)value).intValue();
319            if (i < 0 || i > 255)
320                throw new IllegalArgumentException("Invalid IP_TOS value");
321        }
322        if (name == StandardSocketOptions.IP_MULTICAST_TTL) {
323            int i = ((Integer)value).intValue();
324            if (i < 0 || i > 255)
325                throw new IllegalArgumentException("Invalid TTL/hop value");
326        }
327
328        // map option name to platform level/name
329        OptionKey key = SocketOptionRegistry.findOption(name, family);
330        if (key == null)
331            throw new AssertionError("Option not found");
332
333        int arg;
334        if (type == Integer.class) {
335            arg = ((Integer)value).intValue();
336        } else {
337            boolean b = ((Boolean)value).booleanValue();
338            arg = (b) ? 1 : 0;
339        }
340
341        boolean mayNeedConversion = (family == UNSPEC);
342        boolean isIPv6 = (family == StandardProtocolFamily.INET6);
343        setIntOption0(fd, mayNeedConversion, key.level(), key.name(), arg, isIPv6);
344    }
345
346    static Object getSocketOption(FileDescriptor fd, ProtocolFamily family,
347                                  SocketOption<?> name)
348        throws IOException
349    {
350        Class<?> type = name.type();
351
352        if (type == SocketFlow.class) {
353            SecurityManager sm = System.getSecurityManager();
354            if (sm != null) {
355                sm.checkPermission(new NetworkPermission("getOption.SO_FLOW_SLA"));
356            }
357            SocketFlow flow = SocketFlow.create();
358            ExtendedOptionsImpl.getFlowOption(fd, flow);
359            return flow;
360        }
361
362        // only simple values supported by this method
363        if (type != Integer.class && type != Boolean.class)
364            throw new AssertionError("Should not reach here");
365
366        // map option name to platform level/name
367        OptionKey key = SocketOptionRegistry.findOption(name, family);
368        if (key == null)
369            throw new AssertionError("Option not found");
370
371        boolean mayNeedConversion = (family == UNSPEC);
372        int value = getIntOption0(fd, mayNeedConversion, key.level(), key.name());
373
374        if (type == Integer.class) {
375            return Integer.valueOf(value);
376        } else {
377            return (value == 0) ? Boolean.FALSE : Boolean.TRUE;
378        }
379    }
380
381    public static boolean isFastTcpLoopbackRequested() {
382        String loopbackProp = java.security.AccessController.doPrivileged(
383            new PrivilegedAction<String>() {
384                @Override
385                public String run() {
386                    return System.getProperty("jdk.net.useFastTcpLoopback");
387                }
388            });
389        boolean enable;
390        if ("".equals(loopbackProp)) {
391            enable = true;
392        } else {
393            enable = Boolean.parseBoolean(loopbackProp);
394        }
395        return enable;
396    }
397
398    // -- Socket operations --
399
400    private static native boolean isIPv6Available0();
401
402    /*
403     * Returns 1 for Windows versions that support exclusive binding by default, 0
404     * for those that do not, and -1 for Solaris/Linux/Mac OS
405     */
406    private static native int isExclusiveBindAvailable();
407
408    private static native boolean canIPv6SocketJoinIPv4Group0();
409
410    private static native boolean canJoin6WithIPv4Group0();
411
412    static FileDescriptor socket(boolean stream) throws IOException {
413        return socket(UNSPEC, stream);
414    }
415
416    static FileDescriptor socket(ProtocolFamily family, boolean stream)
417        throws IOException {
418        boolean preferIPv6 = isIPv6Available() &&
419            (family != StandardProtocolFamily.INET);
420        return IOUtil.newFD(socket0(preferIPv6, stream, false, fastLoopback));
421    }
422
423    static FileDescriptor serverSocket(boolean stream) {
424        return IOUtil.newFD(socket0(isIPv6Available(), stream, true, fastLoopback));
425    }
426
427    // Due to oddities SO_REUSEADDR on windows reuse is ignored
428    private static native int socket0(boolean preferIPv6, boolean stream, boolean reuse,
429                                      boolean fastLoopback);
430
431    public static void bind(FileDescriptor fd, InetAddress addr, int port)
432        throws IOException
433    {
434        bind(UNSPEC, fd, addr, port);
435    }
436
437    static void bind(ProtocolFamily family, FileDescriptor fd,
438                     InetAddress addr, int port) throws IOException
439    {
440        boolean preferIPv6 = isIPv6Available() &&
441            (family != StandardProtocolFamily.INET);
442        bind0(fd, preferIPv6, exclusiveBind, addr, port);
443    }
444
445    private static native void bind0(FileDescriptor fd, boolean preferIPv6,
446                                     boolean useExclBind, InetAddress addr,
447                                     int port)
448        throws IOException;
449
450    static native void listen(FileDescriptor fd, int backlog) throws IOException;
451
452    static int connect(FileDescriptor fd, InetAddress remote, int remotePort)
453        throws IOException
454    {
455        return connect(UNSPEC, fd, remote, remotePort);
456    }
457
458    static int connect(ProtocolFamily family, FileDescriptor fd, InetAddress remote, int remotePort)
459        throws IOException
460    {
461        BlockGuard.getThreadPolicy().onNetwork();
462
463        boolean preferIPv6 = isIPv6Available() &&
464            (family != StandardProtocolFamily.INET);
465        return connect0(preferIPv6, fd, remote, remotePort);
466    }
467
468    private static native int connect0(boolean preferIPv6,
469                                       FileDescriptor fd,
470                                       InetAddress remote,
471                                       int remotePort)
472        throws IOException;
473
474
475    public final static int SHUT_RD = 0;
476    public final static int SHUT_WR = 1;
477    public final static int SHUT_RDWR = 2;
478
479    static native void shutdown(FileDescriptor fd, int how) throws IOException;
480
481    private static native int localPort(FileDescriptor fd)
482        throws IOException;
483
484    private static native InetAddress localInetAddress(FileDescriptor fd)
485        throws IOException;
486
487    public static InetSocketAddress localAddress(FileDescriptor fd)
488        throws IOException
489    {
490        return new InetSocketAddress(localInetAddress(fd), localPort(fd));
491    }
492
493    private static native int remotePort(FileDescriptor fd)
494        throws IOException;
495
496    private static native InetAddress remoteInetAddress(FileDescriptor fd)
497        throws IOException;
498
499    static InetSocketAddress remoteAddress(FileDescriptor fd)
500        throws IOException
501    {
502        return new InetSocketAddress(remoteInetAddress(fd), remotePort(fd));
503    }
504
505    private static native int getIntOption0(FileDescriptor fd, boolean mayNeedConversion,
506                                            int level, int opt)
507        throws IOException;
508
509    private static native void setIntOption0(FileDescriptor fd, boolean mayNeedConversion,
510                                             int level, int opt, int arg, boolean isIPv6)
511        throws IOException;
512
513    static native int poll(FileDescriptor fd, int events, long timeout)
514        throws IOException;
515
516    // -- Multicast support --
517
518
519    /**
520     * Join IPv4 multicast group
521     */
522    static int join4(FileDescriptor fd, int group, int interf, int source)
523        throws IOException
524    {
525        return joinOrDrop4(true, fd, group, interf, source);
526    }
527
528    /**
529     * Drop membership of IPv4 multicast group
530     */
531    static void drop4(FileDescriptor fd, int group, int interf, int source)
532        throws IOException
533    {
534        joinOrDrop4(false, fd, group, interf, source);
535    }
536
537    private static native int joinOrDrop4(boolean join, FileDescriptor fd, int group, int interf, int source)
538        throws IOException;
539
540    /**
541     * Block IPv4 source
542     */
543    static int block4(FileDescriptor fd, int group, int interf, int source)
544        throws IOException
545    {
546        return blockOrUnblock4(true, fd, group, interf, source);
547    }
548
549    /**
550     * Unblock IPv6 source
551     */
552    static void unblock4(FileDescriptor fd, int group, int interf, int source)
553        throws IOException
554    {
555        blockOrUnblock4(false, fd, group, interf, source);
556    }
557
558    private static native int blockOrUnblock4(boolean block, FileDescriptor fd, int group,
559                                              int interf, int source)
560        throws IOException;
561
562    /**
563     * Join IPv6 multicast group
564     */
565    static int join6(FileDescriptor fd, byte[] group, int index, byte[] source)
566        throws IOException
567    {
568        return joinOrDrop6(true, fd, group, index, source);
569    }
570
571    /**
572     * Drop membership of IPv6 multicast group
573     */
574    static void drop6(FileDescriptor fd, byte[] group, int index, byte[] source)
575        throws IOException
576    {
577        joinOrDrop6(false, fd, group, index, source);
578    }
579
580    private static native int joinOrDrop6(boolean join, FileDescriptor fd, byte[] group, int index, byte[] source)
581        throws IOException;
582
583    /**
584     * Block IPv6 source
585     */
586    static int block6(FileDescriptor fd, byte[] group, int index, byte[] source)
587        throws IOException
588    {
589        return blockOrUnblock6(true, fd, group, index, source);
590    }
591
592    /**
593     * Unblock IPv6 source
594     */
595    static void unblock6(FileDescriptor fd, byte[] group, int index, byte[] source)
596        throws IOException
597    {
598        blockOrUnblock6(false, fd, group, index, source);
599    }
600
601    static native int blockOrUnblock6(boolean block, FileDescriptor fd, byte[] group, int index, byte[] source)
602        throws IOException;
603
604    static native void setInterface4(FileDescriptor fd, int interf) throws IOException;
605
606    static native int getInterface4(FileDescriptor fd) throws IOException;
607
608    static native void setInterface6(FileDescriptor fd, int index) throws IOException;
609
610    static native int getInterface6(FileDescriptor fd) throws IOException;
611
612    /**
613     * Event masks for the various poll system calls.
614     * They will be set platform dependant in the static initializer below.
615     */
616    public static final short POLLIN;
617    public static final short POLLOUT;
618    public static final short POLLERR;
619    public static final short POLLHUP;
620    public static final short POLLNVAL;
621    public static final short POLLCONN;
622
623    static native short pollinValue();
624    static native short polloutValue();
625    static native short pollerrValue();
626    static native short pollhupValue();
627    static native short pollnvalValue();
628    static native short pollconnValue();
629
630    static {
631
632        POLLIN     = pollinValue();
633        POLLOUT    = polloutValue();
634        POLLERR    = pollerrValue();
635        POLLHUP    = pollhupValue();
636        POLLNVAL   = pollnvalValue();
637        POLLCONN   = pollconnValue();
638    }
639
640    static {
641        int availLevel = isExclusiveBindAvailable();
642        if (availLevel >= 0) {
643            String exclBindProp =
644                java.security.AccessController.doPrivileged(
645                    new PrivilegedAction<String>() {
646                        @Override
647                        public String run() {
648                            return System.getProperty(
649                                    "sun.net.useExclusiveBind");
650                        }
651                    });
652            if (exclBindProp != null) {
653                exclusiveBind = exclBindProp.length() == 0 ?
654                        true : Boolean.parseBoolean(exclBindProp);
655            } else if (availLevel == 1) {
656                exclusiveBind = true;
657            } else {
658                exclusiveBind = false;
659            }
660        } else {
661            exclusiveBind = false;
662        }
663
664        fastLoopback = isFastTcpLoopbackRequested();
665    }
666}
667