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 sun.nio.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 import java.security.AccessController;
  42 import java.security.PrivilegedActionException;
  43 import java.security.PrivilegedExceptionAction;
  44 
  45 // Make a server-socket channel look like a server socket.
  46 //
  47 // The methods in this class are defined in exactly the same order as in
  48 // java.net.ServerSocket so as to simplify tracking future changes to that
  49 // class.
  50 //
  51 
  52 class ServerSocketAdaptor                        // package-private
  53     extends ServerSocket
  54 {
  55     // The channel being adapted
  56     private final ServerSocketChannelImpl ssc;
  57 
  58     // Timeout "option" value for accepts
  59     private volatile int timeout;
  60 
  61     public static ServerSocket create(ServerSocketChannelImpl ssc) {
  62         PrivilegedExceptionAction<ServerSocket> pa = () -> new ServerSocketAdaptor(ssc);
  63         try {
  64             return AccessController.doPrivileged(pa);
  65         } catch (PrivilegedActionException pae) {
  66             throw new InternalError("Should not reach here", pae);
  67         }
  68     }
  69 
  70     // ## super will create a useless impl
  71     private ServerSocketAdaptor(ServerSocketChannelImpl ssc) throws IOException {
  72         this.ssc = ssc;
  73     }
  74 
  75     public void bind(SocketAddress local) throws IOException {
  76         bind(local, 50);
  77     }
  78 
  79     public void bind(SocketAddress local, int backlog) throws IOException {
  80         if (local == null)
  81             local = new InetSocketAddress(0);
  82         try {
  83             ssc.bind(local, backlog);
  84         } catch (Exception x) {
  85             Net.translateException(x);
  86         }
  87     }
  88 
  89     public InetAddress getInetAddress() {
  90         InetSocketAddress local = ssc.localAddress();
  91         if (local == null) {
  92             return null;
  93         } else {
  94             return Net.getRevealedLocalAddress(local).getAddress();
  95         }
  96     }
  97 
  98     public int getLocalPort() {
  99         InetSocketAddress local = ssc.localAddress();
 100         if (local == null) {
 101             return -1;
 102         } else {
 103             return local.getPort();
 104         }
 105     }
 106 
 107     public Socket accept() throws IOException {
 108         synchronized (ssc.blockingLock()) {
 109             try {
 110                 if (!ssc.isBound())
 111                     throw new NotYetBoundException();
 112 
 113                 long to = this.timeout;
 114                 if (to == 0) {
 115                     // for compatibility reasons: accept connection if available
 116                     // when configured non-blocking
 117                     SocketChannel sc = ssc.accept();
 118                     if (sc == null && !ssc.isBlocking())
 119                         throw new IllegalBlockingModeException();
 120                     return sc.socket();
 121                 }
 122 
 123                 if (!ssc.isBlocking())
 124                     throw new IllegalBlockingModeException();
 125                 for (;;) {
 126                     long st = System.currentTimeMillis();
 127                     if (ssc.pollAccept(to))
 128                         return ssc.accept().socket();
 129                     to -= System.currentTimeMillis() - st;
 130                     if (to <= 0)
 131                         throw new SocketTimeoutException();
 132                 }
 133 
 134             } catch (Exception x) {
 135                 Net.translateException(x);
 136                 assert false;
 137                 return null;            // Never happens
 138             }
 139         }
 140     }
 141 
 142     public void close() throws IOException {
 143         ssc.close();
 144     }
 145 
 146     public ServerSocketChannel getChannel() {
 147         return ssc;
 148     }
 149 
 150     public boolean isBound() {
 151         return ssc.isBound();
 152     }
 153 
 154     public boolean isClosed() {
 155         return !ssc.isOpen();
 156     }
 157 
 158     public void setSoTimeout(int timeout) throws SocketException {
 159         this.timeout = timeout;
 160     }
 161 
 162     public int getSoTimeout() throws SocketException {
 163         return timeout;
 164     }
 165 
 166     public void setReuseAddress(boolean on) throws SocketException {
 167         try {
 168             ssc.setOption(StandardSocketOptions.SO_REUSEADDR, on);
 169         } catch (IOException x) {
 170             Net.translateToSocketException(x);
 171         }
 172     }
 173 
 174     public boolean getReuseAddress() throws SocketException {
 175         try {
 176             return ssc.getOption(StandardSocketOptions.SO_REUSEADDR).booleanValue();
 177         } catch (IOException x) {
 178             Net.translateToSocketException(x);
 179             return false;       // Never happens
 180         }
 181     }
 182 
 183     public String toString() {
 184         if (!isBound())
 185             return "ServerSocket[unbound]";
 186         return "ServerSocket[addr=" + getInetAddress() +
 187                ",localport=" + getLocalPort()  + "]";
 188     }
 189 
 190     public void setReceiveBufferSize(int size) throws SocketException {
 191         // size 0 valid for ServerSocketChannel, invalid for ServerSocket
 192         if (size <= 0)
 193             throw new IllegalArgumentException("size cannot be 0 or negative");
 194         try {
 195             ssc.setOption(StandardSocketOptions.SO_RCVBUF, size);
 196         } catch (IOException x) {
 197             Net.translateToSocketException(x);
 198         }
 199     }
 200 
 201     public int getReceiveBufferSize() throws SocketException {
 202         try {
 203             return ssc.getOption(StandardSocketOptions.SO_RCVBUF).intValue();
 204         } catch (IOException x) {
 205             Net.translateToSocketException(x);
 206             return -1;          // Never happens
 207         }
 208     }
 209 }