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