blob: 7f91cf3b89743209f360a29c175db2ce87586063 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.nio.ch;
27
28import java.io.FileDescriptor;
29import java.io.IOException;
30import java.lang.reflect.*;
31import java.net.*;
32import java.nio.channels.*;
33import java.nio.channels.spi.*;
34import java.security.AccessController;
35import java.security.PrivilegedAction;
36import java.util.HashSet;
37import java.util.Iterator;
38
39
40/**
41 * An implementation of ServerSocketChannels
42 */
43
44class ServerSocketChannelImpl
45 extends ServerSocketChannel
46 implements SelChImpl
47{
48
49 // Used to make native close and configure calls
50 private static NativeDispatcher nd;
51
52 // Our file descriptor
53 private final FileDescriptor fd;
54
55 // fd value needed for dev/poll. This value will remain valid
56 // even after the value in the file descriptor object has been set to -1
57 private int fdVal;
58
59 // ID of native thread currently blocked in this channel, for signalling
60 private volatile long thread = 0;
61
62 // Lock held by thread currently blocked in this channel
63 private final Object lock = new Object();
64
65 // Lock held by any thread that modifies the state fields declared below
66 // DO NOT invoke a blocking I/O operation while holding this lock!
67 private final Object stateLock = new Object();
68
69 // -- The following fields are protected by stateLock
70
71 // Channel state, increases monotonically
72 private static final int ST_UNINITIALIZED = -1;
73 private static final int ST_INUSE = 0;
74 private static final int ST_KILLED = 1;
75 private int state = ST_UNINITIALIZED;
76
77 // Binding
78 private SocketAddress localAddress = null; // null => unbound
79
80 // Options, created on demand
81 private SocketOpts.IP.TCP options = null;
82
83 // Our socket adaptor, if any
84 ServerSocket socket;
85
86 // -- End of fields protected by stateLock
87
88
89 public ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
90 super(sp);
91 this.fd = Net.serverSocket(true);
92 this.fdVal = IOUtil.fdVal(fd);
93 this.state = ST_INUSE;
94 }
95
96 public ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd)
97 throws IOException
98 {
99 super(sp);
100 this.fd = fd;
101 this.fdVal = IOUtil.fdVal(fd);
102 this.state = ST_INUSE;
103 localAddress = Net.localAddress(fd);
104 }
105
106
107 public ServerSocket socket() {
108 synchronized (stateLock) {
109 if (socket == null)
110 socket = ServerSocketAdaptor.create(this);
111 return socket;
112 }
113 }
114
115 public boolean isBound() {
116 synchronized (stateLock) {
117 return localAddress != null;
118 }
119 }
120
121 public SocketAddress localAddress() {
122 synchronized (stateLock) {
123 return localAddress;
124 }
125 }
126
127 public void bind(SocketAddress local, int backlog) throws IOException {
128 synchronized (lock) {
129 if (!isOpen())
130 throw new ClosedChannelException();
131 if (isBound())
132 throw new AlreadyBoundException();
133 InetSocketAddress isa = Net.checkAddress(local);
134 SecurityManager sm = System.getSecurityManager();
135 if (sm != null)
136 sm.checkListen(isa.getPort());
137 Net.bind(fd, isa.getAddress(), isa.getPort());
138 listen(fd, backlog < 1 ? 50 : backlog);
139 synchronized (stateLock) {
140 localAddress = Net.localAddress(fd);
141 }
142 }
143 }
144
145 public SocketChannel accept() throws IOException {
146 synchronized (lock) {
147 if (!isOpen())
148 throw new ClosedChannelException();
149 if (!isBound())
150 throw new NotYetBoundException();
151 SocketChannel sc = null;
152
153 int n = 0;
154 FileDescriptor newfd = new FileDescriptor();
155 InetSocketAddress[] isaa = new InetSocketAddress[1];
156
157 try {
158 begin();
159 if (!isOpen())
160 return null;
161 thread = NativeThread.current();
162 for (;;) {
163 n = accept0(this.fd, newfd, isaa);
164 if ((n == IOStatus.INTERRUPTED) && isOpen())
165 continue;
166 break;
167 }
168 } finally {
169 thread = 0;
170 end(n > 0);
171 assert IOStatus.check(n);
172 }
173
174 if (n < 1)
175 return null;
176
177 IOUtil.configureBlocking(newfd, true);
178 InetSocketAddress isa = isaa[0];
179 sc = new SocketChannelImpl(provider(), newfd, isa);
180 SecurityManager sm = System.getSecurityManager();
181 if (sm != null) {
182 try {
183 sm.checkAccept(isa.getAddress().getHostAddress(),
184 isa.getPort());
185 } catch (SecurityException x) {
186 sc.close();
187 throw x;
188 }
189 }
190 return sc;
191
192 }
193 }
194
195 protected void implConfigureBlocking(boolean block) throws IOException {
196 IOUtil.configureBlocking(fd, block);
197 }
198
199 public SocketOpts options() {
200 synchronized (stateLock) {
201 if (options == null) {
202 SocketOptsImpl.Dispatcher d
203 = new SocketOptsImpl.Dispatcher() {
204 int getInt(int opt) throws IOException {
205 return Net.getIntOption(fd, opt);
206 }
207 void setInt(int opt, int arg) throws IOException {
208 Net.setIntOption(fd, opt, arg);
209 }
210 };
211 options = new SocketOptsImpl.IP.TCP(d);
212 }
213 return options;
214 }
215 }
216
217 protected void implCloseSelectableChannel() throws IOException {
218 synchronized (stateLock) {
219 nd.preClose(fd);
220 long th = thread;
221 if (th != 0)
222 NativeThread.signal(th);
223 if (!isRegistered())
224 kill();
225 }
226 }
227
228 public void kill() throws IOException {
229 synchronized (stateLock) {
230 if (state == ST_KILLED)
231 return;
232 if (state == ST_UNINITIALIZED) {
233 state = ST_KILLED;
234 return;
235 }
236 assert !isOpen() && !isRegistered();
237 nd.close(fd);
238 state = ST_KILLED;
239 }
240 }
241
242 /**
243 * Translates native poll revent set into a ready operation set
244 */
245 public boolean translateReadyOps(int ops, int initialOps,
246 SelectionKeyImpl sk) {
247 int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
248 int oldOps = sk.nioReadyOps();
249 int newOps = initialOps;
250
251 if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
252 // This should only happen if this channel is pre-closed while a
253 // selection operation is in progress
254 // ## Throw an error if this channel has not been pre-closed
255 return false;
256 }
257
258 if ((ops & (PollArrayWrapper.POLLERR
259 | PollArrayWrapper.POLLHUP)) != 0) {
260 newOps = intOps;
261 sk.nioReadyOps(newOps);
262 return (newOps & ~oldOps) != 0;
263 }
264
265 if (((ops & PollArrayWrapper.POLLIN) != 0) &&
266 ((intOps & SelectionKey.OP_ACCEPT) != 0))
267 newOps |= SelectionKey.OP_ACCEPT;
268
269 sk.nioReadyOps(newOps);
270 return (newOps & ~oldOps) != 0;
271 }
272
273 public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
274 return translateReadyOps(ops, sk.nioReadyOps(), sk);
275 }
276
277 public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
278 return translateReadyOps(ops, 0, sk);
279 }
280
281 /**
282 * Translates an interest operation set into a native poll event set
283 */
284 public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
285 int newOps = 0;
286
287 // Translate ops
288 if ((ops & SelectionKey.OP_ACCEPT) != 0)
289 newOps |= PollArrayWrapper.POLLIN;
290 // Place ops into pollfd array
291 sk.selector.putEventOps(sk, newOps);
292 }
293
294 public FileDescriptor getFD() {
295 return fd;
296 }
297
298 public int getFDVal() {
299 return fdVal;
300 }
301
302 public String toString() {
303 StringBuffer sb = new StringBuffer();
304 sb.append(this.getClass().getName());
305 sb.append('[');
306 if (!isOpen())
307 sb.append("closed");
308 else {
309 synchronized (stateLock) {
310 if (localAddress() == null) {
311 sb.append("unbound");
312 } else {
313 sb.append(localAddress().toString());
314 }
315 }
316 }
317 sb.append(']');
318 return sb.toString();
319 }
320
321 // -- Native methods --
322
323 private static native void listen(FileDescriptor fd, int backlog)
324 throws IOException;
325
326 // Accepts a new connection, setting the given file descriptor to refer to
327 // the new socket and setting isaa[0] to the socket's remote address.
328 // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no
329 // connections are pending) or IOStatus.INTERRUPTED.
330 //
331 private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,
332 InetSocketAddress[] isaa)
333 throws IOException;
334
335 private static native void initIDs();
336
337 static {
338 Util.load();
339 initIDs();
340 nd = new SocketDispatcher();
341 }
342
343}