0N/A/*
3909N/A * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage java.net;
0N/A
0N/Aimport java.io.IOException;
0N/Aimport java.io.InputStream;
0N/Aimport java.io.OutputStream;
0N/Aimport java.io.FileDescriptor;
0N/A
0N/Aimport sun.net.ConnectionResetException;
1040N/Aimport sun.net.NetHooks;
3788N/Aimport sun.net.ResourceManager;
0N/A
0N/A/**
0N/A * Default Socket Implementation. This implementation does
0N/A * not implement any security checks.
0N/A * Note this class should <b>NOT</b> be public.
0N/A *
0N/A * @author Steven B. Byrne
0N/A */
0N/Aabstract class AbstractPlainSocketImpl extends SocketImpl
0N/A{
0N/A /* instance variable for SO_TIMEOUT */
0N/A int timeout; // timeout in millisec
0N/A // traffic class
0N/A private int trafficClass;
0N/A
0N/A private boolean shut_rd = false;
0N/A private boolean shut_wr = false;
0N/A
0N/A private SocketInputStream socketInputStream = null;
0N/A
0N/A /* number of threads using the FileDescriptor */
0N/A protected int fdUseCount = 0;
0N/A
0N/A /* lock when increment/decrementing fdUseCount */
2986N/A protected final Object fdLock = new Object();
0N/A
0N/A /* indicates a close is pending on the file descriptor */
0N/A protected boolean closePending = false;
0N/A
0N/A /* indicates connection reset state */
0N/A private int CONNECTION_NOT_RESET = 0;
0N/A private int CONNECTION_RESET_PENDING = 1;
0N/A private int CONNECTION_RESET = 2;
0N/A private int resetState;
2986N/A private final Object resetLock = new Object();
0N/A
3788N/A /* whether this Socket is a stream (TCP) socket or not (UDP)
3788N/A */
4480N/A protected boolean stream;
3788N/A
0N/A /**
0N/A * Load net library into runtime.
0N/A */
0N/A static {
0N/A java.security.AccessController.doPrivileged(
0N/A new sun.security.action.LoadLibraryAction("net"));
0N/A }
0N/A
0N/A /**
0N/A * Creates a socket with a boolean that specifies whether this
0N/A * is a stream socket (true) or an unconnected UDP socket (false).
0N/A */
0N/A protected synchronized void create(boolean stream) throws IOException {
3788N/A this.stream = stream;
3788N/A if (!stream) {
3788N/A ResourceManager.beforeUdpCreate();
4479N/A // only create the fd after we know we will be able to create the socket
4479N/A fd = new FileDescriptor();
3788N/A try {
3788N/A socketCreate(false);
3788N/A } catch (IOException ioe) {
3788N/A ResourceManager.afterUdpClose();
3788N/A fd = null;
3788N/A throw ioe;
3788N/A }
3788N/A } else {
4479N/A fd = new FileDescriptor();
3788N/A socketCreate(true);
3788N/A }
0N/A if (socket != null)
0N/A socket.setCreated();
0N/A if (serverSocket != null)
0N/A serverSocket.setCreated();
0N/A }
0N/A
0N/A /**
0N/A * Creates a socket and connects it to the specified port on
0N/A * the specified host.
0N/A * @param host the specified host
0N/A * @param port the specified port
0N/A */
0N/A protected void connect(String host, int port)
0N/A throws UnknownHostException, IOException
0N/A {
2986N/A boolean connected = false;
0N/A try {
0N/A InetAddress address = InetAddress.getByName(host);
0N/A this.port = port;
0N/A this.address = address;
0N/A
2986N/A connectToAddress(address, port, timeout);
2986N/A connected = true;
2986N/A } finally {
2986N/A if (!connected) {
2986N/A try {
2986N/A close();
2986N/A } catch (IOException ioe) {
2986N/A /* Do nothing. If connect threw an exception then
2986N/A it will be passed up the call stack */
2986N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Creates a socket and connects it to the specified address on
0N/A * the specified port.
0N/A * @param address the address
0N/A * @param port the specified port
0N/A */
0N/A protected void connect(InetAddress address, int port) throws IOException {
0N/A this.port = port;
0N/A this.address = address;
0N/A
0N/A try {
0N/A connectToAddress(address, port, timeout);
0N/A return;
0N/A } catch (IOException e) {
0N/A // everything failed
0N/A close();
0N/A throw e;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Creates a socket and connects it to the specified address on
0N/A * the specified port.
0N/A * @param address the address
0N/A * @param timeout the timeout value in milliseconds, or zero for no timeout.
0N/A * @throws IOException if connection fails
0N/A * @throws IllegalArgumentException if address is null or is a
0N/A * SocketAddress subclass not supported by this socket
0N/A * @since 1.4
0N/A */
2986N/A protected void connect(SocketAddress address, int timeout)
2986N/A throws IOException {
2986N/A boolean connected = false;
2986N/A try {
2986N/A if (address == null || !(address instanceof InetSocketAddress))
2986N/A throw new IllegalArgumentException("unsupported address type");
2986N/A InetSocketAddress addr = (InetSocketAddress) address;
2986N/A if (addr.isUnresolved())
2986N/A throw new UnknownHostException(addr.getHostName());
2986N/A this.port = addr.getPort();
2986N/A this.address = addr.getAddress();
0N/A
0N/A connectToAddress(this.address, port, timeout);
2986N/A connected = true;
2986N/A } finally {
2986N/A if (!connected) {
2986N/A try {
2986N/A close();
2986N/A } catch (IOException ioe) {
2986N/A /* Do nothing. If connect threw an exception then
2986N/A it will be passed up the call stack */
2986N/A }
2986N/A }
0N/A }
0N/A }
0N/A
0N/A private void connectToAddress(InetAddress address, int port, int timeout) throws IOException {
0N/A if (address.isAnyLocalAddress()) {
0N/A doConnect(InetAddress.getLocalHost(), port, timeout);
0N/A } else {
0N/A doConnect(address, port, timeout);
0N/A }
0N/A }
0N/A
0N/A public void setOption(int opt, Object val) throws SocketException {
0N/A if (isClosedOrPending()) {
0N/A throw new SocketException("Socket Closed");
0N/A }
0N/A boolean on = true;
0N/A switch (opt) {
0N/A /* check type safety b4 going native. These should never
0N/A * fail, since only java.Socket* has access to
0N/A * PlainSocketImpl.setOption().
0N/A */
0N/A case SO_LINGER:
0N/A if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))
0N/A throw new SocketException("Bad parameter for option");
0N/A if (val instanceof Boolean) {
0N/A /* true only if disabling - enabling should be Integer */
0N/A on = false;
0N/A }
0N/A break;
0N/A case SO_TIMEOUT:
0N/A if (val == null || (!(val instanceof Integer)))
0N/A throw new SocketException("Bad parameter for SO_TIMEOUT");
0N/A int tmp = ((Integer) val).intValue();
0N/A if (tmp < 0)
0N/A throw new IllegalArgumentException("timeout < 0");
0N/A timeout = tmp;
0N/A break;
0N/A case IP_TOS:
0N/A if (val == null || !(val instanceof Integer)) {
0N/A throw new SocketException("bad argument for IP_TOS");
0N/A }
0N/A trafficClass = ((Integer)val).intValue();
0N/A break;
0N/A case SO_BINDADDR:
0N/A throw new SocketException("Cannot re-bind socket");
0N/A case TCP_NODELAY:
0N/A if (val == null || !(val instanceof Boolean))
0N/A throw new SocketException("bad parameter for TCP_NODELAY");
0N/A on = ((Boolean)val).booleanValue();
0N/A break;
0N/A case SO_SNDBUF:
0N/A case SO_RCVBUF:
0N/A if (val == null || !(val instanceof Integer) ||
0N/A !(((Integer)val).intValue() > 0)) {
0N/A throw new SocketException("bad parameter for SO_SNDBUF " +
0N/A "or SO_RCVBUF");
0N/A }
0N/A break;
0N/A case SO_KEEPALIVE:
0N/A if (val == null || !(val instanceof Boolean))
0N/A throw new SocketException("bad parameter for SO_KEEPALIVE");
0N/A on = ((Boolean)val).booleanValue();
0N/A break;
0N/A case SO_OOBINLINE:
0N/A if (val == null || !(val instanceof Boolean))
0N/A throw new SocketException("bad parameter for SO_OOBINLINE");
0N/A on = ((Boolean)val).booleanValue();
0N/A break;
0N/A case SO_REUSEADDR:
0N/A if (val == null || !(val instanceof Boolean))
0N/A throw new SocketException("bad parameter for SO_REUSEADDR");
0N/A on = ((Boolean)val).booleanValue();
0N/A break;
0N/A default:
0N/A throw new SocketException("unrecognized TCP option: " + opt);
0N/A }
0N/A socketSetOption(opt, on, val);
0N/A }
0N/A public Object getOption(int opt) throws SocketException {
0N/A if (isClosedOrPending()) {
0N/A throw new SocketException("Socket Closed");
0N/A }
0N/A if (opt == SO_TIMEOUT) {
0N/A return new Integer(timeout);
0N/A }
0N/A int ret = 0;
0N/A /*
0N/A * The native socketGetOption() knows about 3 options.
0N/A * The 32 bit value it returns will be interpreted according
0N/A * to what we're asking. A return of -1 means it understands
0N/A * the option but its turned off. It will raise a SocketException
0N/A * if "opt" isn't one it understands.
0N/A */
0N/A
0N/A switch (opt) {
0N/A case TCP_NODELAY:
0N/A ret = socketGetOption(opt, null);
0N/A return Boolean.valueOf(ret != -1);
0N/A case SO_OOBINLINE:
0N/A ret = socketGetOption(opt, null);
0N/A return Boolean.valueOf(ret != -1);
0N/A case SO_LINGER:
0N/A ret = socketGetOption(opt, null);
0N/A return (ret == -1) ? Boolean.FALSE: (Object)(new Integer(ret));
0N/A case SO_REUSEADDR:
0N/A ret = socketGetOption(opt, null);
0N/A return Boolean.valueOf(ret != -1);
0N/A case SO_BINDADDR:
0N/A InetAddressContainer in = new InetAddressContainer();
0N/A ret = socketGetOption(opt, in);
0N/A return in.addr;
0N/A case SO_SNDBUF:
0N/A case SO_RCVBUF:
0N/A ret = socketGetOption(opt, null);
0N/A return new Integer(ret);
0N/A case IP_TOS:
0N/A ret = socketGetOption(opt, null);
0N/A if (ret == -1) { // ipv6 tos
0N/A return new Integer(trafficClass);
0N/A } else {
0N/A return new Integer(ret);
0N/A }
0N/A case SO_KEEPALIVE:
0N/A ret = socketGetOption(opt, null);
0N/A return Boolean.valueOf(ret != -1);
0N/A // should never get here
0N/A default:
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * The workhorse of the connection operation. Tries several times to
0N/A * establish a connection to the given <host, port>. If unsuccessful,
0N/A * throws an IOException indicating what went wrong.
0N/A */
0N/A
0N/A synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
1040N/A synchronized (fdLock) {
1040N/A if (!closePending && (socket == null || !socket.isBound())) {
1040N/A NetHooks.beforeTcpConnect(fd, address, port);
1040N/A }
1040N/A }
0N/A try {
2986N/A acquireFD();
0N/A try {
0N/A socketConnect(address, port, timeout);
659N/A /* socket may have been closed during poll/select */
659N/A synchronized (fdLock) {
659N/A if (closePending) {
659N/A throw new SocketException ("Socket closed");
659N/A }
659N/A }
0N/A // If we have a ref. to the Socket, then sets the flags
0N/A // created, bound & connected to true.
0N/A // This is normally done in Socket.connect() but some
0N/A // subclasses of Socket may call impl.connect() directly!
0N/A if (socket != null) {
0N/A socket.setBound();
0N/A socket.setConnected();
0N/A }
0N/A } finally {
0N/A releaseFD();
0N/A }
0N/A } catch (IOException e) {
0N/A close();
0N/A throw e;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Binds the socket to the specified address of the specified local port.
0N/A * @param address the address
0N/A * @param port the port
0N/A */
0N/A protected synchronized void bind(InetAddress address, int lport)
0N/A throws IOException
0N/A {
1040N/A synchronized (fdLock) {
1040N/A if (!closePending && (socket == null || !socket.isBound())) {
1040N/A NetHooks.beforeTcpBind(fd, address, lport);
1040N/A }
1040N/A }
0N/A socketBind(address, lport);
0N/A if (socket != null)
0N/A socket.setBound();
0N/A if (serverSocket != null)
0N/A serverSocket.setBound();
0N/A }
0N/A
0N/A /**
0N/A * Listens, for a specified amount of time, for connections.
0N/A * @param count the amount of time to listen for connections
0N/A */
0N/A protected synchronized void listen(int count) throws IOException {
0N/A socketListen(count);
0N/A }
0N/A
0N/A /**
0N/A * Accepts connections.
0N/A * @param s the connection
0N/A */
0N/A protected void accept(SocketImpl s) throws IOException {
2986N/A acquireFD();
0N/A try {
0N/A socketAccept(s);
0N/A } finally {
0N/A releaseFD();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Gets an InputStream for this socket.
0N/A */
0N/A protected synchronized InputStream getInputStream() throws IOException {
0N/A if (isClosedOrPending()) {
0N/A throw new IOException("Socket Closed");
0N/A }
0N/A if (shut_rd) {
0N/A throw new IOException("Socket input is shutdown");
0N/A }
0N/A if (socketInputStream == null) {
0N/A socketInputStream = new SocketInputStream(this);
0N/A }
0N/A return socketInputStream;
0N/A }
0N/A
0N/A void setInputStream(SocketInputStream in) {
0N/A socketInputStream = in;
0N/A }
0N/A
0N/A /**
0N/A * Gets an OutputStream for this socket.
0N/A */
0N/A protected synchronized OutputStream getOutputStream() throws IOException {
0N/A if (isClosedOrPending()) {
0N/A throw new IOException("Socket Closed");
0N/A }
0N/A if (shut_wr) {
0N/A throw new IOException("Socket output is shutdown");
0N/A }
0N/A return new SocketOutputStream(this);
0N/A }
0N/A
0N/A void setFileDescriptor(FileDescriptor fd) {
0N/A this.fd = fd;
0N/A }
0N/A
0N/A void setAddress(InetAddress address) {
0N/A this.address = address;
0N/A }
0N/A
0N/A void setPort(int port) {
0N/A this.port = port;
0N/A }
0N/A
0N/A void setLocalPort(int localport) {
0N/A this.localport = localport;
0N/A }
0N/A
0N/A /**
0N/A * Returns the number of bytes that can be read without blocking.
0N/A */
0N/A protected synchronized int available() throws IOException {
0N/A if (isClosedOrPending()) {
0N/A throw new IOException("Stream closed.");
0N/A }
0N/A
0N/A /*
0N/A * If connection has been reset then return 0 to indicate
0N/A * there are no buffered bytes.
0N/A */
0N/A if (isConnectionReset()) {
0N/A return 0;
0N/A }
0N/A
0N/A /*
0N/A * If no bytes available and we were previously notified
0N/A * of a connection reset then we move to the reset state.
0N/A *
0N/A * If are notified of a connection reset then check
0N/A * again if there are bytes buffered on the socket.
0N/A */
0N/A int n = 0;
0N/A try {
0N/A n = socketAvailable();
0N/A if (n == 0 && isConnectionResetPending()) {
0N/A setConnectionReset();
0N/A }
0N/A } catch (ConnectionResetException exc1) {
0N/A setConnectionResetPending();
0N/A try {
0N/A n = socketAvailable();
0N/A if (n == 0) {
0N/A setConnectionReset();
0N/A }
0N/A } catch (ConnectionResetException exc2) {
0N/A }
0N/A }
0N/A return n;
0N/A }
0N/A
0N/A /**
0N/A * Closes the socket.
0N/A */
0N/A protected void close() throws IOException {
0N/A synchronized(fdLock) {
0N/A if (fd != null) {
3788N/A if (!stream) {
3788N/A ResourceManager.afterUdpClose();
3788N/A }
0N/A if (fdUseCount == 0) {
0N/A if (closePending) {
0N/A return;
0N/A }
0N/A closePending = true;
0N/A /*
0N/A * We close the FileDescriptor in two-steps - first the
0N/A * "pre-close" which closes the socket but doesn't
0N/A * release the underlying file descriptor. This operation
0N/A * may be lengthy due to untransmitted data and a long
0N/A * linger interval. Once the pre-close is done we do the
0N/A * actual socket to release the fd.
0N/A */
0N/A try {
0N/A socketPreClose();
0N/A } finally {
0N/A socketClose();
0N/A }
0N/A fd = null;
0N/A return;
0N/A } else {
0N/A /*
0N/A * If a thread has acquired the fd and a close
0N/A * isn't pending then use a deferred close.
0N/A * Also decrement fdUseCount to signal the last
0N/A * thread that releases the fd to close it.
0N/A */
0N/A if (!closePending) {
0N/A closePending = true;
0N/A fdUseCount--;
0N/A socketPreClose();
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A void reset() throws IOException {
0N/A if (fd != null) {
0N/A socketClose();
0N/A }
0N/A fd = null;
0N/A super.reset();
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Shutdown read-half of the socket connection;
0N/A */
0N/A protected void shutdownInput() throws IOException {
0N/A if (fd != null) {
0N/A socketShutdown(SHUT_RD);
0N/A if (socketInputStream != null) {
0N/A socketInputStream.setEOF(true);
0N/A }
0N/A shut_rd = true;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Shutdown write-half of the socket connection;
0N/A */
0N/A protected void shutdownOutput() throws IOException {
0N/A if (fd != null) {
0N/A socketShutdown(SHUT_WR);
0N/A shut_wr = true;
0N/A }
0N/A }
0N/A
0N/A protected boolean supportsUrgentData () {
0N/A return true;
0N/A }
0N/A
0N/A protected void sendUrgentData (int data) throws IOException {
0N/A if (fd == null) {
0N/A throw new IOException("Socket Closed");
0N/A }
0N/A socketSendUrgentData (data);
0N/A }
0N/A
0N/A /**
0N/A * Cleans up if the user forgets to close it.
0N/A */
0N/A protected void finalize() throws IOException {
0N/A close();
0N/A }
0N/A
0N/A /*
0N/A * "Acquires" and returns the FileDescriptor for this impl
0N/A *
0N/A * A corresponding releaseFD is required to "release" the
0N/A * FileDescriptor.
0N/A */
0N/A FileDescriptor acquireFD() {
0N/A synchronized (fdLock) {
0N/A fdUseCount++;
0N/A return fd;
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * "Release" the FileDescriptor for this impl.
0N/A *
0N/A * If the use count goes to -1 then the socket is closed.
0N/A */
0N/A void releaseFD() {
0N/A synchronized (fdLock) {
0N/A fdUseCount--;
0N/A if (fdUseCount == -1) {
0N/A if (fd != null) {
0N/A try {
0N/A socketClose();
0N/A } catch (IOException e) {
0N/A } finally {
0N/A fd = null;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A public boolean isConnectionReset() {
0N/A synchronized (resetLock) {
0N/A return (resetState == CONNECTION_RESET);
0N/A }
0N/A }
0N/A
0N/A public boolean isConnectionResetPending() {
0N/A synchronized (resetLock) {
0N/A return (resetState == CONNECTION_RESET_PENDING);
0N/A }
0N/A }
0N/A
0N/A public void setConnectionReset() {
0N/A synchronized (resetLock) {
0N/A resetState = CONNECTION_RESET;
0N/A }
0N/A }
0N/A
0N/A public void setConnectionResetPending() {
0N/A synchronized (resetLock) {
0N/A if (resetState == CONNECTION_NOT_RESET) {
0N/A resetState = CONNECTION_RESET_PENDING;
0N/A }
0N/A }
0N/A
0N/A }
0N/A
0N/A /*
0N/A * Return true if already closed or close is pending
0N/A */
0N/A public boolean isClosedOrPending() {
0N/A /*
0N/A * Lock on fdLock to ensure that we wait if a
0N/A * close is in progress.
0N/A */
0N/A synchronized (fdLock) {
0N/A if (closePending || (fd == null)) {
0N/A return true;
0N/A } else {
0N/A return false;
0N/A }
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Return the current value of SO_TIMEOUT
0N/A */
0N/A public int getTimeout() {
0N/A return timeout;
0N/A }
0N/A
0N/A /*
0N/A * "Pre-close" a socket by dup'ing the file descriptor - this enables
0N/A * the socket to be closed without releasing the file descriptor.
0N/A */
0N/A private void socketPreClose() throws IOException {
0N/A socketClose0(true);
0N/A }
0N/A
0N/A /*
0N/A * Close the socket (and release the file descriptor).
0N/A */
0N/A protected void socketClose() throws IOException {
0N/A socketClose0(false);
0N/A }
0N/A
0N/A abstract void socketCreate(boolean isServer) throws IOException;
0N/A abstract void socketConnect(InetAddress address, int port, int timeout)
0N/A throws IOException;
0N/A abstract void socketBind(InetAddress address, int port)
0N/A throws IOException;
0N/A abstract void socketListen(int count)
0N/A throws IOException;
0N/A abstract void socketAccept(SocketImpl s)
0N/A throws IOException;
0N/A abstract int socketAvailable()
0N/A throws IOException;
0N/A abstract void socketClose0(boolean useDeferredClose)
0N/A throws IOException;
0N/A abstract void socketShutdown(int howto)
0N/A throws IOException;
0N/A abstract void socketSetOption(int cmd, boolean on, Object value)
0N/A throws SocketException;
0N/A abstract int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
0N/A abstract void socketSendUrgentData(int data)
0N/A throws IOException;
0N/A
0N/A public final static int SHUT_RD = 0;
0N/A public final static int SHUT_WR = 1;
0N/A}
0N/A
0N/Aclass InetAddressContainer {
0N/A InetAddress addr;
0N/A}