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 
26 package sun.nio.ch;
27 
28 import java.io.FileDescriptor;
29 import java.io.IOException;
30 import java.net.*;
31 import java.nio.channels.*;
32 import java.nio.channels.spi.*;
33 import java.util.*;
34 import sun.net.NetHooks;
35 
36 
37 /**
38  * An implementation of ServerSocketChannels
39  */
40 
41 class ServerSocketChannelImpl
42     extends ServerSocketChannel
43     implements SelChImpl
44 {
45 
46     // Used to make native close and configure calls
47     private static NativeDispatcher nd;
48 
49     // Our file descriptor
50     private final FileDescriptor fd;
51 
52     // fd value needed for dev/poll. This value will remain valid
53     // even after the value in the file descriptor object has been set to -1
54     private int fdVal;
55 
56     // ID of native thread currently blocked in this channel, for signalling
57     private volatile long thread = 0;
58 
59     // Lock held by thread currently blocked in this channel
60     private final Object lock = new Object();
61 
62     // Lock held by any thread that modifies the state fields declared below
63     // DO NOT invoke a blocking I/O operation while holding this lock!
64     private final Object stateLock = new Object();
65 
66     // -- The following fields are protected by stateLock
67 
68     // Channel state, increases monotonically
69     private static final int ST_UNINITIALIZED = -1;
70     private static final int ST_INUSE = 0;
71     private static final int ST_KILLED = 1;
72     private int state = ST_UNINITIALIZED;
73 
74     // Binding
75     private InetSocketAddress localAddress; // null => unbound
76 
77     // set true when exclusive binding is on and SO_REUSEADDR is emulated
78     private boolean isReuseAddress;
79 
80     // Our socket adaptor, if any
81     ServerSocket socket;
82 
83     // -- End of fields protected by stateLock
84 
85 
ServerSocketChannelImpl(SelectorProvider sp)86     ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
87         super(sp);
88         this.fd =  Net.serverSocket(true);
89         this.fdVal = IOUtil.fdVal(fd);
90         this.state = ST_INUSE;
91     }
92 
ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound)93     ServerSocketChannelImpl(SelectorProvider sp,
94                             FileDescriptor fd,
95                             boolean bound)
96         throws IOException
97     {
98         super(sp);
99         this.fd =  fd;
100         this.fdVal = IOUtil.fdVal(fd);
101         this.state = ST_INUSE;
102         if (bound)
103             localAddress = Net.localAddress(fd);
104     }
105 
socket()106     public ServerSocket socket() {
107         synchronized (stateLock) {
108             if (socket == null)
109 
110                 socket = ServerSocketAdaptor.create(this);
111             return socket;
112         }
113     }
114 
115     @Override
getLocalAddress()116     public SocketAddress getLocalAddress() throws IOException {
117         synchronized (stateLock) {
118             if (!isOpen())
119                 throw new ClosedChannelException();
120             return localAddress == null ? localAddress
121                     : Net.getRevealedLocalAddress(
122                           Net.asInetSocketAddress(localAddress));
123         }
124     }
125 
126     @Override
setOption(SocketOption<T> name, T value)127     public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
128         throws IOException
129     {
130         if (name == null)
131             throw new NullPointerException();
132         if (!supportedOptions().contains(name))
133             throw new UnsupportedOperationException("'" + name + "' not supported");
134         synchronized (stateLock) {
135             if (!isOpen())
136                 throw new ClosedChannelException();
137 
138             if (name == StandardSocketOptions.IP_TOS) {
139                 ProtocolFamily family = Net.isIPv6Available() ?
140                     StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
141                 Net.setSocketOption(fd, family, name, value);
142                 return this;
143             }
144 
145             if (name == StandardSocketOptions.SO_REUSEADDR &&
146                     Net.useExclusiveBind())
147             {
148                 // SO_REUSEADDR emulated when using exclusive bind
149                 isReuseAddress = (Boolean)value;
150             } else {
151                 // no options that require special handling
152                 Net.setSocketOption(fd, Net.UNSPEC, name, value);
153             }
154             return this;
155         }
156     }
157 
158     @Override
159     @SuppressWarnings("unchecked")
getOption(SocketOption<T> name)160     public <T> T getOption(SocketOption<T> name)
161         throws IOException
162     {
163         if (name == null)
164             throw new NullPointerException();
165         if (!supportedOptions().contains(name))
166             throw new UnsupportedOperationException("'" + name + "' not supported");
167 
168         synchronized (stateLock) {
169             if (!isOpen())
170                 throw new ClosedChannelException();
171             if (name == StandardSocketOptions.SO_REUSEADDR &&
172                     Net.useExclusiveBind())
173             {
174                 // SO_REUSEADDR emulated when using exclusive bind
175                 return (T)Boolean.valueOf(isReuseAddress);
176             }
177             // no options that require special handling
178             return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
179         }
180     }
181 
182     private static class DefaultOptionsHolder {
183         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
184 
defaultOptions()185         private static Set<SocketOption<?>> defaultOptions() {
186             HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(2);
187             set.add(StandardSocketOptions.SO_RCVBUF);
188             set.add(StandardSocketOptions.SO_REUSEADDR);
189             set.add(StandardSocketOptions.IP_TOS);
190             return Collections.unmodifiableSet(set);
191         }
192     }
193 
194     @Override
supportedOptions()195     public final Set<SocketOption<?>> supportedOptions() {
196         return DefaultOptionsHolder.defaultOptions;
197     }
198 
isBound()199     public boolean isBound() {
200         synchronized (stateLock) {
201             return localAddress != null;
202         }
203     }
204 
localAddress()205     public InetSocketAddress localAddress() {
206         synchronized (stateLock) {
207             return localAddress;
208         }
209     }
210 
211     @Override
bind(SocketAddress local, int backlog)212     public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException {
213         synchronized (lock) {
214             if (!isOpen())
215                 throw new ClosedChannelException();
216             if (isBound())
217                 throw new AlreadyBoundException();
218             InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) :
219                 Net.checkAddress(local);
220             SecurityManager sm = System.getSecurityManager();
221             if (sm != null)
222                 sm.checkListen(isa.getPort());
223             NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
224             Net.bind(fd, isa.getAddress(), isa.getPort());
225             Net.listen(fd, backlog < 1 ? 50 : backlog);
226             synchronized (stateLock) {
227                 localAddress = Net.localAddress(fd);
228             }
229         }
230         return this;
231     }
232 
accept()233     public SocketChannel accept() throws IOException {
234         synchronized (lock) {
235             if (!isOpen())
236                 throw new ClosedChannelException();
237             if (!isBound())
238                 throw new NotYetBoundException();
239             SocketChannel sc = null;
240 
241             int n = 0;
242             FileDescriptor newfd = new FileDescriptor();
243             InetSocketAddress[] isaa = new InetSocketAddress[1];
244 
245             try {
246                 begin();
247                 if (!isOpen())
248                     return null;
249                 thread = NativeThread.current();
250                 for (;;) {
251                     n = accept(this.fd, newfd, isaa);
252                     if ((n == IOStatus.INTERRUPTED) && isOpen())
253                         continue;
254                     break;
255                 }
256             } finally {
257                 thread = 0;
258                 end(n > 0);
259                 assert IOStatus.check(n);
260             }
261 
262             if (n < 1)
263                 return null;
264 
265             IOUtil.configureBlocking(newfd, true);
266             InetSocketAddress isa = isaa[0];
267             sc = new SocketChannelImpl(provider(), newfd, isa);
268             SecurityManager sm = System.getSecurityManager();
269             if (sm != null) {
270                 try {
271                     sm.checkAccept(isa.getAddress().getHostAddress(),
272                                    isa.getPort());
273                 } catch (SecurityException x) {
274                     sc.close();
275                     throw x;
276                 }
277             }
278             return sc;
279 
280         }
281     }
282 
implConfigureBlocking(boolean block)283     protected void implConfigureBlocking(boolean block) throws IOException {
284         IOUtil.configureBlocking(fd, block);
285     }
286 
implCloseSelectableChannel()287     protected void implCloseSelectableChannel() throws IOException {
288         synchronized (stateLock) {
289             if (state != ST_KILLED)
290                 nd.preClose(fd);
291             long th = thread;
292             if (th != 0)
293                 NativeThread.signal(th);
294             if (!isRegistered())
295                 kill();
296         }
297     }
298 
kill()299     public void kill() throws IOException {
300         synchronized (stateLock) {
301             if (state == ST_KILLED)
302                 return;
303             if (state == ST_UNINITIALIZED) {
304                 state = ST_KILLED;
305                 return;
306             }
307             assert !isOpen() && !isRegistered();
308             nd.close(fd);
309             state = ST_KILLED;
310         }
311     }
312 
313     /**
314      * Translates native poll revent set into a ready operation set
315      */
translateReadyOps(int ops, int initialOps, SelectionKeyImpl sk)316     public boolean translateReadyOps(int ops, int initialOps,
317                                      SelectionKeyImpl sk) {
318         int intOps = sk.nioInterestOps(); // Do this just once, it synchronizes
319         int oldOps = sk.nioReadyOps();
320         int newOps = initialOps;
321 
322         if ((ops & Net.POLLNVAL) != 0) {
323             // This should only happen if this channel is pre-closed while a
324             // selection operation is in progress
325             // ## Throw an error if this channel has not been pre-closed
326             return false;
327         }
328 
329         if ((ops & (Net.POLLERR | Net.POLLHUP)) != 0) {
330             newOps = intOps;
331             sk.nioReadyOps(newOps);
332             return (newOps & ~oldOps) != 0;
333         }
334 
335         if (((ops & Net.POLLIN) != 0) &&
336             ((intOps & SelectionKey.OP_ACCEPT) != 0))
337                 newOps |= SelectionKey.OP_ACCEPT;
338 
339         sk.nioReadyOps(newOps);
340         return (newOps & ~oldOps) != 0;
341     }
342 
translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk)343     public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
344         return translateReadyOps(ops, sk.nioReadyOps(), sk);
345     }
346 
translateAndSetReadyOps(int ops, SelectionKeyImpl sk)347     public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
348         return translateReadyOps(ops, 0, sk);
349     }
350 
351     // package-private
poll(int events, long timeout)352     int poll(int events, long timeout) throws IOException {
353         assert Thread.holdsLock(blockingLock()) && !isBlocking();
354 
355         synchronized (lock) {
356             int n = 0;
357             try {
358                 begin();
359                 synchronized (stateLock) {
360                     if (!isOpen())
361                         return 0;
362                     thread = NativeThread.current();
363                 }
364                 n = Net.poll(fd, events, timeout);
365             } finally {
366                 thread = 0;
367                 end(n > 0);
368             }
369             return n;
370         }
371     }
372 
373     /**
374      * Translates an interest operation set into a native poll event set
375      */
translateAndSetInterestOps(int ops, SelectionKeyImpl sk)376     public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
377         int newOps = 0;
378 
379         // Translate ops
380         if ((ops & SelectionKey.OP_ACCEPT) != 0)
381             newOps |= Net.POLLIN;
382         // Place ops into pollfd array
383         sk.selector.putEventOps(sk, newOps);
384     }
385 
getFD()386     public FileDescriptor getFD() {
387         return fd;
388     }
389 
getFDVal()390     public int getFDVal() {
391         return fdVal;
392     }
393 
toString()394     public String toString() {
395         StringBuffer sb = new StringBuffer();
396         sb.append(this.getClass().getName());
397         sb.append('[');
398         if (!isOpen()) {
399             sb.append("closed");
400         } else {
401             synchronized (stateLock) {
402                 InetSocketAddress addr = localAddress();
403                 if (addr == null) {
404                     sb.append("unbound");
405                 } else {
406                     sb.append(Net.getRevealedLocalAddressAsString(addr));
407                 }
408             }
409         }
410         sb.append(']');
411         return sb.toString();
412     }
413 
414     /**
415      * Accept a connection on a socket.
416      *
417      * @implNote Wrap native call to allow instrumentation.
418      */
accept(FileDescriptor ssfd, FileDescriptor newfd, InetSocketAddress[] isaa)419     private int accept(FileDescriptor ssfd, FileDescriptor newfd,
420                        InetSocketAddress[] isaa)
421         throws IOException
422     {
423         return accept0(ssfd, newfd, isaa);
424     }
425 
426     // -- Native methods --
427 
428     // Accepts a new connection, setting the given file descriptor to refer to
429     // the new socket and setting isaa[0] to the socket's remote address.
430     // Returns 1 on success, or IOStatus.UNAVAILABLE (if non-blocking and no
431     // connections are pending) or IOStatus.INTERRUPTED.
432     //
accept0(FileDescriptor ssfd, FileDescriptor newfd, InetSocketAddress[] isaa)433     private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,
434                                InetSocketAddress[] isaa)
435         throws IOException;
436 
initIDs()437     private static native void initIDs();
438 
439     static {
initIDs()440         initIDs();
441         nd = new SocketDispatcher();
442     }
443 
444 }
445