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