Home | History | Annotate | Download | only in io
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.io;
     18 
     19 import android.system.ErrnoException;
     20 import android.system.StructGroupReq;
     21 import android.system.StructGroupSourceReq;
     22 import android.system.StructLinger;
     23 import android.system.StructPollfd;
     24 import android.system.StructTimeval;
     25 import android.util.MutableInt;
     26 import java.io.FileDescriptor;
     27 import java.io.FileNotFoundException;
     28 import java.io.IOException;
     29 import java.net.BindException;
     30 import java.net.ConnectException;
     31 import java.net.DatagramPacket;
     32 import java.net.Inet4Address;
     33 import java.net.Inet6Address;
     34 import java.net.InetAddress;
     35 import java.net.InetSocketAddress;
     36 import java.net.NetworkInterface;
     37 import java.net.PortUnreachableException;
     38 import java.net.SocketAddress;
     39 import java.net.SocketException;
     40 import java.net.SocketOptions;
     41 import java.net.SocketTimeoutException;
     42 import java.net.UnknownHostException;
     43 import java.nio.ByteBuffer;
     44 import java.util.Arrays;
     45 import java.util.concurrent.TimeUnit;
     46 
     47 import static android.system.OsConstants.*;
     48 
     49 /**
     50  * Implements java.io/java.net/java.nio semantics in terms of the underlying POSIX system calls.
     51  */
     52 public final class IoBridge {
     53 
     54     private IoBridge() {
     55     }
     56 
     57     public static int available(FileDescriptor fd) throws IOException {
     58         try {
     59             MutableInt available = new MutableInt(0);
     60             Libcore.os.ioctlInt(fd, FIONREAD, available);
     61             if (available.value < 0) {
     62                 // If the fd refers to a regular file, the result is the difference between
     63                 // the file size and the file position. This may be negative if the position
     64                 // is past the end of the file. If the fd refers to a special file masquerading
     65                 // as a regular file, the result may be negative because the special file
     66                 // may appear to have zero size and yet a previous read call may have
     67                 // read some amount of data and caused the file position to be advanced.
     68                 available.value = 0;
     69             }
     70             return available.value;
     71         } catch (ErrnoException errnoException) {
     72             if (errnoException.errno == ENOTTY) {
     73                 // The fd is unwilling to opine about its read buffer.
     74                 return 0;
     75             }
     76             throw errnoException.rethrowAsIOException();
     77         }
     78     }
     79 
     80 
     81     public static void bind(FileDescriptor fd, InetAddress address, int port) throws SocketException {
     82         if (address instanceof Inet6Address) {
     83             Inet6Address inet6Address = (Inet6Address) address;
     84             if (inet6Address.getScopeId() == 0 && inet6Address.isLinkLocalAddress()) {
     85                 // Linux won't let you bind a link-local address without a scope id.
     86                 // Find one.
     87                 NetworkInterface nif = NetworkInterface.getByInetAddress(address);
     88                 if (nif == null) {
     89                     throw new SocketException("Can't bind to a link-local address without a scope id: " + address);
     90                 }
     91                 try {
     92                     address = Inet6Address.getByAddress(address.getHostName(), address.getAddress(), nif.getIndex());
     93                 } catch (UnknownHostException ex) {
     94                     throw new AssertionError(ex); // Can't happen.
     95                 }
     96             }
     97         }
     98         try {
     99             Libcore.os.bind(fd, address, port);
    100         } catch (ErrnoException errnoException) {
    101             throw new BindException(errnoException.getMessage(), errnoException);
    102         }
    103     }
    104 
    105 
    106     /**
    107      * Connects socket 'fd' to 'inetAddress' on 'port', with no timeout. The lack of a timeout
    108      * means this method won't throw SocketTimeoutException.
    109      */
    110     public static void connect(FileDescriptor fd, InetAddress inetAddress, int port) throws SocketException {
    111         try {
    112             IoBridge.connect(fd, inetAddress, port, 0);
    113         } catch (SocketTimeoutException ex) {
    114             throw new AssertionError(ex); // Can't happen for a connect without a timeout.
    115         }
    116     }
    117 
    118     /**
    119      * Connects socket 'fd' to 'inetAddress' on 'port', with a the given 'timeoutMs'.
    120      * Use timeoutMs == 0 for a blocking connect with no timeout.
    121      */
    122     public static void connect(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws SocketException, SocketTimeoutException {
    123         try {
    124             connectErrno(fd, inetAddress, port, timeoutMs);
    125         } catch (ErrnoException errnoException) {
    126             throw new ConnectException(connectDetail(inetAddress, port, timeoutMs, errnoException), errnoException);
    127         } catch (SocketException ex) {
    128             throw ex; // We don't want to doubly wrap these.
    129         } catch (SocketTimeoutException ex) {
    130             throw ex; // We don't want to doubly wrap these.
    131         } catch (IOException ex) {
    132             throw new SocketException(ex);
    133         }
    134     }
    135 
    136     private static void connectErrno(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws ErrnoException, IOException {
    137         // With no timeout, just call connect(2) directly.
    138         if (timeoutMs == 0) {
    139             Libcore.os.connect(fd, inetAddress, port);
    140             return;
    141         }
    142 
    143         // For connect with a timeout, we:
    144         //   1. set the socket to non-blocking,
    145         //   2. connect(2),
    146         //   3. loop using poll(2) to decide whether we're connected, whether we should keep
    147         //      waiting, or whether we've seen a permanent failure and should give up,
    148         //   4. set the socket back to blocking.
    149 
    150         // 1. set the socket to non-blocking.
    151         IoUtils.setBlocking(fd, false);
    152 
    153         // 2. call connect(2) non-blocking.
    154         long finishTimeNanos = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeoutMs);
    155         try {
    156             Libcore.os.connect(fd, inetAddress, port);
    157             IoUtils.setBlocking(fd, true); // 4. set the socket back to blocking.
    158             return; // We connected immediately.
    159         } catch (ErrnoException errnoException) {
    160             if (errnoException.errno != EINPROGRESS) {
    161                 throw errnoException;
    162             }
    163             // EINPROGRESS means we should keep trying...
    164         }
    165 
    166         // 3. loop using poll(2).
    167         int remainingTimeoutMs;
    168         do {
    169             remainingTimeoutMs =
    170                     (int) TimeUnit.NANOSECONDS.toMillis(finishTimeNanos - System.nanoTime());
    171             if (remainingTimeoutMs <= 0) {
    172                 throw new SocketTimeoutException(connectDetail(inetAddress, port, timeoutMs, null));
    173             }
    174         } while (!IoBridge.isConnected(fd, inetAddress, port, timeoutMs, remainingTimeoutMs));
    175         IoUtils.setBlocking(fd, true); // 4. set the socket back to blocking.
    176     }
    177 
    178     private static String connectDetail(InetAddress inetAddress, int port, int timeoutMs, ErrnoException cause) {
    179         String detail = "failed to connect to " + inetAddress + " (port " + port + ")";
    180         if (timeoutMs > 0) {
    181             detail += " after " + timeoutMs + "ms";
    182         }
    183         if (cause != null) {
    184             detail += ": " + cause.getMessage();
    185         }
    186         return detail;
    187     }
    188 
    189     /**
    190      * Closes the supplied file descriptor and sends a signal to any threads are currently blocking.
    191      * In order for the signal to be sent the blocked threads must have registered with
    192      * the AsynchronousCloseMonitor before they entered the blocking operation.
    193      *
    194      * <p>This method is a no-op if passed a {@code null} or already-closed file descriptor.
    195      */
    196     public static void closeAndSignalBlockedThreads(FileDescriptor fd) throws IOException {
    197         if (fd == null || !fd.valid()) {
    198             return;
    199         }
    200         int intFd = fd.getInt$();
    201         fd.setInt$(-1);
    202         FileDescriptor oldFd = new FileDescriptor();
    203         oldFd.setInt$(intFd);
    204         AsynchronousCloseMonitor.signalBlockedThreads(oldFd);
    205         try {
    206             Libcore.os.close(oldFd);
    207         } catch (ErrnoException errnoException) {
    208             // TODO: are there any cases in which we should throw?
    209         }
    210     }
    211 
    212     public static boolean isConnected(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs, int remainingTimeoutMs) throws IOException {
    213         ErrnoException cause;
    214         try {
    215             StructPollfd[] pollFds = new StructPollfd[] { new StructPollfd() };
    216             pollFds[0].fd = fd;
    217             pollFds[0].events = (short) POLLOUT;
    218             int rc = Libcore.os.poll(pollFds, remainingTimeoutMs);
    219             if (rc == 0) {
    220                 return false; // Timeout.
    221             }
    222             int connectError = Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_ERROR);
    223             if (connectError == 0) {
    224                 return true; // Success!
    225             }
    226             throw new ErrnoException("isConnected", connectError); // The connect(2) failed.
    227         } catch (ErrnoException errnoException) {
    228             if (!fd.valid()) {
    229                 throw new SocketException("Socket closed");
    230             }
    231             cause = errnoException;
    232         }
    233         String detail = connectDetail(inetAddress, port, timeoutMs, cause);
    234         if (cause.errno == ETIMEDOUT) {
    235             throw new SocketTimeoutException(detail, cause);
    236         }
    237         throw new ConnectException(detail, cause);
    238     }
    239 
    240     // Socket options used by java.net but not exposed in SocketOptions.
    241     public static final int JAVA_MCAST_JOIN_GROUP = 19;
    242     public static final int JAVA_MCAST_LEAVE_GROUP = 20;
    243     public static final int JAVA_MCAST_JOIN_SOURCE_GROUP = 21;
    244     public static final int JAVA_MCAST_LEAVE_SOURCE_GROUP = 22;
    245     public static final int JAVA_MCAST_BLOCK_SOURCE = 23;
    246     public static final int JAVA_MCAST_UNBLOCK_SOURCE = 24;
    247     public static final int JAVA_IP_MULTICAST_TTL = 17;
    248 
    249     /**
    250      * java.net has its own socket options similar to the underlying Unix ones. We paper over the
    251      * differences here.
    252      */
    253     public static Object getSocketOption(FileDescriptor fd, int option) throws SocketException {
    254         try {
    255             return getSocketOptionErrno(fd, option);
    256         } catch (ErrnoException errnoException) {
    257             throw errnoException.rethrowAsSocketException();
    258         }
    259     }
    260 
    261     private static Object getSocketOptionErrno(FileDescriptor fd, int option) throws ErrnoException, SocketException {
    262         switch (option) {
    263         case SocketOptions.IP_MULTICAST_IF:
    264             // This is IPv4-only.
    265             return Libcore.os.getsockoptInAddr(fd, IPPROTO_IP, IP_MULTICAST_IF);
    266         case SocketOptions.IP_MULTICAST_IF2:
    267             // This is IPv6-only.
    268             return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF);
    269         case SocketOptions.IP_MULTICAST_LOOP:
    270             // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
    271             // it doesn't matter which we return.
    272             return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP));
    273         case IoBridge.JAVA_IP_MULTICAST_TTL:
    274             // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
    275             // it doesn't matter which we return.
    276             return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
    277         case SocketOptions.IP_TOS:
    278             // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
    279             // it doesn't matter which we return.
    280             return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_TCLASS);
    281         case SocketOptions.SO_BROADCAST:
    282             return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_BROADCAST));
    283         case SocketOptions.SO_KEEPALIVE:
    284             return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_KEEPALIVE));
    285         case SocketOptions.SO_LINGER:
    286             StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER);
    287             if (!linger.isOn()) {
    288                 return false;
    289             }
    290             return linger.l_linger;
    291         case SocketOptions.SO_OOBINLINE:
    292             return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_OOBINLINE));
    293         case SocketOptions.SO_RCVBUF:
    294             return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_RCVBUF);
    295         case SocketOptions.SO_REUSEADDR:
    296             return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR));
    297         case SocketOptions.SO_SNDBUF:
    298             return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_SNDBUF);
    299         case SocketOptions.SO_TIMEOUT:
    300             return (int) Libcore.os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO).toMillis();
    301         case SocketOptions.TCP_NODELAY:
    302             return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY));
    303         default:
    304             throw new SocketException("Unknown socket option: " + option);
    305         }
    306     }
    307 
    308     private static boolean booleanFromInt(int i) {
    309         return (i != 0);
    310     }
    311 
    312     private static int booleanToInt(boolean b) {
    313         return b ? 1 : 0;
    314     }
    315 
    316     /**
    317      * java.net has its own socket options similar to the underlying Unix ones. We paper over the
    318      * differences here.
    319      */
    320     public static void setSocketOption(FileDescriptor fd, int option, Object value) throws SocketException {
    321         try {
    322             setSocketOptionErrno(fd, option, value);
    323         } catch (ErrnoException errnoException) {
    324             throw errnoException.rethrowAsSocketException();
    325         }
    326     }
    327 
    328     private static void setSocketOptionErrno(FileDescriptor fd, int option, Object value) throws ErrnoException, SocketException {
    329         switch (option) {
    330         case SocketOptions.IP_MULTICAST_IF:
    331             throw new UnsupportedOperationException("Use IP_MULTICAST_IF2 on Android");
    332         case SocketOptions.IP_MULTICAST_IF2:
    333             // Although IPv6 was cleaned up to use int, IPv4 uses an ip_mreqn containing an int.
    334             Libcore.os.setsockoptIpMreqn(fd, IPPROTO_IP, IP_MULTICAST_IF, (Integer) value);
    335             Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (Integer) value);
    336             return;
    337         case SocketOptions.IP_MULTICAST_LOOP:
    338             // Although IPv6 was cleaned up to use int, IPv4 multicast loopback uses a byte.
    339             Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_LOOP, booleanToInt((Boolean) value));
    340             Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, booleanToInt((Boolean) value));
    341             return;
    342         case IoBridge.JAVA_IP_MULTICAST_TTL:
    343             // Although IPv6 was cleaned up to use int, and IPv4 non-multicast TTL uses int,
    344             // IPv4 multicast TTL uses a byte.
    345             Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_TTL, (Integer) value);
    346             Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (Integer) value);
    347             return;
    348         case SocketOptions.IP_TOS:
    349             Libcore.os.setsockoptInt(fd, IPPROTO_IP, IP_TOS, (Integer) value);
    350             Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_TCLASS, (Integer) value);
    351             return;
    352         case SocketOptions.SO_BROADCAST:
    353             Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_BROADCAST, booleanToInt((Boolean) value));
    354             return;
    355         case SocketOptions.SO_KEEPALIVE:
    356             Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_KEEPALIVE, booleanToInt((Boolean) value));
    357             return;
    358         case SocketOptions.SO_LINGER:
    359             boolean on = false;
    360             int seconds = 0;
    361             if (value instanceof Integer) {
    362                 on = true;
    363                 seconds = Math.min((Integer) value, 65535);
    364             }
    365             StructLinger linger = new StructLinger(booleanToInt(on), seconds);
    366             Libcore.os.setsockoptLinger(fd, SOL_SOCKET, SO_LINGER, linger);
    367             return;
    368         case SocketOptions.SO_OOBINLINE:
    369             Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_OOBINLINE, booleanToInt((Boolean) value));
    370             return;
    371         case SocketOptions.SO_RCVBUF:
    372             Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, (Integer) value);
    373             return;
    374         case SocketOptions.SO_REUSEADDR:
    375             Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR, booleanToInt((Boolean) value));
    376             return;
    377         case SocketOptions.SO_SNDBUF:
    378             Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_SNDBUF, (Integer) value);
    379             return;
    380         case SocketOptions.SO_TIMEOUT:
    381             int millis = (Integer) value;
    382             StructTimeval tv = StructTimeval.fromMillis(millis);
    383             Libcore.os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, tv);
    384             return;
    385         case SocketOptions.TCP_NODELAY:
    386             Libcore.os.setsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY, booleanToInt((Boolean) value));
    387             return;
    388         case IoBridge.JAVA_MCAST_JOIN_GROUP:
    389         case IoBridge.JAVA_MCAST_LEAVE_GROUP:
    390         {
    391             StructGroupReq groupReq = (StructGroupReq) value;
    392             int level = (groupReq.gr_group instanceof Inet4Address) ? IPPROTO_IP : IPPROTO_IPV6;
    393             int op = (option == JAVA_MCAST_JOIN_GROUP) ? MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP;
    394             Libcore.os.setsockoptGroupReq(fd, level, op, groupReq);
    395             return;
    396         }
    397         case IoBridge.JAVA_MCAST_JOIN_SOURCE_GROUP:
    398         case IoBridge.JAVA_MCAST_LEAVE_SOURCE_GROUP:
    399         case IoBridge.JAVA_MCAST_BLOCK_SOURCE:
    400         case IoBridge.JAVA_MCAST_UNBLOCK_SOURCE:
    401         {
    402             StructGroupSourceReq groupSourceReq = (StructGroupSourceReq) value;
    403             int level = (groupSourceReq.gsr_group instanceof Inet4Address)
    404                 ? IPPROTO_IP : IPPROTO_IPV6;
    405             int op = getGroupSourceReqOp(option);
    406             Libcore.os.setsockoptGroupSourceReq(fd, level, op, groupSourceReq);
    407             return;
    408         }
    409         default:
    410             throw new SocketException("Unknown socket option: " + option);
    411         }
    412     }
    413 
    414     private static int getGroupSourceReqOp(int javaValue) {
    415         switch (javaValue) {
    416             case IoBridge.JAVA_MCAST_JOIN_SOURCE_GROUP:
    417                 return MCAST_JOIN_SOURCE_GROUP;
    418             case IoBridge.JAVA_MCAST_LEAVE_SOURCE_GROUP:
    419                 return MCAST_LEAVE_SOURCE_GROUP;
    420             case IoBridge.JAVA_MCAST_BLOCK_SOURCE:
    421                 return MCAST_BLOCK_SOURCE;
    422             case IoBridge.JAVA_MCAST_UNBLOCK_SOURCE:
    423                 return MCAST_UNBLOCK_SOURCE;
    424             default:
    425                 throw new AssertionError(
    426                         "Unknown java value for setsocketopt op lookup: " + javaValue);
    427         }
    428     }
    429 
    430     /**
    431      * java.io only throws FileNotFoundException when opening files, regardless of what actually
    432      * went wrong. Additionally, java.io is more restrictive than POSIX when it comes to opening
    433      * directories: POSIX says read-only is okay, but java.io doesn't even allow that. We also
    434      * have an Android-specific hack to alter the default permissions.
    435      */
    436     public static FileDescriptor open(String path, int flags) throws FileNotFoundException {
    437         FileDescriptor fd = null;
    438         try {
    439             // On Android, we don't want default permissions to allow global access.
    440             int mode = ((flags & O_ACCMODE) == O_RDONLY) ? 0 : 0600;
    441             fd = Libcore.os.open(path, flags, mode);
    442             // Posix open(2) fails with EISDIR only if you ask for write permission.
    443             // Java disallows reading directories too.
    444             if (S_ISDIR(Libcore.os.fstat(fd).st_mode)) {
    445                 throw new ErrnoException("open", EISDIR);
    446             }
    447             return fd;
    448         } catch (ErrnoException errnoException) {
    449             try {
    450                 if (fd != null) {
    451                     IoUtils.close(fd);
    452                 }
    453             } catch (IOException ignored) {
    454             }
    455             FileNotFoundException ex = new FileNotFoundException(path + ": " + errnoException.getMessage());
    456             ex.initCause(errnoException);
    457             throw ex;
    458         }
    459     }
    460 
    461     /**
    462      * java.io thinks that a read at EOF is an error and should return -1, contrary to traditional
    463      * Unix practice where you'd read until you got 0 bytes (and any future read would return -1).
    464      */
    465     public static int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {
    466         Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount);
    467         if (byteCount == 0) {
    468             return 0;
    469         }
    470         try {
    471             int readCount = Libcore.os.read(fd, bytes, byteOffset, byteCount);
    472             if (readCount == 0) {
    473                 return -1;
    474             }
    475             return readCount;
    476         } catch (ErrnoException errnoException) {
    477             if (errnoException.errno == EAGAIN) {
    478                 // We return 0 rather than throw if we try to read from an empty non-blocking pipe.
    479                 return 0;
    480             }
    481             throw errnoException.rethrowAsIOException();
    482         }
    483     }
    484 
    485     /**
    486      * java.io always writes every byte it's asked to, or fails with an error. (That is, unlike
    487      * Unix it never just writes as many bytes as happens to be convenient.)
    488      */
    489     public static void write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {
    490         Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount);
    491         if (byteCount == 0) {
    492             return;
    493         }
    494         try {
    495             while (byteCount > 0) {
    496                 int bytesWritten = Libcore.os.write(fd, bytes, byteOffset, byteCount);
    497                 byteCount -= bytesWritten;
    498                 byteOffset += bytesWritten;
    499             }
    500         } catch (ErrnoException errnoException) {
    501             throw errnoException.rethrowAsIOException();
    502         }
    503     }
    504 
    505     public static int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws IOException {
    506         boolean isDatagram = (inetAddress != null);
    507         if (!isDatagram && byteCount <= 0) {
    508             return 0;
    509         }
    510         int result;
    511         try {
    512             result = Libcore.os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port);
    513         } catch (ErrnoException errnoException) {
    514             result = maybeThrowAfterSendto(isDatagram, errnoException);
    515         }
    516         return result;
    517     }
    518 
    519     public static int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws IOException {
    520         boolean isDatagram = (inetAddress != null);
    521         if (!isDatagram && buffer.remaining() == 0) {
    522             return 0;
    523         }
    524         int result;
    525         try {
    526             result = Libcore.os.sendto(fd, buffer, flags, inetAddress, port);
    527         } catch (ErrnoException errnoException) {
    528             result = maybeThrowAfterSendto(isDatagram, errnoException);
    529         }
    530         return result;
    531     }
    532 
    533     private static int maybeThrowAfterSendto(boolean isDatagram, ErrnoException errnoException) throws SocketException {
    534         if (isDatagram) {
    535             if (errnoException.errno == ECONNRESET || errnoException.errno == ECONNREFUSED) {
    536                 return 0;
    537             }
    538         } else {
    539             if (errnoException.errno == EAGAIN) {
    540                 // We were asked to write to a non-blocking socket, but were told
    541                 // it would block, so report "no bytes written".
    542                 return 0;
    543             }
    544         }
    545         throw errnoException.rethrowAsSocketException();
    546     }
    547 
    548     public static int recvfrom(boolean isRead, FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, DatagramPacket packet, boolean isConnected) throws IOException {
    549         int result;
    550         try {
    551             InetSocketAddress srcAddress = (packet != null && !isConnected) ? new InetSocketAddress() : null;
    552             result = Libcore.os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress);
    553             result = postRecvfrom(isRead, packet, isConnected, srcAddress, result);
    554         } catch (ErrnoException errnoException) {
    555             result = maybeThrowAfterRecvfrom(isRead, isConnected, errnoException);
    556         }
    557         return result;
    558     }
    559 
    560     public static int recvfrom(boolean isRead, FileDescriptor fd, ByteBuffer buffer, int flags, DatagramPacket packet, boolean isConnected) throws IOException {
    561         int result;
    562         try {
    563             InetSocketAddress srcAddress = (packet != null && !isConnected) ? new InetSocketAddress() : null;
    564             result = Libcore.os.recvfrom(fd, buffer, flags, srcAddress);
    565             result = postRecvfrom(isRead, packet, isConnected, srcAddress, result);
    566         } catch (ErrnoException errnoException) {
    567             result = maybeThrowAfterRecvfrom(isRead, isConnected, errnoException);
    568         }
    569         return result;
    570     }
    571 
    572     private static int postRecvfrom(boolean isRead, DatagramPacket packet, boolean isConnected, InetSocketAddress srcAddress, int byteCount) {
    573         if (isRead && byteCount == 0) {
    574             return -1;
    575         }
    576         if (packet != null) {
    577             packet.setReceivedLength(byteCount);
    578             if (!isConnected) {
    579                 packet.setAddress(srcAddress.getAddress());
    580                 packet.setPort(srcAddress.getPort());
    581             }
    582         }
    583         return byteCount;
    584     }
    585 
    586     private static int maybeThrowAfterRecvfrom(boolean isRead, boolean isConnected, ErrnoException errnoException) throws SocketException, SocketTimeoutException {
    587         if (isRead) {
    588             if (errnoException.errno == EAGAIN) {
    589                 return 0;
    590             } else {
    591                 throw errnoException.rethrowAsSocketException();
    592             }
    593         } else {
    594             if (isConnected && errnoException.errno == ECONNREFUSED) {
    595                 throw new PortUnreachableException("", errnoException);
    596             } else if (errnoException.errno == EAGAIN) {
    597                 throw new SocketTimeoutException(errnoException);
    598             } else {
    599                 throw errnoException.rethrowAsSocketException();
    600             }
    601         }
    602     }
    603 
    604     public static FileDescriptor socket(boolean stream) throws SocketException {
    605         FileDescriptor fd;
    606         try {
    607             fd = Libcore.os.socket(AF_INET6, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
    608 
    609             // The RFC (http://www.ietf.org/rfc/rfc3493.txt) says that IPV6_MULTICAST_HOPS defaults
    610             // to 1. The Linux kernel (at least up to 2.6.38) accidentally defaults to 64 (which
    611             // would be correct for the *unicast* hop limit).
    612             // See http://www.spinics.net/lists/netdev/msg129022.html, though no patch appears to
    613             // have been applied as a result of that discussion. If that bug is ever fixed, we can
    614             // remove this code. Until then, we manually set the hop limit on IPv6 datagram sockets.
    615             // (IPv4 is already correct.)
    616             if (!stream) {
    617                 Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 1);
    618             }
    619 
    620             return fd;
    621         } catch (ErrnoException errnoException) {
    622             throw errnoException.rethrowAsSocketException();
    623         }
    624     }
    625 
    626     public static InetAddress getSocketLocalAddress(FileDescriptor fd) throws SocketException {
    627         try {
    628             SocketAddress sa = Libcore.os.getsockname(fd);
    629             InetSocketAddress isa = (InetSocketAddress) sa;
    630             return isa.getAddress();
    631         } catch (ErrnoException errnoException) {
    632             throw errnoException.rethrowAsSocketException();
    633         }
    634     }
    635 
    636     public static int getSocketLocalPort(FileDescriptor fd) throws SocketException {
    637         try {
    638             SocketAddress sa = Libcore.os.getsockname(fd);
    639             InetSocketAddress isa = (InetSocketAddress) sa;
    640             return isa.getPort();
    641         } catch (ErrnoException errnoException) {
    642             throw errnoException.rethrowAsSocketException();
    643         }
    644     }
    645 }
    646