mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8278326: Socket close is not thread safe and other cleanup
Reviewed-by: jpai
This commit is contained in:
parent
036c80844e
commit
4b573343a6
5 changed files with 835 additions and 232 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -124,8 +124,8 @@ import java.util.Set;
|
|||
// close the original socket impl and release its descriptor
|
||||
close();
|
||||
|
||||
// update the Sockets impl to the impl from the http Socket
|
||||
SocketImpl si = httpSocket.impl;
|
||||
// change Socket to use httpSocket's SocketImpl
|
||||
SocketImpl si = httpSocket.impl();
|
||||
socket.setImpl(si);
|
||||
|
||||
// best effort is made to try and reset options previously set
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -78,18 +78,23 @@ import sun.net.PlatformSocketImpl;
|
|||
* @since 1.0
|
||||
*/
|
||||
public class ServerSocket implements java.io.Closeable {
|
||||
/**
|
||||
* The underlying SocketImpl
|
||||
*/
|
||||
// the underlying SocketImpl
|
||||
private final SocketImpl impl;
|
||||
|
||||
/**
|
||||
* Various states of this socket, need stateLock to change.
|
||||
*/
|
||||
// various states
|
||||
private volatile boolean created; // impl.create(boolean) called
|
||||
private volatile boolean bound;
|
||||
private volatile boolean closed;
|
||||
private final Object stateLock = new Object();
|
||||
|
||||
// used to coordinate creating and closing underlying socket
|
||||
private final Object socketLock = new Object();
|
||||
|
||||
/**
|
||||
* Creates a server socket with the given {@code SocketImpl}.
|
||||
*/
|
||||
private ServerSocket(Void unused, SocketImpl impl) {
|
||||
this.impl = Objects.requireNonNull(impl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a server socket with a user-specified {@code SocketImpl}.
|
||||
|
@ -104,9 +109,7 @@ public class ServerSocket implements java.io.Closeable {
|
|||
* @since 12
|
||||
*/
|
||||
protected ServerSocket(SocketImpl impl) {
|
||||
Objects.requireNonNull(impl);
|
||||
checkPermission();
|
||||
this.impl = impl;
|
||||
this(checkPermission(), impl);
|
||||
}
|
||||
|
||||
private static Void checkPermission() {
|
||||
|
@ -280,16 +283,26 @@ public class ServerSocket implements java.io.Closeable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the {@code SocketImpl} attached to this socket, creating
|
||||
* it if necessary.
|
||||
*
|
||||
* @return the {@code SocketImpl} attached to that ServerSocket.
|
||||
* @throws SocketException if creation fails.
|
||||
* @since 1.4
|
||||
* Create a SocketImpl for a server socket. The SocketImpl is created
|
||||
* without an underlying socket.
|
||||
*/
|
||||
private static SocketImpl createImpl() {
|
||||
SocketImplFactory factory = ServerSocket.factory;
|
||||
if (factory != null) {
|
||||
return factory.createSocketImpl();
|
||||
} else {
|
||||
return SocketImpl.createPlatformSocketImpl(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code SocketImpl} for this ServerSocket, creating the
|
||||
* underlying socket if required.
|
||||
* @throws SocketException if creating the underlying socket fails
|
||||
*/
|
||||
private SocketImpl getImpl() throws SocketException {
|
||||
if (!created) {
|
||||
synchronized (stateLock) {
|
||||
synchronized (socketLock) {
|
||||
if (!created) {
|
||||
if (closed) {
|
||||
throw new SocketException("Socket is closed");
|
||||
|
@ -308,18 +321,6 @@ public class ServerSocket implements java.io.Closeable {
|
|||
return impl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SocketImpl for a server socket.
|
||||
*/
|
||||
private static SocketImpl createImpl() {
|
||||
SocketImplFactory factory = ServerSocket.factory;
|
||||
if (factory != null) {
|
||||
return factory.createSocketImpl();
|
||||
} else {
|
||||
return SocketImpl.createPlatformSocketImpl(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Binds the {@code ServerSocket} to a specific address
|
||||
|
@ -385,15 +386,11 @@ public class ServerSocket implements java.io.Closeable {
|
|||
if (security != null)
|
||||
security.checkListen(epoint.getPort());
|
||||
|
||||
synchronized (stateLock) {
|
||||
if (closed)
|
||||
throw new SocketException("Socket is closed");
|
||||
if (bound)
|
||||
throw new SocketException("Already bound");
|
||||
getImpl().bind(epoint.getAddress(), epoint.getPort());
|
||||
getImpl().listen(backlog);
|
||||
bound = true;
|
||||
}
|
||||
// SocketImpl bind+listen throw if already bound or closed
|
||||
SocketImpl impl = getImpl();
|
||||
impl.bind(epoint.getAddress(), epoint.getPort());
|
||||
impl.listen(backlog);
|
||||
bound = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -581,19 +578,24 @@ public class ServerSocket implements java.io.Closeable {
|
|||
* @revised 1.4
|
||||
*/
|
||||
protected final void implAccept(Socket s) throws IOException {
|
||||
SocketImpl si = s.impl;
|
||||
SocketImpl si = s.impl();
|
||||
|
||||
// Socket has no SocketImpl
|
||||
if (si == null) {
|
||||
si = implAccept();
|
||||
s.setImpl(si);
|
||||
s.postAccept();
|
||||
try {
|
||||
s.setConnectedImpl(si);
|
||||
} catch (SocketException e) {
|
||||
// s has been closed so newly accepted connection needs to be closed
|
||||
si.closeQuietly();
|
||||
throw e;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Socket has a SOCKS or HTTP SocketImpl, need delegate
|
||||
if (si instanceof DelegatingSocketImpl) {
|
||||
si = ((DelegatingSocketImpl) si).delegate();
|
||||
if (si instanceof DelegatingSocketImpl dsi) {
|
||||
si = dsi.delegate();
|
||||
assert si instanceof PlatformSocketImpl;
|
||||
}
|
||||
|
||||
|
@ -609,17 +611,23 @@ public class ServerSocket implements java.io.Closeable {
|
|||
if (impl instanceof PlatformSocketImpl) {
|
||||
SocketImpl psi = platformImplAccept();
|
||||
si.copyOptionsTo(psi);
|
||||
s.setImpl(psi);
|
||||
si.closeQuietly();
|
||||
try {
|
||||
s.setConnectedImpl(psi);
|
||||
} catch (SocketException e) {
|
||||
// s has been closed so newly accepted connection needs to be closed
|
||||
psi.closeQuietly();
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
s.impl = null; // temporarily break connection to impl
|
||||
s.setImpl(null); // temporarily break connection to impl
|
||||
try {
|
||||
customImplAccept(si);
|
||||
} finally {
|
||||
s.impl = si; // restore connection to impl
|
||||
s.setImpl(si); // restore connection to impl
|
||||
}
|
||||
s.setConnected();
|
||||
}
|
||||
s.postAccept();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -736,7 +744,7 @@ public class ServerSocket implements java.io.Closeable {
|
|||
* @revised 1.4
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
synchronized (stateLock) {
|
||||
synchronized (socketLock) {
|
||||
if (!closed) {
|
||||
closed = true;
|
||||
|
||||
|
@ -830,8 +838,8 @@ public class ServerSocket implements java.io.Closeable {
|
|||
throw new SocketException("Socket is closed");
|
||||
Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
|
||||
/* extra type safety */
|
||||
if (o instanceof Integer) {
|
||||
return ((Integer) o).intValue();
|
||||
if (o instanceof Integer i) {
|
||||
return i.intValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1010,10 +1018,9 @@ public class ServerSocket implements java.io.Closeable {
|
|||
* @since 1.4
|
||||
* @see #getReceiveBufferSize
|
||||
*/
|
||||
public void setReceiveBufferSize (int size) throws SocketException {
|
||||
if (!(size > 0)) {
|
||||
public void setReceiveBufferSize(int size) throws SocketException {
|
||||
if (size <= 0)
|
||||
throw new IllegalArgumentException("negative receive size");
|
||||
}
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
getImpl().setOption(SocketOptions.SO_RCVBUF, size);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -98,31 +98,11 @@ import java.util.Collections;
|
|||
* @since 1.0
|
||||
*/
|
||||
public class Socket implements java.io.Closeable {
|
||||
/**
|
||||
* Various states of this socket.
|
||||
*/
|
||||
private boolean created = false;
|
||||
private boolean bound = false;
|
||||
private boolean connected = false;
|
||||
private boolean closed = false;
|
||||
private Object closeLock = new Object();
|
||||
private boolean shutIn = false;
|
||||
private boolean shutOut = false;
|
||||
|
||||
/**
|
||||
* The implementation of this Socket.
|
||||
*/
|
||||
SocketImpl impl;
|
||||
|
||||
/**
|
||||
* Socket input/output streams
|
||||
*/
|
||||
private volatile InputStream in;
|
||||
private volatile OutputStream out;
|
||||
private static final VarHandle IN, OUT;
|
||||
private static final VarHandle STATE, IN, OUT;
|
||||
static {
|
||||
try {
|
||||
MethodHandles.Lookup l = MethodHandles.lookup();
|
||||
STATE = l.findVarHandle(Socket.class, "state", int.class);
|
||||
IN = l.findVarHandle(Socket.class, "in", InputStream.class);
|
||||
OUT = l.findVarHandle(Socket.class, "out", OutputStream.class);
|
||||
} catch (Exception e) {
|
||||
|
@ -130,6 +110,63 @@ public class Socket implements java.io.Closeable {
|
|||
}
|
||||
}
|
||||
|
||||
// the underlying SocketImpl, may be null, may be swapped when connecting
|
||||
private volatile SocketImpl impl;
|
||||
|
||||
// state bits
|
||||
private static final int SOCKET_CREATED = 1 << 0; // impl.create(boolean) called
|
||||
private static final int BOUND = 1 << 1;
|
||||
private static final int CONNECTED = 1 << 2;
|
||||
private static final int CLOSED = 1 << 3;
|
||||
private static final int SHUT_IN = 1 << 9;
|
||||
private static final int SHUT_OUT = 1 << 10;
|
||||
private volatile int state;
|
||||
|
||||
// used to coordinate creating and closing underlying socket
|
||||
private final Object socketLock = new Object();
|
||||
|
||||
// input/output streams
|
||||
private volatile InputStream in;
|
||||
private volatile OutputStream out;
|
||||
|
||||
/**
|
||||
* Atomically sets state to the result of a bitwise OR of the current value
|
||||
* and the given mask.
|
||||
* @return the previous state value
|
||||
*/
|
||||
private int getAndBitwiseOrState(int mask) {
|
||||
return (int) STATE.getAndBitwiseOr(this, mask);
|
||||
}
|
||||
|
||||
private static boolean isBound(int s) {
|
||||
return (s & BOUND) != 0;
|
||||
}
|
||||
|
||||
private static boolean isConnected(int s) {
|
||||
return (s & CONNECTED) != 0;
|
||||
}
|
||||
|
||||
private static boolean isClosed(int s) {
|
||||
return (s & CLOSED) != 0;
|
||||
}
|
||||
|
||||
private static boolean isInputShutdown(int s) {
|
||||
return (s & SHUT_IN) != 0;
|
||||
}
|
||||
|
||||
private static boolean isOutputShutdown(int s) {
|
||||
return (s & SHUT_OUT) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unconnected socket with the given {@code SocketImpl}.
|
||||
*/
|
||||
private Socket(Void unused, SocketImpl impl) {
|
||||
if (impl != null) {
|
||||
this.impl = impl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unconnected Socket.
|
||||
* <p>
|
||||
|
@ -142,7 +179,7 @@ public class Socket implements java.io.Closeable {
|
|||
* @revised 1.4
|
||||
*/
|
||||
public Socket() {
|
||||
setImpl();
|
||||
this.impl = createImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -232,18 +269,16 @@ public class Socket implements java.io.Closeable {
|
|||
* @since 1.1
|
||||
*/
|
||||
protected Socket(SocketImpl impl) throws SocketException {
|
||||
checkPermission(impl);
|
||||
this.impl = impl;
|
||||
this(checkPermission(impl), impl);
|
||||
}
|
||||
|
||||
private static Void checkPermission(SocketImpl impl) {
|
||||
if (impl == null) {
|
||||
return null;
|
||||
}
|
||||
@SuppressWarnings("removal")
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(SecurityConstants.SET_SOCKETIMPL_PERMISSION);
|
||||
if (impl != null) {
|
||||
@SuppressWarnings("removal")
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(SecurityConstants.SET_SOCKETIMPL_PERMISSION);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -494,16 +529,27 @@ public class Socket implements java.io.Closeable {
|
|||
new InetSocketAddress(0), stream);
|
||||
}
|
||||
|
||||
private Socket(SocketAddress address, SocketAddress localAddr,
|
||||
boolean stream) throws IOException {
|
||||
setImpl();
|
||||
/**
|
||||
* Initialize a new Socket that is connected to the given remote address.
|
||||
* The socket is optionally bound to a local address before connecting.
|
||||
*
|
||||
* @param address the remote address to connect to
|
||||
* @param localAddr the local address to bind to, can be null
|
||||
* @param stream true for a stream socket, false for a datagram socket
|
||||
*/
|
||||
private Socket(SocketAddress address, SocketAddress localAddr, boolean stream)
|
||||
throws IOException
|
||||
{
|
||||
Objects.requireNonNull(address);
|
||||
|
||||
// backward compatibility
|
||||
if (address == null)
|
||||
throw new NullPointerException();
|
||||
// create the SocketImpl and the underlying socket
|
||||
SocketImpl impl = createImpl();
|
||||
impl.create(stream);
|
||||
|
||||
this.impl = impl;
|
||||
this.state = SOCKET_CREATED;
|
||||
|
||||
try {
|
||||
createImpl(stream);
|
||||
if (localAddr != null)
|
||||
bind(localAddr);
|
||||
connect(address);
|
||||
|
@ -518,59 +564,97 @@ public class Socket implements java.io.Closeable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates the socket implementation.
|
||||
*
|
||||
* @param stream a {@code boolean} value : {@code true} for a TCP socket,
|
||||
* {@code false} for UDP.
|
||||
* @throws SocketException if creation fails
|
||||
* @since 1.4
|
||||
* Create a new SocketImpl for a connecting/client socket. The SocketImpl
|
||||
* is created without an underlying socket.
|
||||
*/
|
||||
void createImpl(boolean stream) throws SocketException {
|
||||
if (impl == null)
|
||||
setImpl();
|
||||
try {
|
||||
impl.create(stream);
|
||||
created = true;
|
||||
} catch (SocketException e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new SocketException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
void setImpl(SocketImpl si) {
|
||||
impl = si;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets impl to the system-default type of SocketImpl.
|
||||
* @since 1.4
|
||||
*/
|
||||
void setImpl() {
|
||||
private static SocketImpl createImpl() {
|
||||
SocketImplFactory factory = Socket.factory;
|
||||
if (factory != null) {
|
||||
impl = factory.createSocketImpl();
|
||||
return factory.createSocketImpl();
|
||||
} else {
|
||||
// create a SOCKS SocketImpl that delegates to a platform SocketImpl
|
||||
SocketImpl delegate = SocketImpl.createPlatformSocketImpl(false);
|
||||
impl = new SocksSocketImpl(delegate);
|
||||
return new SocksSocketImpl(delegate);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@code SocketImpl} attached to this socket, creating
|
||||
* it if necessary.
|
||||
*
|
||||
* @return the {@code SocketImpl} attached to that ServerSocket.
|
||||
* @throws SocketException if creation fails
|
||||
* @since 1.4
|
||||
* Returns the {@code SocketImpl} for this Socket, creating it, and the
|
||||
* underlying socket, if required.
|
||||
* @throws SocketException if creating the underlying socket fails
|
||||
*/
|
||||
SocketImpl getImpl() throws SocketException {
|
||||
if (!created)
|
||||
createImpl(true);
|
||||
private SocketImpl getImpl() throws SocketException {
|
||||
if ((state & SOCKET_CREATED) == 0) {
|
||||
synchronized (socketLock) {
|
||||
int s = state; // re-read state
|
||||
if ((s & SOCKET_CREATED) == 0) {
|
||||
if (isClosed(s)) {
|
||||
throw new SocketException("Socket is closed");
|
||||
}
|
||||
SocketImpl impl = this.impl;
|
||||
if (impl == null) {
|
||||
this.impl = impl = createImpl();
|
||||
}
|
||||
try {
|
||||
impl.create(true);
|
||||
} catch (SocketException e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new SocketException(e.getMessage(), e);
|
||||
}
|
||||
getAndBitwiseOrState(SOCKET_CREATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
return impl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SocketImpl, may be null.
|
||||
*/
|
||||
SocketImpl impl() {
|
||||
return impl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SocketImpl. The SocketImpl is connected to a peer. The behavior for
|
||||
* the case that the Socket was not a newly created Socket is unspecified. If
|
||||
* there is an existing SocketImpl then it closed to avoid leaking resources.
|
||||
* @throws SocketException if the Socket is closed
|
||||
* @apiNote For ServerSocket use when accepting connections
|
||||
*/
|
||||
void setConnectedImpl(SocketImpl si) throws SocketException {
|
||||
synchronized (socketLock) {
|
||||
if ((state & CLOSED) != 0) {
|
||||
throw new SocketException("Socket is closed");
|
||||
}
|
||||
SocketImpl previous = impl;
|
||||
impl = si;
|
||||
state = (SOCKET_CREATED | BOUND | CONNECTED);
|
||||
if (previous != null) {
|
||||
in = null;
|
||||
out = null;
|
||||
previous.closeQuietly();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SocketImpl.
|
||||
* @apiNote For ServerSocket use when accepting connections with a custom SocketImpl
|
||||
*/
|
||||
void setImpl(SocketImpl si) {
|
||||
impl = si;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets to Socket state for a newly accepted connection.
|
||||
* @apiNote For ServerSocket use when accepting connections with a custom SocketImpl
|
||||
*/
|
||||
void setConnected() {
|
||||
getAndBitwiseOrState(SOCKET_CREATED | BOUND | CONNECTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects this socket to the server.
|
||||
*
|
||||
|
@ -639,18 +723,18 @@ public class Socket implements java.io.Closeable {
|
|||
throw new IllegalArgumentException("connect: The address can't be null");
|
||||
|
||||
if (timeout < 0)
|
||||
throw new IllegalArgumentException("connect: timeout can't be negative");
|
||||
throw new IllegalArgumentException("connect: timeout can't be negative");
|
||||
|
||||
if (isClosed())
|
||||
int s = state;
|
||||
if (isClosed(s))
|
||||
throw new SocketException("Socket is closed");
|
||||
|
||||
if (isConnected())
|
||||
if (isConnected(s))
|
||||
throw new SocketException("already connected");
|
||||
|
||||
if (!(endpoint instanceof InetSocketAddress epoint))
|
||||
throw new IllegalArgumentException("Unsupported address type");
|
||||
|
||||
InetAddress addr = epoint.getAddress ();
|
||||
InetAddress addr = epoint.getAddress();
|
||||
int port = epoint.getPort();
|
||||
checkAddress(addr, "connect");
|
||||
|
||||
|
@ -662,10 +746,9 @@ public class Socket implements java.io.Closeable {
|
|||
else
|
||||
security.checkConnect(addr.getHostAddress(), port);
|
||||
}
|
||||
if (!created)
|
||||
createImpl(true);
|
||||
|
||||
try {
|
||||
impl.connect(epoint, timeout);
|
||||
getImpl().connect(epoint, timeout);
|
||||
} catch (SocketTimeoutException e) {
|
||||
throw e;
|
||||
} catch (InterruptedIOException e) {
|
||||
|
@ -676,12 +759,9 @@ public class Socket implements java.io.Closeable {
|
|||
}
|
||||
throw e;
|
||||
}
|
||||
connected = true;
|
||||
/*
|
||||
* If the socket was not bound before the connect, it is now because
|
||||
* the kernel will have picked an ephemeral port & a local address
|
||||
*/
|
||||
bound = true;
|
||||
|
||||
// connect will bind the socket if not previously bound
|
||||
getAndBitwiseOrState(BOUND | CONNECTED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -703,9 +783,10 @@ public class Socket implements java.io.Closeable {
|
|||
* @see #isBound
|
||||
*/
|
||||
public void bind(SocketAddress bindpoint) throws IOException {
|
||||
if (isClosed())
|
||||
int s = state;
|
||||
if (isClosed(s))
|
||||
throw new SocketException("Socket is closed");
|
||||
if (isBound())
|
||||
if (isBound(s))
|
||||
throw new SocketException("Already bound");
|
||||
|
||||
if (bindpoint != null && (!(bindpoint instanceof InetSocketAddress)))
|
||||
|
@ -724,11 +805,11 @@ public class Socket implements java.io.Closeable {
|
|||
if (security != null) {
|
||||
security.checkListen(port);
|
||||
}
|
||||
getImpl().bind (addr, port);
|
||||
bound = true;
|
||||
getImpl().bind(addr, port);
|
||||
getAndBitwiseOrState(BOUND);
|
||||
}
|
||||
|
||||
private void checkAddress (InetAddress addr, String op) {
|
||||
private void checkAddress(InetAddress addr, String op) {
|
||||
if (addr == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -737,15 +818,6 @@ public class Socket implements java.io.Closeable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set the flags after an accept() call.
|
||||
*/
|
||||
final void postAccept() {
|
||||
connected = true;
|
||||
created = true;
|
||||
bound = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address to which the socket is connected.
|
||||
* <p>
|
||||
|
@ -896,7 +968,6 @@ public class Socket implements java.io.Closeable {
|
|||
* @see SecurityManager#checkConnect
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public SocketAddress getLocalSocketAddress() {
|
||||
if (!isBound())
|
||||
return null;
|
||||
|
@ -984,11 +1055,12 @@ public class Socket implements java.io.Closeable {
|
|||
* @revised 1.4
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
if (isClosed())
|
||||
int s = state;
|
||||
if (isClosed(s))
|
||||
throw new SocketException("Socket is closed");
|
||||
if (!isConnected())
|
||||
if (!isConnected(s))
|
||||
throw new SocketException("Socket is not connected");
|
||||
if (isInputShutdown())
|
||||
if (isInputShutdown(s))
|
||||
throw new SocketException("Socket input is shutdown");
|
||||
InputStream in = this.in;
|
||||
if (in == null) {
|
||||
|
@ -1080,11 +1152,12 @@ public class Socket implements java.io.Closeable {
|
|||
* @revised 1.4
|
||||
*/
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
if (isClosed())
|
||||
int s = state;
|
||||
if (isClosed(s))
|
||||
throw new SocketException("Socket is closed");
|
||||
if (!isConnected())
|
||||
if (!isConnected(s))
|
||||
throw new SocketException("Socket is not connected");
|
||||
if (isOutputShutdown())
|
||||
if (isOutputShutdown(s))
|
||||
throw new SocketException("Socket output is shutdown");
|
||||
OutputStream out = this.out;
|
||||
if (out == null) {
|
||||
|
@ -1218,8 +1291,8 @@ public class Socket implements java.io.Closeable {
|
|||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
Object o = getImpl().getOption(SocketOptions.SO_LINGER);
|
||||
if (o instanceof Integer) {
|
||||
return ((Integer) o).intValue();
|
||||
if (o instanceof Integer i) {
|
||||
return i.intValue();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
@ -1235,8 +1308,8 @@ public class Socket implements java.io.Closeable {
|
|||
* sending the data.
|
||||
* @since 1.4
|
||||
*/
|
||||
public void sendUrgentData (int data) throws IOException {
|
||||
if (!getImpl().supportsUrgentData ()) {
|
||||
public void sendUrgentData(int data) throws IOException {
|
||||
if (!getImpl().supportsUrgentData()) {
|
||||
throw new SocketException ("Urgent data not supported");
|
||||
}
|
||||
getImpl().sendUrgentData (data);
|
||||
|
@ -1307,12 +1380,11 @@ public class Socket implements java.io.Closeable {
|
|||
* @since 1.1
|
||||
* @see #getSoTimeout()
|
||||
*/
|
||||
public synchronized void setSoTimeout(int timeout) throws SocketException {
|
||||
public void setSoTimeout(int timeout) throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
if (timeout < 0)
|
||||
throw new IllegalArgumentException("timeout can't be negative");
|
||||
|
||||
throw new IllegalArgumentException("timeout can't be negative");
|
||||
getImpl().setOption(SocketOptions.SO_TIMEOUT, timeout);
|
||||
}
|
||||
|
||||
|
@ -1327,13 +1399,13 @@ public class Socket implements java.io.Closeable {
|
|||
* @since 1.1
|
||||
* @see #setSoTimeout(int)
|
||||
*/
|
||||
public synchronized int getSoTimeout() throws SocketException {
|
||||
public int getSoTimeout() throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
|
||||
/* extra type safety */
|
||||
if (o instanceof Integer) {
|
||||
return ((Integer) o).intValue();
|
||||
if (o instanceof Integer i) {
|
||||
return i.intValue();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1362,11 +1434,9 @@ public class Socket implements java.io.Closeable {
|
|||
* @see #getSendBufferSize()
|
||||
* @since 1.2
|
||||
*/
|
||||
public synchronized void setSendBufferSize(int size)
|
||||
throws SocketException{
|
||||
if (!(size > 0)) {
|
||||
public void setSendBufferSize(int size) throws SocketException {
|
||||
if (size <= 0)
|
||||
throw new IllegalArgumentException("negative send size");
|
||||
}
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
getImpl().setOption(SocketOptions.SO_SNDBUF, size);
|
||||
|
@ -1385,13 +1455,13 @@ public class Socket implements java.io.Closeable {
|
|||
* @see #setSendBufferSize(int)
|
||||
* @since 1.2
|
||||
*/
|
||||
public synchronized int getSendBufferSize() throws SocketException {
|
||||
public int getSendBufferSize() throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
int result = 0;
|
||||
Object o = getImpl().getOption(SocketOptions.SO_SNDBUF);
|
||||
if (o instanceof Integer) {
|
||||
result = ((Integer)o).intValue();
|
||||
if (o instanceof Integer i) {
|
||||
result = i.intValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1436,11 +1506,9 @@ public class Socket implements java.io.Closeable {
|
|||
* @see ServerSocket#setReceiveBufferSize(int)
|
||||
* @since 1.2
|
||||
*/
|
||||
public synchronized void setReceiveBufferSize(int size)
|
||||
throws SocketException{
|
||||
if (size <= 0) {
|
||||
public void setReceiveBufferSize(int size) throws SocketException {
|
||||
if (size <= 0)
|
||||
throw new IllegalArgumentException("invalid receive size");
|
||||
}
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
getImpl().setOption(SocketOptions.SO_RCVBUF, size);
|
||||
|
@ -1458,14 +1526,13 @@ public class Socket implements java.io.Closeable {
|
|||
* @see #setReceiveBufferSize(int)
|
||||
* @since 1.2
|
||||
*/
|
||||
public synchronized int getReceiveBufferSize()
|
||||
throws SocketException{
|
||||
public int getReceiveBufferSize() throws SocketException {
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
int result = 0;
|
||||
Object o = getImpl().getOption(SocketOptions.SO_RCVBUF);
|
||||
if (o instanceof Integer) {
|
||||
result = ((Integer)o).intValue();
|
||||
if (o instanceof Integer i) {
|
||||
result = i.intValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1550,17 +1617,9 @@ public class Socket implements java.io.Closeable {
|
|||
public void setTrafficClass(int tc) throws SocketException {
|
||||
if (tc < 0 || tc > 255)
|
||||
throw new IllegalArgumentException("tc is not in range 0 -- 255");
|
||||
|
||||
if (isClosed())
|
||||
throw new SocketException("Socket is closed");
|
||||
try {
|
||||
getImpl().setOption(SocketOptions.IP_TOS, tc);
|
||||
} catch (SocketException se) {
|
||||
// not supported if socket already connected
|
||||
// Solaris returns error in such cases
|
||||
if(!isConnected())
|
||||
throw se;
|
||||
}
|
||||
getImpl().setOption(SocketOptions.IP_TOS, tc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1661,13 +1720,15 @@ public class Socket implements java.io.Closeable {
|
|||
* @revised 1.4
|
||||
* @see #isClosed
|
||||
*/
|
||||
public synchronized void close() throws IOException {
|
||||
synchronized(closeLock) {
|
||||
if (isClosed())
|
||||
return;
|
||||
if (created)
|
||||
impl.close();
|
||||
closed = true;
|
||||
public void close() throws IOException {
|
||||
synchronized (socketLock) {
|
||||
if ((state & CLOSED) == 0) {
|
||||
int s = getAndBitwiseOrState(CLOSED);
|
||||
if ((s & (SOCKET_CREATED | CLOSED)) == SOCKET_CREATED) {
|
||||
// close underlying socket if created
|
||||
impl.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1689,16 +1750,16 @@ public class Socket implements java.io.Closeable {
|
|||
* @see java.net.Socket#setSoLinger(boolean, int)
|
||||
* @see #isInputShutdown
|
||||
*/
|
||||
public void shutdownInput() throws IOException
|
||||
{
|
||||
if (isClosed())
|
||||
public void shutdownInput() throws IOException {
|
||||
int s = state;
|
||||
if (isClosed(s))
|
||||
throw new SocketException("Socket is closed");
|
||||
if (!isConnected())
|
||||
if (!isConnected(s))
|
||||
throw new SocketException("Socket is not connected");
|
||||
if (isInputShutdown())
|
||||
if (isInputShutdown(s))
|
||||
throw new SocketException("Socket input is already shutdown");
|
||||
getImpl().shutdownInput();
|
||||
shutIn = true;
|
||||
getAndBitwiseOrState(SHUT_IN);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1719,16 +1780,16 @@ public class Socket implements java.io.Closeable {
|
|||
* @see java.net.Socket#setSoLinger(boolean, int)
|
||||
* @see #isOutputShutdown
|
||||
*/
|
||||
public void shutdownOutput() throws IOException
|
||||
{
|
||||
if (isClosed())
|
||||
public void shutdownOutput() throws IOException {
|
||||
int s = state;
|
||||
if (isClosed(s))
|
||||
throw new SocketException("Socket is closed");
|
||||
if (!isConnected())
|
||||
if (!isConnected(s))
|
||||
throw new SocketException("Socket is not connected");
|
||||
if (isOutputShutdown())
|
||||
if (isOutputShutdown(s))
|
||||
throw new SocketException("Socket output is already shutdown");
|
||||
getImpl().shutdownOutput();
|
||||
shutOut = true;
|
||||
getAndBitwiseOrState(SHUT_OUT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1759,7 +1820,7 @@ public class Socket implements java.io.Closeable {
|
|||
* @since 1.4
|
||||
*/
|
||||
public boolean isConnected() {
|
||||
return connected;
|
||||
return isConnected(state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1775,7 +1836,7 @@ public class Socket implements java.io.Closeable {
|
|||
* @see #bind
|
||||
*/
|
||||
public boolean isBound() {
|
||||
return bound;
|
||||
return isBound(state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1786,9 +1847,7 @@ public class Socket implements java.io.Closeable {
|
|||
* @see #close
|
||||
*/
|
||||
public boolean isClosed() {
|
||||
synchronized(closeLock) {
|
||||
return closed;
|
||||
}
|
||||
return isClosed(state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1799,7 +1858,7 @@ public class Socket implements java.io.Closeable {
|
|||
* @see #shutdownInput
|
||||
*/
|
||||
public boolean isInputShutdown() {
|
||||
return shutIn;
|
||||
return isInputShutdown(state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1810,7 +1869,7 @@ public class Socket implements java.io.Closeable {
|
|||
* @see #shutdownOutput
|
||||
*/
|
||||
public boolean isOutputShutdown() {
|
||||
return shutOut;
|
||||
return isOutputShutdown(state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue