1 /* 2 * Copyright (c) 2008, 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.nio.channels.*; 29 import java.net.SocketAddress; 30 import java.net.SocketOption; 31 import java.net.StandardSocketOptions; 32 import java.net.InetSocketAddress; 33 import java.io.FileDescriptor; 34 import java.io.IOException; 35 import java.util.Set; 36 import java.util.HashSet; 37 import java.util.Collections; 38 import java.util.concurrent.Future; 39 import java.util.concurrent.locks.ReadWriteLock; 40 import java.util.concurrent.locks.ReentrantReadWriteLock; 41 import sun.net.NetHooks; 42 43 /** 44 * Base implementation of AsynchronousServerSocketChannel. 45 */ 46 47 abstract class AsynchronousServerSocketChannelImpl 48 extends AsynchronousServerSocketChannel 49 implements Cancellable, Groupable 50 { 51 protected final FileDescriptor fd; 52 53 // the local address to which the channel's socket is bound 54 protected volatile InetSocketAddress localAddress = null; 55 56 // need this lock to set local address 57 private final Object stateLock = new Object(); 58 59 // close support 60 private ReadWriteLock closeLock = new ReentrantReadWriteLock(); 61 private volatile boolean open = true; 62 63 // set true when accept operation is cancelled 64 private volatile boolean acceptKilled; 65 66 // set true when exclusive binding is on and SO_REUSEADDR is emulated 67 private boolean isReuseAddress; 68 AsynchronousServerSocketChannelImpl(AsynchronousChannelGroupImpl group)69 AsynchronousServerSocketChannelImpl(AsynchronousChannelGroupImpl group) { 70 super(group.provider()); 71 this.fd = Net.serverSocket(true); 72 } 73 74 @Override isOpen()75 public final boolean isOpen() { 76 return open; 77 } 78 79 /** 80 * Marks beginning of access to file descriptor/handle 81 */ begin()82 final void begin() throws IOException { 83 closeLock.readLock().lock(); 84 if (!isOpen()) 85 throw new ClosedChannelException(); 86 } 87 88 /** 89 * Marks end of access to file descriptor/handle 90 */ end()91 final void end() { 92 closeLock.readLock().unlock(); 93 } 94 95 /** 96 * Invoked to close file descriptor/handle. 97 */ implClose()98 abstract void implClose() throws IOException; 99 100 @Override close()101 public final void close() throws IOException { 102 // synchronize with any threads using file descriptor/handle 103 closeLock.writeLock().lock(); 104 try { 105 if (!open) 106 return; // already closed 107 open = false; 108 } finally { 109 closeLock.writeLock().unlock(); 110 } 111 implClose(); 112 } 113 114 /** 115 * Invoked by accept to accept connection 116 */ 117 abstract Future<AsynchronousSocketChannel> implAccept(Object attachment, CompletionHandler<AsynchronousSocketChannel,Object> handler)118 implAccept(Object attachment, 119 CompletionHandler<AsynchronousSocketChannel,Object> handler); 120 121 122 @Override accept()123 public final Future<AsynchronousSocketChannel> accept() { 124 return implAccept(null, null); 125 } 126 127 @Override 128 @SuppressWarnings("unchecked") accept(A attachment, CompletionHandler<AsynchronousSocketChannel,? super A> handler)129 public final <A> void accept(A attachment, 130 CompletionHandler<AsynchronousSocketChannel,? super A> handler) 131 { 132 if (handler == null) 133 throw new NullPointerException("'handler' is null"); 134 implAccept(attachment, (CompletionHandler<AsynchronousSocketChannel,Object>)handler); 135 } 136 isAcceptKilled()137 final boolean isAcceptKilled() { 138 return acceptKilled; 139 } 140 141 @Override onCancel(PendingFuture<?,?> task)142 public final void onCancel(PendingFuture<?,?> task) { 143 acceptKilled = true; 144 } 145 146 @Override bind(SocketAddress local, int backlog)147 public final AsynchronousServerSocketChannel bind(SocketAddress local, int backlog) 148 throws IOException 149 { 150 InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) : 151 Net.checkAddress(local); 152 SecurityManager sm = System.getSecurityManager(); 153 if (sm != null) 154 sm.checkListen(isa.getPort()); 155 156 try { 157 begin(); 158 synchronized (stateLock) { 159 if (localAddress != null) 160 throw new AlreadyBoundException(); 161 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); 162 Net.bind(fd, isa.getAddress(), isa.getPort()); 163 Net.listen(fd, backlog < 1 ? 50 : backlog); 164 localAddress = Net.localAddress(fd); 165 } 166 } finally { 167 end(); 168 } 169 return this; 170 } 171 172 @Override getLocalAddress()173 public final SocketAddress getLocalAddress() throws IOException { 174 if (!isOpen()) 175 throw new ClosedChannelException(); 176 return Net.getRevealedLocalAddress(localAddress); 177 } 178 179 @Override setOption(SocketOption<T> name, T value)180 public final <T> AsynchronousServerSocketChannel setOption(SocketOption<T> name, 181 T value) 182 throws IOException 183 { 184 if (name == null) 185 throw new NullPointerException(); 186 if (!supportedOptions().contains(name)) 187 throw new UnsupportedOperationException("'" + name + "' not supported"); 188 189 try { 190 begin(); 191 if (name == StandardSocketOptions.SO_REUSEADDR && 192 Net.useExclusiveBind()) 193 { 194 // SO_REUSEADDR emulated when using exclusive bind 195 isReuseAddress = (Boolean)value; 196 } else { 197 Net.setSocketOption(fd, Net.UNSPEC, name, value); 198 } 199 return this; 200 } finally { 201 end(); 202 } 203 } 204 205 @Override 206 @SuppressWarnings("unchecked") getOption(SocketOption<T> name)207 public final <T> T getOption(SocketOption<T> name) throws IOException { 208 if (name == null) 209 throw new NullPointerException(); 210 if (!supportedOptions().contains(name)) 211 throw new UnsupportedOperationException("'" + name + "' not supported"); 212 213 try { 214 begin(); 215 if (name == StandardSocketOptions.SO_REUSEADDR && 216 Net.useExclusiveBind()) 217 { 218 // SO_REUSEADDR emulated when using exclusive bind 219 return (T)Boolean.valueOf(isReuseAddress); 220 } 221 return (T) Net.getSocketOption(fd, Net.UNSPEC, name); 222 } finally { 223 end(); 224 } 225 } 226 227 private static class DefaultOptionsHolder { 228 static final Set<SocketOption<?>> defaultOptions = defaultOptions(); 229 defaultOptions()230 private static Set<SocketOption<?>> defaultOptions() { 231 HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(2); 232 set.add(StandardSocketOptions.SO_RCVBUF); 233 set.add(StandardSocketOptions.SO_REUSEADDR); 234 return Collections.unmodifiableSet(set); 235 } 236 } 237 238 @Override supportedOptions()239 public final Set<SocketOption<?>> supportedOptions() { 240 return DefaultOptionsHolder.defaultOptions; 241 } 242 243 @Override toString()244 public final String toString() { 245 StringBuilder sb = new StringBuilder(); 246 sb.append(this.getClass().getName()); 247 sb.append('['); 248 if (!isOpen()) 249 sb.append("closed"); 250 else { 251 if (localAddress == null) { 252 sb.append("unbound"); 253 } else { 254 sb.append(Net.getRevealedLocalAddressAsString(localAddress)); 255 } 256 } 257 sb.append(']'); 258 return sb.toString(); 259 } 260 } 261