520 } |
520 } |
521 } |
521 } |
522 } |
522 } |
523 |
523 |
524 /** |
524 /** |
525 * Waits for a connection attempt to finish with a timeout. |
525 * Waits for a connection attempt to finish with a timeout |
526 * @throws SocketTimeoutException if the connect timeout elapses |
526 * @throws SocketTimeoutException if the connect timeout elapses |
527 */ |
527 */ |
528 private boolean timedFinishConnect(FileDescriptor fd, int millis) throws IOException { |
528 private void timedFinishConnect(FileDescriptor fd, int millis) throws IOException { |
529 long nanos = NANOSECONDS.convert(millis, TimeUnit.MILLISECONDS); |
529 long nanos = NANOSECONDS.convert(millis, TimeUnit.MILLISECONDS); |
530 long remainingNanos = nanos; |
530 long remainingNanos = nanos; |
531 long startNanos = System.nanoTime(); |
531 long startNanos = System.nanoTime(); |
532 boolean connected; |
532 boolean polled; |
533 do { |
533 do { |
534 park(fd, Net.POLLOUT, remainingNanos); |
534 park(fd, Net.POLLOUT, remainingNanos); |
535 connected = Net.pollConnectNow(fd); |
535 polled = Net.pollConnectNow(fd); |
536 if (!connected) { |
536 if (!polled) { |
537 remainingNanos = nanos - (System.nanoTime() - startNanos); |
537 remainingNanos = nanos - (System.nanoTime() - startNanos); |
538 if (remainingNanos <= 0) { |
538 if (remainingNanos <= 0) { |
539 throw new SocketTimeoutException("Connect timed out"); |
539 throw new SocketTimeoutException("Connect timed out"); |
540 } |
540 } |
541 } |
541 } |
542 } while (!connected && isOpen()); |
542 } while (!polled && isOpen()); |
543 return connected; |
|
544 } |
543 } |
545 |
544 |
546 /** |
545 /** |
547 * Attempts to establish a connection to the given socket address with a |
546 * Attempts to establish a connection to the given socket address with a |
548 * timeout. Closes the socket if connection cannot be established. |
547 * timeout. Closes the socket if connection cannot be established. |
549 * @throws IllegalArgumentException if the address is not an InetSocketAddress |
548 * @throws IOException if the address is not a resolved InetSocketAdress or |
550 * @throws UnknownHostException if the InetSocketAddress is not resolved |
549 * the connection cannot be established |
551 * @throws IOException if the connection cannot be established |
|
552 */ |
550 */ |
553 private void implConnect(SocketAddress remote, int millis) throws IOException { |
551 private void implConnect(SocketAddress remote, int millis) throws IOException { |
|
552 // SocketImpl connect only specifies IOException |
554 if (!(remote instanceof InetSocketAddress)) |
553 if (!(remote instanceof InetSocketAddress)) |
555 throw new IllegalArgumentException("Unsupported address type"); |
554 throw new IOException("Unsupported address type"); |
556 InetSocketAddress isa = (InetSocketAddress) remote; |
555 InetSocketAddress isa = (InetSocketAddress) remote; |
557 if (isa.isUnresolved()) { |
556 if (isa.isUnresolved()) { |
558 throw new UnknownHostException(isa.getHostName()); |
557 throw new UnknownHostException(isa.getHostName()); |
559 } |
558 } |
560 |
559 |
570 boolean connected = false; |
569 boolean connected = false; |
571 FileDescriptor fd = beginConnect(address, port); |
570 FileDescriptor fd = beginConnect(address, port); |
572 try { |
571 try { |
573 configureNonBlockingIfNeeded(fd, millis); |
572 configureNonBlockingIfNeeded(fd, millis); |
574 int n = Net.connect(fd, address, port); |
573 int n = Net.connect(fd, address, port); |
575 if (n > 0 && isOpen()) { |
574 if (isOpen()) { |
576 connected = true; |
575 if (n > 0) { |
577 } else if (IOStatus.okayToRetry(n) && isOpen()) { |
576 // connection established |
578 if (millis > 0) { |
577 connected = true; |
579 // finish connect with timeout |
578 } else if (IOStatus.okayToRetry(n)) { |
580 connected = timedFinishConnect(fd, millis); |
579 // not established or interrupted |
581 } else { |
580 if (millis > 0) { |
582 // finish connect, no timeout |
581 // finish connect with timeout |
583 do { |
582 timedFinishConnect(fd, millis); |
584 park(fd, Net.POLLOUT); |
583 } else { |
585 connected = Net.pollConnectNow(fd); |
584 // finish connect, no timeout |
586 } while (!connected && isOpen()); |
585 boolean polled; |
|
586 do { |
|
587 park(fd, Net.POLLOUT); |
|
588 polled = Net.pollConnectNow(fd); |
|
589 } while (!polled && isOpen()); |
|
590 } |
|
591 connected = isOpen(); |
587 } |
592 } |
588 } |
593 } |
589 } finally { |
594 } finally { |
590 endConnect(connected); |
595 endConnect(connected); |
591 } |
596 } |
884 // restore interrupt status |
889 // restore interrupt status |
885 if (interrupted) |
890 if (interrupted) |
886 Thread.currentThread().interrupt(); |
891 Thread.currentThread().interrupt(); |
887 } |
892 } |
888 |
893 |
|
894 // the socket options supported by client and server sockets |
|
895 private static volatile Set<SocketOption<?>> clientSocketOptions; |
|
896 private static volatile Set<SocketOption<?>> serverSocketOptions; |
|
897 |
889 @Override |
898 @Override |
890 protected Set<SocketOption<?>> supportedOptions() { |
899 protected Set<SocketOption<?>> supportedOptions() { |
891 Set<SocketOption<?>> options = new HashSet<>(); |
900 Set<SocketOption<?>> options = (server) ? serverSocketOptions : clientSocketOptions; |
892 options.addAll(super.supportedOptions()); |
901 if (options == null) { |
893 if (server) { |
902 options = new HashSet<>(); |
894 options.addAll(ExtendedSocketOptions.serverSocketOptions()); |
903 options.add(StandardSocketOptions.SO_RCVBUF); |
895 } else { |
904 options.add(StandardSocketOptions.SO_REUSEADDR); |
896 options.addAll(ExtendedSocketOptions.clientSocketOptions()); |
905 if (server) { |
897 } |
906 // IP_TOS added for server socket to maintain compatibility |
898 if (Net.isReusePortAvailable()) |
907 options.add(StandardSocketOptions.IP_TOS); |
899 options.add(StandardSocketOptions.SO_REUSEPORT); |
908 options.addAll(ExtendedSocketOptions.serverSocketOptions()); |
900 return Collections.unmodifiableSet(options); |
909 } else { |
|
910 options.add(StandardSocketOptions.IP_TOS); |
|
911 options.add(StandardSocketOptions.SO_KEEPALIVE); |
|
912 options.add(StandardSocketOptions.SO_SNDBUF); |
|
913 options.add(StandardSocketOptions.SO_LINGER); |
|
914 options.add(StandardSocketOptions.TCP_NODELAY); |
|
915 options.addAll(ExtendedSocketOptions.clientSocketOptions()); |
|
916 } |
|
917 if (Net.isReusePortAvailable()) |
|
918 options.add(StandardSocketOptions.SO_REUSEPORT); |
|
919 options = Collections.unmodifiableSet(options); |
|
920 if (server) { |
|
921 serverSocketOptions = options; |
|
922 } else { |
|
923 clientSocketOptions = options; |
|
924 } |
|
925 } |
|
926 return options; |
901 } |
927 } |
902 |
928 |
903 @Override |
929 @Override |
904 protected <T> void setOption(SocketOption<T> opt, T value) throws IOException { |
930 protected <T> void setOption(SocketOption<T> opt, T value) throws IOException { |
905 if (!supportedOptions().contains(opt)) |
931 if (!supportedOptions().contains(opt)) |