1/*
2 * Copyright (c) 2000, 2013, 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;
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            try {
97                if (!ssc.isBound())
98                    throw new NotYetBoundException();
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                ssc.configureBlocking(false);
107                try {
108                    SocketChannel sc;
109                    if ((sc = ssc.accept()) != null)
110                        return sc.socket();
111                    long to = timeout;
112                    for (;;) {
113                        if (!ssc.isOpen())
114                            throw new ClosedChannelException();
115                        long st = System.currentTimeMillis();
116                        int result = ssc.poll(Net.POLLIN, to);
117                        if (result > 0 && ((sc = ssc.accept()) != null))
118                            return sc.socket();
119                        to -= System.currentTimeMillis() - st;
120                        if (to <= 0)
121                            throw new SocketTimeoutException();
122                    }
123                } finally {
124                    if (ssc.isOpen())
125                        ssc.configureBlocking(true);
126                }
127
128            } catch (Exception x) {
129                Net.translateException(x);
130                assert false;
131                return null;            // Never happens
132            }
133        }
134    }
135
136    public void close() throws IOException {
137        ssc.close();
138    }
139
140    public ServerSocketChannel getChannel() {
141        return ssc;
142    }
143
144    public boolean isBound() {
145        return ssc.isBound();
146    }
147
148    public boolean isClosed() {
149        return !ssc.isOpen();
150    }
151
152    public void setSoTimeout(int timeout) throws SocketException {
153        this.timeout = timeout;
154    }
155
156    public int getSoTimeout() throws SocketException {
157        return timeout;
158    }
159
160    public void setReuseAddress(boolean on) throws SocketException {
161        try {
162            ssc.setOption(StandardSocketOptions.SO_REUSEADDR, on);
163        } catch (IOException x) {
164            Net.translateToSocketException(x);
165        }
166    }
167
168    public boolean getReuseAddress() throws SocketException {
169        try {
170            return ssc.getOption(StandardSocketOptions.SO_REUSEADDR).booleanValue();
171        } catch (IOException x) {
172            Net.translateToSocketException(x);
173            return false;       // Never happens
174        }
175    }
176
177    public String toString() {
178        if (!isBound())
179            return "ServerSocket[unbound]";
180        return "ServerSocket[addr=" + getInetAddress() +
181            //          ",port=" + getPort() +
182                ",localport=" + getLocalPort()  + "]";
183    }
184
185    public void setReceiveBufferSize(int size) throws SocketException {
186        // size 0 valid for ServerSocketChannel, invalid for ServerSocket
187        if (size <= 0)
188            throw new IllegalArgumentException("size cannot be 0 or negative");
189        try {
190            ssc.setOption(StandardSocketOptions.SO_RCVBUF, size);
191        } catch (IOException x) {
192            Net.translateToSocketException(x);
193        }
194    }
195
196    public int getReceiveBufferSize() throws SocketException {
197        try {
198            return ssc.getOption(StandardSocketOptions.SO_RCVBUF).intValue();
199        } catch (IOException x) {
200            Net.translateToSocketException(x);
201            return -1;          // Never happens
202        }
203    }
204
205}
206