1 /*
   2  * Copyright (c) 1995, 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.IOException;
  29 import java.io.InputStream;
  30 import java.io.OutputStream;
  31 import java.io.FileDescriptor;
  32 
  33 import java.util.Set;
  34 import java.util.HashSet;
  35 import java.util.Collections;
  36 import java.net.Socket;
  37 import java.net.ServerSocket;
  38 import java.net.SocketImpl;
  39 import java.net.SocketOption;
  40 import java.net.SocketException;
  41 import java.net.UnknownHostException;
  42 import java.net.InetAddress;
  43 import java.net.SocketAddress;
  44 import java.net.InetSocketAddress;
  45 import java.net.StandardSocketOptions;
  46 import java.net.SocketOptions;
  47 import java.lang.reflect.Field;
  48 import sun.net.ConnectionResetException;
  49 import java.security.AccessController;
  50 import java.security.PrivilegedAction;
  51 import sun.net.ext.RdmaSocketOptions;
  52 
  53 public class RdmaSocketImpl extends SocketImpl
  54 {
  55     Socket socket = null;
  56     ServerSocket serverSocket = null;
  57 
  58     int timeout;   // timeout in millisec
  59 
  60     int trafficClass;
  61 
  62     private boolean shut_rd = false;
  63     private boolean shut_wr = false;
  64 
  65     private RdmaSocketInputStream socketInputStream = null;
  66     private RdmaSocketOutputStream socketOutputStream = null;
  67 
  68     /* number of threads using the FileDescriptor */
  69     protected int fdUseCount = 0;
  70 
  71     /* lock when increment/decrementing fdUseCount */
  72     protected final Object fdLock = new Object();
  73 
  74     /* indicates a close is pending on the file descriptor */
  75     protected boolean closePending = false;
  76 
  77     /* indicates connection reset state */
  78     private int CONNECTION_NOT_RESET = 0;
  79     private int CONNECTION_RESET_PENDING = 1;
  80     private int CONNECTION_RESET = 2;
  81     private int resetState;
  82     private final Object resetLock = new Object();
  83 
  84    /* whether this Socket is a stream (TCP) socket or not (UDP)
  85     */
  86     protected boolean stream;
  87 
  88     static final sun.net.ext.RdmaSocketOptions rdmaOptions =
  89             sun.net.ext.RdmaSocketOptions.getInstance();
  90 
  91     private static PlatformRdmaSocketImpl platformRdmaSocketImpl =
  92             PlatformRdmaSocketImpl.get();
  93 
  94     private static Field sCreateState;
  95     private static Field sBoundState;
  96     private static Field sConnectState;
  97     private static Field ssCreateState;
  98     private static Field ssBoundState;
  99     private static boolean socketStateSet;
 100     private static boolean serverSocketStateSet;
 101 
 102     boolean isRdmaAvailable() {
 103         return platformRdmaSocketImpl.isRdmaAvailable();
 104     }
 105 
 106     @Override
 107     protected void setSocket(Socket soc) {
 108         this.socket = soc;
 109         try {
 110             if (!socketStateSet) {
 111                 sCreateState = Socket.class.getDeclaredField("created");
 112                 sCreateState.setAccessible(true);
 113                 sBoundState = Socket.class.getDeclaredField("bound");
 114                 sBoundState.setAccessible(true);
 115                 sConnectState= Socket.class.getDeclaredField("connected");
 116                 sConnectState.setAccessible(true);
 117                 sCreateState.setBoolean(socket, false);
 118                 sBoundState.setBoolean(socket, false);
 119                 sConnectState.setBoolean(socket, false);
 120             }
 121         } catch (NoSuchFieldException | IllegalAccessException e) {
 122             throw new Error(e);
 123         }
 124         socketStateSet = true;
 125     }
 126 
 127     Socket getSocket() {
 128         return socket;
 129     }
 130 
 131     @Override
 132     protected void setServerSocket(ServerSocket soc) {
 133         this.serverSocket = soc;
 134         try {
 135             if (!serverSocketStateSet) {
 136                 ssCreateState = ServerSocket.class.getDeclaredField("created");
 137                 ssCreateState.setAccessible(true);
 138                 ssBoundState = ServerSocket.class.getDeclaredField("bound");
 139                 ssBoundState.setAccessible(true);
 140                 ssCreateState.setBoolean(serverSocket, false);
 141                 ssBoundState.setBoolean(serverSocket, false);
 142             }
 143         } catch (NoSuchFieldException | IllegalAccessException e) {
 144             throw new Error(e);
 145         }
 146         serverSocketStateSet = true;
 147     }
 148 
 149     ServerSocket getServerSocket() {
 150         return serverSocket;
 151     }
 152 
 153     private static final Set<SocketOption<?>> socketOptions;
 154 
 155     private static final Set<SocketOption<?>> serverSocketOptions;
 156 
 157     static {
 158         socketOptions = Set.of(StandardSocketOptions.SO_SNDBUF,
 159                                StandardSocketOptions.SO_RCVBUF,
 160                                StandardSocketOptions.SO_REUSEADDR,
 161                                StandardSocketOptions.SO_LINGER,
 162                                StandardSocketOptions.TCP_NODELAY);
 163 
 164         serverSocketOptions = Set.of(StandardSocketOptions.SO_RCVBUF,
 165                                      StandardSocketOptions.SO_REUSEADDR);
 166     }
 167 
 168     @Override
 169     protected Set<SocketOption<?>> supportedOptions() {
 170         Set<SocketOption<?>> options = new HashSet<>();
 171         if (socket != null)
 172             options.addAll(socketOptions);
 173         else
 174             options.addAll(serverSocketOptions);
 175 
 176         if (isRdmaAvailable()) {
 177             RdmaSocketOptions rdmaOptions =
 178                     RdmaSocketOptions.getInstance();
 179             options.addAll(rdmaOptions.options());
 180         }
 181         options = Collections.unmodifiableSet(options);
 182         return options;
 183     }
 184 
 185     protected synchronized void create(boolean stream) throws IOException {
 186         this.stream = stream;
 187         if (stream) {
 188             fd = new FileDescriptor();
 189             platformRdmaSocketImpl.rdmaSocketCreate(true, this);
 190         }
 191         try {
 192             if (socket != null) {
 193                 sCreateState.setBoolean(socket, true);
 194             }
 195             if (serverSocket != null)
 196                 ssCreateState.setBoolean(serverSocket, true);
 197         } catch (IllegalAccessException e) {
 198             throw new AssertionError(e);
 199         }
 200     }
 201 
 202     protected void connect(String host, int port)
 203         throws UnknownHostException, IOException
 204     {
 205         boolean connected = false;
 206         try {
 207             InetAddress address = InetAddress.getByName(host);
 208             this.port = port;
 209             this.address = address;
 210 
 211             connectToAddress(address, port, timeout);
 212             connected = true;
 213         } finally {
 214             if (!connected) {
 215                 try {
 216                     close();
 217                 } catch (IOException ioe) {
 218                 }
 219             }
 220         }
 221     }
 222 
 223     protected void connect(InetAddress address, int port) throws IOException {
 224         this.port = port;
 225         this.address = address;
 226 
 227         try {
 228             connectToAddress(address, port, timeout);
 229             return;
 230         } catch (IOException e) {
 231             close();
 232             throw e;
 233         }
 234     }
 235 
 236     protected void connect(SocketAddress address, int timeout)
 237             throws IOException {
 238         boolean connected = false;
 239         try {
 240             if (address == null || !(address instanceof InetSocketAddress))
 241                 throw new IllegalArgumentException("unsupported address type");
 242             InetSocketAddress addr = (InetSocketAddress) address;
 243             if (addr.isUnresolved())
 244                 throw new UnknownHostException(addr.getHostName());
 245             this.port = addr.getPort();
 246             this.address = addr.getAddress();
 247 
 248             connectToAddress(this.address, port, timeout);
 249             connected = true;
 250         } finally {
 251             if (!connected) {
 252                 try {
 253                     close();
 254                 } catch (IOException ioe) {
 255                 }
 256             }
 257         }
 258     }
 259 
 260     private void connectToAddress(InetAddress address, int port, int timeout) throws IOException {
 261         if (address.isAnyLocalAddress()) {
 262             doConnect(InetAddress.getLocalHost(), port, timeout);
 263         } else {
 264             doConnect(address, port, timeout);
 265         }
 266     }
 267 
 268     protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
 269         if (!rdmaOptions.isOptionSupported(name)) {
 270             int opt;
 271             if (name == StandardSocketOptions.SO_SNDBUF &&
 272                     socket != null) {
 273                 if (socket.isConnected())
 274                     throw new UnsupportedOperationException(
 275                             "RDMA socket cannot set SO_SNDBUF after connect.");
 276                 opt = SocketOptions.SO_SNDBUF;
 277             } else if (name == StandardSocketOptions.SO_RCVBUF) {
 278                 if (socket != null && socket.isConnected())
 279                     throw new UnsupportedOperationException(
 280                             "RDMA socket cannot set SO_RCVBUF after connect.");
 281                 if (serverSocket != null && serverSocket.isBound())
 282                     throw new UnsupportedOperationException(
 283                             "RDMA server socket cannot set SO_RCVBUF after bind.");
 284                 opt = SocketOptions.SO_RCVBUF;
 285             } else if (name == StandardSocketOptions.SO_REUSEADDR) {
 286                 opt = SocketOptions.SO_REUSEADDR;
 287             } else if (name == StandardSocketOptions.TCP_NODELAY &&
 288                     (socket != null)) {
 289                 opt = SocketOptions.TCP_NODELAY;
 290             } else if (name == StandardSocketOptions.SO_LINGER &&
 291                 (socket != null)) {
 292                 opt = SocketOptions.SO_LINGER;
 293             } else {
 294                 throw new UnsupportedOperationException("unsupported option");
 295             }
 296             setOption(opt, value);
 297         } else {
 298             rdmaOptions.setOption(fd, name, value);
 299         }
 300     }
 301 
 302     @SuppressWarnings("unchecked")
 303     protected <T> T getOption(SocketOption<T> name) throws IOException {
 304         if (!rdmaOptions.isOptionSupported(name)) {
 305             int opt;
 306             if (name == StandardSocketOptions.SO_SNDBUF &&
 307                     (socket != null)) {
 308                 opt = SocketOptions.SO_SNDBUF;
 309             } else if (name == StandardSocketOptions.SO_RCVBUF) {
 310                 opt = SocketOptions.SO_RCVBUF;
 311             } else if (name == StandardSocketOptions.SO_REUSEADDR) {
 312                 opt = SocketOptions.SO_REUSEADDR;
 313             } else if (name == StandardSocketOptions.SO_LINGER &&
 314                 (socket != null)) {
 315                 return (T)getOption(SocketOptions.SO_LINGER);
 316             } else if (name == StandardSocketOptions.TCP_NODELAY &&
 317                     (socket != null)) {
 318                 opt = SocketOptions.TCP_NODELAY;
 319             } else {
 320                 throw new UnsupportedOperationException("unsupported option");
 321             }
 322             return (T) getOption(opt);
 323         } else {
 324             return (T) rdmaOptions.getOption(fd, name);
 325         }
 326     }
 327 
 328     public void setOption(int opt, Object val) throws SocketException {
 329         if (isClosedOrPending()) {
 330             throw new SocketException("Socket Closed");
 331         }
 332         boolean on = true;
 333         switch (opt) {
 334         case SO_LINGER:
 335             if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))
 336                 throw new SocketException("Bad parameter for option");
 337             if (val instanceof Boolean) {
 338                 /* true only if disabling - enabling should be Integer */
 339                 on = false;
 340             }
 341             break;
 342         case SO_TIMEOUT:
 343             if (val == null || (!(val instanceof Integer)))
 344                 throw new SocketException("Bad parameter for SO_TIMEOUT");
 345             int tmp = ((Integer) val).intValue();
 346             if (tmp < 0)
 347                 throw new IllegalArgumentException("timeout < 0");
 348             timeout = tmp;
 349             break;
 350         case SO_BINDADDR:
 351             throw new SocketException("Cannot re-bind socket");
 352         case TCP_NODELAY:
 353             if (val == null || !(val instanceof Boolean))
 354                 throw new SocketException("bad parameter for TCP_NODELAY");
 355             on = ((Boolean)val).booleanValue();
 356             break;
 357         case SO_SNDBUF:
 358         case SO_RCVBUF:
 359             int value = ((Integer)val).intValue();
 360             int maxValue = 1024 * 1024 * 1024 - 1;   //maximum value for the buffer
 361             if (val == null || !(val instanceof Integer) ||
 362                 !(value > 0)) {
 363                 throw new SocketException("bad parameter for SO_SNDBUF " +
 364                                           "or SO_RCVBUF");
 365             }
 366             if (value >= maxValue)
 367                 value = maxValue;
 368             break;
 369         case SO_REUSEADDR:
 370             if (val == null || !(val instanceof Boolean))
 371                 throw new SocketException("bad parameter for SO_REUSEADDR");
 372             on = ((Boolean)val).booleanValue();
 373             if (serverSocket != null && serverSocket.isBound())
 374                     throw new UnsupportedOperationException(
 375                             "RDMA server socket cannot set " +
 376                             "SO_REUSEADDR after bind.");
 377             if (socket != null && socket.isConnected())
 378                     throw new UnsupportedOperationException(
 379                             "RDMA socket cannot set " +
 380                             "SO_REUSEADDR after connect.");
 381             break;
 382         default:
 383             throw new SocketException("unrecognized TCP option: " + opt);
 384         }
 385         socketSetOption(opt, on, val);
 386     }
 387 
 388     public Object getOption(int opt) throws SocketException {
 389         if (isClosedOrPending()) {
 390             throw new SocketException("Socket Closed");
 391         }
 392         if (opt == SO_TIMEOUT) {
 393             return timeout;
 394         }
 395         int ret = 0;
 396 
 397         switch (opt) {
 398         case TCP_NODELAY:
 399             ret = platformRdmaSocketImpl.rdmaSocketGetOption(this, opt, null);
 400             return Boolean.valueOf(ret != -1);
 401         case SO_LINGER:
 402             ret = platformRdmaSocketImpl.rdmaSocketGetOption(this, opt, null);
 403             return (ret == -1) ? Boolean.FALSE: (Object)(ret);
 404         case SO_REUSEADDR:
 405             ret = platformRdmaSocketImpl.rdmaSocketGetOption(this, opt, null);
 406             return Boolean.valueOf(ret != -1);
 407         case SO_BINDADDR:
 408             RdmaInetAddressContainer in = new RdmaInetAddressContainer();
 409             ret = platformRdmaSocketImpl.rdmaSocketGetOption(this, opt, in);
 410             return in.addr;
 411         case SO_SNDBUF:
 412         case SO_RCVBUF:
 413             ret = platformRdmaSocketImpl.rdmaSocketGetOption(this, opt, null);
 414             return ret;
 415         default:
 416             return null;
 417         }
 418     }
 419 
 420     protected void socketSetOption(int opt, boolean b, Object val) throws SocketException {
 421         if (opt == SocketOptions.SO_REUSEPORT &&
 422             !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
 423             throw new UnsupportedOperationException("unsupported option");
 424         }
 425         try {
 426             platformRdmaSocketImpl.rdmaSocketSetOption(this, opt, b, val);
 427         } catch (SocketException se) {
 428             if (socket == null || !socket.isConnected())
 429                 throw se;
 430         }
 431     }
 432 
 433     synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
 434         try {
 435             acquireFD();
 436             try {
 437                 platformRdmaSocketImpl.rdmaSocketConnect(this, address, port, timeout);
 438                 synchronized (fdLock) {
 439                     if (closePending) {
 440                         throw new SocketException ("Socket closed");
 441                     }
 442                 }
 443                 try {
 444                     if (socket != null) {
 445                         sBoundState.setBoolean(socket, true);
 446                         sConnectState.setBoolean(socket, true);
 447                     }
 448                 } catch (IllegalAccessException e) {
 449                     throw new AssertionError(e);
 450                 }
 451             } finally {
 452                 releaseFD();
 453             }
 454         } catch (IOException e) {
 455             close();
 456             throw e;
 457         }
 458     }
 459 
 460     protected synchronized void bind(InetAddress address, int lport)
 461         throws IOException
 462     {
 463         platformRdmaSocketImpl.rdmaSocketBind(this, address, lport);
 464         try {
 465             if (socket != null)
 466                 sBoundState.setBoolean(socket, true);
 467             if (serverSocket != null)
 468                 ssBoundState.setBoolean(serverSocket, true);
 469         } catch (IllegalAccessException e) {
 470             throw new AssertionError(e);
 471         }
 472     }
 473 
 474     protected synchronized void listen(int count) throws IOException {
 475         platformRdmaSocketImpl.rdmaSocketListen(this, count);
 476     }
 477 
 478     protected void accept(SocketImpl s) throws IOException {
 479         acquireFD();
 480         try {
 481             platformRdmaSocketImpl.rdmaSocketAccept(s, this);
 482         } finally {
 483             releaseFD();
 484         }
 485     }
 486 
 487     protected synchronized InputStream getInputStream() throws IOException {
 488         synchronized (fdLock) {
 489             if (isClosedOrPending())
 490                 throw new IOException("Socket Closed");
 491             if (shut_rd)
 492                 throw new IOException("Socket input is shutdown");
 493             if (socketInputStream == null)
 494                 socketInputStream = new RdmaSocketInputStream(this);
 495         }
 496         return socketInputStream;
 497     }
 498 
 499     void setInputStream(RdmaSocketInputStream in) {
 500         socketInputStream = in;
 501     }
 502 
 503     protected synchronized OutputStream getOutputStream() throws IOException {
 504         synchronized (fdLock) {
 505             if (isClosedOrPending())
 506                 throw new IOException("Socket Closed");
 507             if (shut_wr)
 508                 throw new IOException("Socket output is shutdown");
 509             if (socketOutputStream == null)
 510                 socketOutputStream = new RdmaSocketOutputStream(this);
 511         }
 512         return socketOutputStream;
 513     }
 514 
 515     protected FileDescriptor getFileDescriptor() {
 516         return fd;
 517     }
 518 
 519     protected void setFileDescriptor(FileDescriptor fd) {
 520         this.fd = fd;
 521     }
 522 
 523     protected void setAddress(InetAddress address) {
 524         this.address = address;
 525     }
 526 
 527     void setPort(int port) {
 528         this.port = port;
 529     }
 530 
 531     void setLocalPort(int localport) {
 532         this.localport = localport;
 533     }
 534 
 535     protected synchronized int available() throws IOException {
 536         if (isClosedOrPending()) {
 537             throw new IOException("Stream closed.");
 538         }
 539 
 540         if (isConnectionReset() || shut_rd) {
 541             return 0;
 542         }
 543 
 544         int n = 0;
 545         try {
 546             n = platformRdmaSocketImpl.rdmaSocketAvailable(this);
 547             if (n == 0 && isConnectionResetPending()) {
 548                 setConnectionReset();
 549             }
 550         } catch (ConnectionResetException exc1) {
 551             setConnectionResetPending();
 552             try {
 553                 n = platformRdmaSocketImpl.rdmaSocketAvailable(this);
 554                 if (n == 0) {
 555                     setConnectionReset();
 556                 }
 557             } catch (ConnectionResetException exc2) {
 558             }
 559         }
 560         return n;
 561     }
 562 
 563     protected void close() throws IOException {
 564         synchronized(fdLock) {
 565             if (fd != null) {
 566                 if (fdUseCount == 0) {
 567                     if (closePending) {
 568                         return;
 569                     }
 570                     closePending = true;
 571                     try {
 572                         platformRdmaSocketImpl.rdmaSocketClose(true, this);
 573                     } finally {
 574                         platformRdmaSocketImpl.rdmaSocketClose(false, this);
 575                     }
 576                     fd = null;
 577                     return;
 578                 } else {
 579                     if (!closePending) {
 580                         closePending = true;
 581                         fdUseCount--;
 582                         platformRdmaSocketImpl.rdmaSocketClose(true, this);
 583                     }
 584                 }
 585             }
 586         }
 587     }
 588 
 589     void reset() throws IOException {
 590         if (fd != null) {
 591             platformRdmaSocketImpl.rdmaSocketClose(false, this);
 592         }
 593         fd = null;
 594         postReset();
 595     }
 596 
 597     void postReset() throws IOException {
 598         address = null;
 599         port = 0;
 600         localport = 0;
 601     }
 602 
 603     protected void shutdownInput() throws IOException {
 604       if (fd != null) {
 605           platformRdmaSocketImpl.rdmaSocketShutdown(SHUT_RD, this);
 606           if (socketInputStream != null) {
 607               socketInputStream.setEOF(true);
 608           }
 609           shut_rd = true;
 610       }
 611     }
 612 
 613     protected void shutdownOutput() throws IOException {
 614       if (fd != null) {
 615           platformRdmaSocketImpl.rdmaSocketShutdown(SHUT_WR, this);
 616           shut_wr = true;
 617       }
 618     }
 619 
 620     protected boolean supportsUrgentData () {
 621         return true;
 622     }
 623 
 624     protected void sendUrgentData (int data) throws IOException {
 625         if (fd == null) {
 626             throw new IOException("Socket Closed");
 627         }
 628         platformRdmaSocketImpl.rdmaSocketSendUrgentData(this, data);
 629     }
 630 
 631     FileDescriptor acquireFD() {
 632         synchronized (fdLock) {
 633             fdUseCount++;
 634             return fd;
 635         }
 636     }
 637 
 638     void releaseFD() {
 639         synchronized (fdLock) {
 640             fdUseCount--;
 641             if (fdUseCount == -1) {
 642                 if (fd != null) {
 643                     try {
 644                         platformRdmaSocketImpl.rdmaSocketClose(false, this);
 645                     } catch (IOException e) {
 646                     } finally {
 647                         fd = null;
 648                     }
 649                 }
 650             }
 651         }
 652     }
 653 
 654     public boolean isConnectionReset() {
 655         synchronized (resetLock) {
 656             return (resetState == CONNECTION_RESET);
 657         }
 658     }
 659 
 660     public boolean isConnectionResetPending() {
 661         synchronized (resetLock) {
 662             return (resetState == CONNECTION_RESET_PENDING);
 663         }
 664     }
 665 
 666     public void setConnectionReset() {
 667         synchronized (resetLock) {
 668             resetState = CONNECTION_RESET;
 669         }
 670     }
 671 
 672     public void setConnectionResetPending() {
 673         synchronized (resetLock) {
 674             if (resetState == CONNECTION_NOT_RESET) {
 675                 resetState = CONNECTION_RESET_PENDING;
 676             }
 677         }
 678 
 679     }
 680 
 681     public boolean isClosedOrPending() {
 682         synchronized (fdLock) {
 683             if (closePending || (fd == null)) {
 684                 return true;
 685             } else {
 686                 return false;
 687             }
 688         }
 689     }
 690 
 691     public int getTimeout() {
 692         return timeout;
 693     }
 694 
 695     protected InetAddress getInetAddress() {
 696         return address;
 697     }
 698 
 699     protected int getPort() {
 700         return port;
 701     }
 702 
 703     protected int getLocalPort() {
 704         return localport;
 705     }
 706 
 707     public static final int SHUT_RD = 0;
 708     public static final int SHUT_WR = 1;
 709 
 710     static class PlatformRdmaSocketImpl {
 711 
 712         @SuppressWarnings("unchecked")
 713         private static PlatformRdmaSocketImpl newInstance(String cn) {
 714             Class<PlatformRdmaSocketImpl> c;
 715             try {
 716                 c = (Class<PlatformRdmaSocketImpl>)Class.forName(cn);
 717                 return c.getConstructor(new Class<?>[] {}).newInstance();
 718             } catch (ReflectiveOperationException x) {
 719                 throw new AssertionError(x);
 720             }
 721         }
 722 
 723         private static PlatformRdmaSocketImpl create() {
 724             String osname = AccessController.doPrivileged(
 725                     new PrivilegedAction<String>() {
 726                         public String run() {
 727                             return System.getProperty("os.name");
 728                         }
 729                     });
 730             if ("Linux".equals(osname))
 731                 return newInstance("rdma.ch.LinuxRdmaSocketImpl");
 732             return new PlatformRdmaSocketImpl();
 733         }
 734 
 735         private static final PlatformRdmaSocketImpl instance = create();
 736 
 737         static PlatformRdmaSocketImpl get() {
 738             return instance;
 739         }
 740 
 741         boolean isRdmaAvailable() {
 742             return false;
 743         }
 744 
 745         void rdmaSocketClose(boolean useDeferredClose, RdmaSocketImpl impl) throws IOException {
 746             throw new UnsupportedOperationException("unsupported socket option");
 747         }
 748 
 749         void rdmaSocketCreate(boolean isServer, RdmaSocketImpl impl) throws IOException {
 750             throw new UnsupportedOperationException("unsupported socket option");
 751         }
 752 
 753         void rdmaSocketConnect(RdmaSocketImpl impl, InetAddress address, int port, int timeout)
 754             throws IOException {
 755             throw new UnsupportedOperationException("unsupported socket option");
 756         }
 757 
 758         void rdmaSocketBind(RdmaSocketImpl impl, InetAddress address, int port)
 759             throws IOException {
 760             throw new UnsupportedOperationException("unsupported socket option");
 761         }
 762 
 763         void rdmaSocketListen(RdmaSocketImpl impl, int count)
 764             throws IOException {
 765             throw new UnsupportedOperationException("unsupported socket option");
 766         }
 767 
 768         void rdmaSocketAccept(SocketImpl s, RdmaSocketImpl impl)
 769             throws IOException {
 770             throw new UnsupportedOperationException("unsupported socket option");
 771         }
 772 
 773         int rdmaSocketAvailable(RdmaSocketImpl impl)
 774             throws IOException {
 775             throw new UnsupportedOperationException("unsupported socket option");
 776         }
 777 
 778         void rdmaSocketShutdown(int howto, RdmaSocketImpl impl)
 779             throws IOException {
 780             throw new UnsupportedOperationException("unsupported socket option");
 781         }
 782 
 783         void rdmaSocketSetOption(RdmaSocketImpl impl, int cmd, boolean on, Object value)
 784             throws SocketException {
 785             throw new UnsupportedOperationException("unsupported socket option");
 786         }
 787 
 788         int rdmaSocketGetOption(RdmaSocketImpl impl, int opt, Object iaContainerObj)
 789             throws SocketException {
 790             throw new UnsupportedOperationException("unsupported socket option");
 791         }
 792 
 793         void rdmaSocketSendUrgentData(RdmaSocketImpl impl, int data)
 794             throws IOException {
 795             throw new UnsupportedOperationException("unsupported socket option");
 796         }
 797     }
 798 }