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.IOException;
  29 import java.net.ServerSocket;
  30 import java.net.Socket;
  31 import java.net.SocketException;
  32 import java.net.SocketOption;
  33 import java.net.SocketOptions;
  34 import java.net.StandardSocketOptions;
  35 import java.util.HashMap;
  36 import java.util.Map;
  37 import java.util.Set;
  38 import jdk.net.RdmaSocketOptions;
  39 
  40 public class RdmaSocketProvider {
  41     private static boolean rdmaLibInstalled = false;
  42     private static boolean rdmaLibChecked = false;
  43 
  44     static class RdmaClientSocketImpl extends RdmaSocketImpl {
  45     
  46         @Override
  47         protected <T> void setOption(SocketOption<T> name, T value)
  48                 throws IOException {
  49             if(rdmaLibChecked && !rdmaLibInstalled)
  50                 throw new UnsupportedOperationException(
  51                         "librdmacm library is not installed!");
  52 
  53             rdmaLibChecked = true;
  54             try {
  55                 if (!rdmaOptions.isOptionSupported(name)) {
  56                     int opt;
  57                     if (name == StandardSocketOptions.SO_SNDBUF) {
  58                         opt = SocketOptions.SO_SNDBUF;
  59                     } else if (name == StandardSocketOptions.SO_RCVBUF) {
  60                         opt = SocketOptions.SO_RCVBUF;
  61                     } else if (name == StandardSocketOptions.SO_REUSEADDR) {
  62                         opt = SocketOptions.SO_REUSEADDR;
  63                     } else if (name == StandardSocketOptions.TCP_NODELAY) {
  64                         opt = SocketOptions.TCP_NODELAY;
  65                     } else {
  66                         throw new UnsupportedOperationException(
  67                                 "unsupported option: " + name);
  68                     }
  69                     setOption(opt, value);
  70                 } else {
  71                     rdmaOptions.setOption(fd, name, value);
  72                 }
  73                 rdmaLibInstalled = true;
  74             } catch (ExceptionInInitializerError e) {
  75                 rdmaLibInstalled = false;
  76                 throw new UnsupportedOperationException(
  77                         "librdmacm library is not installed!");
  78             }
  79         }
  80 
  81         @SuppressWarnings("unchecked")
  82         @Override
  83         protected <T> T getOption(SocketOption<T> name) throws IOException {
  84             if(rdmaLibChecked && !rdmaLibInstalled)
  85                 throw new UnsupportedOperationException(
  86                         "librdmacm library is not installed!");
  87 
  88             rdmaLibChecked = true;
  89             Object value;
  90             try {
  91                 if (!rdmaOptions.isOptionSupported(name)) {
  92                     int opt;
  93                     if (name == StandardSocketOptions.SO_SNDBUF) {
  94                         opt = SocketOptions.SO_SNDBUF;
  95                     } else if (name == StandardSocketOptions.SO_RCVBUF) {
  96                         opt = SocketOptions.SO_RCVBUF;
  97                     } else if (name == StandardSocketOptions.SO_REUSEADDR) {
  98                         opt = SocketOptions.SO_REUSEADDR;
  99                     } else if (name == StandardSocketOptions.TCP_NODELAY) {
 100                         opt = SocketOptions.TCP_NODELAY;
 101                     } else {
 102                         throw new UnsupportedOperationException(
 103                                 "unsupported option: " + name);
 104                     }
 105                     value = getOption(opt);
 106                 } else {
 107                     value = rdmaOptions.getOption(fd, name);
 108                 }
 109                 rdmaLibInstalled = true;
 110                 return (T) value;
 111             } catch (ExceptionInInitializerError e) {
 112                 rdmaLibInstalled = false;
 113                 throw new UnsupportedOperationException(
 114                         "librdmacm library is not installed!");
 115             }
 116         }
 117     }
 118 
 119     static class RdmaServerSocketImpl extends RdmaSocketImpl {
 120 
 121         @Override
 122         protected <T> void setOption(SocketOption<T> name, T value)
 123                 throws IOException {
 124             if(rdmaLibChecked && !rdmaLibInstalled)
 125                 throw new UnsupportedOperationException(
 126                         "librdmacm library is not installed!");
 127 
 128             rdmaLibChecked = true;
 129 
 130             try {
 131                 if (!rdmaOptions.isOptionSupported(name)) {
 132                     int opt;
 133                     if (name == StandardSocketOptions.SO_RCVBUF) {
 134                         opt = SocketOptions.SO_RCVBUF;
 135                     } else if (name == StandardSocketOptions.SO_REUSEADDR) {
 136                         opt = SocketOptions.SO_REUSEADDR;
 137                     } else {
 138                         throw new UnsupportedOperationException(
 139                                 "unsupported option: " + name);
 140                     }
 141                     setOption(opt, value);
 142                 } else {
 143                     rdmaOptions.setOption(fd, name, value);
 144                 }
 145                 rdmaLibInstalled = true;
 146             } catch (ExceptionInInitializerError e) {
 147                 rdmaLibInstalled = false;
 148                 throw new UnsupportedOperationException(
 149                         "librdmacm library is not installed!");
 150             }
 151         }
 152 
 153         @SuppressWarnings("unchecked")
 154         @Override
 155         protected <T> T getOption(SocketOption<T> name) throws IOException {
 156             if(rdmaLibChecked && !rdmaLibInstalled)
 157                 throw new UnsupportedOperationException(
 158                         "librdmacm library is not installed!");
 159 
 160             rdmaLibChecked = true;
 161             Object value;
 162             try {
 163                 if (!rdmaOptions.isOptionSupported(name)) {
 164                     int opt;
 165                     if (name == StandardSocketOptions.SO_RCVBUF) {
 166                         opt = SocketOptions.SO_RCVBUF;
 167                     } else if (name == StandardSocketOptions.SO_REUSEADDR) {
 168                         opt = SocketOptions.SO_REUSEADDR;
 169                     } else {
 170                         throw new UnsupportedOperationException(
 171                                 "unsupported option: " + name);
 172                     }
 173                     rdmaLibInstalled = true;
 174                     value = getOption(opt);
 175                 } else {
 176                     rdmaLibInstalled = true;
 177                     value = rdmaOptions.getOption(fd, name);
 178                 }
 179                 rdmaLibInstalled = true;
 180                 return (T) value;
 181             } catch (ExceptionInInitializerError e) {
 182                 rdmaLibInstalled = false;
 183                 throw new UnsupportedOperationException(
 184                         "librdmacm library is not installed!");
 185             }
 186         }
 187     }
 188 
 189     public static Socket openSocket() throws IOException {
 190         if(rdmaLibChecked && !rdmaLibInstalled)
 191             throw new UnsupportedOperationException(
 192                     "librdmacm library is not installed!");
 193 
 194         rdmaLibChecked = true;
 195   
 196         RdmaClientSocketImpl impl;
 197         try {
 198             impl = new RdmaClientSocketImpl();
 199             rdmaLibInstalled = true;
 200         } catch (ExceptionInInitializerError e) {
 201             rdmaLibInstalled = false;
 202             throw new UnsupportedOperationException(
 203                     "librdmacm library is not installed!");
 204         }
 205         Socket s = new Socket(impl) {
 206             private final Set<SocketOption<?>> options =
 207                     Set.of(StandardSocketOptions.SO_SNDBUF,
 208                            StandardSocketOptions.SO_RCVBUF,
 209                            StandardSocketOptions.SO_REUSEADDR,
 210                            StandardSocketOptions.TCP_NODELAY,
 211                            RdmaSocketOptions.RDMA_SQSIZE,
 212                            RdmaSocketOptions.RDMA_RQSIZE,
 213                            RdmaSocketOptions.RDMA_INLINE);
 214 
 215             @Override
 216             public Set<SocketOption<?>> supportedOptions() {
 217                 return options;
 218             }
 219         };
 220         return s;
 221     }
 222 
 223     public static ServerSocket openServerSocket() throws IOException {
 224         if(rdmaLibChecked && !rdmaLibInstalled)
 225             throw new UnsupportedOperationException(
 226                     "librdmacm library is not installed!");
 227 
 228         rdmaLibChecked = true;
 229 
 230         RdmaServerSocketImpl impl;
 231         try {
 232             impl = new RdmaServerSocketImpl();
 233             rdmaLibInstalled = true;
 234         } catch (ExceptionInInitializerError e) {
 235             rdmaLibInstalled = false;
 236             throw new UnsupportedOperationException(
 237                     "librdmacm library is not installed!");
 238         }
 239         ServerSocket ss = new ServerSocket(impl) {
 240             private final Set<SocketOption<?>> options =
 241                     Set.of(StandardSocketOptions.SO_RCVBUF,
 242                            StandardSocketOptions.SO_REUSEADDR,
 243                            RdmaSocketOptions.RDMA_SQSIZE,
 244                            RdmaSocketOptions.RDMA_RQSIZE,
 245                            RdmaSocketOptions.RDMA_INLINE);
 246 
 247             @Override
 248             public Set<SocketOption<?>> supportedOptions() {
 249                 return options;
 250             }
 251             public Socket accept() throws IOException {
 252                 if (isClosed())
 253                     throw new SocketException("Socket is closed");
 254                 if (!isBound())
 255                     throw new SocketException("Socket is not bound yet");
 256 
 257                 Socket s = openSocket();
 258                 implAccept(s);
 259                 return s;
 260             }    
 261         };
 262         return ss;
 263     }
 264 
 265     private RdmaSocketProvider() {}
 266 }