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