Path: blob/master/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java
41159 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.ch;2627import java.io.IOException;28import java.io.InputStream;29import java.io.OutputStream;30import java.net.InetAddress;31import java.net.InetSocketAddress;32import java.net.Socket;33import java.net.SocketAddress;34import java.net.SocketException;35import java.net.SocketOption;36import java.net.StandardSocketOptions;37import java.nio.channels.SocketChannel;38import java.security.AccessController;39import java.security.PrivilegedActionException;40import java.security.PrivilegedExceptionAction;41import java.util.Set;4243import static java.util.concurrent.TimeUnit.MILLISECONDS;4445// Make a socket channel look like a socket.46//47// The methods in this class are defined in exactly the same order as in48// java.net.Socket so as to simplify tracking future changes to that class.49//5051class SocketAdaptor52extends Socket53{54// The channel being adapted55private final SocketChannelImpl sc;5657// Timeout "option" value for reads58private volatile int timeout;5960private SocketAdaptor(SocketChannelImpl sc) throws SocketException {61super(DummySocketImpl.create());62this.sc = sc;63}6465@SuppressWarnings("removal")66static Socket create(SocketChannelImpl sc) {67PrivilegedExceptionAction<Socket> pa = () -> new SocketAdaptor(sc);68try {69return AccessController.doPrivileged(pa);70} catch (PrivilegedActionException pae) {71throw new InternalError("Should not reach here", pae);72}73}7475private InetSocketAddress localAddress() {76return (InetSocketAddress) sc.localAddress();77}7879private InetSocketAddress remoteAddress() {80return (InetSocketAddress) sc.remoteAddress();81}8283@Override84public void connect(SocketAddress remote) throws IOException {85connect(remote, 0);86}8788@Override89public void connect(SocketAddress remote, int timeout) throws IOException {90if (remote == null)91throw new IllegalArgumentException("connect: The address can't be null");92if (timeout < 0)93throw new IllegalArgumentException("connect: timeout can't be negative");94try {95if (timeout > 0) {96long nanos = MILLISECONDS.toNanos(timeout);97sc.blockingConnect(remote, nanos);98} else {99sc.blockingConnect(remote, Long.MAX_VALUE);100}101} catch (Exception e) {102Net.translateException(e, true);103}104}105106@Override107public void bind(SocketAddress local) throws IOException {108try {109sc.bind(local);110} catch (Exception x) {111Net.translateException(x);112}113}114115@Override116public InetAddress getInetAddress() {117InetSocketAddress remote = remoteAddress();118if (remote == null) {119return null;120} else {121return remote.getAddress();122}123}124125@Override126public InetAddress getLocalAddress() {127if (sc.isOpen()) {128InetSocketAddress local = localAddress();129if (local != null) {130return Net.getRevealedLocalAddress(local).getAddress();131}132}133return new InetSocketAddress(0).getAddress();134}135136@Override137public int getPort() {138InetSocketAddress remote = remoteAddress();139if (remote == null) {140return 0;141} else {142return remote.getPort();143}144}145146@Override147public int getLocalPort() {148InetSocketAddress local = localAddress();149if (local == null) {150return -1;151} else {152return local.getPort();153}154}155156@Override157public SocketAddress getRemoteSocketAddress() {158return sc.remoteAddress();159}160161@Override162public SocketAddress getLocalSocketAddress() {163return Net.getRevealedLocalAddress(sc.localAddress());164}165166@Override167public SocketChannel getChannel() {168return sc;169}170171@Override172public InputStream getInputStream() throws IOException {173if (!sc.isOpen())174throw new SocketException("Socket is closed");175if (!sc.isConnected())176throw new SocketException("Socket is not connected");177if (!sc.isInputOpen())178throw new SocketException("Socket input is shutdown");179return new InputStream() {180@Override181public int read() throws IOException {182byte[] a = new byte[1];183int n = read(a, 0, 1);184return (n > 0) ? (a[0] & 0xff) : -1;185}186@Override187public int read(byte[] b, int off, int len) throws IOException {188int timeout = SocketAdaptor.this.timeout;189if (timeout > 0) {190long nanos = MILLISECONDS.toNanos(timeout);191return sc.blockingRead(b, off, len, nanos);192} else {193return sc.blockingRead(b, off, len, 0);194}195}196@Override197public int available() throws IOException {198return sc.available();199}200@Override201public void close() throws IOException {202sc.close();203}204};205}206207@Override208public OutputStream getOutputStream() throws IOException {209if (!sc.isOpen())210throw new SocketException("Socket is closed");211if (!sc.isConnected())212throw new SocketException("Socket is not connected");213if (!sc.isOutputOpen())214throw new SocketException("Socket output is shutdown");215return new OutputStream() {216@Override217public void write(int b) throws IOException {218byte[] a = new byte[]{(byte) b};219write(a, 0, 1);220}221@Override222public void write(byte[] b, int off, int len) throws IOException {223sc.blockingWriteFully(b, off, len);224}225@Override226public void close() throws IOException {227sc.close();228}229};230}231232private void setBooleanOption(SocketOption<Boolean> name, boolean value)233throws SocketException234{235try {236sc.setOption(name, value);237} catch (IOException x) {238Net.translateToSocketException(x);239}240}241242private void setIntOption(SocketOption<Integer> name, int value)243throws SocketException244{245try {246sc.setOption(name, value);247} catch (IOException x) {248Net.translateToSocketException(x);249}250}251252private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {253try {254return sc.getOption(name).booleanValue();255} catch (IOException x) {256Net.translateToSocketException(x);257return false; // keep compiler happy258}259}260261private int getIntOption(SocketOption<Integer> name) throws SocketException {262try {263return sc.getOption(name).intValue();264} catch (IOException x) {265Net.translateToSocketException(x);266return -1; // keep compiler happy267}268}269270@Override271public void setTcpNoDelay(boolean on) throws SocketException {272setBooleanOption(StandardSocketOptions.TCP_NODELAY, on);273}274275@Override276public boolean getTcpNoDelay() throws SocketException {277return getBooleanOption(StandardSocketOptions.TCP_NODELAY);278}279280@Override281public void setSoLinger(boolean on, int linger) throws SocketException {282if (!on)283linger = -1;284setIntOption(StandardSocketOptions.SO_LINGER, linger);285}286287@Override288public int getSoLinger() throws SocketException {289return getIntOption(StandardSocketOptions.SO_LINGER);290}291292@Override293public void sendUrgentData(int data) throws IOException {294int n = sc.sendOutOfBandData((byte) data);295if (n == 0)296throw new IOException("Socket buffer full");297}298299@Override300public void setOOBInline(boolean on) throws SocketException {301setBooleanOption(ExtendedSocketOption.SO_OOBINLINE, on);302}303304@Override305public boolean getOOBInline() throws SocketException {306return getBooleanOption(ExtendedSocketOption.SO_OOBINLINE);307}308309@Override310public void setSoTimeout(int timeout) throws SocketException {311if (!sc.isOpen())312throw new SocketException("Socket is closed");313if (timeout < 0)314throw new IllegalArgumentException("timeout < 0");315this.timeout = timeout;316}317318@Override319public int getSoTimeout() throws SocketException {320if (!sc.isOpen())321throw new SocketException("Socket is closed");322return timeout;323}324325@Override326public void setSendBufferSize(int size) throws SocketException {327// size 0 valid for SocketChannel, invalid for Socket328if (size <= 0)329throw new IllegalArgumentException("Invalid send size");330setIntOption(StandardSocketOptions.SO_SNDBUF, size);331}332333@Override334public int getSendBufferSize() throws SocketException {335return getIntOption(StandardSocketOptions.SO_SNDBUF);336}337338@Override339public void setReceiveBufferSize(int size) throws SocketException {340// size 0 valid for SocketChannel, invalid for Socket341if (size <= 0)342throw new IllegalArgumentException("Invalid receive size");343setIntOption(StandardSocketOptions.SO_RCVBUF, size);344}345346@Override347public int getReceiveBufferSize() throws SocketException {348return getIntOption(StandardSocketOptions.SO_RCVBUF);349}350351@Override352public void setKeepAlive(boolean on) throws SocketException {353setBooleanOption(StandardSocketOptions.SO_KEEPALIVE, on);354}355356@Override357public boolean getKeepAlive() throws SocketException {358return getBooleanOption(StandardSocketOptions.SO_KEEPALIVE);359}360361@Override362public void setTrafficClass(int tc) throws SocketException {363setIntOption(StandardSocketOptions.IP_TOS, tc);364}365366@Override367public int getTrafficClass() throws SocketException {368return getIntOption(StandardSocketOptions.IP_TOS);369}370371@Override372public void setReuseAddress(boolean on) throws SocketException {373setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);374}375376@Override377public boolean getReuseAddress() throws SocketException {378return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);379}380381@Override382public void close() throws IOException {383sc.close();384}385386@Override387public void shutdownInput() throws IOException {388try {389sc.shutdownInput();390} catch (Exception x) {391Net.translateException(x);392}393}394395@Override396public void shutdownOutput() throws IOException {397try {398sc.shutdownOutput();399} catch (Exception x) {400Net.translateException(x);401}402}403404@Override405public String toString() {406if (sc.isConnected())407return "Socket[addr=" + getInetAddress() +408",port=" + getPort() +409",localport=" + getLocalPort() + "]";410return "Socket[unconnected]";411}412413@Override414public boolean isConnected() {415return sc.isConnected();416}417418@Override419public boolean isBound() {420return sc.localAddress() != null;421}422423@Override424public boolean isClosed() {425return !sc.isOpen();426}427428@Override429public boolean isInputShutdown() {430return !sc.isInputOpen();431}432433@Override434public boolean isOutputShutdown() {435return !sc.isOutputOpen();436}437438@Override439public <T> Socket setOption(SocketOption<T> name, T value) throws IOException {440sc.setOption(name, value);441return this;442}443444@Override445public <T> T getOption(SocketOption<T> name) throws IOException {446return sc.getOption(name);447}448449@Override450public Set<SocketOption<?>> supportedOptions() {451return sc.supportedOptions();452}453}454455456