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 
27 package sun.nio.ch;
28 
29 import dalvik.system.BlockGuard;
30 
31 import java.io.*;
32 import java.net.*;
33 import jdk.net.*;
34 import java.nio.channels.*;
35 import java.util.*;
36 import java.security.AccessController;
37 import java.security.PrivilegedAction;
38 import sun.net.ExtendedOptionsImpl;
39 
40 
41 public class Net {
42 
Net()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      */
isIPv6Available()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      */
useExclusiveBind()77     static boolean useExclusiveBind() {
78         return exclusiveBind;
79     }
80 
81     /**
82      * Tells whether IPv6 sockets can join IPv4 multicast groups
83      */
canIPv6SocketJoinIPv4Group()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      */
canJoin6WithIPv4Group()92     static boolean canJoin6WithIPv4Group() {
93         return canJoin6WithIPv4Group0();
94     }
95 
checkAddress(SocketAddress sa)96     public static InetSocketAddress checkAddress(SocketAddress sa) {
97         if (sa == null)
98             // BEGIN Android-changed: Throw IllegalArgumentException not NullPointerException.
99             //throw new NullPointerException();
100             throw new IllegalArgumentException("sa == null");
101             // END Android-changed: Throw IllegalArgumentException not NullPointerException.
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 
asInetSocketAddress(SocketAddress sa)114     static InetSocketAddress asInetSocketAddress(SocketAddress sa) {
115         if (!(sa instanceof InetSocketAddress))
116             throw new UnsupportedAddressTypeException();
117         return (InetSocketAddress)sa;
118     }
119 
translateToSocketException(Exception x)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         // Android-added: Handling for AlreadyConnectedException.
139         } else if (x instanceof AlreadyConnectedException) {
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 
translateException(Exception x, boolean unknownHostForUnresolved)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 
translateException(Exception x)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      */
getRevealedLocalAddress(InetSocketAddress addr)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 
getRevealedLocalAddressAsString(InetSocketAddress addr)193     static String getRevealedLocalAddressAsString(InetSocketAddress addr) {
194         return System.getSecurityManager() == null ? addr.toString() :
195                 getLoopbackAddress(addr.getPort()).toString();
196     }
197 
getLoopbackAddress(int port)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      */
anyInet4Address(final NetworkInterface interf)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         // Android-added: BlockGuard support.
462         BlockGuard.getThreadPolicy().onNetwork();
463 
464         boolean preferIPv6 = isIPv6Available() &&
465             (family != StandardProtocolFamily.INET);
466         return connect0(preferIPv6, fd, remote, remotePort);
467     }
468 
469     private static native int connect0(boolean preferIPv6,
470                                        FileDescriptor fd,
471                                        InetAddress remote,
472                                        int remotePort)
473         throws IOException;
474 
475 
476     public final static int SHUT_RD = 0;
477     public final static int SHUT_WR = 1;
478     public final static int SHUT_RDWR = 2;
479 
480     static native void shutdown(FileDescriptor fd, int how) throws IOException;
481 
482     private static native int localPort(FileDescriptor fd)
483         throws IOException;
484 
485     private static native InetAddress localInetAddress(FileDescriptor fd)
486         throws IOException;
487 
488     public static InetSocketAddress localAddress(FileDescriptor fd)
489         throws IOException
490     {
491         return new InetSocketAddress(localInetAddress(fd), localPort(fd));
492     }
493 
494     private static native int remotePort(FileDescriptor fd)
495         throws IOException;
496 
497     private static native InetAddress remoteInetAddress(FileDescriptor fd)
498         throws IOException;
499 
500     static InetSocketAddress remoteAddress(FileDescriptor fd)
501         throws IOException
502     {
503         return new InetSocketAddress(remoteInetAddress(fd), remotePort(fd));
504     }
505 
506     private static native int getIntOption0(FileDescriptor fd, boolean mayNeedConversion,
507                                             int level, int opt)
508         throws IOException;
509 
510     private static native void setIntOption0(FileDescriptor fd, boolean mayNeedConversion,
511                                              int level, int opt, int arg, boolean isIPv6)
512         throws IOException;
513 
514     static native int poll(FileDescriptor fd, int events, long timeout)
515         throws IOException;
516 
517     // -- Multicast support --
518 
519 
520     /**
521      * Join IPv4 multicast group
522      */
523     static int join4(FileDescriptor fd, int group, int interf, int source)
524         throws IOException
525     {
526         return joinOrDrop4(true, fd, group, interf, source);
527     }
528 
529     /**
530      * Drop membership of IPv4 multicast group
531      */
532     static void drop4(FileDescriptor fd, int group, int interf, int source)
533         throws IOException
534     {
535         joinOrDrop4(false, fd, group, interf, source);
536     }
537 
538     private static native int joinOrDrop4(boolean join, FileDescriptor fd, int group, int interf, int source)
539         throws IOException;
540 
541     /**
542      * Block IPv4 source
543      */
544     static int block4(FileDescriptor fd, int group, int interf, int source)
545         throws IOException
546     {
547         return blockOrUnblock4(true, fd, group, interf, source);
548     }
549 
550     /**
551      * Unblock IPv6 source
552      */
553     static void unblock4(FileDescriptor fd, int group, int interf, int source)
554         throws IOException
555     {
556         blockOrUnblock4(false, fd, group, interf, source);
557     }
558 
559     private static native int blockOrUnblock4(boolean block, FileDescriptor fd, int group,
560                                               int interf, int source)
561         throws IOException;
562 
563     /**
564      * Join IPv6 multicast group
565      */
566     static int join6(FileDescriptor fd, byte[] group, int index, byte[] source)
567         throws IOException
568     {
569         return joinOrDrop6(true, fd, group, index, source);
570     }
571 
572     /**
573      * Drop membership of IPv6 multicast group
574      */
575     static void drop6(FileDescriptor fd, byte[] group, int index, byte[] source)
576         throws IOException
577     {
578         joinOrDrop6(false, fd, group, index, source);
579     }
580 
581     private static native int joinOrDrop6(boolean join, FileDescriptor fd, byte[] group, int index, byte[] source)
582         throws IOException;
583 
584     /**
585      * Block IPv6 source
586      */
587     static int block6(FileDescriptor fd, byte[] group, int index, byte[] source)
588         throws IOException
589     {
590         return blockOrUnblock6(true, fd, group, index, source);
591     }
592 
593     /**
594      * Unblock IPv6 source
595      */
596     static void unblock6(FileDescriptor fd, byte[] group, int index, byte[] source)
597         throws IOException
598     {
599         blockOrUnblock6(false, fd, group, index, source);
600     }
601 
602     static native int blockOrUnblock6(boolean block, FileDescriptor fd, byte[] group, int index, byte[] source)
603         throws IOException;
604 
605     static native void setInterface4(FileDescriptor fd, int interf) throws IOException;
606 
607     static native int getInterface4(FileDescriptor fd) throws IOException;
608 
609     static native void setInterface6(FileDescriptor fd, int index) throws IOException;
610 
611     static native int getInterface6(FileDescriptor fd) throws IOException;
612 
613     // Android-removed: Code to load native libraries, doesn't make sense on Android.
614     // private static native void initIDs();
615 
616     /**
617      * Event masks for the various poll system calls.
618      * They will be set platform dependant in the static initializer below.
619      */
620     public static final short POLLIN;
621     public static final short POLLOUT;
622     public static final short POLLERR;
623     public static final short POLLHUP;
624     public static final short POLLNVAL;
625     public static final short POLLCONN;
626 
627     static native short pollinValue();
628     static native short polloutValue();
629     static native short pollerrValue();
630     static native short pollhupValue();
631     static native short pollnvalValue();
632     static native short pollconnValue();
633 
634     static {
635         // Android-removed: Code to load native libraries, doesn't make sense on Android.
636         /*
637         IOUtil.load();
638         initIDs();
639         */
640 
641         POLLIN     = pollinValue();
642         POLLOUT    = polloutValue();
643         POLLERR    = pollerrValue();
644         POLLHUP    = pollhupValue();
645         POLLNVAL   = pollnvalValue();
646         POLLCONN   = pollconnValue();
647     }
648 
649     static {
650         int availLevel = isExclusiveBindAvailable();
651         if (availLevel >= 0) {
652             String exclBindProp =
653                 java.security.AccessController.doPrivileged(
654                     new PrivilegedAction<String>() {
655                         @Override
656                         public String run() {
657                             return System.getProperty(
658                                     "sun.net.useExclusiveBind");
659                         }
660                     });
661             if (exclBindProp != null) {
662                 exclusiveBind = exclBindProp.length() == 0 ?
663                         true : Boolean.parseBoolean(exclBindProp);
664             } else if (availLevel == 1) {
665                 exclusiveBind = true;
666             } else {
667                 exclusiveBind = false;
668             }
669         } else {
670             exclusiveBind = false;
671         }
672 
673         fastLoopback = isFastTcpLoopbackRequested();
674     }
675 }
676