1 /*
2  * Copyright (c) 2000, 2010, 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 
create(ServerSocketChannelImpl ssc)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
ServerSocketAdaptor(ServerSocketChannelImpl ssc)59     private ServerSocketAdaptor(ServerSocketChannelImpl ssc)
60         throws IOException
61     {
62         this.ssc = ssc;
63     }
64 
65 
bind(SocketAddress local)66     public void bind(SocketAddress local) throws IOException {
67         bind(local, 50);
68     }
69 
bind(SocketAddress local, int backlog)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 
getInetAddress()80     public InetAddress getInetAddress() {
81         if (!ssc.isBound())
82             return null;
83         return Net.getRevealedLocalAddress(ssc.localAddress()).getAddress();
84 
85     }
86 
getLocalPort()87     public int getLocalPort() {
88         if (!ssc.isBound())
89             return -1;
90         return Net.asInetSocketAddress(ssc.localAddress()).getPort();
91     }
92 
93 
accept()94     public Socket accept() throws IOException {
95         synchronized (ssc.blockingLock()) {
96             if (!ssc.isBound())
97                 throw new IllegalBlockingModeException();
98             try {
99                 if (timeout == 0) {
100                     SocketChannel sc = ssc.accept();
101                     if (sc == null && !ssc.isBlocking())
102                         throw new IllegalBlockingModeException();
103                     return sc.socket();
104                 }
105 
106                 // Implement timeout with a selector
107                 SelectionKey sk = null;
108                 Selector sel = null;
109                 ssc.configureBlocking(false);
110                 try {
111                     SocketChannel sc;
112                     if ((sc = ssc.accept()) != null)
113                         return sc.socket();
114                     sel = Util.getTemporarySelector(ssc);
115                     sk = ssc.register(sel, SelectionKey.OP_ACCEPT);
116                     long to = timeout;
117                     for (;;) {
118                         if (!ssc.isOpen())
119                             throw new ClosedChannelException();
120                         long st = System.currentTimeMillis();
121                         int ns = sel.select(to);
122                         if (ns > 0 &&
123                             sk.isAcceptable() && ((sc = ssc.accept()) != null))
124                             return sc.socket();
125                         sel.selectedKeys().remove(sk);
126                         to -= System.currentTimeMillis() - st;
127                         if (to <= 0)
128                             throw new SocketTimeoutException();
129                     }
130                 } finally {
131                     if (sk != null)
132                         sk.cancel();
133                     if (ssc.isOpen())
134                         ssc.configureBlocking(true);
135                     if (sel != null)
136                         Util.releaseTemporarySelector(sel);
137                 }
138 
139             } catch (Exception x) {
140                 Net.translateException(x);
141                 assert false;
142                 return null;            // Never happens
143             }
144         }
145     }
146 
close()147     public void close() throws IOException {
148         ssc.close();
149     }
150 
getChannel()151     public ServerSocketChannel getChannel() {
152         return ssc;
153     }
154 
isBound()155     public boolean isBound() {
156         return ssc.isBound();
157     }
158 
isClosed()159     public boolean isClosed() {
160         return !ssc.isOpen();
161     }
162 
setSoTimeout(int timeout)163     public void setSoTimeout(int timeout) throws SocketException {
164         this.timeout = timeout;
165     }
166 
getSoTimeout()167     public int getSoTimeout() throws SocketException {
168         return timeout;
169     }
170 
setReuseAddress(boolean on)171     public void setReuseAddress(boolean on) throws SocketException {
172         try {
173             ssc.setOption(StandardSocketOptions.SO_REUSEADDR, on);
174         } catch (IOException x) {
175             Net.translateToSocketException(x);
176         }
177     }
178 
getReuseAddress()179     public boolean getReuseAddress() throws SocketException {
180         try {
181             return ssc.getOption(StandardSocketOptions.SO_REUSEADDR).booleanValue();
182         } catch (IOException x) {
183             Net.translateToSocketException(x);
184             return false;       // Never happens
185         }
186     }
187 
toString()188     public String toString() {
189         if (!isBound())
190             return "ServerSocket[unbound]";
191         return "ServerSocket[addr=" + getInetAddress() +
192             //          ",port=" + getPort() +
193                 ",localport=" + getLocalPort()  + "]";
194     }
195 
setReceiveBufferSize(int size)196     public void setReceiveBufferSize(int size) throws SocketException {
197         // size 0 valid for ServerSocketChannel, invalid for ServerSocket
198         if (size <= 0)
199             throw new IllegalArgumentException("size cannot be 0 or negative");
200         try {
201             ssc.setOption(StandardSocketOptions.SO_RCVBUF, size);
202         } catch (IOException x) {
203             Net.translateToSocketException(x);
204         }
205     }
206 
getReceiveBufferSize()207     public int getReceiveBufferSize() throws SocketException {
208         try {
209             return ssc.getOption(StandardSocketOptions.SO_RCVBUF).intValue();
210         } catch (IOException x) {
211             Net.translateToSocketException(x);
212             return -1;          // Never happens
213         }
214     }
215 
216 }
217