Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 package java.net;
     27 
     28 import android.system.ErrnoException;
     29 
     30 import java.io.IOException;
     31 import java.io.FileDescriptor;
     32 import java.util.Set;
     33 import java.util.HashSet;
     34 import java.util.Collections;
     35 import libcore.io.AsynchronousCloseMonitor;
     36 import libcore.io.IoBridge;
     37 import libcore.io.IoUtils;
     38 import libcore.io.Libcore;
     39 
     40 import jdk.net.*;
     41 
     42 import static android.system.OsConstants.AF_INET6;
     43 import static android.system.OsConstants.AF_UNIX;
     44 import static android.system.OsConstants.EAGAIN;
     45 import static android.system.OsConstants.EBADF;
     46 import static android.system.OsConstants.EINVAL;
     47 import static android.system.OsConstants.MSG_OOB;
     48 import static android.system.OsConstants.POLLERR;
     49 import static android.system.OsConstants.POLLIN;
     50 import static android.system.OsConstants.SOCK_DGRAM;
     51 import static android.system.OsConstants.SOCK_STREAM;
     52 import static android.system.OsConstants.SHUT_RDWR;
     53 import static sun.net.ExtendedOptionsImpl.*;
     54 
     55 // Android-changed: Rewritten to use android.system POSIX calls and assume AF_INET6.
     56 /*
     57  * On Unix systems we simply delegate to native methods.
     58  *
     59  * @author Chris Hegarty
     60  */
     61 
     62 class PlainSocketImpl extends AbstractPlainSocketImpl
     63 {
     64     // Android-removed: Android doesn't need to call native initProto.
     65     /*
     66     static {
     67         initProto();
     68     }
     69     */
     70 
     71     /**
     72      * Constructs an empty instance.
     73      */
     74     PlainSocketImpl() {
     75         this(new FileDescriptor());
     76     }
     77 
     78     /**
     79      * Constructs an instance with the given file descriptor.
     80      */
     81     PlainSocketImpl(FileDescriptor fd) {
     82         this.fd = fd;
     83     }
     84 
     85     protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
     86         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
     87             super.setOption(name, value);
     88         } else {
     89             if (isClosedOrPending()) {
     90                 throw new SocketException("Socket closed");
     91             }
     92             checkSetOptionPermission(name);
     93             checkValueType(value, SocketFlow.class);
     94             setFlowOption(getFileDescriptor(), (SocketFlow)value);
     95         }
     96     }
     97 
     98     protected <T> T getOption(SocketOption<T> name) throws IOException {
     99         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
    100             return super.getOption(name);
    101         }
    102         if (isClosedOrPending()) {
    103             throw new SocketException("Socket closed");
    104         }
    105         checkGetOptionPermission(name);
    106         SocketFlow flow = SocketFlow.create();
    107         getFlowOption(getFileDescriptor(), flow);
    108         return (T)flow;
    109     }
    110 
    111     // BEGIN Android-changed: Rewrote on top of Libcore.io.
    112     protected void socketSetOption(int opt, Object val) throws SocketException {
    113         try {
    114             socketSetOption0(opt, val);
    115         } catch (SocketException se) {
    116             if (socket == null || !socket.isConnected())
    117                 throw se;
    118         }
    119     }
    120 
    121     void socketCreate(boolean isStream) throws IOException {
    122         // The fd object must not change after calling bind, because we rely on this undocumented
    123         // behaviour. See libcore.java.net.SocketTest#testFileDescriptorStaysSame.
    124         fd.setInt$(IoBridge.socket(AF_INET6, isStream ? SOCK_STREAM : SOCK_DGRAM, 0).getInt$());
    125 
    126         if (serverSocket != null) {
    127             IoUtils.setBlocking(fd, false);
    128             IoBridge.setSocketOption(fd, SO_REUSEADDR, true);
    129         }
    130     }
    131 
    132     void socketConnect(InetAddress address, int port, int timeout) throws IOException {
    133         if (fd == null || !fd.valid()) {
    134             throw new SocketException("Socket closed");
    135         }
    136 
    137         IoBridge.connect(fd, address, port, timeout);
    138 
    139         this.address = address;
    140         this.port = port;
    141 
    142         if (localport == 0) {
    143             // If socket is pending close, fd becomes an AF_UNIX socket and calling
    144             // getLocalInetSocketAddress will fail.
    145             // http://b/34645743
    146             if (!isClosedOrPending()) {
    147                 localport = IoBridge.getLocalInetSocketAddress(fd).getPort();
    148             }
    149         }
    150     }
    151 
    152     void socketBind(InetAddress address, int port) throws IOException {
    153         if (fd == null || !fd.valid()) {
    154             throw new SocketException("Socket closed");
    155         }
    156 
    157         IoBridge.bind(fd, address, port);
    158 
    159         this.address = address;
    160         if (port == 0) {
    161             // Now that we're a connected socket, let's extract the port number that the system
    162             // chose for us and store it in the Socket object.
    163             localport = IoBridge.getLocalInetSocketAddress(fd).getPort();
    164         } else {
    165             localport = port;
    166         }
    167     }
    168 
    169     void socketListen(int count) throws IOException {
    170         if (fd == null || !fd.valid()) {
    171             throw new SocketException("Socket closed");
    172         }
    173 
    174         try {
    175             Libcore.os.listen(fd, count);
    176         } catch (ErrnoException errnoException) {
    177             throw errnoException.rethrowAsSocketException();
    178         }
    179     }
    180 
    181     void socketAccept(SocketImpl s) throws IOException {
    182         if (fd == null || !fd.valid()) {
    183             throw new SocketException("Socket closed");
    184         }
    185 
    186         // poll() with a timeout of 0 means "poll for zero millis", but a Socket timeout == 0 means
    187         // "wait forever". When timeout == 0 we pass -1 to poll.
    188         if (timeout <= 0) {
    189             IoBridge.poll(fd, POLLIN | POLLERR, -1);
    190         } else {
    191             IoBridge.poll(fd, POLLIN | POLLERR, timeout);
    192         }
    193 
    194         InetSocketAddress peerAddress = new InetSocketAddress();
    195         try {
    196             FileDescriptor newfd = Libcore.os.accept(fd, peerAddress);
    197 
    198             s.fd.setInt$(newfd.getInt$());
    199             s.address = peerAddress.getAddress();
    200             s.port = peerAddress.getPort();
    201         } catch (ErrnoException errnoException) {
    202             if (errnoException.errno == EAGAIN) {
    203                 throw new SocketTimeoutException(errnoException);
    204             } else if (errnoException.errno == EINVAL || errnoException.errno == EBADF) {
    205                 throw new SocketException("Socket closed");
    206             }
    207             errnoException.rethrowAsSocketException();
    208         }
    209 
    210         s.localport = IoBridge.getLocalInetSocketAddress(s.fd).getPort();
    211     }
    212 
    213     int socketAvailable() throws IOException {
    214         return IoBridge.available(fd);
    215     }
    216 
    217     void socketClose0(boolean useDeferredClose) throws IOException {
    218         if (fd == null || !fd.valid()) {
    219             throw new SocketException("socket already closed");
    220         }
    221 
    222         FileDescriptor markerFD = null;
    223         if (useDeferredClose) {
    224             markerFD = getMarkerFD();
    225         }
    226 
    227         if (useDeferredClose && markerFD != null) {
    228             try {
    229                 Libcore.os.dup2(markerFD, fd.getInt$());
    230                 Libcore.os.close(markerFD);
    231 
    232                 // This effectively closes the socket, needs to signal threads that blocks on this
    233                 // file descriptor.
    234                 AsynchronousCloseMonitor.signalBlockedThreads(fd);
    235             } catch (ErrnoException errnoException) {
    236                 // close should not throw
    237             }
    238         } else {
    239             // If requested or a markerFD cannot be created, a non-deferred close is performed
    240             // instead.
    241             IoBridge.closeAndSignalBlockedThreads(fd);
    242         }
    243     }
    244 
    245     /*
    246      * Create the marker file descriptor by establishing a loopback connection which we shutdown but
    247      * do not close the fd. The result is an fd that can be used for read/write.
    248      *
    249      * The purpose is to keep hold of the raw fd handle until we are sure it is not used in any
    250      * thread. Otherwise if we close the file descriptor directly, the system might reuse the raw fd
    251      * number and threads holding old fd value might behave incorrectly.
    252      */
    253     private FileDescriptor getMarkerFD() throws SocketException {
    254         FileDescriptor fd1 = new FileDescriptor();
    255         FileDescriptor fd2 = new FileDescriptor();
    256         try {
    257             Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd1, fd2);
    258 
    259             // Shutdown fd1, any reads to this fd will get EOF; any writes will get an error.
    260             Libcore.os.shutdown(fd1, SHUT_RDWR);
    261             Libcore.os.close(fd2);
    262         } catch (ErrnoException errnoException) {
    263             // We might have reached the maximum file descriptor number and socketpair(2) would
    264             // fail. In this case, return null and let caller to fall back to an alternative method
    265             // that does not allocate more file descriptors.
    266             return null;
    267         }
    268         return fd1;
    269     }
    270 
    271     void socketShutdown(int howto) throws IOException {
    272         try {
    273             Libcore.os.shutdown(fd, howto);
    274         } catch (ErrnoException errnoException) {
    275             throw errnoException.rethrowAsIOException();
    276         }
    277     }
    278 
    279     void socketSetOption0(int cmd, Object value) throws SocketException {
    280         // OpenJDK does not set SO_TIMEOUT on Linux.
    281         if (cmd == SO_TIMEOUT) {
    282             return;
    283         }
    284 
    285         IoBridge.setSocketOption(fd, cmd, value);
    286     }
    287 
    288     Object socketGetOption(int opt) throws SocketException {
    289         return IoBridge.getSocketOption(fd, opt);
    290     }
    291 
    292     void socketSendUrgentData(int data) throws IOException {
    293         if (fd == null || !fd.valid()) {
    294             throw new SocketException("Socket closed");
    295         }
    296 
    297         try {
    298             byte[] buffer = new byte[] { (byte) data };
    299             Libcore.os.sendto(fd, buffer, 0, 1, MSG_OOB, null, 0);
    300         } catch (ErrnoException errnoException) {
    301             throw errnoException.rethrowAsSocketException();
    302         }
    303     }
    304     // END Android-changed: Rewrote on top of Libcore.io.
    305 
    306 }
    307