PageRenderTime 66ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/src/solaris/classes/sun/nio/ch/SctpServerChannelImpl.java

https://github.com/ikeji/openjdk7-jdk
Java | 424 lines | 313 code | 59 blank | 52 comment | 69 complexity | 2b710bddb521248b690cab2712416c06 MD5 | raw file
  1. /*
  2. * Copyright (c) 2009, 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. package sun.nio.ch;
  26. import java.net.SocketAddress;
  27. import java.net.InetSocketAddress;
  28. import java.net.InetAddress;
  29. import java.io.FileDescriptor;
  30. import java.io.IOException;
  31. import java.util.Collections;
  32. import java.util.Set;
  33. import java.util.HashSet;
  34. import java.nio.channels.SelectionKey;
  35. import java.nio.channels.ClosedChannelException;
  36. import java.nio.channels.NotYetBoundException;
  37. import java.nio.channels.spi.SelectorProvider;
  38. import com.sun.nio.sctp.IllegalUnbindException;
  39. import com.sun.nio.sctp.SctpChannel;
  40. import com.sun.nio.sctp.SctpServerChannel;
  41. import com.sun.nio.sctp.SctpSocketOption;
  42. import com.sun.nio.sctp.SctpStandardSocketOptions;
  43. /**
  44. * An implementation of SctpServerChannel
  45. */
  46. public class SctpServerChannelImpl extends SctpServerChannel
  47. implements SelChImpl
  48. {
  49. private final FileDescriptor fd;
  50. private final int fdVal;
  51. /* IDs of native thread doing accept, for signalling */
  52. private volatile long thread = 0;
  53. /* Lock held by thread currently blocked in this channel */
  54. private final Object lock = new Object();
  55. /* Lock held by any thread that modifies the state fields declared below
  56. * DO NOT invoke a blocking I/O operation while holding this lock! */
  57. private final Object stateLock = new Object();
  58. private enum ChannelState {
  59. UNINITIALIZED,
  60. INUSE,
  61. KILLPENDING,
  62. KILLED,
  63. }
  64. /* -- The following fields are protected by stateLock -- */
  65. private ChannelState state = ChannelState.UNINITIALIZED;
  66. /* Binding: Once bound the port will remain constant. */
  67. int port = -1;
  68. private HashSet<InetSocketAddress> localAddresses = new HashSet<InetSocketAddress>();
  69. /* Has the channel been bound to the wildcard address */
  70. private boolean wildcard; /* false */
  71. /* -- End of fields protected by stateLock -- */
  72. /**
  73. * Initializes a new instance of this class.
  74. */
  75. public SctpServerChannelImpl(SelectorProvider provider)
  76. throws IOException {
  77. //TODO: update provider remove public modifier
  78. super(provider);
  79. this.fd = SctpNet.socket(true);
  80. this.fdVal = IOUtil.fdVal(fd);
  81. this.state = ChannelState.INUSE;
  82. }
  83. @Override
  84. public SctpServerChannel bind(SocketAddress local, int backlog)
  85. throws IOException {
  86. synchronized (lock) {
  87. synchronized (stateLock) {
  88. if (!isOpen())
  89. throw new ClosedChannelException();
  90. if (isBound())
  91. SctpNet.throwAlreadyBoundException();
  92. InetSocketAddress isa = (local == null) ?
  93. new InetSocketAddress(0) : Net.checkAddress(local);
  94. SecurityManager sm = System.getSecurityManager();
  95. if (sm != null)
  96. sm.checkListen(isa.getPort());
  97. Net.bind(fd, isa.getAddress(), isa.getPort());
  98. InetSocketAddress boundIsa = Net.localAddress(fd);
  99. port = boundIsa.getPort();
  100. localAddresses.add(isa);
  101. if (isa.getAddress().isAnyLocalAddress())
  102. wildcard = true;
  103. SctpNet.listen(fdVal, backlog < 1 ? 50 : backlog);
  104. }
  105. }
  106. return this;
  107. }
  108. @Override
  109. public SctpServerChannel bindAddress(InetAddress address)
  110. throws IOException {
  111. return bindUnbindAddress(address, true);
  112. }
  113. @Override
  114. public SctpServerChannel unbindAddress(InetAddress address)
  115. throws IOException {
  116. return bindUnbindAddress(address, false);
  117. }
  118. private SctpServerChannel bindUnbindAddress(InetAddress address, boolean add)
  119. throws IOException {
  120. if (address == null)
  121. throw new IllegalArgumentException();
  122. synchronized (lock) {
  123. synchronized (stateLock) {
  124. if (!isOpen())
  125. throw new ClosedChannelException();
  126. if (!isBound())
  127. throw new NotYetBoundException();
  128. if (wildcard)
  129. throw new IllegalStateException(
  130. "Cannot add or remove addresses from a channel that is bound to the wildcard address");
  131. if (address.isAnyLocalAddress())
  132. throw new IllegalArgumentException(
  133. "Cannot add or remove the wildcard address");
  134. if (add) {
  135. for (InetSocketAddress addr : localAddresses) {
  136. if (addr.getAddress().equals(address)) {
  137. SctpNet.throwAlreadyBoundException();
  138. }
  139. }
  140. } else { /*removing */
  141. /* Verify that there is more than one address
  142. * and that address is already bound */
  143. if (localAddresses.size() <= 1)
  144. throw new IllegalUnbindException("Cannot remove address from a channel with only one address bound");
  145. boolean foundAddress = false;
  146. for (InetSocketAddress addr : localAddresses) {
  147. if (addr.getAddress().equals(address)) {
  148. foundAddress = true;
  149. break;
  150. }
  151. }
  152. if (!foundAddress )
  153. throw new IllegalUnbindException("Cannot remove address from a channel that is not bound to that address");
  154. }
  155. SctpNet.bindx(fdVal, new InetAddress[]{address}, port, add);
  156. /* Update our internal Set to reflect the addition/removal */
  157. if (add)
  158. localAddresses.add(new InetSocketAddress(address, port));
  159. else {
  160. for (InetSocketAddress addr : localAddresses) {
  161. if (addr.getAddress().equals(address)) {
  162. localAddresses.remove(addr);
  163. break;
  164. }
  165. }
  166. }
  167. }
  168. }
  169. return this;
  170. }
  171. private boolean isBound() {
  172. synchronized (stateLock) {
  173. return port == -1 ? false : true;
  174. }
  175. }
  176. private void acceptCleanup() throws IOException {
  177. synchronized (stateLock) {
  178. thread = 0;
  179. if (state == ChannelState.KILLPENDING)
  180. kill();
  181. }
  182. }
  183. @Override
  184. public SctpChannel accept() throws IOException {
  185. synchronized (lock) {
  186. if (!isOpen())
  187. throw new ClosedChannelException();
  188. if (!isBound())
  189. throw new NotYetBoundException();
  190. SctpChannel sc = null;
  191. int n = 0;
  192. FileDescriptor newfd = new FileDescriptor();
  193. InetSocketAddress[] isaa = new InetSocketAddress[1];
  194. try {
  195. begin();
  196. if (!isOpen())
  197. return null;
  198. thread = NativeThread.current();
  199. for (;;) {
  200. n = accept0(fd, newfd, isaa);
  201. if ((n == IOStatus.INTERRUPTED) && isOpen())
  202. continue;
  203. break;
  204. }
  205. } finally {
  206. acceptCleanup();
  207. end(n > 0);
  208. assert IOStatus.check(n);
  209. }
  210. if (n < 1)
  211. return null;
  212. IOUtil.configureBlocking(newfd, true);
  213. InetSocketAddress isa = isaa[0];
  214. sc = new SctpChannelImpl(provider(), newfd);
  215. SecurityManager sm = System.getSecurityManager();
  216. if (sm != null)
  217. sm.checkAccept(isa.getAddress().getHostAddress(),
  218. isa.getPort());
  219. return sc;
  220. }
  221. }
  222. @Override
  223. protected void implConfigureBlocking(boolean block) throws IOException {
  224. IOUtil.configureBlocking(fd, block);
  225. }
  226. @Override
  227. public void implCloseSelectableChannel() throws IOException {
  228. synchronized (stateLock) {
  229. SctpNet.preClose(fdVal);
  230. if (thread != 0)
  231. NativeThread.signal(thread);
  232. if (!isRegistered())
  233. kill();
  234. }
  235. }
  236. @Override
  237. public void kill() throws IOException {
  238. synchronized (stateLock) {
  239. if (state == ChannelState.KILLED)
  240. return;
  241. if (state == ChannelState.UNINITIALIZED) {
  242. state = ChannelState.KILLED;
  243. return;
  244. }
  245. assert !isOpen() && !isRegistered();
  246. // Postpone the kill if there is a thread in accept
  247. if (thread == 0) {
  248. SctpNet.close(fdVal);
  249. state = ChannelState.KILLED;
  250. } else {
  251. state = ChannelState.KILLPENDING;
  252. }
  253. }
  254. }
  255. @Override
  256. public FileDescriptor getFD() {
  257. return fd;
  258. }
  259. @Override
  260. public int getFDVal() {
  261. return fdVal;
  262. }
  263. /**
  264. * Translates native poll revent ops into a ready operation ops
  265. */
  266. private boolean translateReadyOps(int ops, int initialOps,
  267. SelectionKeyImpl sk) {
  268. int intOps = sk.nioInterestOps();
  269. int oldOps = sk.nioReadyOps();
  270. int newOps = initialOps;
  271. if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
  272. /* This should only happen if this channel is pre-closed while a
  273. * selection operation is in progress
  274. * ## Throw an error if this channel has not been pre-closed */
  275. return false;
  276. }
  277. if ((ops & (PollArrayWrapper.POLLERR
  278. | PollArrayWrapper.POLLHUP)) != 0) {
  279. newOps = intOps;
  280. sk.nioReadyOps(newOps);
  281. return (newOps & ~oldOps) != 0;
  282. }
  283. if (((ops & PollArrayWrapper.POLLIN) != 0) &&
  284. ((intOps & SelectionKey.OP_ACCEPT) != 0))
  285. newOps |= SelectionKey.OP_ACCEPT;
  286. sk.nioReadyOps(newOps);
  287. return (newOps & ~oldOps) != 0;
  288. }
  289. @Override
  290. public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
  291. return translateReadyOps(ops, sk.nioReadyOps(), sk);
  292. }
  293. @Override
  294. public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
  295. return translateReadyOps(ops, 0, sk);
  296. }
  297. @Override
  298. public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
  299. int newOps = 0;
  300. /* Translate ops */
  301. if ((ops & SelectionKey.OP_ACCEPT) != 0)
  302. newOps |= PollArrayWrapper.POLLIN;
  303. /* Place ops into pollfd array */
  304. sk.selector.putEventOps(sk, newOps);
  305. }
  306. @Override
  307. public <T> SctpServerChannel setOption(SctpSocketOption<T> name, T value)
  308. throws IOException {
  309. if (name == null)
  310. throw new NullPointerException();
  311. if (!supportedOptions().contains(name))
  312. throw new UnsupportedOperationException("'" + name + "' not supported");
  313. synchronized (stateLock) {
  314. if (!isOpen())
  315. throw new ClosedChannelException();
  316. SctpNet.setSocketOption(fdVal, name, value, 0 /*oneToOne*/);
  317. return this;
  318. }
  319. }
  320. @Override
  321. public <T> T getOption(SctpSocketOption<T> name) throws IOException {
  322. if (name == null)
  323. throw new NullPointerException();
  324. if (!supportedOptions().contains(name))
  325. throw new UnsupportedOperationException("'" + name + "' not supported");
  326. synchronized (stateLock) {
  327. if (!isOpen())
  328. throw new ClosedChannelException();
  329. return (T) SctpNet.getSocketOption(fdVal, name, 0 /*oneToOne*/);
  330. }
  331. }
  332. private static class DefaultOptionsHolder {
  333. static final Set<SctpSocketOption<?>> defaultOptions = defaultOptions();
  334. private static Set<SctpSocketOption<?>> defaultOptions() {
  335. HashSet<SctpSocketOption<?>> set = new HashSet<SctpSocketOption<?>>(1);
  336. set.add(SctpStandardSocketOptions.SCTP_INIT_MAXSTREAMS);
  337. return Collections.unmodifiableSet(set);
  338. }
  339. }
  340. @Override
  341. public final Set<SctpSocketOption<?>> supportedOptions() {
  342. return DefaultOptionsHolder.defaultOptions;
  343. }
  344. @Override
  345. public Set<SocketAddress> getAllLocalAddresses()
  346. throws IOException {
  347. synchronized (stateLock) {
  348. if (!isOpen())
  349. throw new ClosedChannelException();
  350. if (!isBound())
  351. return Collections.EMPTY_SET;
  352. return SctpNet.getLocalAddresses(fdVal);
  353. }
  354. }
  355. /* Native */
  356. private static native void initIDs();
  357. private static native int accept0(FileDescriptor ssfd,
  358. FileDescriptor newfd, InetSocketAddress[] isaa) throws IOException;
  359. static {
  360. Util.load(); // loads nio & net native libraries
  361. java.security.AccessController.doPrivileged(
  362. new sun.security.action.LoadLibraryAction("sctp"));
  363. initIDs();
  364. }
  365. }