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