History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/nio/ch/AsynchronousSocketChannelImpl.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/nio/ch/AsynchronousSocketChannelImpl.java+580−0
@@ -0,0 +1,580 @@
1/*
2 * Copyright (c) 2008, 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
26package sun.nio.ch;
27
28import java.nio.ByteBuffer;
29import java.nio.channels.*;
30import java.net.SocketOption;
31import java.net.StandardSocketOptions;
32import java.net.SocketAddress;
33import java.net.InetSocketAddress;
34import java.io.IOException;
35import java.io.FileDescriptor;
36import java.util.Set;
37import java.util.HashSet;
38import java.util.Collections;
39import java.util.concurrent.*;
40import java.util.concurrent.locks.*;
41import sun.net.NetHooks;
42
43/**
44 * Base implementation of AsynchronousSocketChannel
45 */
46
47abstract class AsynchronousSocketChannelImpl
48 extends AsynchronousSocketChannel
49 implements Cancellable, Groupable
50{
51 protected final FileDescriptor fd;
52
53 // protects state, localAddress, and remoteAddress
54 protected final Object stateLock = new Object();
55
56 protected volatile SocketAddress localAddress = null;
57 protected volatile SocketAddress remoteAddress = null;
58
59 // State, increases monotonically
60 static final int ST_UNINITIALIZED = -1;
61 static final int ST_UNCONNECTED = 0;
62 static final int ST_PENDING = 1;
63 static final int ST_CONNECTED = 2;
64 protected volatile int state = ST_UNINITIALIZED;
65
66 // reading state
67 private final Object readLock = new Object();
68 private boolean reading;
69 private boolean readShutdown;
70 private boolean readKilled; // further reading disallowed due to timeout
71
72 // writing state
73 private final Object writeLock = new Object();
74 private boolean writing;
75 private boolean writeShutdown;
76 private boolean writeKilled; // further writing disallowed due to timeout
77
78 // close support
79 private final ReadWriteLock closeLock = new ReentrantReadWriteLock();
80 private volatile boolean open = true;
81
82 AsynchronousSocketChannelImpl(AsynchronousChannelGroupImpl group)
83 throws IOException
84 {
85 super(group.provider());
86 this.fd = Net.socket(true);
87 this.state = ST_UNCONNECTED;
88 }
89
90 // Constructor for sockets obtained from AsynchronousServerSocketChannelImpl
91 AsynchronousSocketChannelImpl(AsynchronousChannelGroupImpl group,
92 FileDescriptor fd,
93 InetSocketAddress remote)
94 throws IOException
95 {
96 super(group.provider());
97 this.fd = fd;
98 this.state = ST_CONNECTED;
99 this.localAddress = Net.localAddress(fd);
100 this.remoteAddress = remote;
101 }
102
103 @Override
104 public final boolean isOpen() {
105 return open;
106 }
107
108 /**
109 * Marks beginning of access to file descriptor/handle
110 */
111 final void begin() throws IOException {
112 closeLock.readLock().lock();
113 if (!isOpen())
114 throw new ClosedChannelException();
115 }
116
117 /**
118 * Marks end of access to file descriptor/handle
119 */
120 final void end() {
121 closeLock.readLock().unlock();
122 }
123
124 /**
125 * Invoked to close socket and release other resources.
126 */
127 abstract void implClose() throws IOException;
128
129 @Override
130 public final void close() throws IOException {
131 // synchronize with any threads initiating asynchronous operations
132 closeLock.writeLock().lock();
133 try {
134 if (!open)
135 return; // already closed
136 open = false;
137 } finally {
138 closeLock.writeLock().unlock();
139 }
140 implClose();
141 }
142
143 final void enableReading(boolean killed) {
144 synchronized (readLock) {
145 reading = false;
146 if (killed)
147 readKilled = true;
148 }
149 }
150
151 final void enableReading() {
152 enableReading(false);
153 }
154
155 final void enableWriting(boolean killed) {
156 synchronized (writeLock) {
157 writing = false;
158 if (killed)
159 writeKilled = true;
160 }
161 }
162
163 final void enableWriting() {
164 enableWriting(false);
165 }
166
167 final void killReading() {
168 synchronized (readLock) {
169 readKilled = true;
170 }
171 }
172
173 final void killWriting() {
174 synchronized (writeLock) {
175 writeKilled = true;
176 }
177 }
178
179 final void killConnect() {
180 // when a connect is cancelled then the connection may have been
181 // established so prevent reading or writing.
182 killReading();
183 killWriting();
184 }
185
186 /**
187 * Invoked by connect to initiate the connect operation.
188 */
189 abstract <A> Future<Void> implConnect(SocketAddress remote,
190 A attachment,
191 CompletionHandler<Void,? super A> handler);
192
193 @Override
194 public final Future<Void> connect(SocketAddress remote) {
195 return implConnect(remote, null, null);
196 }
197
198 @Override
199 public final <A> void connect(SocketAddress remote,
200 A attachment,
201 CompletionHandler<Void,? super A> handler)
202 {
203 if (handler == null)
204 throw new NullPointerException("'handler' is null");
205 implConnect(remote, attachment, handler);
206 }
207
208 /**
209 * Invoked by read to initiate the I/O operation.
210 */
211 abstract <V extends Number,A> Future<V> implRead(boolean isScatteringRead,
212 ByteBuffer dst,
213 ByteBuffer[] dsts,
214 long timeout,
215 TimeUnit unit,
216 A attachment,
217 CompletionHandler<V,? super A> handler);
218
219 @SuppressWarnings("unchecked")
220 private <V extends Number,A> Future<V> read(boolean isScatteringRead,
221 ByteBuffer dst,
222 ByteBuffer[] dsts,
223 long timeout,
224 TimeUnit unit,
225 A att,
226 CompletionHandler<V,? super A> handler)
227 {
228 if (!isOpen()) {
229 Throwable e = new ClosedChannelException();
230 if (handler == null)
231 return CompletedFuture.withFailure(e);
232 Invoker.invoke(this, handler, att, null, e);
233 return null;
234 }
235
236 if (remoteAddress == null)
237 throw new NotYetConnectedException();
238
239 boolean hasSpaceToRead = isScatteringRead || dst.hasRemaining();
240 boolean shutdown = false;
241
242 // check and update state
243 synchronized (readLock) {
244 if (readKilled)
245 throw new IllegalStateException("Reading not allowed due to timeout or cancellation");
246 if (reading)
247 throw new ReadPendingException();
248 if (readShutdown) {
249 shutdown = true;
250 } else {
251 if (hasSpaceToRead) {
252 reading = true;
253 }
254 }
255 }
256
257 // immediately complete with -1 if shutdown for read
258 // immediately complete with 0 if no space remaining
259 if (shutdown || !hasSpaceToRead) {
260 Number result;
261 if (isScatteringRead) {
262 result = (shutdown) ? Long.valueOf(-1L) : Long.valueOf(0L);
263 } else {
264 result = (shutdown) ? -1 : 0;
265 }
266 if (handler == null)
267 return CompletedFuture.withResult((V)result);
268 Invoker.invoke(this, handler, att, (V)result, null);
269 return null;
270 }
271
272 return implRead(isScatteringRead, dst, dsts, timeout, unit, att, handler);
273 }
274
275 @Override
276 public final Future<Integer> read(ByteBuffer dst) {
277 if (dst.isReadOnly())
278 throw new IllegalArgumentException("Read-only buffer");
279 return read(false, dst, null, 0L, TimeUnit.MILLISECONDS, null, null);
280 }
281
282 @Override
283 public final <A> void read(ByteBuffer dst,
284 long timeout,
285 TimeUnit unit,
286 A attachment,
287 CompletionHandler<Integer,? super A> handler)
288 {
289 if (handler == null)
290 throw new NullPointerException("'handler' is null");
291 if (dst.isReadOnly())
292 throw new IllegalArgumentException("Read-only buffer");
293 read(false, dst, null, timeout, unit, attachment, handler);
294 }
295
296 @Override
297 public final <A> void read(ByteBuffer[] dsts,
298 int offset,
299 int length,
300 long timeout,
301 TimeUnit unit,
302 A attachment,
303 CompletionHandler<Long,? super A> handler)
304 {
305 if (handler == null)
306 throw new NullPointerException("'handler' is null");
307 if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
308 throw new IndexOutOfBoundsException();
309 ByteBuffer[] bufs = Util.subsequence(dsts, offset, length);
310 for (int i=0; i<bufs.length; i++) {
311 if (bufs[i].isReadOnly())
312 throw new IllegalArgumentException("Read-only buffer");
313 }
314 read(true, null, bufs, timeout, unit, attachment, handler);
315 }
316
317 /**
318 * Invoked by write to initiate the I/O operation.
319 */
320 abstract <V extends Number,A> Future<V> implWrite(boolean isGatheringWrite,
321 ByteBuffer src,
322 ByteBuffer[] srcs,
323 long timeout,
324 TimeUnit unit,
325 A attachment,
326 CompletionHandler<V,? super A> handler);
327
328 @SuppressWarnings("unchecked")
329 private <V extends Number,A> Future<V> write(boolean isGatheringWrite,
330 ByteBuffer src,
331 ByteBuffer[] srcs,
332 long timeout,
333 TimeUnit unit,
334 A att,
335 CompletionHandler<V,? super A> handler)
336 {
337 boolean hasDataToWrite = isGatheringWrite || src.hasRemaining();
338
339 boolean closed = false;
340 if (isOpen()) {
341 if (remoteAddress == null)
342 throw new NotYetConnectedException();
343 // check and update state
344 synchronized (writeLock) {
345 if (writeKilled)
346 throw new IllegalStateException("Writing not allowed due to timeout or cancellation");
347 if (writing)
348 throw new WritePendingException();
349 if (writeShutdown) {
350 closed = true;
351 } else {
352 if (hasDataToWrite)
353 writing = true;
354 }
355 }
356 } else {
357 closed = true;
358 }
359
360 // channel is closed or shutdown for write
361 if (closed) {
362 Throwable e = new ClosedChannelException();
363 if (handler == null)
364 return CompletedFuture.withFailure(e);
365 Invoker.invoke(this, handler, att, null, e);
366 return null;
367 }
368
369 // nothing to write so complete immediately
370 if (!hasDataToWrite) {
371 Number result = (isGatheringWrite) ? (Number)0L : (Number)0;
372 if (handler == null)
373 return CompletedFuture.withResult((V)result);
374 Invoker.invoke(this, handler, att, (V)result, null);
375 return null;
376 }
377
378 return implWrite(isGatheringWrite, src, srcs, timeout, unit, att, handler);
379 }
380
381 @Override
382 public final Future<Integer> write(ByteBuffer src) {
383 return write(false, src, null, 0L, TimeUnit.MILLISECONDS, null, null);
384 }
385
386 @Override
387 public final <A> void write(ByteBuffer src,
388 long timeout,
389 TimeUnit unit,
390 A attachment,
391 CompletionHandler<Integer,? super A> handler)
392 {
393 if (handler == null)
394 throw new NullPointerException("'handler' is null");
395 write(false, src, null, timeout, unit, attachment, handler);
396 }
397
398 @Override
399 public final <A> void write(ByteBuffer[] srcs,
400 int offset,
401 int length,
402 long timeout,
403 TimeUnit unit,
404 A attachment,
405 CompletionHandler<Long,? super A> handler)
406 {
407 if (handler == null)
408 throw new NullPointerException("'handler' is null");
409 if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
410 throw new IndexOutOfBoundsException();
411 srcs = Util.subsequence(srcs, offset, length);
412 write(true, null, srcs, timeout, unit, attachment, handler);
413 }
414
415 @Override
416 public final AsynchronousSocketChannel bind(SocketAddress local)
417 throws IOException
418 {
419 try {
420 begin();
421 synchronized (stateLock) {
422 if (state == ST_PENDING)
423 throw new ConnectionPendingException();
424 if (localAddress != null)
425 throw new AlreadyBoundException();
426 InetSocketAddress isa = (local == null) ?
427 new InetSocketAddress(0) : Net.checkAddress(local);
428 NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
429 Net.bind(fd, isa.getAddress(), isa.getPort());
430 localAddress = Net.localAddress(fd);
431 }
432 } finally {
433 end();
434 }
435 return this;
436 }
437
438 @Override
439 public final SocketAddress getLocalAddress() throws IOException {
440 if (!isOpen())
441 throw new ClosedChannelException();
442 return localAddress;
443 }
444
445 @Override
446 public final <T> AsynchronousSocketChannel setOption(SocketOption<T> name, T value)
447 throws IOException
448 {
449 if (name == null)
450 throw new NullPointerException();
451 if (!supportedOptions().contains(name))
452 throw new UnsupportedOperationException("'" + name + "' not supported");
453
454 try {
455 begin();
456 if (writeShutdown)
457 throw new IOException("Connection has been shutdown for writing");
458 Net.setSocketOption(fd, Net.UNSPEC, name, value);
459 return this;
460 } finally {
461 end();
462 }
463 }
464
465 @Override
466 @SuppressWarnings("unchecked")
467 public final <T> T getOption(SocketOption<T> name) throws IOException {
468 if (name == null)
469 throw new NullPointerException();
470 if (!supportedOptions().contains(name))
471 throw new UnsupportedOperationException("'" + name + "' not supported");
472
473 try {
474 begin();
475 return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
476 } finally {
477 end();
478 }
479 }
480
481 private static class DefaultOptionsHolder {
482 static final Set<SocketOption<?>> defaultOptions = defaultOptions();
483
484 private static Set<SocketOption<?>> defaultOptions() {
485 HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(5);
486 set.add(StandardSocketOptions.SO_SNDBUF);
487 set.add(StandardSocketOptions.SO_RCVBUF);
488 set.add(StandardSocketOptions.SO_KEEPALIVE);
489 set.add(StandardSocketOptions.SO_REUSEADDR);
490 set.add(StandardSocketOptions.TCP_NODELAY);
491 return Collections.unmodifiableSet(set);
492 }
493 }
494
495 @Override
496 public final Set<SocketOption<?>> supportedOptions() {
497 return DefaultOptionsHolder.defaultOptions;
498 }
499
500 @Override
501 public final SocketAddress getRemoteAddress() throws IOException {
502 if (!isOpen())
503 throw new ClosedChannelException();
504 return remoteAddress;
505 }
506
507 @Override
508 public final AsynchronousSocketChannel shutdownInput() throws IOException {
509 try {
510 begin();
511 if (remoteAddress == null)
512 throw new NotYetConnectedException();
513 synchronized (readLock) {
514 if (!readShutdown) {
515 Net.shutdown(fd, Net.SHUT_RD);
516 readShutdown = true;
517 }
518 }
519 } finally {
520 end();
521 }
522 return this;
523 }
524
525 @Override
526 public final AsynchronousSocketChannel shutdownOutput() throws IOException {
527 try {
528 begin();
529 if (remoteAddress == null)
530 throw new NotYetConnectedException();
531 synchronized (writeLock) {
532 if (!writeShutdown) {
533 Net.shutdown(fd, Net.SHUT_WR);
534 writeShutdown = true;
535 }
536 }
537 } finally {
538 end();
539 }
540 return this;
541 }
542
543 @Override
544 public final String toString() {
545 StringBuilder sb = new StringBuilder();
546 sb.append(this.getClass().getName());
547 sb.append('[');
548 synchronized (stateLock) {
549 if (!isOpen()) {
550 sb.append("closed");
551 } else {
552 switch (state) {
553 case ST_UNCONNECTED:
554 sb.append("unconnected");
555 break;
556 case ST_PENDING:
557 sb.append("connection-pending");
558 break;
559 case ST_CONNECTED:
560 sb.append("connected");
561 if (readShutdown)
562 sb.append(" ishut");
563 if (writeShutdown)
564 sb.append(" oshut");
565 break;
566 }
567 if (localAddress != null) {
568 sb.append(" local=");
569 sb.append(localAddress.toString());
570 }
571 if (remoteAddress != null) {
572 sb.append(" remote=");
573 sb.append(remoteAddress.toString());
574 }
575 }
576 }
577 sb.append(']');
578 return sb.toString();
579 }
580}