10b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes/*
20b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes * Copyright (C) 2011 The Android Open Source Project
30b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes *
40b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
50b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes * you may not use this file except in compliance with the License.
60b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes * You may obtain a copy of the License at
70b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes *
80b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
90b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes *
100b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes * Unless required by applicable law or agreed to in writing, software
110b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
120b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes * See the License for the specific language governing permissions and
140b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes * limitations under the License.
150b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes */
160b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
170b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughespackage libcore.io;
180b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
1941d8acb87dd1b722cf54e4c64e72c6a13688a849Elliott Hughesimport android.system.ErrnoException;
205d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.StructGroupReq;
215d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.StructGroupSourceReq;
225d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.StructLinger;
235d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.StructPollfd;
245d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.StructTimeval;
255d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.util.MutableInt;
260b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.io.FileDescriptor;
270b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.io.FileNotFoundException;
280b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.io.IOException;
290b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.net.BindException;
300b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.net.ConnectException;
310b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.net.DatagramPacket;
320b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.net.Inet4Address;
330b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.net.Inet6Address;
340b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.net.InetAddress;
350b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.net.InetSocketAddress;
360b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.net.NetworkInterface;
370b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.net.PortUnreachableException;
380b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.net.SocketAddress;
390b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.net.SocketException;
400b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.net.SocketOptions;
410b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.net.SocketTimeoutException;
420b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.net.UnknownHostException;
430b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.nio.ByteBuffer;
440b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport java.util.Arrays;
455d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport static android.system.OsConstants.*;
460b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
470b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes/**
480b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes * Implements java.io/java.net/java.nio semantics in terms of the underlying POSIX system calls.
490b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes */
500b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughespublic final class IoBridge {
510b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
520b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    private IoBridge() {
530b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
540b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
550b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static int available(FileDescriptor fd) throws IOException {
560b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
570b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            MutableInt available = new MutableInt(0);
582ca11d6eae460f94bc42bc2e453fac93f4b94eb0Jesse Wilson            Libcore.os.ioctlInt(fd, FIONREAD, available);
590b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            if (available.value < 0) {
600b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                // If the fd refers to a regular file, the result is the difference between
610b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                // the file size and the file position. This may be negative if the position
620b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                // is past the end of the file. If the fd refers to a special file masquerading
630b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                // as a regular file, the result may be negative because the special file
640b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                // may appear to have zero size and yet a previous read call may have
650b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                // read some amount of data and caused the file position to be advanced.
660b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                available.value = 0;
670b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
680b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return available.value;
690b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
700b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            if (errnoException.errno == ENOTTY) {
710b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                // The fd is unwilling to opine about its read buffer.
720b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                return 0;
730b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
740b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw errnoException.rethrowAsIOException();
750b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
760b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
770b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
780b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
790b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static void bind(FileDescriptor fd, InetAddress address, int port) throws SocketException {
80df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller        if (address instanceof Inet6Address) {
81df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller            Inet6Address inet6Address = (Inet6Address) address;
82df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller            if (inet6Address.getScopeId() == 0 && inet6Address.isLinkLocalAddress()) {
83df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                // Linux won't let you bind a link-local address without a scope id.
84df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                // Find one.
85df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                NetworkInterface nif = NetworkInterface.getByInetAddress(address);
86df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                if (nif == null) {
87df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                    throw new SocketException("Can't bind to a link-local address without a scope id: " + address);
88df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                }
89df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                try {
90df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                    address = Inet6Address.getByAddress(address.getHostName(), address.getAddress(), nif.getIndex());
91df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                } catch (UnknownHostException ex) {
92df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                    throw new AssertionError(ex); // Can't happen.
93df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                }
940b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
950b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
960b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
970b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.bind(fd, address, port);
980b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
990b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw new BindException(errnoException.getMessage(), errnoException);
1000b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
1010b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
1020b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
1030b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
1040b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    /**
1050b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * Connects socket 'fd' to 'inetAddress' on 'port', with no timeout. The lack of a timeout
1060b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * means this method won't throw SocketTimeoutException.
1070b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     */
108933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller    public static void connect(FileDescriptor fd, InetAddress inetAddress, int port) throws SocketException {
1090b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
110933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller            IoBridge.connect(fd, inetAddress, port, 0);
1110b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (SocketTimeoutException ex) {
1120b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw new AssertionError(ex); // Can't happen for a connect without a timeout.
1130b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
1140b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
1150b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
1160b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    /**
1170b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * Connects socket 'fd' to 'inetAddress' on 'port', with a the given 'timeoutMs'.
1180b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * Use timeoutMs == 0 for a blocking connect with no timeout.
1190b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     */
120933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller    public static void connect(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws SocketException, SocketTimeoutException {
1210b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
122933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller            connectErrno(fd, inetAddress, port, timeoutMs);
1230b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
1240b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw new ConnectException(connectDetail(inetAddress, port, timeoutMs, errnoException), errnoException);
1250b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (SocketException ex) {
1260b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw ex; // We don't want to doubly wrap these.
1270b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (SocketTimeoutException ex) {
1280b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw ex; // We don't want to doubly wrap these.
1290b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (IOException ex) {
1300b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw new SocketException(ex);
1310b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
1320b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
1330b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
134933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller    private static void connectErrno(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws ErrnoException, IOException {
1350b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        // With no timeout, just call connect(2) directly.
1360b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        if (timeoutMs == 0) {
1370b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.connect(fd, inetAddress, port);
138933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller            return;
1390b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
1400b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
141796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        // For connect with a timeout, we:
142796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        //   1. set the socket to non-blocking,
143796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        //   2. connect(2),
144796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        //   3. loop using poll(2) to decide whether we're connected, whether we should keep
145796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        //      waiting, or whether we've seen a permanent failure and should give up,
146796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        //   4. set the socket back to blocking.
147796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes
148796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        // 1. set the socket to non-blocking.
1490b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        IoUtils.setBlocking(fd, false);
150796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes
151796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        // 2. call connect(2) non-blocking.
152796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        long finishTimeMs = System.currentTimeMillis() + timeoutMs;
1530b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
154796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes            Libcore.os.connect(fd, inetAddress, port);
155796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes            IoUtils.setBlocking(fd, true); // 4. set the socket back to blocking.
156933fbbf606268eec9fc430632b8bca7002a833b3Neil Fuller            return; // We connected immediately.
157796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        } catch (ErrnoException errnoException) {
158796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes            if (errnoException.errno != EINPROGRESS) {
159796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes                throw errnoException;
1600b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
161796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes            // EINPROGRESS means we should keep trying...
1620b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
163796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes
164796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        // 3. loop using poll(2).
165796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        int remainingTimeoutMs;
166796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        do {
167796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes            remainingTimeoutMs = (int) (finishTimeMs - System.currentTimeMillis());
168796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes            if (remainingTimeoutMs <= 0) {
169796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes                throw new SocketTimeoutException(connectDetail(inetAddress, port, timeoutMs, null));
170796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes            }
171796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        } while (!IoBridge.isConnected(fd, inetAddress, port, timeoutMs, remainingTimeoutMs));
172796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        IoUtils.setBlocking(fd, true); // 4. set the socket back to blocking.
1730b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
1740b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
1750b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    private static String connectDetail(InetAddress inetAddress, int port, int timeoutMs, ErrnoException cause) {
1760b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        String detail = "failed to connect to " + inetAddress + " (port " + port + ")";
1770b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        if (timeoutMs > 0) {
1780b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            detail += " after " + timeoutMs + "ms";
1790b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
1800b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        if (cause != null) {
1810b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            detail += ": " + cause.getMessage();
1820b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
1830b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        return detail;
1840b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
1850b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
186f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    /**
187f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller     * Closes the supplied file descriptor and sends a signal to any threads are currently blocking.
188f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller     * In order for the signal to be sent the blocked threads must have registered with
189f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller     * the AsynchronousCloseMonitor before they entered the blocking operation.
190f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller     *
191f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller     * <p>This method is a no-op if passed a {@code null} or already-closed file descriptor.
192f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller     */
193f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    public static void closeAndSignalBlockedThreads(FileDescriptor fd) throws IOException {
194f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        if (fd == null || !fd.valid()) {
1950b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
1960b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
1970b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        int intFd = fd.getInt$();
1980b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        fd.setInt$(-1);
1990b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        FileDescriptor oldFd = new FileDescriptor();
2000b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        oldFd.setInt$(intFd);
2010b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        AsynchronousCloseMonitor.signalBlockedThreads(oldFd);
2020b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
2030b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.close(oldFd);
2040b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
2050b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // TODO: are there any cases in which we should throw?
2060b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
2070b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
2080b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
2090b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static boolean isConnected(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs, int remainingTimeoutMs) throws IOException {
2102ca11d6eae460f94bc42bc2e453fac93f4b94eb0Jesse Wilson        ErrnoException cause;
2110b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
2120b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            StructPollfd[] pollFds = new StructPollfd[] { new StructPollfd() };
2130b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            pollFds[0].fd = fd;
2140b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            pollFds[0].events = (short) POLLOUT;
2150b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            int rc = Libcore.os.poll(pollFds, remainingTimeoutMs);
2160b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            if (rc == 0) {
2170b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                return false; // Timeout.
2180b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
2190b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            int connectError = Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_ERROR);
2200b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            if (connectError == 0) {
2210b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                return true; // Success!
2220b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
2230b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw new ErrnoException("isConnected", connectError); // The connect(2) failed.
2240b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
225796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes            if (!fd.valid()) {
226796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes                throw new SocketException("Socket closed");
227796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes            }
228fa542091e45db699a937c5ac0191194405107827Elliott Hughes            cause = errnoException;
2290b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
2300b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        String detail = connectDetail(inetAddress, port, timeoutMs, cause);
23151f50987458f4b9c3bf3d53f829331a335f67113Elliott Hughes        if (cause.errno == ETIMEDOUT) {
2320b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw new SocketTimeoutException(detail, cause);
2330b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
23451f50987458f4b9c3bf3d53f829331a335f67113Elliott Hughes        throw new ConnectException(detail, cause);
2350b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
2360b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
2370b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    // Socket options used by java.net but not exposed in SocketOptions.
2380b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static final int JAVA_MCAST_JOIN_GROUP = 19;
2390b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static final int JAVA_MCAST_LEAVE_GROUP = 20;
240df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller    public static final int JAVA_MCAST_JOIN_SOURCE_GROUP = 21;
241df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller    public static final int JAVA_MCAST_LEAVE_SOURCE_GROUP = 22;
242df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller    public static final int JAVA_MCAST_BLOCK_SOURCE = 23;
243df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller    public static final int JAVA_MCAST_UNBLOCK_SOURCE = 24;
2440b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static final int JAVA_IP_MULTICAST_TTL = 17;
2450b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
2460b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    /**
2470b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * java.net has its own socket options similar to the underlying Unix ones. We paper over the
2480b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * differences here.
2490b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     */
2500b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static Object getSocketOption(FileDescriptor fd, int option) throws SocketException {
2510b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
2520b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return getSocketOptionErrno(fd, option);
2530b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
2540b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw errnoException.rethrowAsSocketException();
2550b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
2560b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
2570b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
2589b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes    private static Object getSocketOptionErrno(FileDescriptor fd, int option) throws ErrnoException, SocketException {
2590b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        switch (option) {
2600b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.IP_MULTICAST_IF:
2610b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // This is IPv4-only.
2620b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return Libcore.os.getsockoptInAddr(fd, IPPROTO_IP, IP_MULTICAST_IF);
2630b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.IP_MULTICAST_IF2:
2640b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // This is IPv6-only.
2650b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF);
2660b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.IP_MULTICAST_LOOP:
2670b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
2680b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // it doesn't matter which we return.
2690b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP));
2700b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case IoBridge.JAVA_IP_MULTICAST_TTL:
2710b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
2720b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // it doesn't matter which we return.
2730b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
2740b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.IP_TOS:
2750b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
2760b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // it doesn't matter which we return.
2770b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_TCLASS);
2780b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_BROADCAST:
2790b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_BROADCAST));
2800b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_KEEPALIVE:
2810b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_KEEPALIVE));
2820b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_LINGER:
2830b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER);
2840b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            if (!linger.isOn()) {
2850b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                return false;
2860b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
2870b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return linger.l_linger;
2880b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_OOBINLINE:
2890b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_OOBINLINE));
2900b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_RCVBUF:
29151cf1b49bca54ec0229a51df400ad1bee580b1bbBrian Carlstrom            return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_RCVBUF);
2920b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_REUSEADDR:
2930b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR));
2940b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_SNDBUF:
2950b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_SNDBUF);
2960b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_TIMEOUT:
2970b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return (int) Libcore.os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO).toMillis();
2980b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.TCP_NODELAY:
2990b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY));
3000b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        default:
3010b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw new SocketException("Unknown socket option: " + option);
3020b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
3030b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
3040b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
3050b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    private static boolean booleanFromInt(int i) {
3060b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        return (i != 0);
3070b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
3080b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
3090b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    private static int booleanToInt(boolean b) {
3100b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        return b ? 1 : 0;
3110b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
3120b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
3130b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    /**
3140b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * java.net has its own socket options similar to the underlying Unix ones. We paper over the
3150b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * differences here.
3160b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     */
3170b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static void setSocketOption(FileDescriptor fd, int option, Object value) throws SocketException {
3180b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
3190b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            setSocketOptionErrno(fd, option, value);
3200b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
3210b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw errnoException.rethrowAsSocketException();
3220b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
3230b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
3240b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
3259b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes    private static void setSocketOptionErrno(FileDescriptor fd, int option, Object value) throws ErrnoException, SocketException {
3260b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        switch (option) {
3270b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.IP_MULTICAST_IF:
3280b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw new UnsupportedOperationException("Use IP_MULTICAST_IF2 on Android");
3290b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.IP_MULTICAST_IF2:
3300b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // Although IPv6 was cleaned up to use int, IPv4 uses an ip_mreqn containing an int.
3310b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptIpMreqn(fd, IPPROTO_IP, IP_MULTICAST_IF, (Integer) value);
3320b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (Integer) value);
3330b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
3340b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.IP_MULTICAST_LOOP:
3350b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // Although IPv6 was cleaned up to use int, IPv4 multicast loopback uses a byte.
3360b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_LOOP, booleanToInt((Boolean) value));
3370b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, booleanToInt((Boolean) value));
3380b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
3390b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case IoBridge.JAVA_IP_MULTICAST_TTL:
3400b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // Although IPv6 was cleaned up to use int, and IPv4 non-multicast TTL uses int,
3410b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // IPv4 multicast TTL uses a byte.
3420b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_TTL, (Integer) value);
3430b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (Integer) value);
3440b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
3450b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.IP_TOS:
3460b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptInt(fd, IPPROTO_IP, IP_TOS, (Integer) value);
3470b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_TCLASS, (Integer) value);
3480b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
3490b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_BROADCAST:
3500b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_BROADCAST, booleanToInt((Boolean) value));
3510b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
3520b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_KEEPALIVE:
3530b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_KEEPALIVE, booleanToInt((Boolean) value));
3540b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
3550b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_LINGER:
3560b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            boolean on = false;
3570b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            int seconds = 0;
3580b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            if (value instanceof Integer) {
3590b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                on = true;
3600b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                seconds = Math.min((Integer) value, 65535);
3610b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
3620b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            StructLinger linger = new StructLinger(booleanToInt(on), seconds);
3630b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptLinger(fd, SOL_SOCKET, SO_LINGER, linger);
3640b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
3650b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_OOBINLINE:
3660b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_OOBINLINE, booleanToInt((Boolean) value));
3670b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
3680b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_RCVBUF:
3690b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, (Integer) value);
3700b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
3710b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_REUSEADDR:
3720b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR, booleanToInt((Boolean) value));
3730b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
3740b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_SNDBUF:
3750b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_SNDBUF, (Integer) value);
3760b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
3770b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.SO_TIMEOUT:
3780b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            int millis = (Integer) value;
3790b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            StructTimeval tv = StructTimeval.fromMillis(millis);
3800b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, tv);
3810b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
3820b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case SocketOptions.TCP_NODELAY:
3830b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY, booleanToInt((Boolean) value));
3840b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
3850b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case IoBridge.JAVA_MCAST_JOIN_GROUP:
3860b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        case IoBridge.JAVA_MCAST_LEAVE_GROUP:
387df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller        {
3880b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            StructGroupReq groupReq = (StructGroupReq) value;
3890b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            int level = (groupReq.gr_group instanceof Inet4Address) ? IPPROTO_IP : IPPROTO_IPV6;
3900b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            int op = (option == JAVA_MCAST_JOIN_GROUP) ? MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP;
3910b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            Libcore.os.setsockoptGroupReq(fd, level, op, groupReq);
3920b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
393df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller        }
394df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller        case IoBridge.JAVA_MCAST_JOIN_SOURCE_GROUP:
395df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller        case IoBridge.JAVA_MCAST_LEAVE_SOURCE_GROUP:
396df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller        case IoBridge.JAVA_MCAST_BLOCK_SOURCE:
397df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller        case IoBridge.JAVA_MCAST_UNBLOCK_SOURCE:
398df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller        {
399df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller            StructGroupSourceReq groupSourceReq = (StructGroupSourceReq) value;
400df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller            int level = (groupSourceReq.gsr_group instanceof Inet4Address)
401df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                ? IPPROTO_IP : IPPROTO_IPV6;
402df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller            int op = getGroupSourceReqOp(option);
403df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller            Libcore.os.setsockoptGroupSourceReq(fd, level, op, groupSourceReq);
404df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller            return;
405df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller        }
4060b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        default:
4070b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw new SocketException("Unknown socket option: " + option);
4080b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
4090b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
4100b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
411df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller    private static int getGroupSourceReqOp(int javaValue) {
412df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller        switch (javaValue) {
413df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller            case IoBridge.JAVA_MCAST_JOIN_SOURCE_GROUP:
414df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                return MCAST_JOIN_SOURCE_GROUP;
415df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller            case IoBridge.JAVA_MCAST_LEAVE_SOURCE_GROUP:
416df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                return MCAST_LEAVE_SOURCE_GROUP;
417df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller            case IoBridge.JAVA_MCAST_BLOCK_SOURCE:
418df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                return MCAST_BLOCK_SOURCE;
419df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller            case IoBridge.JAVA_MCAST_UNBLOCK_SOURCE:
420df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                return MCAST_UNBLOCK_SOURCE;
421df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller            default:
422df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                throw new AssertionError(
423df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller                        "Unknown java value for setsocketopt op lookup: " + javaValue);
424df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller        }
425df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller    }
426df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller
4270b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    /**
4280b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * java.io only throws FileNotFoundException when opening files, regardless of what actually
4290b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * went wrong. Additionally, java.io is more restrictive than POSIX when it comes to opening
4300b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * directories: POSIX says read-only is okay, but java.io doesn't even allow that. We also
4310b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * have an Android-specific hack to alter the default permissions.
4320b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     */
4330b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static FileDescriptor open(String path, int flags) throws FileNotFoundException {
4340b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        FileDescriptor fd = null;
4350b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
4360b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // On Android, we don't want default permissions to allow global access.
4370b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            int mode = ((flags & O_ACCMODE) == O_RDONLY) ? 0 : 0600;
4380b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            fd = Libcore.os.open(path, flags, mode);
43915443035ff7b8ac7d6a7e6e2caffcd88f2faef67Narayan Kamath            // Posix open(2) fails with EISDIR only if you ask for write permission.
44015443035ff7b8ac7d6a7e6e2caffcd88f2faef67Narayan Kamath            // Java disallows reading directories too.
44115443035ff7b8ac7d6a7e6e2caffcd88f2faef67Narayan Kamath            if (S_ISDIR(Libcore.os.fstat(fd).st_mode)) {
44215443035ff7b8ac7d6a7e6e2caffcd88f2faef67Narayan Kamath                throw new ErrnoException("open", EISDIR);
4430b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
4440b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return fd;
4450b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
4460b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            try {
4470b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                if (fd != null) {
4480b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                    IoUtils.close(fd);
4490b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                }
4500b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            } catch (IOException ignored) {
4510b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
4520b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            FileNotFoundException ex = new FileNotFoundException(path + ": " + errnoException.getMessage());
4530b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            ex.initCause(errnoException);
4540b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw ex;
4550b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
4560b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
4570b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
4580b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    /**
4590b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * java.io thinks that a read at EOF is an error and should return -1, contrary to traditional
4600b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * Unix practice where you'd read until you got 0 bytes (and any future read would return -1).
4610b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     */
4620b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {
4630b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount);
4640b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        if (byteCount == 0) {
4650b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return 0;
4660b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
4670b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
4680b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            int readCount = Libcore.os.read(fd, bytes, byteOffset, byteCount);
4690b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            if (readCount == 0) {
4700b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                return -1;
4710b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
4720b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return readCount;
4730b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
4740b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            if (errnoException.errno == EAGAIN) {
4750b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                // We return 0 rather than throw if we try to read from an empty non-blocking pipe.
4760b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                return 0;
4770b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
4780b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw errnoException.rethrowAsIOException();
4790b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
4800b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
4810b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
4820b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    /**
4830b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * java.io always writes every byte it's asked to, or fails with an error. (That is, unlike
4840b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     * Unix it never just writes as many bytes as happens to be convenient.)
4850b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes     */
4860b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static void write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {
4870b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount);
4880b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        if (byteCount == 0) {
4890b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return;
4900b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
4910b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
4920b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            while (byteCount > 0) {
4930b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                int bytesWritten = Libcore.os.write(fd, bytes, byteOffset, byteCount);
4940b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                byteCount -= bytesWritten;
4950b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                byteOffset += bytesWritten;
4960b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
4970b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
4980b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw errnoException.rethrowAsIOException();
4990b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
5000b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
5010b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
5020b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws IOException {
5030b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        boolean isDatagram = (inetAddress != null);
5040b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        if (!isDatagram && byteCount <= 0) {
5050b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return 0;
5060b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
5070b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        int result;
5080b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
5090b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            result = Libcore.os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port);
5100b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
5110b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            result = maybeThrowAfterSendto(isDatagram, errnoException);
5120b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
5130b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        return result;
5140b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
5150b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
5160b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws IOException {
5170b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        boolean isDatagram = (inetAddress != null);
5180b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        if (!isDatagram && buffer.remaining() == 0) {
5190b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return 0;
5200b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
5210b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        int result;
5220b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
5230b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            result = Libcore.os.sendto(fd, buffer, flags, inetAddress, port);
5240b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
5250b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            result = maybeThrowAfterSendto(isDatagram, errnoException);
5260b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
5270b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        return result;
5280b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
5290b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
5300b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    private static int maybeThrowAfterSendto(boolean isDatagram, ErrnoException errnoException) throws SocketException {
5310b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        if (isDatagram) {
5320b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            if (errnoException.errno == ECONNRESET || errnoException.errno == ECONNREFUSED) {
5330b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                return 0;
5340b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
5350b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } else {
536f4a4259d8a548ab172ca98b702feafcd0ceb1411Elliott Hughes            if (errnoException.errno == EAGAIN) {
5370b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                // We were asked to write to a non-blocking socket, but were told
5380b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                // it would block, so report "no bytes written".
5390b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                return 0;
5400b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
5410b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
5420b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        throw errnoException.rethrowAsSocketException();
5430b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
5440b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
5450b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static int recvfrom(boolean isRead, FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, DatagramPacket packet, boolean isConnected) throws IOException {
5460b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        int result;
5470b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
5480b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            InetSocketAddress srcAddress = (packet != null && !isConnected) ? new InetSocketAddress() : null;
5490b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            result = Libcore.os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress);
5500b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            result = postRecvfrom(isRead, packet, isConnected, srcAddress, result);
5510b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
5520b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            result = maybeThrowAfterRecvfrom(isRead, isConnected, errnoException);
5530b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
5540b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        return result;
5550b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
5560b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
5570b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static int recvfrom(boolean isRead, FileDescriptor fd, ByteBuffer buffer, int flags, DatagramPacket packet, boolean isConnected) throws IOException {
5580b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        int result;
5590b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
5600b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            InetSocketAddress srcAddress = (packet != null && !isConnected) ? new InetSocketAddress() : null;
5610b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            result = Libcore.os.recvfrom(fd, buffer, flags, srcAddress);
5620b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            result = postRecvfrom(isRead, packet, isConnected, srcAddress, result);
5630b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
5640b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            result = maybeThrowAfterRecvfrom(isRead, isConnected, errnoException);
5650b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
5660b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        return result;
5670b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
5680b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
5690b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    private static int postRecvfrom(boolean isRead, DatagramPacket packet, boolean isConnected, InetSocketAddress srcAddress, int byteCount) {
5700b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        if (isRead && byteCount == 0) {
5710b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return -1;
5720b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
5730b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        if (packet != null) {
574e50d82455c813210a2d452070f45fd38d9903159Elliott Hughes            packet.setReceivedLength(byteCount);
5750b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            if (!isConnected) {
5760b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                packet.setAddress(srcAddress.getAddress());
5770b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                packet.setPort(srcAddress.getPort());
5780b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
5790b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
5800b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        return byteCount;
5810b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
5820b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
5830b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    private static int maybeThrowAfterRecvfrom(boolean isRead, boolean isConnected, ErrnoException errnoException) throws SocketException, SocketTimeoutException {
5840b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        if (isRead) {
585f4a4259d8a548ab172ca98b702feafcd0ceb1411Elliott Hughes            if (errnoException.errno == EAGAIN) {
5860b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                return 0;
5870b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            } else {
5880b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                throw errnoException.rethrowAsSocketException();
5890b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
5900b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } else {
5910b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            if (isConnected && errnoException.errno == ECONNREFUSED) {
5920b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                throw new PortUnreachableException("", errnoException);
593f4a4259d8a548ab172ca98b702feafcd0ceb1411Elliott Hughes            } else if (errnoException.errno == EAGAIN) {
5940b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                throw new SocketTimeoutException(errnoException);
5950b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            } else {
5960b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                throw errnoException.rethrowAsSocketException();
5970b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
5980b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
5990b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
6000b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
6010b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    public static FileDescriptor socket(boolean stream) throws SocketException {
6020b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        FileDescriptor fd;
6030b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        try {
6040b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            fd = Libcore.os.socket(AF_INET6, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
6050b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
6060b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // The RFC (http://www.ietf.org/rfc/rfc3493.txt) says that IPV6_MULTICAST_HOPS defaults
6070b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // to 1. The Linux kernel (at least up to 2.6.38) accidentally defaults to 64 (which
6080b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // would be correct for the *unicast* hop limit).
6090b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // See http://www.spinics.net/lists/netdev/msg129022.html, though no patch appears to
6100b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // have been applied as a result of that discussion. If that bug is ever fixed, we can
6110b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // remove this code. Until then, we manually set the hop limit on IPv6 datagram sockets.
6120b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            // (IPv4 is already correct.)
6130b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            if (!stream) {
6140b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes                Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 1);
6150b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            }
6160b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
6170b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            return fd;
6180b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        } catch (ErrnoException errnoException) {
6190b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            throw errnoException.rethrowAsSocketException();
6200b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes        }
6210b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
6220b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
623255a6f4ab321614ed1ca26849d1df7fa9c0610f5Elliott Hughes    public static InetAddress getSocketLocalAddress(FileDescriptor fd) throws SocketException {
6249b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        try {
6259b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes            SocketAddress sa = Libcore.os.getsockname(fd);
6269b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes            InetSocketAddress isa = (InetSocketAddress) sa;
6279b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes            return isa.getAddress();
6289b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        } catch (ErrnoException errnoException) {
629255a6f4ab321614ed1ca26849d1df7fa9c0610f5Elliott Hughes            throw errnoException.rethrowAsSocketException();
6309b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        }
6310b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
6320b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes
633255a6f4ab321614ed1ca26849d1df7fa9c0610f5Elliott Hughes    public static int getSocketLocalPort(FileDescriptor fd) throws SocketException {
6349b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        try {
6359b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes            SocketAddress sa = Libcore.os.getsockname(fd);
6369b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes            InetSocketAddress isa = (InetSocketAddress) sa;
6379b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes            return isa.getPort();
6389b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        } catch (ErrnoException errnoException) {
639255a6f4ab321614ed1ca26849d1df7fa9c0610f5Elliott Hughes            throw errnoException.rethrowAsSocketException();
6409b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        }
6410b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes    }
6420b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes}
643