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
26package sun.nio.ch;
27
28import java.io.*;
29import java.net.*;
30import 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
40public 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.getRevealedLocalAddress(ssc.localAddress()).getAddress();
84
85    }
86
87    public int getLocalPort() {
88        if (!ssc.isBound())
89            return -1;
90        return Net.asInetSocketAddress(ssc.localAddress()).getPort();
91    }
92
93
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
147    public void close() throws IOException {
148        ssc.close();
149    }
150
151    public ServerSocketChannel getChannel() {
152        return ssc;
153    }
154
155    public boolean isBound() {
156        return ssc.isBound();
157    }
158
159    public boolean isClosed() {
160        return !ssc.isOpen();
161    }
162
163    public void setSoTimeout(int timeout) throws SocketException {
164        this.timeout = timeout;
165    }
166
167    public int getSoTimeout() throws SocketException {
168        return timeout;
169    }
170
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
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
188    public String toString() {
189        if (!isBound())
190            return "ServerSocket[unbound]";
191        return "ServerSocket[addr=" + getInetAddress() +
192            //          ",port=" + getPort() +
193                ",localport=" + getLocalPort()  + "]";
194    }
195
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
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