1 /* 2 * Copyright (c) 2018, 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 jdk.internal.net.rdma; 27 28 import java.io.FileDescriptor; 29 import java.io.IOException; 30 import java.net.Inet4Address; 31 import java.net.Inet6Address; 32 import java.net.InetAddress; 33 import java.net.InetSocketAddress; 34 import java.net.ProtocolFamily; 35 import java.net.SocketAddress; 36 import java.net.SocketOption; 37 import java.net.StandardProtocolFamily; 38 import java.net.StandardSocketOptions; 39 import java.nio.channels.UnsupportedAddressTypeException; 40 import java.security.AccessController; 41 import java.security.PrivilegedAction; 42 import java.util.Enumeration; 43 import sun.net.ext.RdmaSocketOptions; 44 import sun.nio.ch.IOUtil; 45 import sun.nio.ch.Net; 46 47 public class RdmaNet { 48 private RdmaNet() { } 49 50 static final ProtocolFamily UNSPEC = new ProtocolFamily() { 51 public String name() { 52 return "UNSPEC"; 53 } 54 }; 55 56 static boolean isReusePortAvailable() { 57 return false; 58 } 59 60 private static volatile boolean checkedRdma; 61 private static volatile boolean isRdmaAvailable; 62 63 static boolean isRdmaAvailable() { 64 if (!checkedRdma) { 65 isRdmaAvailable = isRdmaAvailable0(); 66 checkedRdma = true; 67 } 68 return isRdmaAvailable; 69 } 70 71 private static native boolean isRdmaAvailable0(); 72 73 static InetSocketAddress checkAddress(SocketAddress sa, ProtocolFamily family) { 74 InetSocketAddress isa = Net.checkAddress(sa); 75 if (family == StandardProtocolFamily.INET) { 76 InetAddress addr = isa.getAddress(); 77 if (!(addr instanceof Inet4Address)) 78 throw new UnsupportedAddressTypeException(); 79 } 80 if (family == StandardProtocolFamily.INET6) { 81 InetAddress addr = isa.getAddress(); 82 if (!(addr instanceof Inet6Address)) 83 throw new UnsupportedAddressTypeException(); 84 } 85 return isa; 86 } 87 88 // -- Socket options 89 90 static final RdmaSocketOptions rdmaOptions = 91 RdmaSocketOptions.getInstance(); 92 93 static void setSocketOption(FileDescriptor fd, ProtocolFamily family, 94 SocketOption<?> name, Object value) throws IOException 95 { 96 if (value == null) 97 throw new IllegalArgumentException("Invalid option value"); 98 99 Class<?> type = name.type(); 100 101 if (rdmaOptions.isOptionSupported(name)) { 102 rdmaOptions.setOption(fd, name, value); 103 return; 104 } 105 106 if (type != Integer.class && type != Boolean.class) 107 throw new AssertionError("Should not reach here"); 108 109 if (name == StandardSocketOptions.SO_RCVBUF || 110 name == StandardSocketOptions.SO_SNDBUF) 111 { 112 int i = ((Integer)value).intValue(); 113 if (i < 0) 114 throw new IllegalArgumentException( 115 "Invalid send/receive buffer size"); 116 } 117 RdmaOptionKey key = RdmaSocketOptionRegistry.findOption(name, family); 118 if (key == null) 119 throw new AssertionError("Option not found"); 120 121 int arg; 122 int maxValue = 1024 * 1024 * 1024 - 1; 123 if (type == Integer.class) { 124 arg = ((Integer)value).intValue(); 125 if (arg > maxValue) 126 arg = maxValue; 127 } else { 128 boolean b = ((Boolean)value).booleanValue(); 129 arg = (b) ? 1 : 0; 130 } 131 132 boolean mayNeedConversion = (family == UNSPEC); 133 setIntOption0(fd, mayNeedConversion, key.level(), 134 key.name(), arg); 135 } 136 137 static Object getSocketOption(FileDescriptor fd, ProtocolFamily family, 138 SocketOption<?> name) throws IOException 139 { 140 Class<?> type = name.type(); 141 142 if (rdmaOptions.isOptionSupported(name)) { 143 return rdmaOptions.getOption(fd, name); 144 } 145 146 if (type != Integer.class && type != Boolean.class) 147 throw new AssertionError("Should not reach here"); 148 149 RdmaOptionKey key = RdmaSocketOptionRegistry.findOption(name, family); 150 if (key == null) 151 throw new AssertionError("Option not found"); 152 153 boolean mayNeedConversion = (family == UNSPEC); 154 int value = getIntOption0(fd, mayNeedConversion, key.level(), 155 key.name()); 156 157 if (type == Integer.class) { 158 return Integer.valueOf(value); 159 } else { 160 return (value == 0) ? Boolean.FALSE : Boolean.TRUE; 161 } 162 } 163 164 // -- Socket operations -- 165 static FileDescriptor socket(ProtocolFamily family, boolean stream) 166 throws IOException { 167 boolean preferIPv6 = Net.isIPv6Available() && 168 (family != StandardProtocolFamily.INET); 169 return IOUtil.newFD(socket0(preferIPv6, stream, false)); 170 } 171 172 static FileDescriptor serverSocket(ProtocolFamily family, boolean stream) 173 throws IOException { 174 boolean preferIPv6 = Net.isIPv6Available() && 175 (family != StandardProtocolFamily.INET); 176 return IOUtil.newFD(socket0(preferIPv6, stream, true)); 177 } 178 179 private static native int socket0(boolean preferIPv6, boolean stream, 180 boolean reuse); 181 static void bind(ProtocolFamily family, FileDescriptor fd, 182 InetAddress addr, int port) throws IOException 183 { 184 boolean preferIPv6 = Net.isIPv6Available() && 185 (family != StandardProtocolFamily.INET); 186 bind0(fd, preferIPv6, addr, port); 187 } 188 189 private static native void bind0(FileDescriptor fd, boolean preferIPv6, 190 InetAddress addr, int port) throws IOException; 191 192 static native void listen(FileDescriptor fd, int backlog) 193 throws IOException; 194 195 static int connect(FileDescriptor fd, InetAddress remote, int remotePort) 196 throws IOException 197 { 198 return connect(UNSPEC, fd, remote, remotePort); 199 } 200 201 static int connect(ProtocolFamily family, FileDescriptor fd, 202 InetAddress remote, int remotePort) throws IOException 203 { 204 boolean preferIPv6 = Net.isIPv6Available() && 205 (family != StandardProtocolFamily.INET); 206 return connect0(preferIPv6, fd, remote, remotePort); 207 } 208 209 public static InetSocketAddress localAddress(FileDescriptor fd) 210 throws IOException 211 { 212 return new InetSocketAddress(localInetAddress(fd), localPort(fd)); 213 } 214 215 private static native int connect0(boolean preferIPv6, FileDescriptor fd, 216 InetAddress remote, int remotePort) throws IOException; 217 218 static native void shutdown(FileDescriptor fd, int how) throws IOException; 219 220 private static native int localPort(FileDescriptor fd) 221 throws IOException; 222 223 private static native InetAddress localInetAddress(FileDescriptor fd) 224 throws IOException; 225 226 private static native int getIntOption0(FileDescriptor fd, 227 boolean mayNeedConversion, int level, int opt) throws IOException; 228 229 private static native void setIntOption0(FileDescriptor fd, 230 boolean mayNeedConversion, int level, int opt, int arg) 231 throws IOException; 232 233 static native int poll(FileDescriptor fd, int events, long timeout) 234 throws IOException; 235 236 public static native void configureBlocking(FileDescriptor fd, 237 boolean blocking); 238 239 private static native void initIDs(); 240 241 static { 242 java.security.AccessController.doPrivileged( 243 new java.security.PrivilegedAction<>() { 244 public Void run() { 245 System.loadLibrary("extnet"); 246 return null; 247 } 248 }); 249 IOUtil.load(); 250 initIDs(); 251 } 252 }