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