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