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.net; 27 28 import java.io.FileDescriptor; 29 import java.net.SocketException; 30 import java.net.SocketOption; 31 import java.security.AccessController; 32 import java.security.PrivilegedAction; 33 import java.util.Collections; 34 import java.util.Set; 35 import jdk.internal.misc.JavaIOFileDescriptorAccess; 36 import jdk.internal.misc.SharedSecrets; 37 import java.lang.annotation.Native; 38 39 /** 40 * Defines socket options specific to rsocket. 41 * The rsocket implementation is on Linux only. 42 * 43 * @since 12 44 */ 45 public final class RdmaSocketOptions { 46 47 private static class RdmaSocketOption<T> implements SocketOption<T> { 48 private final String name; 49 private final Class<T> type; 50 RdmaSocketOption(String name, Class<T> type) { 51 this.name = name; 52 this.type = type; 53 } 54 @Override public String name() { return name; } 55 @Override public Class<T> type() { return type; } 56 @Override public String toString() { return name; } 57 } 58 59 private RdmaSocketOptions() { } 60 61 /** 62 * Set the integer size of the underlying RDMA send queue used by the 63 * platform for network I/O. 64 * 65 * Valid for RDMA based TCP sockets: RdmaSocketImpl 66 */ 67 public static final SocketOption<Integer> RDMA_SQSIZE = new 68 RdmaSocketOption<Integer>("RDMA_SQSIZE", Integer.class); 69 70 /** 71 * Set the integer size of the underlying RDMA receive queue used by the 72 * platform for network I/O. 73 * 74 * Valid for RMDA based TCP sockets: RdmaSocketImpl 75 */ 76 public static final SocketOption<Integer> RDMA_RQSIZE = new 77 RdmaSocketOption<Integer>("RDMA_RQSIZE", Integer.class); 78 79 /** 80 * Set the integer size of the underlying RDMA inline data used by the 81 * platform for network I/O. 82 * 83 * Valid for RMDA based TCP sockets: RdmaSocketImpl 84 */ 85 public static final SocketOption<Integer> RDMA_INLINE = new 86 RdmaSocketOption<Integer>("RDMA_INLINE", Integer.class); 87 88 @Native private static final int SQSIZE = 0x3001; 89 90 @Native private static final int RQSIZE = 0x3002; 91 92 @Native private static final int INLINE = 0x3003; 93 94 private static final PlatformRdmaSocketOptions platformRdmaSocketOptions = 95 PlatformRdmaSocketOptions.get(); 96 97 private static final boolean rdmaSocketSupported = 98 platformRdmaSocketOptions.rdmaSocketSupported(); 99 100 private static final Set<SocketOption<?>> rdmaOptions = options(); 101 102 static Set<SocketOption<?>> options() { 103 if (rdmaSocketSupported) 104 return Set.of(RDMA_SQSIZE, RDMA_RQSIZE, RDMA_INLINE); 105 else 106 return Collections.<SocketOption<?>>emptySet(); 107 } 108 109 static { 110 sun.net.ext.RdmaSocketOptions.register( 111 new sun.net.ext.RdmaSocketOptions(rdmaOptions) { 112 113 @Override 114 public void setOption(FileDescriptor fd, 115 SocketOption<?> option, 116 Object value) 117 throws SocketException 118 { 119 SecurityManager sm = System.getSecurityManager(); 120 if (sm != null) 121 sm.checkPermission(new NetworkPermission("setOption." + option.name())); 122 123 if (fd == null || !fd.valid()) 124 throw new SocketException("socket closed"); 125 126 if ((option == RDMA_SQSIZE) || (option == RDMA_RQSIZE) 127 || (option == RDMA_INLINE)) { 128 assert rdmaSocketSupported; 129 130 int val; 131 int opt; 132 if (option == RDMA_SQSIZE) { 133 if (value == null || (!(value instanceof Integer))) 134 throw new SocketException("Bad parameter for RDMA_SQSIZE"); 135 val = ((Integer) value).intValue(); 136 opt = SQSIZE; 137 if (val < 0) 138 throw new IllegalArgumentException("send queue size < 0"); 139 } else if (option == RDMA_RQSIZE) { 140 if (value == null || (!(value instanceof Integer))) 141 throw new SocketException("Bad parameter for RDMA_RQSIZE"); 142 val = ((Integer) value).intValue(); 143 opt = RQSIZE; 144 if (val < 0) 145 throw new IllegalArgumentException("receive queue size < 0"); 146 } else if (option == RDMA_INLINE) { 147 if (value == null || (!(value instanceof Integer))) 148 throw new SocketException("Bad parameter for RDMA_INLINE"); 149 val = ((Integer) value).intValue(); 150 opt = INLINE; 151 if (val < 0) 152 throw new IllegalArgumentException("inline size < 0"); 153 } else { 154 throw new SocketException("unrecognized RDMA socket option: " + option); 155 } 156 157 setSockOpt(fd, opt, val); 158 159 } else { 160 throw new InternalError("Unexpected option " + option); 161 } 162 } 163 164 @Override 165 public Object getOption(FileDescriptor fd, 166 SocketOption<?> option) 167 throws SocketException 168 { 169 SecurityManager sm = System.getSecurityManager(); 170 if (sm != null) 171 sm.checkPermission(new NetworkPermission("getOption." + option.name())); 172 173 if (fd == null || !fd.valid()) 174 throw new SocketException("socket closed"); 175 176 if ((option == RDMA_SQSIZE) || (option == RDMA_RQSIZE) 177 || (option == RDMA_INLINE)) { 178 assert rdmaSocketSupported; 179 int opt; 180 if (option == RDMA_SQSIZE) { 181 opt = SQSIZE; 182 } else if (option == RDMA_RQSIZE) { 183 opt = RQSIZE; 184 } else { 185 opt = INLINE; 186 } 187 return getSockOpt(fd, opt); 188 } else { 189 throw new InternalError("Unexpected option " + option); 190 } 191 } 192 }); 193 } 194 195 private static final JavaIOFileDescriptorAccess fdAccess = 196 SharedSecrets.getJavaIOFileDescriptorAccess(); 197 198 private static void setSockOpt(FileDescriptor fd, int opt, int val) 199 throws SocketException 200 { 201 platformRdmaSocketOptions.setSockOpt(fdAccess.get(fd), opt, val); 202 } 203 204 private static int getSockOpt(FileDescriptor fd, int opt) 205 throws SocketException 206 { 207 return platformRdmaSocketOptions.getSockOpt(fdAccess.get(fd), opt); 208 } 209 210 static class PlatformRdmaSocketOptions { 211 212 protected PlatformRdmaSocketOptions() {} 213 214 @SuppressWarnings("unchecked") 215 private static PlatformRdmaSocketOptions newInstance(String cn) { 216 Class<PlatformRdmaSocketOptions> c; 217 try { 218 c = (Class<PlatformRdmaSocketOptions>)Class.forName(cn); 219 return c.getConstructor(new Class<?>[] { }).newInstance(); 220 } catch (ReflectiveOperationException x) { 221 throw new AssertionError(x); 222 } 223 } 224 225 private static PlatformRdmaSocketOptions create() { 226 String osname = AccessController.doPrivileged( 227 new PrivilegedAction<String>() { 228 public String run() { 229 return System.getProperty("os.name"); 230 } 231 }); 232 if ("Linux".equals(osname)) 233 return newInstance("jdk.net.LinuxRdmaSocketOptions"); 234 return new PlatformRdmaSocketOptions(); 235 } 236 237 private static final PlatformRdmaSocketOptions instance = create(); 238 239 static PlatformRdmaSocketOptions get() { 240 return instance; 241 } 242 243 void setSockOpt(int fd, int opt, int value) 244 throws SocketException 245 { 246 throw new UnsupportedOperationException("unsupported socket option"); 247 } 248 249 int getSockOpt(int fd, int opt) throws SocketException { 250 throw new UnsupportedOperationException("unsupported socket option"); 251 } 252 253 boolean rdmaSocketSupported() { 254 return false; 255 } 256 } 257 }