76 private static final int ST_KILLPENDING = 3; |
77 private static final int ST_KILLPENDING = 3; |
77 private static final int ST_KILLED = 4; |
78 private static final int ST_KILLED = 4; |
78 private int state = ST_UNINITIALIZED; |
79 private int state = ST_UNINITIALIZED; |
79 |
80 |
80 // Binding |
81 // Binding |
81 private SocketAddress localAddress = null; |
82 private SocketAddress localAddress; |
82 private SocketAddress remoteAddress = null; |
83 private SocketAddress remoteAddress; |
83 |
84 |
84 // Input/Output open |
85 // Input/Output open |
85 private boolean isInputOpen = true; |
86 private boolean isInputOpen = true; |
86 private boolean isOutputOpen = true; |
87 private boolean isOutputOpen = true; |
87 private boolean readyToConnect = false; |
88 private boolean readyToConnect = false; |
88 |
89 |
89 // Options, created on demand |
|
90 private SocketOpts.IP.TCP options = null; |
|
91 |
|
92 // Socket adaptor, created on demand |
90 // Socket adaptor, created on demand |
93 private Socket socket = null; |
91 private Socket socket; |
94 |
92 |
95 // -- End of fields protected by stateLock |
93 // -- End of fields protected by stateLock |
96 |
94 |
97 |
95 |
98 // Constructor for normal connecting sockets |
96 // Constructor for normal connecting sockets |
112 { |
110 { |
113 super(sp); |
111 super(sp); |
114 this.fd = fd; |
112 this.fd = fd; |
115 this.fdVal = IOUtil.fdVal(fd); |
113 this.fdVal = IOUtil.fdVal(fd); |
116 this.state = ST_CONNECTED; |
114 this.state = ST_CONNECTED; |
|
115 this.localAddress = Net.localAddress(fd); |
117 this.remoteAddress = remote; |
116 this.remoteAddress = remote; |
118 } |
117 } |
119 |
118 |
120 public Socket socket() { |
119 public Socket socket() { |
121 synchronized (stateLock) { |
120 synchronized (stateLock) { |
122 if (socket == null) |
121 if (socket == null) |
123 socket = SocketAdaptor.create(this); |
122 socket = SocketAdaptor.create(this); |
124 return socket; |
123 return socket; |
125 } |
124 } |
|
125 } |
|
126 |
|
127 @Override |
|
128 public SocketAddress getLocalAddress() throws IOException { |
|
129 synchronized (stateLock) { |
|
130 if (!isOpen()) |
|
131 return null; |
|
132 return localAddress; |
|
133 } |
|
134 } |
|
135 |
|
136 @Override |
|
137 public SocketAddress getConnectedAddress() throws IOException { |
|
138 synchronized (stateLock) { |
|
139 if (!isOpen()) |
|
140 return null; |
|
141 return remoteAddress; |
|
142 } |
|
143 } |
|
144 |
|
145 @Override |
|
146 public SocketChannel setOption(SocketOption name, Object value) |
|
147 throws IOException |
|
148 { |
|
149 if (name == null) |
|
150 throw new NullPointerException(); |
|
151 if (!options().contains(name)) |
|
152 throw new IllegalArgumentException("Invalid option name"); |
|
153 |
|
154 synchronized (stateLock) { |
|
155 if (!isOpen()) |
|
156 throw new ClosedChannelException(); |
|
157 |
|
158 // special handling for IP_TOS: no-op when IPv6 |
|
159 if (name == StandardSocketOption.IP_TOS) { |
|
160 if (!Net.isIPv6Available()) |
|
161 Net.setSocketOption(fd, StandardProtocolFamily.INET, name, value); |
|
162 return this; |
|
163 } |
|
164 |
|
165 // no options that require special handling |
|
166 Net.setSocketOption(fd, Net.UNSPEC, name, value); |
|
167 return this; |
|
168 } |
|
169 } |
|
170 |
|
171 @Override |
|
172 @SuppressWarnings("unchecked") |
|
173 public <T> T getOption(SocketOption<T> name) |
|
174 throws IOException |
|
175 { |
|
176 if (name == null) |
|
177 throw new NullPointerException(); |
|
178 if (!options().contains(name)) |
|
179 throw new IllegalArgumentException("Invalid option name"); |
|
180 |
|
181 synchronized (stateLock) { |
|
182 if (!isOpen()) |
|
183 throw new ClosedChannelException(); |
|
184 |
|
185 // special handling for IP_TOS: always return 0 when IPv6 |
|
186 if (name == StandardSocketOption.IP_TOS) { |
|
187 return (Net.isIPv6Available()) ? (T) Integer.valueOf(0) : |
|
188 (T) Net.getSocketOption(fd, StandardProtocolFamily.INET, name); |
|
189 } |
|
190 |
|
191 // no options that require special handling |
|
192 return (T) Net.getSocketOption(fd, Net.UNSPEC, name); |
|
193 } |
|
194 } |
|
195 |
|
196 private static class LazyInitialization { |
|
197 static final Set<SocketOption<?>> defaultOptions = defaultOptions(); |
|
198 |
|
199 private static Set<SocketOption<?>> defaultOptions() { |
|
200 HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(8); |
|
201 set.add(StandardSocketOption.SO_SNDBUF); |
|
202 set.add(StandardSocketOption.SO_RCVBUF); |
|
203 set.add(StandardSocketOption.SO_KEEPALIVE); |
|
204 set.add(StandardSocketOption.SO_REUSEADDR); |
|
205 set.add(StandardSocketOption.SO_LINGER); |
|
206 set.add(StandardSocketOption.TCP_NODELAY); |
|
207 // additional options required by socket adaptor |
|
208 set.add(StandardSocketOption.IP_TOS); |
|
209 set.add(ExtendedSocketOption.SO_OOBINLINE); |
|
210 return Collections.unmodifiableSet(set); |
|
211 } |
|
212 } |
|
213 |
|
214 @Override |
|
215 public final Set<SocketOption<?>> options() { |
|
216 return LazyInitialization.defaultOptions; |
126 } |
217 } |
127 |
218 |
128 private boolean ensureReadOpen() throws ClosedChannelException { |
219 private boolean ensureReadOpen() throws ClosedChannelException { |
129 synchronized (stateLock) { |
220 synchronized (stateLock) { |
130 if (!isOpen()) |
221 if (!isOpen()) |
408 |
499 |
409 protected void implConfigureBlocking(boolean block) throws IOException { |
500 protected void implConfigureBlocking(boolean block) throws IOException { |
410 IOUtil.configureBlocking(fd, block); |
501 IOUtil.configureBlocking(fd, block); |
411 } |
502 } |
412 |
503 |
413 public SocketOpts options() { |
|
414 synchronized (stateLock) { |
|
415 if (options == null) { |
|
416 SocketOptsImpl.Dispatcher d |
|
417 = new SocketOptsImpl.Dispatcher() { |
|
418 int getInt(int opt) throws IOException { |
|
419 return Net.getIntOption(fd, opt); |
|
420 } |
|
421 void setInt(int opt, int arg) |
|
422 throws IOException |
|
423 { |
|
424 Net.setIntOption(fd, opt, arg); |
|
425 } |
|
426 }; |
|
427 options = new SocketOptsImpl.IP.TCP(d); |
|
428 } |
|
429 return options; |
|
430 } |
|
431 } |
|
432 |
|
433 public boolean isBound() { |
|
434 synchronized (stateLock) { |
|
435 if (state == ST_CONNECTED) |
|
436 return true; |
|
437 return localAddress != null; |
|
438 } |
|
439 } |
|
440 |
|
441 public SocketAddress localAddress() { |
504 public SocketAddress localAddress() { |
442 synchronized (stateLock) { |
505 synchronized (stateLock) { |
443 if (state == ST_CONNECTED && |
|
444 (localAddress == null || |
|
445 ((InetSocketAddress)localAddress).getAddress().isAnyLocalAddress())) { |
|
446 // Socket was not bound before connecting or |
|
447 // Socket was bound with an "anyLocalAddress" |
|
448 localAddress = Net.localAddress(fd); |
|
449 } |
|
450 return localAddress; |
506 return localAddress; |
451 } |
507 } |
452 } |
508 } |
453 |
509 |
454 public SocketAddress remoteAddress() { |
510 public SocketAddress remoteAddress() { |
455 synchronized (stateLock) { |
511 synchronized (stateLock) { |
456 return remoteAddress; |
512 return remoteAddress; |
457 } |
513 } |
458 } |
514 } |
459 |
515 |
460 public void bind(SocketAddress local) throws IOException { |
516 @Override |
|
517 public SocketChannel bind(SocketAddress local) throws IOException { |
461 synchronized (readLock) { |
518 synchronized (readLock) { |
462 synchronized (writeLock) { |
519 synchronized (writeLock) { |
463 synchronized (stateLock) { |
520 synchronized (stateLock) { |
464 ensureOpenAndUnconnected(); |
521 if (!isOpen()) |
|
522 throw new ClosedChannelException(); |
|
523 if (state == ST_PENDING) |
|
524 throw new ConnectionPendingException(); |
465 if (localAddress != null) |
525 if (localAddress != null) |
466 throw new AlreadyBoundException(); |
526 throw new AlreadyBoundException(); |
467 InetSocketAddress isa = Net.checkAddress(local); |
527 InetSocketAddress isa = (local == null) ? |
|
528 new InetSocketAddress(0) : Net.checkAddress(local); |
468 Net.bind(fd, isa.getAddress(), isa.getPort()); |
529 Net.bind(fd, isa.getAddress(), isa.getPort()); |
469 localAddress = Net.localAddress(fd); |
530 localAddress = Net.localAddress(fd); |
470 } |
531 } |
471 } |
532 } |
472 } |
533 } |
|
534 return this; |
473 } |
535 } |
474 |
536 |
475 public boolean isConnected() { |
537 public boolean isConnected() { |
476 synchronized (stateLock) { |
538 synchronized (stateLock) { |
477 return (state == ST_CONNECTED); |
539 return (state == ST_CONNECTED); |
522 InetAddress ia = isa.getAddress(); |
583 InetAddress ia = isa.getAddress(); |
523 if (ia.isAnyLocalAddress()) |
584 if (ia.isAnyLocalAddress()) |
524 ia = InetAddress.getLocalHost(); |
585 ia = InetAddress.getLocalHost(); |
525 n = Net.connect(fd, |
586 n = Net.connect(fd, |
526 ia, |
587 ia, |
527 isa.getPort(), |
588 isa.getPort()); |
528 trafficClass); |
|
529 if ( (n == IOStatus.INTERRUPTED) |
589 if ( (n == IOStatus.INTERRUPTED) |
530 && isOpen()) |
590 && isOpen()) |
531 continue; |
591 continue; |
532 break; |
592 break; |
533 } |
593 } |
|
594 |
|
595 synchronized (stateLock) { |
|
596 if (isOpen() && (localAddress == null) || |
|
597 ((InetSocketAddress)localAddress) |
|
598 .getAddress().isAnyLocalAddress()) |
|
599 { |
|
600 // Socket was not bound before connecting or |
|
601 // Socket was bound with an "anyLocalAddress" |
|
602 localAddress = Net.localAddress(fd); |
|
603 } |
|
604 } |
|
605 |
534 } finally { |
606 } finally { |
535 readerCleanup(); |
607 readerCleanup(); |
536 end((n > 0) || (n == IOStatus.UNAVAILABLE)); |
608 end((n > 0) || (n == IOStatus.UNAVAILABLE)); |
537 assert IOStatus.check(n); |
609 assert IOStatus.check(n); |
538 } |
610 } |
644 return false; |
716 return false; |
645 } |
717 } |
646 } |
718 } |
647 } |
719 } |
648 |
720 |
649 public final static int SHUT_RD = 0; |
721 @Override |
650 public final static int SHUT_WR = 1; |
722 public SocketChannel shutdownInput() throws IOException { |
651 public final static int SHUT_RDWR = 2; |
|
652 |
|
653 public void shutdownInput() throws IOException { |
|
654 synchronized (stateLock) { |
723 synchronized (stateLock) { |
655 if (!isOpen()) |
724 if (!isOpen()) |
656 throw new ClosedChannelException(); |
725 throw new ClosedChannelException(); |
657 isInputOpen = false; |
726 if (!isConnected()) |
658 shutdown(fd, SHUT_RD); |
727 throw new NotYetConnectedException(); |
659 if (readerThread != 0) |
728 if (isInputOpen) { |
660 NativeThread.signal(readerThread); |
729 Net.shutdown(fd, Net.SHUT_RD); |
661 } |
730 if (readerThread != 0) |
662 } |
731 NativeThread.signal(readerThread); |
663 |
732 isInputOpen = false; |
664 public void shutdownOutput() throws IOException { |
733 } |
|
734 return this; |
|
735 } |
|
736 } |
|
737 |
|
738 @Override |
|
739 public SocketChannel shutdownOutput() throws IOException { |
665 synchronized (stateLock) { |
740 synchronized (stateLock) { |
666 if (!isOpen()) |
741 if (!isOpen()) |
667 throw new ClosedChannelException(); |
742 throw new ClosedChannelException(); |
668 isOutputOpen = false; |
743 if (!isConnected()) |
669 shutdown(fd, SHUT_WR); |
744 throw new NotYetConnectedException(); |
670 if (writerThread != 0) |
745 if (isOutputOpen) { |
671 NativeThread.signal(writerThread); |
746 Net.shutdown(fd, Net.SHUT_WR); |
|
747 if (writerThread != 0) |
|
748 NativeThread.signal(writerThread); |
|
749 isOutputOpen = false; |
|
750 } |
|
751 return this; |
672 } |
752 } |
673 } |
753 } |
674 |
754 |
675 public boolean isInputOpen() { |
755 public boolean isInputOpen() { |
676 synchronized (stateLock) { |
756 synchronized (stateLock) { |