src/jdk.net/share/classes/jdk/net/RdmaSocketOptions.java
branchrsocket-branch
changeset 57115 512e7cc6ccce
child 57121 ff7b5750a610
equal deleted inserted replaced
53485:b743968ad646 57115:512e7cc6ccce
       
     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.access.JavaIOFileDescriptorAccess;
       
    36 import jdk.internal.access.SharedSecrets;
       
    37 import java.lang.annotation.Native;
       
    38 
       
    39 /**
       
    40  * Defines socket options specific to RDMA-based TCP sockets and channels.
       
    41  *
       
    42  * @since 12
       
    43  */
       
    44 public final class RdmaSocketOptions {
       
    45 
       
    46     private static class RdmaSocketOption<T> implements SocketOption<T> {
       
    47         private final String name;
       
    48         private final Class<T> type;
       
    49         RdmaSocketOption(String name, Class<T> type) {
       
    50             this.name = name;
       
    51             this.type = type;
       
    52         }
       
    53         @Override public String name() { return name; }
       
    54         @Override public Class<T> type() { return type; }
       
    55         @Override public String toString() { return name; }
       
    56     }
       
    57 
       
    58     private RdmaSocketOptions() { }
       
    59 
       
    60     /**
       
    61      * The integer size of the underlying RDMA send queue used by the
       
    62      * platform for network I/O.
       
    63      *
       
    64      * The initial/default size of the RDMA send queue and the range of
       
    65      * allowable values is system and device dependent although a negative
       
    66      * size is not allowed.
       
    67      *
       
    68      * <p> An implementation allows this socket option to be set before the
       
    69      * socket is bound or connected. Changing the value of this socket option
       
    70      * after the socket is bound or connected has no effect.
       
    71      *
       
    72      * Valid for RDMA-based TCP sockets.
       
    73      */
       
    74     public static final SocketOption<Integer> RDMA_SQSIZE = new
       
    75         RdmaSocketOption<Integer>("RDMA_SQSIZE", Integer.class);
       
    76 
       
    77     /**
       
    78      * The integer size of the underlying RDMA receive queue used by the
       
    79      * platform for network I/O.
       
    80      *
       
    81      * The initial/default size of the RDMA receive queue and the range of
       
    82      * allowable values is system and device dependent although a negative
       
    83      * size is not allowed.
       
    84      *
       
    85      * <p> An implementation allows this socket option to be set before the
       
    86      * socket is bound or connected. Changing the value of this socket option
       
    87      * after the socket is bound or connected has no effect.
       
    88      *
       
    89      * Valid for RDMA-based TCP sockets.
       
    90      */
       
    91     public static final SocketOption<Integer> RDMA_RQSIZE = new
       
    92         RdmaSocketOption<Integer>("RDMA_RQSIZE", Integer.class);
       
    93 
       
    94     /**
       
    95      * The integer size of the underlying RDMA inline data used by the
       
    96      * platform for network I/O.
       
    97      *
       
    98      * The initial/default size of the RDMA inline data and the range of
       
    99      * allowable values is system and device dependent although a negative
       
   100      * size is not allowed.
       
   101      *
       
   102      * <p> An implementation allows this socket option to be set before the
       
   103      * socket is bound or connected. Changing the value of this socket option
       
   104      * after the socket is bound or connected has no effect.
       
   105      *
       
   106      * Valid for RDMA-based TCP sockets.
       
   107      */
       
   108     public static final SocketOption<Integer> RDMA_INLINE = new
       
   109         RdmaSocketOption<Integer>("RDMA_INLINE", Integer.class);
       
   110 
       
   111     @Native private static final int SQSIZE = 0x3001;
       
   112 
       
   113     @Native private static final int RQSIZE = 0x3002;
       
   114 
       
   115     @Native private static final int INLINE = 0x3003;
       
   116 
       
   117     private static final PlatformRdmaSocketOptions platformRdmaSocketOptions =
       
   118             PlatformRdmaSocketOptions.get();
       
   119 
       
   120     private static final boolean rdmaSocketSupported =
       
   121             platformRdmaSocketOptions.rdmaSocketSupported();
       
   122 
       
   123     private static final Set<SocketOption<?>> rdmaOptions = options();
       
   124 
       
   125     static Set<SocketOption<?>> options() {
       
   126         if (rdmaSocketSupported)
       
   127             return Set.of(RDMA_SQSIZE, RDMA_RQSIZE, RDMA_INLINE);
       
   128         else
       
   129             return Collections.<SocketOption<?>>emptySet();
       
   130     }
       
   131 
       
   132     static {
       
   133         sun.net.ext.RdmaSocketOptions.register(
       
   134                 new sun.net.ext.RdmaSocketOptions(rdmaOptions) {
       
   135 
       
   136             @Override
       
   137             public void setOption(FileDescriptor fd,
       
   138                     SocketOption<?> option, Object value)
       
   139                     throws SocketException {
       
   140                 SecurityManager sm = System.getSecurityManager();
       
   141                 if (sm != null)
       
   142                     sm.checkPermission(new NetworkPermission("setOption."
       
   143                             + option.name()));
       
   144 
       
   145                 if (fd == null || !fd.valid())
       
   146                     throw new SocketException("socket closed");
       
   147 
       
   148                 if ((option == RDMA_SQSIZE) || (option == RDMA_RQSIZE)
       
   149                     || (option == RDMA_INLINE)) {
       
   150                     assert rdmaSocketSupported;
       
   151 
       
   152                     int val;
       
   153                     int opt;
       
   154                     if (option == RDMA_SQSIZE) {
       
   155                         if (value == null || (!(value instanceof Integer)))
       
   156                             throw new SocketException(
       
   157                                     "Bad parameter for RDMA_SQSIZE");
       
   158                         val = ((Integer) value).intValue();
       
   159                         opt = SQSIZE;
       
   160                         if (val < 0)
       
   161                             throw new IllegalArgumentException(
       
   162                                     "send queue size < 0");
       
   163                     } else if (option == RDMA_RQSIZE) {
       
   164                         if (value == null || (!(value instanceof Integer)))
       
   165                             throw new SocketException(
       
   166                                     "Bad parameter for RDMA_RQSIZE");
       
   167                         val = ((Integer) value).intValue();
       
   168                         opt = RQSIZE;
       
   169                         if (val < 0)
       
   170                             throw new IllegalArgumentException(
       
   171                                     "receive queue size < 0");
       
   172                     } else if (option == RDMA_INLINE) {
       
   173                         if (value == null || (!(value instanceof Integer)))
       
   174                             throw new SocketException(
       
   175                                     "Bad parameter for RDMA_INLINE");
       
   176                         val = ((Integer) value).intValue();
       
   177                         opt = INLINE;
       
   178                         if (val < 0)
       
   179                             throw new IllegalArgumentException(
       
   180                                     "inline size < 0");
       
   181                     } else {
       
   182                         throw new SocketException(
       
   183                                 "unrecognized RDMA socket option: " + option);
       
   184                     }
       
   185 
       
   186                     setSockOpt(fd, opt, val);
       
   187 
       
   188                 } else {
       
   189                     throw new InternalError("Unexpected option " + option);
       
   190                 }
       
   191             }
       
   192 
       
   193             @Override
       
   194             public Object getOption(FileDescriptor fd,
       
   195                     SocketOption<?> option) throws SocketException {
       
   196                 SecurityManager sm = System.getSecurityManager();
       
   197                 if (sm != null)
       
   198                     sm.checkPermission(new NetworkPermission("getOption."
       
   199                             + option.name()));
       
   200 
       
   201                 if (fd == null || !fd.valid())
       
   202                     throw new SocketException("socket closed");
       
   203 
       
   204                 if ((option == RDMA_SQSIZE) || (option == RDMA_RQSIZE)
       
   205                     || (option == RDMA_INLINE)) {
       
   206                     assert rdmaSocketSupported;
       
   207                     int opt;
       
   208                     if (option == RDMA_SQSIZE) {
       
   209                         opt = SQSIZE;
       
   210                     } else if (option == RDMA_RQSIZE) {
       
   211                         opt = RQSIZE;
       
   212                     } else {
       
   213                         opt = INLINE;
       
   214                     }
       
   215                     return getSockOpt(fd, opt);
       
   216                 } else {
       
   217                     throw new InternalError("Unexpected option " + option);
       
   218                 }
       
   219             }
       
   220         });
       
   221     }
       
   222 
       
   223     private static final JavaIOFileDescriptorAccess fdAccess =
       
   224             SharedSecrets.getJavaIOFileDescriptorAccess();
       
   225 
       
   226     private static void setSockOpt(FileDescriptor fd, int opt, int val)
       
   227             throws SocketException {
       
   228         platformRdmaSocketOptions.setSockOpt(fdAccess.get(fd), opt, val);
       
   229     }
       
   230 
       
   231     private static int getSockOpt(FileDescriptor fd, int opt)
       
   232             throws SocketException {
       
   233         return platformRdmaSocketOptions.getSockOpt(fdAccess.get(fd), opt);
       
   234     }
       
   235 
       
   236     static class PlatformRdmaSocketOptions {
       
   237 
       
   238         protected PlatformRdmaSocketOptions() {}
       
   239 
       
   240         @SuppressWarnings("unchecked")
       
   241         private static PlatformRdmaSocketOptions newInstance(String cn) {
       
   242             Class<PlatformRdmaSocketOptions> c;
       
   243             try {
       
   244                 c = (Class<PlatformRdmaSocketOptions>)Class.forName(cn);
       
   245                 return c.getConstructor(new Class<?>[] { }).newInstance();
       
   246             } catch (ReflectiveOperationException x) {
       
   247                 if (x.getCause() instanceof UnsupportedOperationException)
       
   248                     throw (UnsupportedOperationException)x.getCause();
       
   249                 throw new AssertionError(x);
       
   250             }
       
   251         }
       
   252 
       
   253         private static PlatformRdmaSocketOptions create() {
       
   254             String osname = AccessController.doPrivileged(
       
   255                     new PrivilegedAction<String>() {
       
   256                         public String run() {
       
   257                             return System.getProperty("os.name");
       
   258                         }
       
   259                     });
       
   260             if ("Linux".equals(osname)) {
       
   261                 try {
       
   262                     return newInstance("jdk.net.LinuxRdmaSocketOptions");
       
   263                 } catch (UnsupportedOperationException uoe) {
       
   264                     return new PlatformRdmaSocketOptions();
       
   265                 }
       
   266             }
       
   267             return new PlatformRdmaSocketOptions();
       
   268         }
       
   269 
       
   270         private static final PlatformRdmaSocketOptions instance = create();
       
   271 
       
   272         static PlatformRdmaSocketOptions get() {
       
   273             return instance;
       
   274         }
       
   275 
       
   276         void setSockOpt(int fd, int opt, int value) throws SocketException {
       
   277             throw new UnsupportedOperationException(
       
   278                     "unsupported socket option");
       
   279         }
       
   280 
       
   281         int getSockOpt(int fd, int opt) throws SocketException {
       
   282             throw new UnsupportedOperationException(
       
   283                     "unsupported socket option");
       
   284         }
       
   285 
       
   286         boolean rdmaSocketSupported() {
       
   287             return false;
       
   288         }
       
   289     }
       
   290 }