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.InetAddress;
  30 import java.net.InetSocketAddress;
  31 import java.net.ServerSocket;
  32 import java.net.Socket;
  33 import java.net.SocketAddress;
  34 import java.net.SocketException;
  35 import java.net.SocketTimeoutException;
  36 import java.net.StandardSocketOptions;
  37 import java.nio.channels.IllegalBlockingModeException;
  38 import java.nio.channels.NotYetBoundException;
  39 import java.nio.channels.ServerSocketChannel;
  40 import java.nio.channels.SocketChannel;
  41 import sun.nio.ch.Net;
  42 
  43 class RdmaServerSocketAdaptor
  44     extends ServerSocket
  45 {
  46     private final RdmaServerSocketChannelImpl ssc;
  47 
  48     private volatile int timeout;
  49 
  50     public static ServerSocket create(RdmaServerSocketChannelImpl ssc) {
  51         try {
  52             return new RdmaServerSocketAdaptor(ssc);
  53         } catch (IOException x) {
  54             throw new Error(x);
  55         }
  56     }
  57 
  58     private RdmaServerSocketAdaptor(RdmaServerSocketChannelImpl ssc)
  59             throws IOException {
  60         this.ssc = ssc;
  61     }
  62 
  63     public void bind(SocketAddress local) throws IOException {
  64         bind(local, 50);
  65     }
  66 
  67     public void bind(SocketAddress local, int backlog) throws IOException {
  68         if (local == null)
  69             local = new InetSocketAddress(0);
  70         try {
  71             ssc.bind(local, backlog);
  72         } catch (Exception x) {
  73             Net.translateException(x);
  74         }
  75     }
  76 
  77     public InetAddress getInetAddress() {
  78         InetSocketAddress local = ssc.localAddress();
  79         if (local == null) {
  80             return null;
  81         } else {
  82             return Net.getRevealedLocalAddress(local).getAddress();
  83         }
  84     }
  85 
  86     public int getLocalPort() {
  87         InetSocketAddress local = ssc.localAddress();
  88         if (local == null) {
  89             return -1;
  90         } else {
  91             return local.getPort();
  92         }
  93     }
  94 
  95     public Socket accept() throws IOException {
  96         synchronized (ssc.blockingLock()) {
  97             try {
  98                 if (!ssc.isBound())
  99                     throw new NotYetBoundException();
 100 
 101                 long to = this.timeout;
 102                 if (to == 0) {
 103                     // for compatibility reasons: accept connection if available
 104                     // when configured non-blocking
 105                     SocketChannel sc = ssc.accept();
 106                     if (sc == null && !ssc.isBlocking())
 107                         throw new IllegalBlockingModeException();
 108                     return sc.socket();
 109                 }
 110 
 111                 if (!ssc.isBlocking())
 112                     throw new IllegalBlockingModeException();
 113                 for (;;) {
 114                     long st = System.currentTimeMillis();
 115                     if (ssc.pollAccept(to))
 116                         return ssc.accept().socket();
 117                     to -= System.currentTimeMillis() - st;
 118                     if (to <= 0)
 119                         throw new SocketTimeoutException();
 120                 }
 121 
 122             } catch (Exception x) {
 123                 Net.translateException(x);
 124                 assert false;
 125                 return null;            // Never happens
 126             }
 127         }
 128     }
 129 
 130     public void close() throws IOException {
 131         ssc.close();
 132     }
 133 
 134     public ServerSocketChannel getChannel() {
 135         return ssc;
 136     }
 137 
 138     public boolean isBound() {
 139         return ssc.isBound();
 140     }
 141 
 142     public boolean isClosed() {
 143         return !ssc.isOpen();
 144     }
 145 
 146     public void setSoTimeout(int timeout) throws SocketException {
 147         this.timeout = timeout;
 148     }
 149 
 150     public int getSoTimeout() throws SocketException {
 151         return timeout;
 152     }
 153 
 154     public void setReuseAddress(boolean on) throws SocketException {
 155         try {
 156             ssc.setOption(StandardSocketOptions.SO_REUSEADDR, on);
 157         } catch (IOException x) {
 158             Net.translateToSocketException(x);
 159         }
 160     }
 161 
 162     public boolean getReuseAddress() throws SocketException {
 163         try {
 164             return ssc.getOption(StandardSocketOptions.SO_REUSEADDR)
 165                       .booleanValue();
 166         } catch (IOException x) {
 167             Net.translateToSocketException(x);
 168             return false;       // Never happens
 169         }
 170     }
 171 
 172     public String toString() {
 173         if (!isBound())
 174             return "RdmaServerSocket[unbound]";
 175         return "RdmaServerSocket[addr=" + getInetAddress() +
 176                ",localport=" + getLocalPort()  + "]";
 177     }
 178 
 179     public void setReceiveBufferSize(int size) throws SocketException {
 180         // size 0 valid for ServerSocketChannel, invalid for ServerSocket
 181         if (size <= 0)
 182             throw new IllegalArgumentException("size cannot be 0 or negative");
 183         try {
 184             ssc.setOption(StandardSocketOptions.SO_RCVBUF, size);
 185         } catch (IOException x) {
 186             Net.translateToSocketException(x);
 187         }
 188     }
 189 
 190     public int getReceiveBufferSize() throws SocketException {
 191         try {
 192             return ssc.getOption(StandardSocketOptions.SO_RCVBUF).intValue();
 193         } catch (IOException x) {
 194             Net.translateToSocketException(x);
 195             return -1;          // Never happens
 196         }
 197     }
 198 }