src/jdk.net/linux/classes/jdk/internal/net/rdma/RdmaSocketImpl.java
branchrsocket-branch
changeset 57115 512e7cc6ccce
child 57156 81e4a12fd1a4
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.internal.net.rdma;
       
    27 
       
    28 import java.io.FileDescriptor;
       
    29 import java.io.IOException;
       
    30 import java.io.InputStream;
       
    31 import java.io.OutputStream;
       
    32 import java.net.Inet4Address;
       
    33 import java.net.Inet6Address;
       
    34 import java.net.InetAddress;
       
    35 import java.net.InetSocketAddress;
       
    36 import java.net.ProtocolFamily;
       
    37 import java.net.ServerSocket;
       
    38 import java.net.Socket;
       
    39 import java.net.SocketAddress;
       
    40 import java.net.SocketException;
       
    41 import java.net.SocketImpl;
       
    42 import java.net.SocketOption;
       
    43 import java.net.SocketOptions;
       
    44 import java.net.StandardSocketOptions;
       
    45 import java.net.UnknownHostException;
       
    46 import java.util.Objects;
       
    47 import java.util.Set;
       
    48 import sun.nio.ch.Net;
       
    49 import static java.net.StandardProtocolFamily.INET;
       
    50 import static java.net.StandardProtocolFamily.INET6;
       
    51 
       
    52 public abstract class RdmaSocketImpl extends SocketImpl
       
    53 {
       
    54     private ProtocolFamily family;
       
    55 
       
    56     Socket socket = null;
       
    57     ServerSocket serverSocket = null;
       
    58 
       
    59     int timeout;   // timeout in millisec
       
    60 
       
    61     int trafficClass;
       
    62 
       
    63     InputStream socketInputStream;
       
    64     OutputStream socketOutputStream;
       
    65 
       
    66     private boolean shut_rd = false;
       
    67     private boolean shut_wr = false;
       
    68 
       
    69     /* number of threads using the FileDescriptor */
       
    70     protected int fdUseCount = 0;
       
    71 
       
    72     /* lock when increment/decrementing fdUseCount */
       
    73     protected final Object fdLock = new Object();
       
    74 
       
    75     /* indicates a close is pending on the file descriptor */
       
    76     protected boolean closePending = false;
       
    77 
       
    78     /* indicates connection reset state */
       
    79     private int CONNECTION_NOT_RESET = 0;
       
    80     private int CONNECTION_RESET_PENDING = 1;
       
    81     private int CONNECTION_RESET = 2;
       
    82     private int resetState;
       
    83     private final Object resetLock = new Object();
       
    84 
       
    85     protected boolean stream;
       
    86 
       
    87     private static UnsupportedOperationException unsupported;
       
    88 
       
    89     static final sun.net.ext.RdmaSocketOptions rdmaOptions =
       
    90             sun.net.ext.RdmaSocketOptions.getInstance();
       
    91 
       
    92     static {
       
    93         java.security.AccessController.doPrivileged(
       
    94             new java.security.PrivilegedAction<>() {
       
    95                 public Void run() {
       
    96                     System.loadLibrary("net");
       
    97                     System.loadLibrary("extnet");
       
    98                     return null;
       
    99                 }
       
   100             });
       
   101         UnsupportedOperationException uoe = null;
       
   102         try {
       
   103             initProto();
       
   104         } catch (UnsupportedOperationException e) {
       
   105             uoe = e;
       
   106         }
       
   107         unsupported = uoe;
       
   108     }
       
   109 
       
   110     private static final Void checkSupported() {
       
   111         if (unsupported != null) {
       
   112             Exception e = unsupported;
       
   113             throw new UnsupportedOperationException(e.getMessage(), e);
       
   114         } else {
       
   115             return null;
       
   116         }
       
   117     }
       
   118 
       
   119     public RdmaSocketImpl(ProtocolFamily family) {
       
   120         this(checkSupported(), family);
       
   121     }
       
   122 
       
   123     private RdmaSocketImpl(Void unused, ProtocolFamily family) {
       
   124         Objects.requireNonNull(family, "null family");
       
   125         if (!(family == INET || family == INET6)) {
       
   126             throw new UnsupportedOperationException("Protocol family not supported");
       
   127         }
       
   128         if (family == INET6) {
       
   129             if (!Net.isIPv6Available()) {
       
   130                 throw new UnsupportedOperationException(
       
   131                         "IPv6 not available");
       
   132             }
       
   133         }
       
   134         this.family = family;
       
   135     }
       
   136 
       
   137     private static volatile boolean checkedRdma;
       
   138     private static volatile boolean isRdmaAvailable;
       
   139 
       
   140     boolean isRdmaAvailable() {
       
   141         if (!checkedRdma) {
       
   142             isRdmaAvailable = isRdmaAvailable0();
       
   143             checkedRdma = true;
       
   144         }
       
   145         return isRdmaAvailable;
       
   146     }
       
   147 
       
   148     void setSocket(Socket soc) {
       
   149         this.socket = soc;
       
   150     }
       
   151 
       
   152     Socket getSocket() {
       
   153         return socket;
       
   154     }
       
   155 
       
   156     void setServerSocket(ServerSocket soc) {
       
   157         this.serverSocket = soc;
       
   158     }
       
   159 
       
   160     ServerSocket getServerSocket() {
       
   161         return serverSocket;
       
   162     }
       
   163 
       
   164     @Override
       
   165     protected abstract Set<SocketOption<?>> supportedOptions();
       
   166 
       
   167     protected synchronized void create(boolean stream) throws IOException {
       
   168         this.stream = stream;
       
   169         if (stream) {
       
   170             fd = new FileDescriptor();
       
   171 
       
   172             boolean preferIPv6 = Net.isIPv6Available() && (family != INET);
       
   173             rdmaSocketCreate(preferIPv6, true);
       
   174         }
       
   175     }
       
   176 
       
   177     protected void connect(String host, int port)
       
   178             throws UnknownHostException, IOException {
       
   179         boolean connected = false;
       
   180         try {
       
   181             InetAddress address = InetAddress.getByName(host);
       
   182             this.port = port;
       
   183             this.address = address;
       
   184 
       
   185             connectToAddress(address, port, timeout);
       
   186             connected = true;
       
   187         } finally {
       
   188             if (!connected) {
       
   189                 try {
       
   190                     close();
       
   191                 } catch (IOException ioe) {
       
   192                 }
       
   193             }
       
   194         }
       
   195     }
       
   196 
       
   197     protected void connect(InetAddress address, int port) throws IOException {
       
   198         if (family == INET && !(address instanceof Inet4Address))
       
   199                 throw new IllegalArgumentException("address type mismatch");
       
   200         if (family == INET6 && !(address instanceof Inet6Address))
       
   201                 throw new IllegalArgumentException("address type mismatch");
       
   202 
       
   203         this.port = port;
       
   204         this.address = address;
       
   205         try {
       
   206             connectToAddress(address, port, timeout);
       
   207             return;
       
   208         } catch (IOException e) {
       
   209             close();
       
   210             throw e;
       
   211         }
       
   212     }
       
   213 
       
   214     protected void connect(SocketAddress address, int timeout)
       
   215             throws IOException {
       
   216         boolean connected = false;
       
   217         try {
       
   218             if (address == null || !(address instanceof InetSocketAddress))
       
   219                 throw new IllegalArgumentException("unsupported address type");
       
   220             InetSocketAddress addr = (InetSocketAddress) address;
       
   221             InetAddress ia = addr.getAddress();
       
   222             if (family == INET && !(ia instanceof Inet4Address))
       
   223                 throw new IllegalArgumentException("address type mismatch");
       
   224             if (family == INET6 && !(ia instanceof Inet6Address))
       
   225                 throw new IllegalArgumentException("address type mismatch");
       
   226             if (addr.isUnresolved())
       
   227                 throw new UnknownHostException(addr.getHostName());
       
   228             this.port = addr.getPort();
       
   229             this.address = addr.getAddress();
       
   230 
       
   231             connectToAddress(this.address, port, timeout);
       
   232             connected = true;
       
   233         } finally {
       
   234             if (!connected) {
       
   235                 try {
       
   236                     close();
       
   237                 } catch (IOException ioe) {
       
   238                 }
       
   239             }
       
   240         }
       
   241     }
       
   242 
       
   243     private void connectToAddress(InetAddress address, int port, int timeout)
       
   244             throws IOException {
       
   245         if (address.isAnyLocalAddress()) {
       
   246             doConnect(InetAddress.getLocalHost(), port, timeout);
       
   247         } else {
       
   248             doConnect(address, port, timeout);
       
   249         }
       
   250     }
       
   251 
       
   252     @Override
       
   253     protected abstract <T> void setOption(SocketOption<T> name, T value)
       
   254             throws IOException;
       
   255 
       
   256     @SuppressWarnings("unchecked")
       
   257     @Override
       
   258     protected abstract <T> T getOption(SocketOption<T> name)
       
   259             throws IOException;
       
   260 
       
   261     public void setOption(int opt, Object val) throws SocketException {
       
   262         if (isClosedOrPending()) {
       
   263             throw new SocketException("Socket Closed");
       
   264         }
       
   265         boolean on = true;
       
   266         switch (opt) {
       
   267         case SO_TIMEOUT:
       
   268             if (val == null || (!(val instanceof Integer)))
       
   269                 throw new SocketException("Bad parameter for SO_TIMEOUT");
       
   270             int tmp = ((Integer) val).intValue();
       
   271             if (tmp < 0)
       
   272                 throw new IllegalArgumentException("timeout < 0");
       
   273             timeout = tmp;
       
   274             break;
       
   275         case SO_BINDADDR:
       
   276             throw new SocketException("Cannot re-bind socket");
       
   277         case TCP_NODELAY:
       
   278             if (val == null || !(val instanceof Boolean))
       
   279                 throw new SocketException("bad parameter for TCP_NODELAY");
       
   280             on = ((Boolean)val).booleanValue();
       
   281             break;
       
   282         case SO_SNDBUF:
       
   283         case SO_RCVBUF:
       
   284             int value = ((Integer)val).intValue();
       
   285             int maxValue = 1024 * 1024 * 1024 - 1;   //maximum value for the buffer
       
   286             if (val == null || !(val instanceof Integer) ||
       
   287                 !(value > 0)) {
       
   288                 throw new SocketException("bad parameter for SO_SNDBUF " +
       
   289                                           "or SO_RCVBUF");
       
   290             }
       
   291             if (value >= maxValue)
       
   292                 value = maxValue;
       
   293             break;
       
   294         case SO_REUSEADDR:
       
   295             if (val == null || !(val instanceof Boolean))
       
   296                 throw new SocketException("bad parameter for SO_REUSEADDR");
       
   297             on = ((Boolean)val).booleanValue();
       
   298             if (serverSocket != null && serverSocket.isBound())
       
   299                     throw new UnsupportedOperationException(
       
   300                             "RDMA server socket cannot set " +
       
   301                             "SO_REUSEADDR after bind.");
       
   302             if (socket != null && socket.isConnected())
       
   303                     throw new UnsupportedOperationException(
       
   304                             "RDMA socket cannot set " +
       
   305                             "SO_REUSEADDR after connect.");
       
   306             break;
       
   307         default:
       
   308             throw new SocketException("unrecognized TCP option: " + opt);
       
   309         }
       
   310         socketSetOption(opt, on, val);
       
   311     }
       
   312 
       
   313     public Object getOption(int opt) throws SocketException {
       
   314         if (isClosedOrPending()) {
       
   315             throw new SocketException("Socket Closed");
       
   316         }
       
   317         if (opt == SO_TIMEOUT) {
       
   318             return timeout;
       
   319         }
       
   320         int ret = 0;
       
   321 
       
   322         switch (opt) {
       
   323         case TCP_NODELAY:
       
   324             ret = rdmaSocketGetOption(opt, null);
       
   325             return Boolean.valueOf(ret != -1);
       
   326         case SO_REUSEADDR:
       
   327             ret = rdmaSocketGetOption(opt, null);
       
   328             return Boolean.valueOf(ret != -1);
       
   329         case SO_BINDADDR:
       
   330             RdmaInetAddressContainer in = new RdmaInetAddressContainer();
       
   331             ret = rdmaSocketGetOption(opt, in);
       
   332             return in.addr;
       
   333         case SO_SNDBUF:
       
   334         case SO_RCVBUF:
       
   335             ret = rdmaSocketGetOption(opt, null);
       
   336             return ret;
       
   337         default:
       
   338             return null;
       
   339         }
       
   340     }
       
   341 
       
   342     protected void socketSetOption(int opt, boolean b, Object val)
       
   343             throws SocketException {
       
   344         if (opt == SocketOptions.SO_REUSEPORT &&
       
   345             !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
       
   346             throw new UnsupportedOperationException("unsupported option");
       
   347         }
       
   348         try {
       
   349             rdmaSocketSetOption(opt, b, val);
       
   350         } catch (SocketException se) {
       
   351             if (socket == null || !socket.isConnected())
       
   352                 throw se;
       
   353         }
       
   354     }
       
   355 
       
   356     synchronized void doConnect(InetAddress address, int port, int timeout)
       
   357             throws IOException {
       
   358         try {
       
   359             acquireFD();
       
   360             boolean preferIPv6 = Net.isIPv6Available() && (family != INET);
       
   361             try {
       
   362                 rdmaSocketConnect(preferIPv6, address, port, timeout);
       
   363                 synchronized (fdLock) {
       
   364                     if (closePending) {
       
   365                         throw new SocketException ("Socket closed");
       
   366                     }
       
   367                 }
       
   368             } finally {
       
   369                 releaseFD();
       
   370             }
       
   371         } catch (IOException e) {
       
   372             close();
       
   373             throw e;
       
   374         }
       
   375     }
       
   376 
       
   377     private final InetAddress anyLocalAddress() throws IOException {
       
   378         if (family == INET)
       
   379             return InetAddress.getByName("0.0.0.0");
       
   380         else if (family == INET6)
       
   381             return InetAddress.getByName("::");
       
   382         else
       
   383             throw new IllegalArgumentException("Unsupported address type " + family);
       
   384     }
       
   385 
       
   386     protected synchronized void bind(InetAddress address, int lport)
       
   387             throws IOException {
       
   388         if (address == null)
       
   389             throw new IllegalArgumentException("address is null");
       
   390 
       
   391         if (address.isAnyLocalAddress())
       
   392             address = anyLocalAddress();
       
   393 
       
   394         if (family == INET && !(address instanceof Inet4Address))
       
   395             throw new IllegalArgumentException("address type mismatch");
       
   396         if (family == INET6 && !(address instanceof Inet6Address))
       
   397             throw new IllegalArgumentException("address type mismatch");
       
   398         boolean preferIPv6 = Net.isIPv6Available() && (family != INET);
       
   399         rdmaSocketBind(preferIPv6, address, lport);
       
   400     }
       
   401 
       
   402     protected synchronized void listen(int count) throws IOException {
       
   403         rdmaSocketListen(count);
       
   404     }
       
   405 
       
   406     protected void accept(SocketImpl s) throws IOException {
       
   407         acquireFD();
       
   408         try {
       
   409             rdmaSocketAccept(s);
       
   410         } finally {
       
   411             releaseFD();
       
   412         }
       
   413     }
       
   414 
       
   415     protected synchronized InputStream getInputStream() throws IOException {
       
   416         synchronized (fdLock) {
       
   417             if (isClosedOrPending())
       
   418                 throw new IOException("Socket Closed");
       
   419             if (shut_rd)
       
   420                 throw new IOException("Socket input is shutdown");
       
   421             if (socketInputStream == null)
       
   422                 socketInputStream = new RdmaSocketInputStream(this);
       
   423         }
       
   424         return socketInputStream;
       
   425     }
       
   426 
       
   427     protected synchronized OutputStream getOutputStream() throws IOException {
       
   428         synchronized (fdLock) {
       
   429             if (isClosedOrPending())
       
   430                 throw new IOException("Socket Closed");
       
   431             if (shut_wr)
       
   432                 throw new IOException("Socket output is shutdown");
       
   433             if (socketOutputStream == null)
       
   434                 socketOutputStream = new RdmaSocketOutputStream(this);
       
   435         }
       
   436         return socketOutputStream;
       
   437     }
       
   438 
       
   439     protected FileDescriptor getFileDescriptor() {
       
   440         return fd;
       
   441     }
       
   442 
       
   443     protected void setFileDescriptor(FileDescriptor fd) {
       
   444         this.fd = fd;
       
   445     }
       
   446 
       
   447     protected void setAddress(InetAddress address) {
       
   448         this.address = address;
       
   449     }
       
   450 
       
   451     void setPort(int port) {
       
   452         this.port = port;
       
   453     }
       
   454 
       
   455     void setLocalPort(int localport) {
       
   456         this.localport = localport;
       
   457     }
       
   458 
       
   459     protected synchronized int available() throws IOException {
       
   460         throw new UnsupportedOperationException(
       
   461                 "unsupported socket operation");
       
   462     }
       
   463 
       
   464     protected void close() throws IOException {
       
   465         synchronized(fdLock) {
       
   466             if (fd != null) {
       
   467                 if (fdUseCount == 0) {
       
   468                     if (closePending) {
       
   469                         return;
       
   470                     }
       
   471                     closePending = true;
       
   472                     rdmaSocketClose();
       
   473                     fd = null;
       
   474                     return;
       
   475                 } else {
       
   476                     if (!closePending) {
       
   477                         closePending = true;
       
   478                         fdUseCount--;
       
   479                         rdmaSocketClose();
       
   480                     }
       
   481                 }
       
   482             }
       
   483         }
       
   484     }
       
   485 
       
   486     void reset() throws IOException {
       
   487         if (fd != null) {
       
   488             rdmaSocketClose();
       
   489         }
       
   490         fd = null;
       
   491         postReset();
       
   492     }
       
   493 
       
   494     void postReset() throws IOException {
       
   495         address = null;
       
   496         port = 0;
       
   497         localport = 0;
       
   498     }
       
   499 
       
   500     protected void shutdownInput() throws IOException {
       
   501         if (fd != null) {
       
   502             rdmaSocketShutdown(SHUT_RD);
       
   503             if (socketInputStream != null) {
       
   504                 ((RdmaSocketInputStream)socketInputStream).setEOF(true);
       
   505             }
       
   506             shut_rd = true;
       
   507         }
       
   508     }
       
   509 
       
   510     protected void shutdownOutput() throws IOException {
       
   511         if (fd != null) {
       
   512             rdmaSocketShutdown(SHUT_WR);
       
   513             shut_wr = true;
       
   514         }
       
   515     }
       
   516 
       
   517     protected boolean supportsUrgentData () {
       
   518         return true;
       
   519     }
       
   520 
       
   521     protected void sendUrgentData (int data) throws IOException {
       
   522         if (fd == null) {
       
   523             throw new IOException("Socket Closed");
       
   524         }
       
   525         rdmaSocketSendUrgentData(data);
       
   526     }
       
   527 
       
   528     FileDescriptor acquireFD() {
       
   529         synchronized (fdLock) {
       
   530             fdUseCount++;
       
   531             return fd;
       
   532         }
       
   533     }
       
   534 
       
   535     void releaseFD() {
       
   536         synchronized (fdLock) {
       
   537             fdUseCount--;
       
   538             if (fdUseCount == -1) {
       
   539                 if (fd != null) {
       
   540                     try {
       
   541                         rdmaSocketClose();
       
   542                     } catch (IOException e) {
       
   543                     } finally {
       
   544                         fd = null;
       
   545                     }
       
   546                 }
       
   547             }
       
   548         }
       
   549     }
       
   550 
       
   551     public boolean isConnectionReset() {
       
   552         synchronized (resetLock) {
       
   553             return (resetState == CONNECTION_RESET);
       
   554         }
       
   555     }
       
   556 
       
   557     public boolean isConnectionResetPending() {
       
   558         synchronized (resetLock) {
       
   559             return (resetState == CONNECTION_RESET_PENDING);
       
   560         }
       
   561     }
       
   562 
       
   563     public void setConnectionReset() {
       
   564         synchronized (resetLock) {
       
   565             resetState = CONNECTION_RESET;
       
   566         }
       
   567     }
       
   568 
       
   569     public void setConnectionResetPending() {
       
   570         synchronized (resetLock) {
       
   571             if (resetState == CONNECTION_NOT_RESET) {
       
   572                 resetState = CONNECTION_RESET_PENDING;
       
   573             }
       
   574         }
       
   575 
       
   576     }
       
   577 
       
   578     public boolean isClosedOrPending() {
       
   579         synchronized (fdLock) {
       
   580             if (closePending || (fd == null)) {
       
   581                 return true;
       
   582             } else {
       
   583                 return false;
       
   584             }
       
   585         }
       
   586     }
       
   587 
       
   588     public int getTimeout() {
       
   589         return timeout;
       
   590     }
       
   591 
       
   592     protected InetAddress getInetAddress() {
       
   593         return address;
       
   594     }
       
   595 
       
   596     protected int getPort() {
       
   597         return port;
       
   598     }
       
   599 
       
   600     protected int getLocalPort() {
       
   601         return localport;
       
   602     }
       
   603 
       
   604     public static final int SHUT_RD = 0;
       
   605     public static final int SHUT_WR = 1;
       
   606 
       
   607     static native void initProto() throws UnsupportedOperationException;
       
   608 
       
   609     private static native boolean isRdmaAvailable0();
       
   610 
       
   611     native void rdmaSocketCreate(boolean preferIPv6, boolean isServer)
       
   612             throws IOException;
       
   613 
       
   614     native void rdmaSocketConnect(boolean preferIPv6, InetAddress address,
       
   615             int port, int timeout) throws IOException;
       
   616 
       
   617     native void rdmaSocketBind(boolean preferIPv6, InetAddress address,
       
   618             int port) throws IOException;
       
   619 
       
   620     native void rdmaSocketListen(int count) throws IOException;
       
   621 
       
   622     native void rdmaSocketAccept(SocketImpl s) throws IOException;
       
   623 
       
   624     native void rdmaSocketClose() throws IOException;
       
   625 
       
   626     native void rdmaSocketShutdown(int howto) throws IOException;
       
   627 
       
   628     native void rdmaSocketSetOption(int cmd, boolean on, Object value)
       
   629             throws SocketException;
       
   630 
       
   631     native int rdmaSocketGetOption(int opt, Object iaContainerObj)
       
   632             throws SocketException;
       
   633 
       
   634     native void rdmaSocketSendUrgentData(int data) throws IOException;
       
   635 }