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