1 /* 2 * Copyright (c) 2020, 2021, 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 26 package sun.nio.ch; 27 28 import java.io.FileDescriptor; 29 import java.io.IOException; 30 import java.net.BindException; 31 import java.net.NetPermission; 32 import java.net.SocketAddress; 33 import java.net.UnixDomainSocketAddress; 34 import java.nio.channels.UnsupportedAddressTypeException; 35 import java.nio.file.FileSystems; 36 import java.nio.file.InvalidPathException; 37 import java.nio.file.Path; 38 import java.nio.file.spi.FileSystemProvider; 39 import java.security.NoSuchAlgorithmException; 40 import java.security.SecureRandom; 41 import java.util.Random; 42 import sun.nio.fs.AbstractFileSystemProvider; 43 44 /* 45 * @hide 46 */ 47 class UnixDomainSockets { UnixDomainSockets()48 private UnixDomainSockets() { } 49 50 static final UnixDomainSocketAddress UNNAMED = UnixDomainSocketAddress.of(""); 51 52 private static final boolean supported; 53 54 private static final String tempDir = UnixDomainSocketsUtil.getTempDir(); 55 56 private static final NetPermission accessUnixDomainSocket = 57 new NetPermission("accessUnixDomainSocket"); 58 isSupported()59 static boolean isSupported() { 60 return supported; 61 } 62 checkPermission()63 static void checkPermission() { 64 @SuppressWarnings("removal") 65 SecurityManager sm = System.getSecurityManager(); 66 if (sm != null) 67 sm.checkPermission(accessUnixDomainSocket); 68 } 69 getRevealedLocalAddress(SocketAddress sa)70 static UnixDomainSocketAddress getRevealedLocalAddress(SocketAddress sa) { 71 UnixDomainSocketAddress addr = (UnixDomainSocketAddress) sa; 72 try { 73 checkPermission(); 74 // Security check passed 75 } catch (SecurityException e) { 76 // Return unnamed address only if security check fails 77 addr = UNNAMED; 78 } 79 return addr; 80 } 81 localAddress(FileDescriptor fd)82 static UnixDomainSocketAddress localAddress(FileDescriptor fd) throws IOException { 83 String path = new String(localAddress0(fd), UnixDomainSocketsUtil.getCharset()); 84 return UnixDomainSocketAddress.of(path); 85 } 86 localAddress0(FileDescriptor fd)87 private static native byte[] localAddress0(FileDescriptor fd) throws IOException; 88 89 @SuppressWarnings("removal") getRevealedLocalAddressAsString(SocketAddress sa)90 static String getRevealedLocalAddressAsString(SocketAddress sa) { 91 return (System.getSecurityManager() != null) ? sa.toString() : ""; 92 } 93 checkAddress(SocketAddress sa)94 static UnixDomainSocketAddress checkAddress(SocketAddress sa) { 95 if (sa == null) 96 throw new NullPointerException(); 97 if (!(sa instanceof UnixDomainSocketAddress)) 98 throw new UnsupportedAddressTypeException(); 99 return (UnixDomainSocketAddress) sa; 100 } 101 getPathBytes(Path path)102 static byte[] getPathBytes(Path path) { 103 FileSystemProvider provider = FileSystems.getDefault().provider(); 104 return ((AbstractFileSystemProvider) provider).getSunPathForSocketFile(path); 105 } 106 socket()107 static FileDescriptor socket() throws IOException { 108 return IOUtil.newFD(socket0()); 109 } 110 bind(FileDescriptor fd, Path addr)111 static void bind(FileDescriptor fd, Path addr) throws IOException { 112 byte[] path = getPathBytes(addr); 113 if (path.length == 0) { 114 throw new BindException("Server socket cannot bind to unnamed address"); 115 } 116 bind0(fd, path); 117 } 118 getRandom()119 private static Random getRandom() { 120 try { 121 return SecureRandom.getInstance("NativePRNGNonBlocking"); 122 } catch (NoSuchAlgorithmException e) { 123 return new SecureRandom(); // This should not fail 124 } 125 } 126 127 private static final Random random = getRandom(); 128 129 /** 130 * Return a possible temporary name to bind to, which is different for each call 131 * Name is of the form <temp dir>/socket_<random> 132 */ generateTempName()133 static UnixDomainSocketAddress generateTempName() throws IOException { 134 String dir = UnixDomainSockets.tempDir; 135 if (dir == null) 136 throw new BindException("Could not locate temporary directory for sockets"); 137 int rnd = random.nextInt(Integer.MAX_VALUE); 138 try { 139 Path path = Path.of(dir, "socket_" + rnd); 140 return UnixDomainSocketAddress.of(path); 141 } catch (InvalidPathException e) { 142 throw new BindException("Invalid temporary directory"); 143 } 144 } 145 connect(FileDescriptor fd, SocketAddress sa)146 static int connect(FileDescriptor fd, SocketAddress sa) throws IOException { 147 return UnixDomainSockets.connect(fd, ((UnixDomainSocketAddress) sa).getPath()); 148 } 149 connect(FileDescriptor fd, Path path)150 static int connect(FileDescriptor fd, Path path) throws IOException { 151 return connect0(fd, getPathBytes(path)); 152 } 153 accept(FileDescriptor fd, FileDescriptor newfd, String[] paths)154 static int accept(FileDescriptor fd, FileDescriptor newfd, String[] paths) 155 throws IOException 156 { 157 Object[] array = new Object[1]; 158 int n = accept0(fd, newfd, array); 159 if (n > 0) { 160 byte[] bytes = (byte[]) array[0]; 161 paths[0] = new String(bytes, UnixDomainSocketsUtil.getCharset()); 162 } 163 return n; 164 } 165 init()166 private static native boolean init(); 167 socket0()168 private static native int socket0() throws IOException; 169 bind0(FileDescriptor fd, byte[] path)170 private static native void bind0(FileDescriptor fd, byte[] path) 171 throws IOException; 172 connect0(FileDescriptor fd, byte[] path)173 private static native int connect0(FileDescriptor fd, byte[] path) 174 throws IOException; 175 accept0(FileDescriptor fd, FileDescriptor newfd, Object[] array)176 private static native int accept0(FileDescriptor fd, FileDescriptor newfd, Object[] array) 177 throws IOException; 178 179 static { 180 // Load all required native libs 181 // Android-removed: no native libs. 182 // IOUtil.load(); 183 supported = init(); 184 } 185 } 186