/* * Copyright (C) 2014 The Android Open Source Project * Copyright (c) 2007, 2008, 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.net; import android.system.ErrnoException; import java.io.IOException; import java.io.FileDescriptor; import java.util.Set; import java.util.HashSet; import java.util.Collections; import libcore.io.AsynchronousCloseMonitor; import libcore.io.IoBridge; import libcore.io.IoUtils; import libcore.io.Libcore; import jdk.net.*; import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.AF_UNIX; import static android.system.OsConstants.EAGAIN; import static android.system.OsConstants.EBADF; import static android.system.OsConstants.EINVAL; import static android.system.OsConstants.MSG_OOB; import static android.system.OsConstants.POLLERR; import static android.system.OsConstants.POLLIN; import static android.system.OsConstants.SOCK_DGRAM; import static android.system.OsConstants.SOCK_STREAM; import static android.system.OsConstants.SHUT_RDWR; import static sun.net.ExtendedOptionsImpl.*; // Android-changed: Rewritten to use android.system POSIX calls and assume AF_INET6. /* * On Unix systems we simply delegate to native methods. * * @author Chris Hegarty */ class PlainSocketImpl extends AbstractPlainSocketImpl { /** * Constructs an empty instance. */ PlainSocketImpl() { this(new FileDescriptor()); } /** * Constructs an instance with the given file descriptor. */ PlainSocketImpl(FileDescriptor fd) { this.fd = fd; } protected void setOption(SocketOption name, T value) throws IOException { if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { super.setOption(name, value); } else { if (isClosedOrPending()) { throw new SocketException("Socket closed"); } checkSetOptionPermission(name); checkValueType(value, SocketFlow.class); setFlowOption(getFileDescriptor(), (SocketFlow)value); } } protected T getOption(SocketOption name) throws IOException { if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { return super.getOption(name); } if (isClosedOrPending()) { throw new SocketException("Socket closed"); } checkGetOptionPermission(name); SocketFlow flow = SocketFlow.create(); getFlowOption(getFileDescriptor(), flow); return (T)flow; } protected void socketSetOption(int opt, Object val) throws SocketException { try { socketSetOption0(opt, val); } catch (SocketException se) { if (socket == null || !socket.isConnected()) throw se; } } void socketCreate(boolean isStream) throws IOException { // The fd object must not change after calling bind, because we rely on this undocumented // behaviour. See libcore.java.net.SocketTest#testFileDescriptorStaysSame. fd.setInt$(IoBridge.socket(AF_INET6, isStream ? SOCK_STREAM : SOCK_DGRAM, 0).getInt$()); if (serverSocket != null) { IoUtils.setBlocking(fd, false); IoBridge.setSocketOption(fd, SO_REUSEADDR, true); } } void socketConnect(InetAddress address, int port, int timeout) throws IOException { if (fd == null || !fd.valid()) { throw new SocketException("Socket closed"); } IoBridge.connect(fd, address, port, timeout); this.address = address; this.port = port; if (localport == 0) { // If socket is pending close, fd becomes an AF_UNIX socket and calling // getLocalInetSocketAddress will fail. // http://b/34645743 if (!isClosedOrPending()) { localport = IoBridge.getLocalInetSocketAddress(fd).getPort(); } } } void socketBind(InetAddress address, int port) throws IOException { if (fd == null || !fd.valid()) { throw new SocketException("Socket closed"); } IoBridge.bind(fd, address, port); this.address = address; if (port == 0) { // Now that we're a connected socket, let's extract the port number that the system // chose for us and store it in the Socket object. localport = IoBridge.getLocalInetSocketAddress(fd).getPort(); } else { localport = port; } } void socketListen(int count) throws IOException { if (fd == null || !fd.valid()) { throw new SocketException("Socket closed"); } try { Libcore.os.listen(fd, count); } catch (ErrnoException errnoException) { throw errnoException.rethrowAsSocketException(); } } void socketAccept(SocketImpl s) throws IOException { if (fd == null || !fd.valid()) { throw new SocketException("Socket closed"); } // poll() with a timeout of 0 means "poll for zero millis", but a Socket timeout == 0 means // "wait forever". When timeout == 0 we pass -1 to poll. if (timeout <= 0) { IoBridge.poll(fd, POLLIN | POLLERR, -1); } else { IoBridge.poll(fd, POLLIN | POLLERR, timeout); } InetSocketAddress peerAddress = new InetSocketAddress(); try { FileDescriptor newfd = Libcore.os.accept(fd, peerAddress); s.fd.setInt$(newfd.getInt$()); s.address = peerAddress.getAddress(); s.port = peerAddress.getPort(); } catch (ErrnoException errnoException) { if (errnoException.errno == EAGAIN) { throw new SocketTimeoutException(errnoException); } else if (errnoException.errno == EINVAL || errnoException.errno == EBADF) { throw new SocketException("Socket closed"); } errnoException.rethrowAsSocketException(); } s.localport = IoBridge.getLocalInetSocketAddress(s.fd).getPort(); } int socketAvailable() throws IOException { return IoBridge.available(fd); } void socketClose0(boolean useDeferredClose) throws IOException { if (fd == null || !fd.valid()) { throw new SocketException("socket already closed"); } FileDescriptor markerFD = null; if (useDeferredClose) { markerFD = getMarkerFD(); } if (useDeferredClose && markerFD != null) { try { Libcore.os.dup2(markerFD, fd.getInt$()); Libcore.os.close(markerFD); // This effectively closes the socket, needs to signal threads that blocks on this // file descriptor. AsynchronousCloseMonitor.signalBlockedThreads(fd); } catch (ErrnoException errnoException) { // close should not throw } } else { // If requested or a markerFD cannot be created, a non-deferred close is performed // instead. IoBridge.closeAndSignalBlockedThreads(fd); } } /* * Create the marker file descriptor by establishing a loopback connection which we shutdown but * do not close the fd. The result is an fd that can be used for read/write. * * The purpose is to keep hold of the raw fd handle until we are sure it is not used in any * thread. Otherwise if we close the file descriptor directly, the system might reuse the raw fd * number and threads holding old fd value might behave incorrectly. */ private FileDescriptor getMarkerFD() throws SocketException { FileDescriptor fd1 = new FileDescriptor(); FileDescriptor fd2 = new FileDescriptor(); try { Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd1, fd2); // Shutdown fd1, any reads to this fd will get EOF; any writes will get an error. Libcore.os.shutdown(fd1, SHUT_RDWR); Libcore.os.close(fd2); } catch (ErrnoException errnoException) { // We might have reached the maximum file descriptor number and socketpair(2) would // fail. In this case, return null and let caller to fall back to an alternative method // that does not allocate more file descriptors. return null; } return fd1; } void socketShutdown(int howto) throws IOException { try { Libcore.os.shutdown(fd, howto); } catch (ErrnoException errnoException) { throw errnoException.rethrowAsIOException(); } } void socketSetOption0(int cmd, Object value) throws SocketException { // OpenJDK does not set SO_TIMEOUT on Linux. if (cmd == SO_TIMEOUT) { return; } IoBridge.setSocketOption(fd, cmd, value); } Object socketGetOption(int opt) throws SocketException { return IoBridge.getSocketOption(fd, opt); } void socketSendUrgentData(int data) throws IOException { if (fd == null || !fd.valid()) { throw new SocketException("Socket closed"); } try { byte[] buffer = new byte[] { (byte) data }; Libcore.os.sendto(fd, buffer, 0, 1, MSG_OOB, null, 0); } catch (ErrnoException errnoException) { throw errnoException.rethrowAsSocketException(); } } }