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 }