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