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 rsockets. 41 * These options may be platform specific. 42 * 43 * @since 11 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 public static final SocketOption<Integer> RDMA_SQSIZE = new 62 RdmaSocketOption<Integer>("RDMA_SQSIZE", Integer.class); 63 64 public static final SocketOption<Integer> RDMA_RQSIZE = new 65 RdmaSocketOption<Integer>("RDMA_RQSIZE", Integer.class); 66 67 public static final SocketOption<Integer> RDMA_INLINE = new 68 RdmaSocketOption<Integer>("RDMA_INLINE", Integer.class); 69 70 @Native public static final int SQSIZE = 0x3001; 71 72 @Native public static final int RQSIZE = 0x3002; 73 74 @Native public static final int INLINE = 0x3003; 75 76 private static final PlatformRdmaSocketOptions platformRdmaSocketOptions = 77 PlatformRdmaSocketOptions.get(); 78 79 private static final boolean rdmaSocketSupported = 80 platformRdmaSocketOptions.rdmaSocketSupported(); 81 82 private static final Set<SocketOption<?>> rdmaOptions = options(); 83 84 static Set<SocketOption<?>> options() { 85 if (rdmaSocketSupported) 86 return Set.of(RDMA_SQSIZE, RDMA_RQSIZE, RDMA_INLINE); 87 else 88 return Collections.<SocketOption<?>>emptySet(); 89 } 90 91 static { 92 sun.net.ext.RdmaSocketOptions.register( 93 new sun.net.ext.RdmaSocketOptions(rdmaOptions) { 94 95 @Override 96 public void setOption(FileDescriptor fd, 97 SocketOption<?> option, 98 Object value) 99 throws SocketException 100 { 101 SecurityManager sm = System.getSecurityManager(); 102 if (sm != null) 103 sm.checkPermission(new NetworkPermission("setOption." + option.name())); 104 105 if (fd == null || !fd.valid()) 106 throw new SocketException("socket closed"); 107 108 if ((option == RDMA_SQSIZE) || (option == RDMA_RQSIZE) 109 || (option == RDMA_INLINE)) { 110 assert rdmaSocketSupported; 111 112 int val; 113 int opt; 114 if (option == RDMA_SQSIZE) { 115 if (value == null || (!(value instanceof Integer))) 116 throw new SocketException("Bad parameter for RDMA_SQSIZE"); 117 val = ((Integer) value).intValue(); 118 opt = SQSIZE; 119 if (val < 0) 120 throw new IllegalArgumentException("send queue size < 0"); 121 } else if (option == RDMA_RQSIZE) { 122 if (value == null || (!(value instanceof Integer))) 123 throw new SocketException("Bad parameter for RDMA_RQSIZE"); 124 val = ((Integer) value).intValue(); 125 opt = RQSIZE; 126 if (val < 0) 127 throw new IllegalArgumentException("receive queue size < 0"); 128 } else if (option == RDMA_INLINE) { 129 if (value == null || (!(value instanceof Integer))) 130 throw new SocketException("Bad parameter for RDMA_INLINE"); 131 val = ((Integer) value).intValue(); 132 opt = INLINE; 133 if (val < 0) 134 throw new IllegalArgumentException("inline size < 0"); 135 } else { 136 throw new SocketException("unrecognized RDMA socket option: " + option); 137 } 138 139 setSockOpt(fd, opt, val); 140 141 } else { 142 throw new InternalError("Unexpected option " + option); 143 } 144 } 145 146 @Override 147 public Object getOption(FileDescriptor fd, 148 SocketOption<?> option) 149 throws SocketException 150 { 151 SecurityManager sm = System.getSecurityManager(); 152 if (sm != null) 153 sm.checkPermission(new NetworkPermission("getOption." + option.name())); 154 155 if (fd == null || !fd.valid()) 156 throw new SocketException("socket closed"); 157 158 if ((option == RDMA_SQSIZE) || (option == RDMA_RQSIZE) 159 || (option == RDMA_INLINE)) { 160 assert rdmaSocketSupported; 161 int opt; 162 if (option == RDMA_SQSIZE) { 163 opt = SQSIZE; 164 } else if (option == RDMA_RQSIZE) { 165 opt = RQSIZE; 166 } else { 167 opt = INLINE; 168 } 169 return getSockOpt(fd, opt); 170 } else { 171 throw new InternalError("Unexpected option " + option); 172 } 173 } 174 }); 175 } 176 177 private static final JavaIOFileDescriptorAccess fdAccess = 178 SharedSecrets.getJavaIOFileDescriptorAccess(); 179 180 private static void setSockOpt(FileDescriptor fd, int opt, int val) 181 throws SocketException 182 { 183 platformRdmaSocketOptions.setSockOpt(fdAccess.get(fd), opt, val); 184 } 185 186 private static int getSockOpt(FileDescriptor fd, int opt) 187 throws SocketException 188 { 189 return platformRdmaSocketOptions.getSockOpt(fdAccess.get(fd), opt); 190 } 191 192 static class PlatformRdmaSocketOptions { 193 194 protected PlatformRdmaSocketOptions() {} 195 196 @SuppressWarnings("unchecked") 197 private static PlatformRdmaSocketOptions newInstance(String cn) { 198 Class<PlatformRdmaSocketOptions> c; 199 try { 200 c = (Class<PlatformRdmaSocketOptions>)Class.forName(cn); 201 return c.getConstructor(new Class<?>[] { }).newInstance(); 202 } catch (ReflectiveOperationException x) { 203 throw new AssertionError(x); 204 } 205 } 206 207 private static PlatformRdmaSocketOptions create() { 208 String osname = AccessController.doPrivileged( 209 new PrivilegedAction<String>() { 210 public String run() { 211 return System.getProperty("os.name"); 212 } 213 }); 214 if ("Linux".equals(osname)) 215 return newInstance("jdk.net.LinuxRdmaSocketOptions"); 216 return new PlatformRdmaSocketOptions(); 217 } 218 219 private static final PlatformRdmaSocketOptions instance = create(); 220 221 static PlatformRdmaSocketOptions get() { 222 return instance; 223 } 224 225 void setSockOpt(int fd, int opt, int value) 226 throws SocketException 227 { 228 throw new UnsupportedOperationException("unsupported socket option"); 229 } 230 231 int getSockOpt(int fd, int opt) throws SocketException { 232 throw new UnsupportedOperationException("unsupported socket option"); 233 } 234 235 boolean rdmaSocketSupported() { 236 return false; 237 } 238 } 239 }