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