1ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes/*
2ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * Copyright (C) 2011 The Android Open Source Project
3ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes *
4ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
5ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * you may not use this file except in compliance with the License.
6ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * You may obtain a copy of the License at
7ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes *
8ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
9ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes *
10ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * Unless required by applicable law or agreed to in writing, software
11ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
12ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * See the License for the specific language governing permissions and
14ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes * limitations under the License.
15ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes */
16ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes
170965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe#define LOG_TAG "Linux"
18ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes
191c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes#include <arpa/inet.h>
20ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes#include <errno.h>
210ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes#include <fcntl.h>
226d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong#include <ifaddrs.h>
238f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline#include <linux/rtnetlink.h>
24b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes#include <net/if.h>
254f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes#include <netdb.h>
260a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes#include <netinet/in.h>
27a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti#include <netpacket/packet.h>
2870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes#include <poll.h>
29d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes#include <pwd.h>
30a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes#include <signal.h>
31ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes#include <stdlib.h>
325744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#include <sys/capability.h>
33461d0d860814c68154d8dd06d24f94118f33d28aElliott Hughes#include <sys/ioctl.h>
347e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes#include <sys/mman.h>
355215e4c0db7530519981f1e505e6db82401802f2Nick Kralevich#include <sys/prctl.h>
36e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath#include <sys/resource.h>
3759e4744d27231f260271dbbca406e0cc39768116Elliott Hughes#include <sys/socket.h>
3847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes#include <sys/stat.h>
39069525a39125c203b658c805685b6045a7d4dfebElliott Hughes#include <sys/syscall.h>
400a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes#include <sys/time.h>
410ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes#include <sys/types.h>
42bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes#include <sys/uio.h>
430ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller#include <sys/un.h>
447341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes#include <sys/utsname.h>
459e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes#include <sys/wait.h>
4690246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey#include <sys/xattr.h>
47bb5816aa1626eb2f6263bd21479600b114c8a1bdJohan Redestig#include <termios.h>
480ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes#include <unistd.h>
496d8d1ea910c1ad026b48c87424da92a250664dd2Mark Salyzyn
50b3aacde3d8af759ee4a7b395c636ea360547d92dIan Rogers#include <memory>
51efae3837b3eb79dea3400735fdcdd5a39020e0b0Ian Rogers
522cb2851f4a528e3e6e3e59cf3e854c2abf9f1811Elliott Hughes#include <android-base/file.h>
532c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe#include <android-base/logging.h>
5455dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong#include <android-base/strings.h>
55d3a88f94be9fb4d0a6da32cf3a820e5b206ded4aMark Salyzyn#include <log/log.h>
56cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/AsynchronousCloseMonitor.h>
57cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/JNIHelp.h>
58cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/JniConstants.h>
59cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/ScopedBytes.h>
60cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/ScopedLocalRef.h>
61cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/ScopedPrimitiveArray.h>
62cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/ScopedUtfChars.h>
63cab01ac294bb8ded259851673baa4c6ca226f828Steven Moreland#include <nativehelper/toStringArray.h>
642cb2851f4a528e3e6e3e59cf3e854c2abf9f1811Elliott Hughes
656d8d1ea910c1ad026b48c87424da92a250664dd2Mark Salyzyn#include "ExecStrings.h"
666d8d1ea910c1ad026b48c87424da92a250664dd2Mark Salyzyn#include "JniException.h"
676d8d1ea910c1ad026b48c87424da92a250664dd2Mark Salyzyn#include "NetworkUtilities.h"
686d8d1ea910c1ad026b48c87424da92a250664dd2Mark Salyzyn#include "Portability.h"
696d8d1ea910c1ad026b48c87424da92a250664dd2Mark Salyzyn
70efae3837b3eb79dea3400735fdcdd5a39020e0b0Ian Rogers#ifndef __unused
7137dd0ac5767197bf7e3e90f1a5d4e54c8f1fe93dIan Rogers#define __unused __attribute__((__unused__))
72efae3837b3eb79dea3400735fdcdd5a39020e0b0Ian Rogers#endif
7337dd0ac5767197bf7e3e90f1a5d4e54c8f1fe93dIan Rogers
74d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes#define TO_JAVA_STRING(NAME, EXP) \
75d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        jstring NAME = env->NewStringUTF(EXP); \
76a0b3a2c22454fad9026cff3b0173ada828bad280Chih-Hung Hsieh        if ((NAME) == NULL) return NULL;
77d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
782c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampenamespace {
792c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe
80e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias ThiererjfieldID int32RefValueFid;
81e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias ThiererjfieldID int64RefValueFid;
822c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe
832c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe}  // namespace
842c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe
851c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughesstruct addrinfo_deleter {
861c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    void operator()(addrinfo* p) const {
871c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        if (p != NULL) { // bionic's freeaddrinfo(3) crashes when passed NULL.
881c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes            freeaddrinfo(p);
891c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        }
901c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
911c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes};
921c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
935d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamathstruct c_deleter {
945d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    void operator()(void* p) const {
955d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath        free(p);
965d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    }
975d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath};
985d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath
99b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colittistatic bool isIPv4MappedAddress(const sockaddr *sa) {
100b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    const sockaddr_in6 *sin6 = reinterpret_cast<const sockaddr_in6*>(sa);
101b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    return sa != NULL && sa->sa_family == AF_INET6 &&
102b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti           (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
103b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr));  // We map 0.0.0.0 to ::, so :: is mapped.
104b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti}
105b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti
106b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti/**
107b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti * Perform a socket operation that specifies an IP address, possibly falling back from specifying
108b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti * the address as an IPv4-mapped IPv6 address in a struct sockaddr_in6 to specifying it as an IPv4
109b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti * address in a struct sockaddr_in.
110b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti *
111b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti * This is needed because all sockets created by the java.net APIs are IPv6 sockets, and on those
112b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti * sockets, IPv4 operations use IPv4-mapped addresses stored in a struct sockaddr_in6. But sockets
1130965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe * created using Linux.socket(AF_INET, ...) are IPv4 sockets and only support operations using IPv4
114b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti * socket addresses structures.
115b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti */
116b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti#define NET_IPV4_FALLBACK(jni_env, return_type, syscall_name, java_fd, java_addr, port, null_addr_ok, args...) ({ \
117b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    return_type _rc = -1; \
118b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    do { \
119b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        sockaddr_storage _ss; \
120b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        socklen_t _salen; \
121a0b3a2c22454fad9026cff3b0173ada828bad280Chih-Hung Hsieh        if ((java_addr) == NULL && (null_addr_ok)) { \
122b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            /* No IP address specified (e.g., sendto() on a connected socket). */ \
123b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            _salen = 0; \
124b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        } else if (!inetAddressToSockaddr(jni_env, java_addr, port, _ss, _salen)) { \
125b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            /* Invalid socket address, return -1. inetAddressToSockaddr has already thrown. */ \
126b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            break; \
127b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        } \
128b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        sockaddr* _sa = _salen ? reinterpret_cast<sockaddr*>(&_ss) : NULL; \
129b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        /* inetAddressToSockaddr always returns an IPv6 sockaddr. Assume that java_fd was created \
130b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti         * by Java API calls, which always create IPv6 socket fds, and pass it in as is. */ \
131b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        _rc = NET_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ##args, _sa, _salen); \
132b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        if (_rc == -1 && errno == EAFNOSUPPORT && _salen && isIPv4MappedAddress(_sa)) { \
133b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            /* We passed in an IPv4 address in an IPv6 sockaddr and the kernel told us that we got \
134b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti             * the address family wrong. Pass in the same address in an IPv4 sockaddr. */ \
135a0b3a2c22454fad9026cff3b0173ada828bad280Chih-Hung Hsieh            (jni_env)->ExceptionClear(); \
136b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            if (!inetAddressToSockaddrVerbatim(jni_env, java_addr, port, _ss, _salen)) { \
137b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti                break; \
138b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            } \
139b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            _sa = reinterpret_cast<sockaddr*>(&_ss); \
140b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti            _rc = NET_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ##args, _sa, _salen); \
141b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti        } \
142b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    } while (0); \
143b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    _rc; }) \
144b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti
145996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes/**
146f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * Used to retry networking system calls that can be interrupted with a signal. Unlike
147f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * TEMP_FAILURE_RETRY, this also handles the case where
148f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * AsynchronousCloseMonitor::signalBlockedThreads(fd) is used to signal a close() or
149f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * Thread.interrupt(). Other signals that result in an EINTR result are ignored and the system call
150f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * is retried.
151996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes *
152f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * Returns the result of the system call though a Java exception will be pending if the result is
153f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * -1:  a SocketException if signaled via AsynchronousCloseMonitor, or ErrnoException for other
154f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * failures.
155996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes */
1561124a814d698ed6fd68ac501f5dddfa103d656fdElliott Hughes#define NET_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ...) ({ \
1571124a814d698ed6fd68ac501f5dddfa103d656fdElliott Hughes    return_type _rc = -1; \
158b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti    int _syscallErrno; \
159996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes    do { \
160f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        bool _wasSignaled; \
161996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes        { \
1621124a814d698ed6fd68ac501f5dddfa103d656fdElliott Hughes            int _fd = jniGetFDFromFileDescriptor(jni_env, java_fd); \
163f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            AsynchronousCloseMonitor _monitor(_fd); \
1641124a814d698ed6fd68ac501f5dddfa103d656fdElliott Hughes            _rc = syscall_name(_fd, __VA_ARGS__); \
165f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            _syscallErrno = errno; \
166f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            _wasSignaled = _monitor.wasSignaled(); \
167996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes        } \
168f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        if (_wasSignaled) { \
169f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            jniThrowException(jni_env, "java/net/SocketException", "Socket closed"); \
1705d7c0a378be3f7f505b30e634e7aabf072c4edd0Serguei Katkov            _rc = -1; \
171f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            break; \
172f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        } \
173f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        if (_rc == -1 && _syscallErrno != EINTR) { \
174f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            /* TODO: with a format string we could show the arguments too, like strace(1). */ \
175f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            throwErrnoException(jni_env, # syscall_name); \
176f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller            break; \
177f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        } \
178f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    } while (_rc == -1); /* _syscallErrno == EINTR && !_wasSignaled */ \
179b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti    if (_rc == -1) { \
180b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti        /* If the syscall failed, re-set errno: throwing an exception might have modified it. */ \
181b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti        errno = _syscallErrno; \
182b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti    } \
183f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    _rc; })
184f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller
185f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller/**
186f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * Used to retry system calls that can be interrupted with a signal. Unlike TEMP_FAILURE_RETRY, this
187f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * also handles the case where AsynchronousCloseMonitor::signalBlockedThreads(fd) is used to signal
188f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * a close() or Thread.interrupt(). Other signals that result in an EINTR result are ignored and the
189f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * system call is retried.
190f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller *
191f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * Returns the result of the system call though a Java exception will be pending if the result is
192f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * -1: an IOException if the file descriptor is already closed, a InterruptedIOException if signaled
193f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller * via AsynchronousCloseMonitor, or ErrnoException for other failures.
194f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller */
195f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller#define IO_FAILURE_RETRY(jni_env, return_type, syscall_name, java_fd, ...) ({ \
196f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    return_type _rc = -1; \
197b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti    int _syscallErrno; \
19899a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller    do { \
19999a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        bool _wasSignaled; \
20099a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        { \
20199a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            int _fd = jniGetFDFromFileDescriptor(jni_env, java_fd); \
20299a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            AsynchronousCloseMonitor _monitor(_fd); \
20399a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            _rc = syscall_name(_fd, __VA_ARGS__); \
20499a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            _syscallErrno = errno; \
20599a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            _wasSignaled = _monitor.wasSignaled(); \
20699a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        } \
20799a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        if (_wasSignaled) { \
20899a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            jniThrowException(jni_env, "java/io/InterruptedIOException", # syscall_name " interrupted"); \
20999a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            _rc = -1; \
21099a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            break; \
21199a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        } \
21299a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        if (_rc == -1 && _syscallErrno != EINTR) { \
21399a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            /* TODO: with a format string we could show the arguments too, like strace(1). */ \
21499a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            throwErrnoException(jni_env, # syscall_name); \
21599a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller            break; \
21699a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller        } \
21799a0c82619a88c6aea038757cf14090f5d33afebNeil Fuller    } while (_rc == -1); /* && _syscallErrno == EINTR && !_wasSignaled */ \
218b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti    if (_rc == -1) { \
219b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti        /* If the syscall failed, re-set errno: throwing an exception might have modified it. */ \
220b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti        errno = _syscallErrno; \
221b4af0b52e1190846edde87f352ca722a7d9e0259Lorenzo Colitti    } \
222996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes    _rc; })
223996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes
224b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti#define NULL_ADDR_OK         true
225b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti#define NULL_ADDR_FORBIDDEN  false
226b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti
2274f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughesstatic void throwException(JNIEnv* env, jclass exceptionClass, jmethodID ctor3, jmethodID ctor2,
2284f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        const char* functionName, int error) {
229ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    jthrowable cause = NULL;
230ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    if (env->ExceptionCheck()) {
231ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes        cause = env->ExceptionOccurred();
232ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes        env->ExceptionClear();
233ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    }
234ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes
2354f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    ScopedLocalRef<jstring> detailMessage(env, env->NewStringUTF(functionName));
2364f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    if (detailMessage.get() == NULL) {
237f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes        // Not really much we can do here. We're probably dead in the water,
238f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes        // but let's try to stumble on...
239f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes        env->ExceptionClear();
240f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes    }
241f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes
242ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    jobject exception;
243ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    if (cause != NULL) {
2444f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        exception = env->NewObject(exceptionClass, ctor3, detailMessage.get(), error, cause);
245ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    } else {
2464f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        exception = env->NewObject(exceptionClass, ctor2, detailMessage.get(), error);
247ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    }
248ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    env->Throw(reinterpret_cast<jthrowable>(exception));
249dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes}
250dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes
2514f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughesstatic void throwErrnoException(JNIEnv* env, const char* functionName) {
2524f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    int error = errno;
2534f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    static jmethodID ctor3 = env->GetMethodID(JniConstants::errnoExceptionClass,
2544f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes            "<init>", "(Ljava/lang/String;ILjava/lang/Throwable;)V");
2554f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    static jmethodID ctor2 = env->GetMethodID(JniConstants::errnoExceptionClass,
2564f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes            "<init>", "(Ljava/lang/String;I)V");
2574f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    throwException(env, JniConstants::errnoExceptionClass, ctor3, ctor2, functionName, error);
2584f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes}
2594f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes
2604f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughesstatic void throwGaiException(JNIEnv* env, const char* functionName, int error) {
261c1cee0db58ec7bc61d5caac79915d744862cbe75Elliott Hughes  // Cache the methods ids before we throw, so we don't call GetMethodID with a pending exception.
262c1cee0db58ec7bc61d5caac79915d744862cbe75Elliott Hughes  static jmethodID ctor3 = env->GetMethodID(JniConstants::gaiExceptionClass, "<init>",
263c1cee0db58ec7bc61d5caac79915d744862cbe75Elliott Hughes                                            "(Ljava/lang/String;ILjava/lang/Throwable;)V");
264c1cee0db58ec7bc61d5caac79915d744862cbe75Elliott Hughes  static jmethodID ctor2 = env->GetMethodID(JniConstants::gaiExceptionClass, "<init>",
265c1cee0db58ec7bc61d5caac79915d744862cbe75Elliott Hughes                                            "(Ljava/lang/String;I)V");
266c1cee0db58ec7bc61d5caac79915d744862cbe75Elliott Hughes  if (errno != 0) {
26775cf14944d476670f6f915e5efd849e238a16250Elliott Hughes        // EAI_SYSTEM should mean "look at errno instead", but both glibc and bionic seem to
26875cf14944d476670f6f915e5efd849e238a16250Elliott Hughes        // mess this up. In particular, if you don't have INTERNET permission, errno will be EACCES
26975cf14944d476670f6f915e5efd849e238a16250Elliott Hughes        // but you'll get EAI_NONAME or EAI_NODATA. So we want our GaiException to have a
27075cf14944d476670f6f915e5efd849e238a16250Elliott Hughes        // potentially-relevant ErrnoException as its cause even if error != EAI_SYSTEM.
27175cf14944d476670f6f915e5efd849e238a16250Elliott Hughes        // http://code.google.com/p/android/issues/detail?id=15722
2724f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        throwErrnoException(env, functionName);
2734f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        // Deliberately fall through to throw another exception...
2744f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    }
2754f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    throwException(env, JniConstants::gaiExceptionClass, ctor3, ctor2, functionName, error);
2764f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes}
2774f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes
278dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughestemplate <typename rc_t>
2797e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughesstatic rc_t throwIfMinusOne(JNIEnv* env, const char* name, rc_t rc) {
280dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    if (rc == rc_t(-1)) {
2817e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes        throwErrnoException(env, name);
282dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    }
283dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    return rc;
28447cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes}
28547cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes
2868dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughestemplate <typename ScopedT>
287bbac92e691de7d570928ddfba639067978e55b06Elliott Hughesclass IoVec {
288bbac92e691de7d570928ddfba639067978e55b06Elliott Hughespublic:
289bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    IoVec(JNIEnv* env, size_t bufferCount) : mEnv(env), mBufferCount(bufferCount) {
290bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
291bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
292bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    bool init(jobjectArray javaBuffers, jintArray javaOffsets, jintArray javaByteCounts) {
293bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        // We can't delete our local references until after the I/O, so make sure we have room.
294bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        if (mEnv->PushLocalFrame(mBufferCount + 16) < 0) {
295bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            return false;
296bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        }
297bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        ScopedIntArrayRO offsets(mEnv, javaOffsets);
298bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        if (offsets.get() == NULL) {
299bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            return false;
300bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        }
301bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        ScopedIntArrayRO byteCounts(mEnv, javaByteCounts);
302bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        if (byteCounts.get() == NULL) {
303bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            return false;
304bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        }
305bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        // TODO: Linux actually has a 1024 buffer limit. glibc works around this, and we should too.
306d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        // TODO: you can query the limit at runtime with sysconf(_SC_IOV_MAX).
307bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        for (size_t i = 0; i < mBufferCount; ++i) {
308e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes            jobject buffer = mEnv->GetObjectArrayElement(javaBuffers, i); // We keep this local ref.
3098dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughes            mScopedBuffers.push_back(new ScopedT(mEnv, buffer));
3108dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughes            jbyte* ptr = const_cast<jbyte*>(mScopedBuffers.back()->get());
311bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            if (ptr == NULL) {
312bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes                return false;
313bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            }
314bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            struct iovec iov;
315bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            iov.iov_base = reinterpret_cast<void*>(ptr + offsets[i]);
316bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            iov.iov_len = byteCounts[i];
317bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes            mIoVec.push_back(iov);
318bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        }
319bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        return true;
320bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
321bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
322bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    ~IoVec() {
3238dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughes        for (size_t i = 0; i < mScopedBuffers.size(); ++i) {
3248dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughes            delete mScopedBuffers[i];
325bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        }
326bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        mEnv->PopLocalFrame(NULL);
327bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
328bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
329bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    iovec* get() {
330bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        return &mIoVec[0];
331bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
332bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
333bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    size_t size() {
334bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        return mBufferCount;
335bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
336bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
337bbac92e691de7d570928ddfba639067978e55b06Elliott Hughesprivate:
338bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    JNIEnv* mEnv;
339bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    size_t mBufferCount;
340bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    std::vector<iovec> mIoVec;
3418dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughes    std::vector<ScopedT*> mScopedBuffers;
342bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes};
343bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
3440ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller/**
3452550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller * Returns a jbyteArray containing the sockaddr_un.sun_path from ss. As per unix(7) sa_len should be
3462550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller * the length of ss as returned by getsockname(2), getpeername(2), or accept(2).
3472550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller * If the returned array is of length 0 the sockaddr_un refers to an unnamed socket.
3482550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller * A null pointer is returned in the event of an error. See unix(7) for more information.
3490ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller */
3502550a252387631b49a00d2ee5587717cd2a6dda3Neil Fullerstatic jbyteArray getUnixSocketPath(JNIEnv* env, const sockaddr_storage& ss,
3512550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        const socklen_t& sa_len) {
3520ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    if (ss.ss_family != AF_UNIX) {
3530ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
3540ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller                "getUnixSocketPath unsupported ss_family: %i", ss.ss_family);
3552550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        return NULL;
3560ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
3572550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller
3580ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    const struct sockaddr_un* un_addr = reinterpret_cast<const struct sockaddr_un*>(&ss);
3592550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    // The length of sun_path is sa_len minus the length of the overhead (ss_family).
3602550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    // See unix(7) for details. This calculation must match that of socket_make_sockaddr_un() in
3612550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    // socket_local_client.c and javaUnixSocketAddressToSockaddr() to interoperate.
3622550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    size_t pathLength = sa_len - offsetof(struct sockaddr_un, sun_path);
3632550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller
3642550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    jbyteArray javaSunPath = env->NewByteArray(pathLength);
3652550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    if (javaSunPath == NULL) {
3662550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        return NULL;
3670ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
3682550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller
3692550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    if (pathLength > 0) {
3702550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        env->SetByteArrayRegion(javaSunPath, 0, pathLength,
3712550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller                reinterpret_cast<const jbyte*>(&un_addr->sun_path));
3722550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    }
3732550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    return javaSunPath;
3740ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller}
3750ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
3760ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fullerstatic jobject makeSocketAddress(JNIEnv* env, const sockaddr_storage& ss, const socklen_t sa_len) {
3770ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
3788f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        jint port;
3798f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        jobject inetAddress = sockaddrToInetAddress(env, ss, &port);
3808f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        if (inetAddress == NULL) {
3818f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline            return NULL;  // Exception already thrown.
3828f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        }
3838f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        static jmethodID ctor = env->GetMethodID(JniConstants::inetSocketAddressClass,
3848f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline                "<init>", "(Ljava/net/InetAddress;I)V");
38593a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        if (ctor == NULL) {
38693a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak            return NULL;
38793a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        }
3888f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        return env->NewObject(JniConstants::inetSocketAddressClass, ctor, inetAddress, port);
3890ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    } else if (ss.ss_family == AF_UNIX) {
3900ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        static jmethodID ctor = env->GetMethodID(JniConstants::unixSocketAddressClass,
3910ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller                "<init>", "([B)V");
39293a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        if (ctor == NULL) {
39393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak            return NULL;
39493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        }
3952550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        jbyteArray javaSunPath = getUnixSocketPath(env, ss, sa_len);
3962550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        if (!javaSunPath) {
3970ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller            return NULL;
3980ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        }
3992550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        return env->NewObject(JniConstants::unixSocketAddressClass, ctor, javaSunPath);
4008f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    } else if (ss.ss_family == AF_NETLINK) {
4018f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        const struct sockaddr_nl* nl_addr = reinterpret_cast<const struct sockaddr_nl*>(&ss);
4028f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        static jmethodID ctor = env->GetMethodID(JniConstants::netlinkSocketAddressClass,
4038f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline                "<init>", "(II)V");
40493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        if (ctor == NULL) {
40593a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak            return NULL;
40693a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        }
4076e888e9390649a9ab2557da5b28bb75be39e1b74Przemyslaw Szczepaniak        return env->NewObject(JniConstants::netlinkSocketAddressClass, ctor,
4086e888e9390649a9ab2557da5b28bb75be39e1b74Przemyslaw Szczepaniak                static_cast<jint>(nl_addr->nl_pid),
4098f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline                static_cast<jint>(nl_addr->nl_groups));
41000bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    } else if (ss.ss_family == AF_PACKET) {
41100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        const struct sockaddr_ll* sll = reinterpret_cast<const struct sockaddr_ll*>(&ss);
41200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        static jmethodID ctor = env->GetMethodID(JniConstants::packetSocketAddressClass,
41300bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti                "<init>", "(SISB[B)V");
41493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        if (ctor == NULL) {
41593a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak            return NULL;
41693a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        }
41700bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(sll->sll_halen));
41800bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        if (byteArray.get() == NULL) {
41900bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            return NULL;
42000bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        }
42100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        env->SetByteArrayRegion(byteArray.get(), 0, sll->sll_halen,
42200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti                reinterpret_cast<const jbyte*>(sll->sll_addr));
42300bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        jobject packetSocketAddress = env->NewObject(JniConstants::packetSocketAddressClass, ctor,
42400bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti                static_cast<jshort>(ntohs(sll->sll_protocol)),
42500bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti                static_cast<jint>(sll->sll_ifindex),
42600bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti                static_cast<jshort>(sll->sll_hatype),
42700bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti                static_cast<jbyte>(sll->sll_pkttype),
42800bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti                byteArray.get());
42900bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        return packetSocketAddress;
43000bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    }
43100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "unsupported ss_family: %d",
43200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            ss.ss_family);
4338f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    return NULL;
4340a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
4350a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
436d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughesstatic jobject makeStructPasswd(JNIEnv* env, const struct passwd& pw) {
437d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(pw_name, pw.pw_name);
438d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(pw_dir, pw.pw_dir);
439d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(pw_shell, pw.pw_shell);
440d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    static jmethodID ctor = env->GetMethodID(JniConstants::structPasswdClass, "<init>",
441d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes            "(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;)V");
44293a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
44393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
44493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
445d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    return env->NewObject(JniConstants::structPasswdClass, ctor,
446d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes            pw_name, static_cast<jint>(pw.pw_uid), static_cast<jint>(pw.pw_gid), pw_dir, pw_shell);
447d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes}
448d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
449108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniakstatic jobject makeStructTimespec(JNIEnv* env, const struct timespec& ts) {
450108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniak    static jmethodID ctor = env->GetMethodID(JniConstants::structTimespecClass, "<init>",
451108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniak            "(JJ)V");
45293a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
45393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
45493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
455108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniak    return env->NewObject(JniConstants::structTimespecClass, ctor,
456108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniak            static_cast<jlong>(ts.tv_sec), static_cast<jlong>(ts.tv_nsec));
457108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniak}
458108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniak
45913a70e6c04157064fc8a61ecfcb1d863f29c239dYi Kongstatic jobject makeStructStat(JNIEnv* env, const struct stat64& sb) {
46047cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    static jmethodID ctor = env->GetMethodID(JniConstants::structStatClass, "<init>",
461108091b6787f37a23862c7c9bb965ccf932430abPrzemyslaw Szczepaniak            "(JJIJIIJJLandroid/system/StructTimespec;Landroid/system/StructTimespec;Landroid/system/StructTimespec;JJ)V");
46293a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
46393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
46493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
46593a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak
466fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    jobject atim_timespec = makeStructTimespec(env, sb.st_atim);
467fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    if (atim_timespec == NULL) {
468fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak        return NULL;
469fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    }
470fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    jobject mtim_timespec = makeStructTimespec(env, sb.st_mtim);
471fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    if (mtim_timespec == NULL) {
472fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak        return NULL;
473fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    }
474fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    jobject ctim_timespec = makeStructTimespec(env, sb.st_ctim);
475fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    if (ctim_timespec == NULL) {
476fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak        return NULL;
477fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak    }
478fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak
47947cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    return env->NewObject(JniConstants::structStatClass, ctor,
48059fa7163774d6930a174bc038414a4b780581957Elliott Hughes            static_cast<jlong>(sb.st_dev), static_cast<jlong>(sb.st_ino),
48159fa7163774d6930a174bc038414a4b780581957Elliott Hughes            static_cast<jint>(sb.st_mode), static_cast<jlong>(sb.st_nlink),
48259fa7163774d6930a174bc038414a4b780581957Elliott Hughes            static_cast<jint>(sb.st_uid), static_cast<jint>(sb.st_gid),
48359fa7163774d6930a174bc038414a4b780581957Elliott Hughes            static_cast<jlong>(sb.st_rdev), static_cast<jlong>(sb.st_size),
484fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak            atim_timespec, mtim_timespec, ctim_timespec,
485fe1c2f9ea0666a129a25b7806c2f9e7af2daf4baPrzemyslaw Szczepaniak            static_cast<jlong>(sb.st_blksize), static_cast<jlong>(sb.st_blocks));
48659fa7163774d6930a174bc038414a4b780581957Elliott Hughes}
48759fa7163774d6930a174bc038414a4b780581957Elliott Hughes
488721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughesstatic jobject makeStructStatVfs(JNIEnv* env, const struct statvfs& sb) {
489721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    static jmethodID ctor = env->GetMethodID(JniConstants::structStatVfsClass, "<init>",
490721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes            "(JJJJJJJJJJJ)V");
49193a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
49293a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
49393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
49493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak
495721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    return env->NewObject(JniConstants::structStatVfsClass, ctor,
496721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_bsize),
497721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_frsize),
498721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_blocks),
499721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_bfree),
500721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_bavail),
501721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_files),
502721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_ffree),
503721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_favail),
504721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_fsid),
505721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes                          static_cast<jlong>(sb.f_flag),
506efe42934a8523f2b051a351e5eceebf6216454aeElliott Hughes                          static_cast<jlong>(sb.f_namemax));
50747cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes}
50847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes
5090a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughesstatic jobject makeStructLinger(JNIEnv* env, const struct linger& l) {
5100a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    static jmethodID ctor = env->GetMethodID(JniConstants::structLingerClass, "<init>", "(II)V");
51193a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
51293a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
51393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
5140a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    return env->NewObject(JniConstants::structLingerClass, ctor, l.l_onoff, l.l_linger);
5150a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
5160a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
5170a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughesstatic jobject makeStructTimeval(JNIEnv* env, const struct timeval& tv) {
5180a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    static jmethodID ctor = env->GetMethodID(JniConstants::structTimevalClass, "<init>", "(JJ)V");
51993a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
52093a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
52193a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
5220a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    return env->NewObject(JniConstants::structTimevalClass, ctor,
5230a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes            static_cast<jlong>(tv.tv_sec), static_cast<jlong>(tv.tv_usec));
5240a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
5250a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
5263deabd220cf7b1ca0824987e90b8ecc07087f05aIan Rogersstatic jobject makeStructUcred(JNIEnv* env, const struct ucred& u __unused) {
52793a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    static jmethodID ctor = env->GetMethodID(JniConstants::structUcredClass, "<init>", "(III)V");
52893a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
52993a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
53093a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
53193a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    return env->NewObject(JniConstants::structUcredClass, ctor, u.pid, u.uid, u.gid);
532482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes}
533482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes
5347341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughesstatic jobject makeStructUtsname(JNIEnv* env, const struct utsname& buf) {
535d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(sysname, buf.sysname);
536d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(nodename, buf.nodename);
537d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(release, buf.release);
538d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(version, buf.version);
539d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    TO_JAVA_STRING(machine, buf.machine);
5407341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes    static jmethodID ctor = env->GetMethodID(JniConstants::structUtsnameClass, "<init>",
5417341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes            "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
54293a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
54393a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
54493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
5457341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes    return env->NewObject(JniConstants::structUtsnameClass, ctor,
5467341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes            sysname, nodename, release, version, machine);
5477341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes};
5487341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes
549a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughesstatic bool fillIfreq(JNIEnv* env, jstring javaInterfaceName, struct ifreq& req) {
550a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    ScopedUtfChars interfaceName(env, javaInterfaceName);
551a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    if (interfaceName.c_str() == NULL) {
552a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes        return false;
553a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    }
554a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    memset(&req, 0, sizeof(req));
555a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    strncpy(req.ifr_name, interfaceName.c_str(), sizeof(req.ifr_name));
556a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    req.ifr_name[sizeof(req.ifr_name) - 1] = '\0';
557a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    return true;
558a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes}
559a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes
5600ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fullerstatic bool fillUnixSocketAddress(JNIEnv* env, jobject javaUnixSocketAddress,
5610ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        const sockaddr_storage& ss, const socklen_t& sa_len) {
5620ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    if (javaUnixSocketAddress == NULL) {
5630ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        return true;
5640ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
5652550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    jbyteArray javaSunPath = getUnixSocketPath(env, ss, sa_len);
5662550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    if (!javaSunPath) {
5670ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        return false;
5680ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
5690ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
5700ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    static jfieldID sunPathFid =
5710ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller            env->GetFieldID(JniConstants::unixSocketAddressClass, "sun_path", "[B");
5722550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    env->SetObjectField(javaUnixSocketAddress, sunPathFid, javaSunPath);
5730ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    return true;
5740ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller}
5750ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
5760ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fullerstatic bool fillInetSocketAddress(JNIEnv* env, jobject javaInetSocketAddress,
5770ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        const sockaddr_storage& ss) {
5780ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    if (javaInetSocketAddress == NULL) {
579553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        return true;
580553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    }
581553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    // Fill out the passed-in InetSocketAddress with the sender's IP address and port number.
582553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    jint port;
583553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    jobject sender = sockaddrToInetAddress(env, ss, &port);
584553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    if (sender == NULL) {
585553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        return false;
586553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    }
5874cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath    static jfieldID holderFid = env->GetFieldID(JniConstants::inetSocketAddressClass, "holder",
5884cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath                                                "Ljava/net/InetSocketAddress$InetSocketAddressHolder;");
589ea544eccd7c78b693804d763dabbd8f7247dc802Piotr Jastrzebski    jobject holder = env->GetObjectField(javaInetSocketAddress, holderFid);
590ea544eccd7c78b693804d763dabbd8f7247dc802Piotr Jastrzebski
5914cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath    static jfieldID addressFid = env->GetFieldID(JniConstants::inetSocketAddressHolderClass,
5924cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath                                                 "addr", "Ljava/net/InetAddress;");
593ea544eccd7c78b693804d763dabbd8f7247dc802Piotr Jastrzebski    static jfieldID portFid = env->GetFieldID(JniConstants::inetSocketAddressHolderClass, "port", "I");
594ea544eccd7c78b693804d763dabbd8f7247dc802Piotr Jastrzebski    env->SetObjectField(holder, addressFid, sender);
595ea544eccd7c78b693804d763dabbd8f7247dc802Piotr Jastrzebski    env->SetIntField(holder, portFid, port);
596553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    return true;
597553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes}
598553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes
5990ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fullerstatic bool fillSocketAddress(JNIEnv* env, jobject javaSocketAddress, const sockaddr_storage& ss,
6000ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        const socklen_t& sa_len) {
6010ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    if (javaSocketAddress == NULL) {
6020ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        return true;
6030ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
6040ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
6050ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    if (env->IsInstanceOf(javaSocketAddress, JniConstants::inetSocketAddressClass)) {
6060ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        return fillInetSocketAddress(env, javaSocketAddress, ss);
6070ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    } else if (env->IsInstanceOf(javaSocketAddress, JniConstants::unixSocketAddressClass)) {
6080ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        return fillUnixSocketAddress(env, javaSocketAddress, ss, sa_len);
6090ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
6100ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    jniThrowException(env, "java/lang/UnsupportedOperationException",
6110ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller            "unsupported SocketAddress subclass");
6120ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    return false;
6130ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
6140ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller}
6150ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
616f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colittistatic void javaInetSocketAddressToInetAddressAndPort(
617f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti        JNIEnv* env, jobject javaInetSocketAddress, jobject& javaInetAddress, jint& port) {
6184cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath    static jfieldID holderFid = env->GetFieldID(JniConstants::inetSocketAddressClass, "holder",
6194cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath                                                "Ljava/net/InetSocketAddress$InetSocketAddressHolder;");
6204cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath    jobject holder = env->GetObjectField(javaInetSocketAddress, holderFid);
6214cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath
6228f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    static jfieldID addressFid = env->GetFieldID(
6234cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath            JniConstants::inetSocketAddressHolderClass, "addr", "Ljava/net/InetAddress;");
6244cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath    static jfieldID portFid = env->GetFieldID(JniConstants::inetSocketAddressHolderClass, "port", "I");
6254cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath
6264cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath    javaInetAddress = env->GetObjectField(holder, addressFid);
6274cb97fe003dcf14ccd8f6e381cd172020248efaeNarayan Kamath    port = env->GetIntField(holder, portFid);
628f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti}
629f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti
630f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colittistatic bool javaInetSocketAddressToSockaddr(
631f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti        JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
632f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti    jobject javaInetAddress;
633f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti    jint port;
634f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti    javaInetSocketAddressToInetAddressAndPort(env, javaSocketAddress, javaInetAddress, port);
635f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti    return inetAddressToSockaddr(env, javaInetAddress, port, ss, sa_len);
6368f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline}
6378f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
6388f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Klinestatic bool javaNetlinkSocketAddressToSockaddr(
6398f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
6408f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    static jfieldID nlPidFid = env->GetFieldID(
6418f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline            JniConstants::netlinkSocketAddressClass, "nlPortId", "I");
6428f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    static jfieldID nlGroupsFid = env->GetFieldID(
6438f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline            JniConstants::netlinkSocketAddressClass, "nlGroupsMask", "I");
6448f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
6458f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    sockaddr_nl *nlAddr = reinterpret_cast<sockaddr_nl *>(&ss);
6468f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    nlAddr->nl_family = AF_NETLINK;
6478f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    nlAddr->nl_pid = env->GetIntField(javaSocketAddress, nlPidFid);
6488f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    nlAddr->nl_groups = env->GetIntField(javaSocketAddress, nlGroupsFid);
6498f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    sa_len = sizeof(sockaddr_nl);
6508f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    return true;
6518f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline}
6528f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
6530ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fullerstatic bool javaUnixSocketAddressToSockaddr(
6540ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        JNIEnv* env, jobject javaUnixSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
6550ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    static jfieldID sunPathFid = env->GetFieldID(
6560ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller            JniConstants::unixSocketAddressClass, "sun_path", "[B");
6570ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
6580ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    struct sockaddr_un* un_addr = reinterpret_cast<struct sockaddr_un*>(&ss);
6592550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    memset (un_addr, 0, sizeof(sockaddr_un));
6600ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    un_addr->sun_family = AF_UNIX;
6610ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
6620ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    jbyteArray javaSunPath = (jbyteArray) env->GetObjectField(javaUnixSocketAddress, sunPathFid);
6630ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    jsize pathLength = env->GetArrayLength(javaSunPath);
6642550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    if ((size_t) pathLength > sizeof(sockaddr_un::sun_path)) {
6652550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
6662550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller                "sun_path too long: max=%i, is=%i",
6672550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller                sizeof(sockaddr_un::sun_path), pathLength);
6682550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller        return false;
6690ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
6702550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    env->GetByteArrayRegion(javaSunPath, 0, pathLength, (jbyte*) un_addr->sun_path);
6712550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    // sa_len is sun_path plus the length of the overhead (ss_family_t). See unix(7) for
6722550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    // details. This calculation must match that of socket_make_sockaddr_un() in
6732550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    // socket_local_client.c and getUnixSocketPath() to interoperate.
6742550a252387631b49a00d2ee5587717cd2a6dda3Neil Fuller    sa_len = offsetof(struct sockaddr_un, sun_path) + pathLength;
6750ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    return true;
6760ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller}
6770ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller
67800bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colittistatic bool javaPacketSocketAddressToSockaddr(
67900bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
68000bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    static jfieldID protocolFid = env->GetFieldID(
68100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            JniConstants::packetSocketAddressClass, "sll_protocol", "S");
68200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    static jfieldID ifindexFid = env->GetFieldID(
68300bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            JniConstants::packetSocketAddressClass, "sll_ifindex", "I");
68400bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    static jfieldID hatypeFid = env->GetFieldID(
68500bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            JniConstants::packetSocketAddressClass, "sll_hatype", "S");
68600bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    static jfieldID pkttypeFid = env->GetFieldID(
68700bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            JniConstants::packetSocketAddressClass, "sll_pkttype", "B");
68800bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    static jfieldID addrFid = env->GetFieldID(
68900bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            JniConstants::packetSocketAddressClass, "sll_addr", "[B");
69000bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti
69100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    sockaddr_ll *sll = reinterpret_cast<sockaddr_ll *>(&ss);
69200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    sll->sll_family = AF_PACKET;
693e0273519773d7b14680fe0aa8bc180836042f245Lorenzo Colitti    sll->sll_protocol = htons(env->GetShortField(javaSocketAddress, protocolFid));
69400bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    sll->sll_ifindex = env->GetIntField(javaSocketAddress, ifindexFid);
69500bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    sll->sll_hatype = env->GetShortField(javaSocketAddress, hatypeFid);
69600bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    sll->sll_pkttype = env->GetByteField(javaSocketAddress, pkttypeFid);
69700bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti
69800bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    jbyteArray sllAddr = (jbyteArray) env->GetObjectField(javaSocketAddress, addrFid);
69900bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    if (sllAddr == NULL) {
70000bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        sll->sll_halen = 0;
70100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        memset(&sll->sll_addr, 0, sizeof(sll->sll_addr));
70200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    } else {
70300bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        jsize len = env->GetArrayLength(sllAddr);
70400bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        if ((size_t) len > sizeof(sll->sll_addr)) {
70500bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti            len = sizeof(sll->sll_addr);
70600bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        }
70700bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        sll->sll_halen = len;
70800bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        env->GetByteArrayRegion(sllAddr, 0, len, (jbyte*) sll->sll_addr);
70900bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    }
71000bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    sa_len = sizeof(sockaddr_ll);
71100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    return true;
71200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti}
71300bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti
7148f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Klinestatic bool javaSocketAddressToSockaddr(
7158f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        JNIEnv* env, jobject javaSocketAddress, sockaddr_storage& ss, socklen_t& sa_len) {
7168f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    if (javaSocketAddress == NULL) {
7178f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        jniThrowNullPointerException(env, NULL);
7188f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        return false;
7198f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    }
7208f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
7218f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    if (env->IsInstanceOf(javaSocketAddress, JniConstants::netlinkSocketAddressClass)) {
7228f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        return javaNetlinkSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len);
7238f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    } else if (env->IsInstanceOf(javaSocketAddress, JniConstants::inetSocketAddressClass)) {
7248f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        return javaInetSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len);
72500bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    } else if (env->IsInstanceOf(javaSocketAddress, JniConstants::packetSocketAddressClass)) {
72600bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        return javaPacketSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len);
7270ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    } else if (env->IsInstanceOf(javaSocketAddress, JniConstants::unixSocketAddressClass)) {
7280ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller        return javaUnixSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len);
7298f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    }
7308f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    jniThrowException(env, "java/lang/UnsupportedOperationException",
7318f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline            "unsupported SocketAddress subclass");
7328f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    return false;
7338f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline}
7348f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
73547cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughesstatic jobject doStat(JNIEnv* env, jstring javaPath, bool isLstat) {
73647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    ScopedUtfChars path(env, javaPath);
73747cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    if (path.c_str() == NULL) {
73847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes        return NULL;
73947cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    }
74013a70e6c04157064fc8a61ecfcb1d863f29c239dYi Kong    struct stat64 sb;
74113a70e6c04157064fc8a61ecfcb1d863f29c239dYi Kong    int rc = isLstat ? TEMP_FAILURE_RETRY(lstat64(path.c_str(), &sb))
74213a70e6c04157064fc8a61ecfcb1d863f29c239dYi Kong                     : TEMP_FAILURE_RETRY(stat64(path.c_str(), &sb));
743dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    if (rc == -1) {
7447e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes        throwErrnoException(env, isLstat ? "lstat" : "stat");
74547cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes        return NULL;
74647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    }
74747cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    return makeStructStat(env, sb);
748ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes}
749ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes
750482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughesstatic jobject doGetSockName(JNIEnv* env, jobject javaFd, bool is_sockname) {
751482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  int fd = jniGetFDFromFileDescriptor(env, javaFd);
752482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  sockaddr_storage ss;
753482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  sockaddr* sa = reinterpret_cast<sockaddr*>(&ss);
754482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  socklen_t byteCount = sizeof(ss);
755482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  memset(&ss, 0, byteCount);
756482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  int rc = is_sockname ? TEMP_FAILURE_RETRY(getsockname(fd, sa, &byteCount))
757482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes      : TEMP_FAILURE_RETRY(getpeername(fd, sa, &byteCount));
758482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  if (rc == -1) {
759482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    throwErrnoException(env, is_sockname ? "getsockname" : "getpeername");
760482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    return NULL;
761482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  }
7620ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller  return makeSocketAddress(env, ss, byteCount);
763482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes}
764482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes
765d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughesclass Passwd {
766d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughespublic:
7673b527308aae5a23ac71cf5f637b4595a9b55a2dbChih-Hung Hsieh    explicit Passwd(JNIEnv* env) : mEnv(env), mResult(NULL) {
768d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        mBufferSize = sysconf(_SC_GETPW_R_SIZE_MAX);
769d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        mBuffer.reset(new char[mBufferSize]);
770d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    }
771d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
772d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    jobject getpwnam(const char* name) {
773d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        return process("getpwnam_r", getpwnam_r(name, &mPwd, mBuffer.get(), mBufferSize, &mResult));
774d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    }
775d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
776d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    jobject getpwuid(uid_t uid) {
777d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        return process("getpwuid_r", getpwuid_r(uid, &mPwd, mBuffer.get(), mBufferSize, &mResult));
778d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    }
779d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
780d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    struct passwd* get() {
781d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        return mResult;
782d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    }
783d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
784d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughesprivate:
785d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    jobject process(const char* syscall, int error) {
786d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        if (mResult == NULL) {
787d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes            errno = error;
788d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes            throwErrnoException(mEnv, syscall);
789d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes            return NULL;
790d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        }
791d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        return makeStructPasswd(mEnv, *mResult);
792d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    }
793d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
794d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    JNIEnv* mEnv;
795b3aacde3d8af759ee4a7b395c636ea360547d92dIan Rogers    std::unique_ptr<char[]> mBuffer;
796d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    size_t mBufferSize;
797d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    struct passwd mPwd;
798d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    struct passwd* mResult;
799d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes};
800d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
8015744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic void AssertException(JNIEnv* env) {
8025744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (env->ExceptionCheck() == JNI_FALSE) {
8035744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        env->FatalError("Expected exception");
8045744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8055744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
8065744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8075744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe// Note for capabilities functions:
8085744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe// We assume the calls are rare enough that it does not make sense to cache class objects. The
8095744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe// advantage is lower maintenance burden.
8105744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8115744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic bool ReadStructCapUserHeader(
8125744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        JNIEnv* env, jobject java_header, __user_cap_header_struct* c_header) {
8135744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (java_header == nullptr) {
8145744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        jniThrowNullPointerException(env, "header is null");
8155744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return false;
8165744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8175744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8185744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    ScopedLocalRef<jclass> header_class(env, env->FindClass("android/system/StructCapUserHeader"));
8195744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (header_class.get() == nullptr) {
8205744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return false;
8215744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8225744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8235744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    {
8245744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        static jfieldID version_fid = env->GetFieldID(header_class.get(), "version", "I");
8255744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (version_fid == nullptr) {
8265744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            return false;
8275744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
8285744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        c_header->version = env->GetIntField(java_header, version_fid);
8295744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8305744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8315744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    {
8325744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        static jfieldID pid_fid = env->GetFieldID(header_class.get(), "pid", "I");
8335744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (pid_fid == nullptr) {
8345744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            return false;
8355744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
8365744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        c_header->pid = env->GetIntField(java_header, pid_fid);
8375744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8385744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8395744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    return true;
8405744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
8415744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8425744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic void SetStructCapUserHeaderVersion(
8435744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        JNIEnv* env, jobject java_header, __user_cap_header_struct* c_header) {
8445744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    ScopedLocalRef<jclass> header_class(env, env->FindClass("android/system/StructCapUserHeader"));
8455744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (header_class.get() == nullptr) {
8465744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        env->ExceptionClear();
8475744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return;
8485744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8495744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8505744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    static jfieldID version_fid = env->GetFieldID(header_class.get(), "version", "I");
8515744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (version_fid == nullptr) {
8525744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        env->ExceptionClear();
8535744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return;
8545744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8555744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    env->SetIntField(java_header, version_fid, c_header->version);
8565744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
8575744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8585744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic jobject CreateStructCapUserData(
8595744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        JNIEnv* env, jclass data_class, __user_cap_data_struct* c_data) {
8605744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (c_data == nullptr) {
8615744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        // Should not happen.
8625744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        jniThrowNullPointerException(env, "data is null");
8635744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return nullptr;
8645744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8655744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8665744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    static jmethodID data_cons = env->GetMethodID(data_class, "<init>", "(III)V");
8675744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (data_cons == nullptr) {
8685744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return nullptr;
8695744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8705744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8715744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    jint e = static_cast<jint>(c_data->effective);
8725744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    jint p = static_cast<jint>(c_data->permitted);
8735744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    jint i = static_cast<jint>(c_data->inheritable);
8745744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    return env->NewObject(data_class, data_cons, e, p, i);
8755744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
8765744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8775744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic bool ReadStructCapUserData(JNIEnv* env, jobject java_data, __user_cap_data_struct* c_data) {
8785744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (java_data == nullptr) {
8795744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        jniThrowNullPointerException(env, "data is null");
8805744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return false;
8815744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8825744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8835744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    ScopedLocalRef<jclass> data_class(env, env->FindClass("android/system/StructCapUserData"));
8845744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (data_class.get() == nullptr) {
8855744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return false;
8865744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8875744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8885744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    {
8895744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        static jfieldID effective_fid = env->GetFieldID(data_class.get(), "effective", "I");
8905744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (effective_fid == nullptr) {
8915744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            return false;
8925744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
8935744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        c_data->effective = env->GetIntField(java_data, effective_fid);
8945744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
8955744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
8965744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    {
8975744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        static jfieldID permitted_fid = env->GetFieldID(data_class.get(), "permitted", "I");
8985744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (permitted_fid == nullptr) {
8995744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            return false;
9005744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
9015744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        c_data->permitted = env->GetIntField(java_data, permitted_fid);
9025744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
9035744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
9045744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
9055744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    {
9065744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        static jfieldID inheritable_fid = env->GetFieldID(data_class.get(), "inheritable", "I");
9075744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (inheritable_fid == nullptr) {
9085744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            return false;
9095744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
9105744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        c_data->inheritable = env->GetIntField(java_data, inheritable_fid);
9115744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
9125744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
9135744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    return true;
9145744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
9155744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
9165744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic constexpr size_t kMaxCapUserDataLength = 2U;
9175744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#ifdef _LINUX_CAPABILITY_VERSION_1
9185744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic_assert(kMaxCapUserDataLength >= _LINUX_CAPABILITY_U32S_1, "Length too small.");
9195744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#endif
9205744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#ifdef _LINUX_CAPABILITY_VERSION_2
9215744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic_assert(kMaxCapUserDataLength >= _LINUX_CAPABILITY_U32S_2, "Length too small.");
9225744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#endif
9235744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#ifdef _LINUX_CAPABILITY_VERSION_3
9245744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic_assert(kMaxCapUserDataLength >= _LINUX_CAPABILITY_U32S_3, "Length too small.");
9255744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#endif
9265744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#ifdef _LINUX_CAPABILITY_VERSION_4
9275744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic_assert(false, "Unsupported capability version, please update.");
9285744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#endif
9295744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
9305744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic size_t GetCapUserDataLength(uint32_t version) {
9315744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#ifdef _LINUX_CAPABILITY_VERSION_1
9325744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (version == _LINUX_CAPABILITY_VERSION_1) {
9335744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return _LINUX_CAPABILITY_U32S_1;
9345744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
9355744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#endif
9365744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#ifdef _LINUX_CAPABILITY_VERSION_2
9375744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (version == _LINUX_CAPABILITY_VERSION_2) {
9385744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return _LINUX_CAPABILITY_U32S_2;
9395744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
9405744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#endif
9415744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#ifdef _LINUX_CAPABILITY_VERSION_3
9425744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (version == _LINUX_CAPABILITY_VERSION_3) {
9435744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return _LINUX_CAPABILITY_U32S_3;
9445744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
9455744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe#endif
9465744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    return 0;
9475744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
9485744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
9490965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_accept(JNIEnv* env, jobject, jobject javaFd, jobject javaSocketAddress) {
950553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    sockaddr_storage ss;
951553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    socklen_t sl = sizeof(ss);
952553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    memset(&ss, 0, sizeof(ss));
9530ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    sockaddr* peer = (javaSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;
9540ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    socklen_t* peerLength = (javaSocketAddress != NULL) ? &sl : 0;
9551124a814d698ed6fd68ac501f5dddfa103d656fdElliott Hughes    jint clientFd = NET_FAILURE_RETRY(env, int, accept, javaFd, peer, peerLength);
9560ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    if (clientFd == -1 || !fillSocketAddress(env, javaSocketAddress, ss, *peerLength)) {
957553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        close(clientFd);
958553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes        return NULL;
959553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    }
960553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes    return (clientFd != -1) ? jniCreateFileDescriptor(env, clientFd) : NULL;
961553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes}
962553d98af897f7202de5e5a776287de0b5ca8fe39Elliott Hughes
9630965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jboolean Linux_access(JNIEnv* env, jobject, jstring javaPath, jint mode) {
964ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    ScopedUtfChars path(env, javaPath);
965ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    if (path.c_str() == NULL) {
966ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes        return JNI_FALSE;
967ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    }
96847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    int rc = TEMP_FAILURE_RETRY(access(path.c_str(), mode));
969dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    if (rc == -1) {
9707e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes        throwErrnoException(env, "access");
971dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    }
972ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    return (rc == 0);
973ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes}
974ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes
9750965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_bind(JNIEnv* env, jobject, jobject javaFd, jobject javaAddress, jint port) {
9761124a814d698ed6fd68ac501f5dddfa103d656fdElliott Hughes    // We don't need the return value because we'll already have thrown.
977b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    (void) NET_IPV4_FALLBACK(env, int, bind, javaFd, javaAddress, port, NULL_ADDR_FORBIDDEN);
978da15009528cc8300a6251f1d0931ac8657c9fc31Elliott Hughes}
979da15009528cc8300a6251f1d0931ac8657c9fc31Elliott Hughes
9800965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_bindSocketAddress(
9818f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        JNIEnv* env, jobject, jobject javaFd, jobject javaSocketAddress) {
9828f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    sockaddr_storage ss;
9838f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    socklen_t sa_len;
9848f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    if (!javaSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len)) {
9858f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        return;  // Exception already thrown.
9868f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    }
9878f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
9888f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
9898f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    // We don't need the return value because we'll already have thrown.
9908f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    (void) NET_FAILURE_RETRY(env, int, bind, javaFd, sa, sa_len);
9918f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline}
9928f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
9935744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic jobjectArray Linux_capget(JNIEnv* env, jobject, jobject header) {
9945744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    // Convert Java header struct to kernel datastructure.
9955744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    __user_cap_header_struct cap_header;
9965744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (!ReadStructCapUserHeader(env, header, &cap_header)) {
9975744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        AssertException(env);
9985744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return nullptr;
9995744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10005744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
10015744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    // Call capget.
10025744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    __user_cap_data_struct cap_data[kMaxCapUserDataLength];
10035744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (capget(&cap_header, &cap_data[0]) == -1) {
10045744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        // Check for EINVAL. In that case, mutate the header.
10055744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (errno == EINVAL) {
10065744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            int saved_errno = errno;
10075744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            SetStructCapUserHeaderVersion(env, header, &cap_header);
10085744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            errno = saved_errno;
10095744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
10105744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        throwErrnoException(env, "capget");
10115744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return nullptr;
10125744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10135744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
10145744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    // Create the result array.
10155744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    ScopedLocalRef<jclass> data_class(env, env->FindClass("android/system/StructCapUserData"));
10165744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (data_class.get() == nullptr) {
10175744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return nullptr;
10185744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10195744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    size_t result_size = GetCapUserDataLength(cap_header.version);
10205744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    ScopedLocalRef<jobjectArray> result(
10215744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            env, env->NewObjectArray(result_size, data_class.get(), nullptr));
10225744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (result.get() == nullptr) {
10235744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return nullptr;
10245744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10255744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    // Translate the values we got.
10265744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    for (size_t i = 0; i < result_size; ++i) {
10275744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        ScopedLocalRef<jobject> value(
10285744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe                env, CreateStructCapUserData(env, data_class.get(), &cap_data[i]));
10295744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (value.get() == nullptr) {
10305744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            AssertException(env);
10315744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            return nullptr;
10325744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
10335744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        env->SetObjectArrayElement(result.get(), i, value.get());
10345744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10355744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    return result.release();
10365744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
10375744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
10385744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampestatic void Linux_capset(
10395744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        JNIEnv* env, jobject, jobject header, jobjectArray data) {
10405744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    // Convert Java header struct to kernel datastructure.
10415744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    __user_cap_header_struct cap_header;
10425744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (!ReadStructCapUserHeader(env, header, &cap_header)) {
10435744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        AssertException(env);
10445744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return;
10455744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10465744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    size_t result_size = GetCapUserDataLength(cap_header.version);
10475744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    // Ensure that the array has the expected length.
10485744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    if (env->GetArrayLength(data) != static_cast<jint>(result_size)) {
10495744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        jniThrowExceptionFmt(env,
10505744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe                             "java/lang/IllegalArgumentException",
10515744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe                             "Unsupported input length %d (expected %zu)",
10525744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe                             env->GetArrayLength(data),
10535744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe                             result_size);
10545744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        return;
10555744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10565744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
10575744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    __user_cap_data_struct cap_data[kMaxCapUserDataLength];
10585744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    // Translate the values we got.
10595744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    for (size_t i = 0; i < result_size; ++i) {
10605744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        ScopedLocalRef<jobject> value(env, env->GetObjectArrayElement(data, i));
10615744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        if (!ReadStructCapUserData(env, value.get(), &cap_data[i])) {
10625744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            AssertException(env);
10635744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe            return;
10645744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe        }
10655744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    }
10665744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
10675744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    throwIfMinusOne(env, "capset", capset(&cap_header, &cap_data[0]));
10685744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe}
10695744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe
10700965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_chmod(JNIEnv* env, jobject, jstring javaPath, jint mode) {
1071b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes    ScopedUtfChars path(env, javaPath);
1072b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes    if (path.c_str() == NULL) {
1073b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes        return;
1074b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes    }
1075b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes    throwIfMinusOne(env, "chmod", TEMP_FAILURE_RETRY(chmod(path.c_str(), mode)));
1076b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes}
1077b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes
10780965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_chown(JNIEnv* env, jobject, jstring javaPath, jint uid, jint gid) {
107944f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    ScopedUtfChars path(env, javaPath);
108044f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    if (path.c_str() == NULL) {
108144f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes        return;
108244f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    }
108344f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    throwIfMinusOne(env, "chown", TEMP_FAILURE_RETRY(chown(path.c_str(), uid, gid)));
108444f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes}
108544f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes
10860965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_close(JNIEnv* env, jobject, jobject javaFd) {
1087462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    // Get the FileDescriptor's 'fd' field and clear it.
1088462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    // We need to do this before we can throw an IOException (http://b/3222087).
1089462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1090462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    jniSetFileDescriptorOfFD(env, javaFd, -1);
1091462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes
1092462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    // Even if close(2) fails with EINTR, the fd will have been closed.
1093462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    // Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone else's fd.
1094462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    // http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
1095462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes    throwIfMinusOne(env, "close", close(fd));
1096462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes}
1097462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes
10980965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_connect(JNIEnv* env, jobject, jobject javaFd, jobject javaAddress, jint port) {
1099b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    (void) NET_IPV4_FALLBACK(env, int, connect, javaFd, javaAddress, port, NULL_ADDR_FORBIDDEN);
1100996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes}
1101996bf79565ac88402920bd826d6f85952c83be20Elliott Hughes
11020965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_connectSocketAddress(
11038f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        JNIEnv* env, jobject, jobject javaFd, jobject javaSocketAddress) {
11048f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    sockaddr_storage ss;
11058f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    socklen_t sa_len;
11068f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    if (!javaSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len)) {
11078f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline        return;  // Exception already thrown.
11088f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    }
11098f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
11108f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
11118f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    // We don't need the return value because we'll already have thrown.
11128f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    (void) NET_FAILURE_RETRY(env, int, connect, javaFd, sa, sa_len);
11138f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline}
11148f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
11150965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_dup(JNIEnv* env, jobject, jobject javaOldFd) {
1116396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    int oldFd = jniGetFDFromFileDescriptor(env, javaOldFd);
1117396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    int newFd = throwIfMinusOne(env, "dup", TEMP_FAILURE_RETRY(dup(oldFd)));
1118396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    return (newFd != -1) ? jniCreateFileDescriptor(env, newFd) : NULL;
1119396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1120396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
11210965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_dup2(JNIEnv* env, jobject, jobject javaOldFd, jint newFd) {
1122396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    int oldFd = jniGetFDFromFileDescriptor(env, javaOldFd);
1123396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    int fd = throwIfMinusOne(env, "dup2", TEMP_FAILURE_RETRY(dup2(oldFd, newFd)));
1124396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    return (fd != -1) ? jniCreateFileDescriptor(env, fd) : NULL;
1125396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1126396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
11270965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobjectArray Linux_environ(JNIEnv* env, jobject) {
1128ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    extern char** environ; // Standard, but not in any header file.
1129ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    return toStringArray(env, environ);
1130ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes}
1131ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes
11320965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_execve(JNIEnv* env, jobject, jstring javaFilename, jobjectArray javaArgv, jobjectArray javaEnvp) {
1133798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    ScopedUtfChars path(env, javaFilename);
1134798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    if (path.c_str() == NULL) {
1135798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich        return;
1136798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    }
1137798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich
1138ad9208affa02f92a6b85354a33123d51d80febe1Elliott Hughes    ExecStrings argv(env, javaArgv);
1139ad9208affa02f92a6b85354a33123d51d80febe1Elliott Hughes    ExecStrings envp(env, javaEnvp);
1140fa542091e45db699a937c5ac0191194405107827Elliott Hughes    TEMP_FAILURE_RETRY(execve(path.c_str(), argv.get(), envp.get()));
1141798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich
1142798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    throwErrnoException(env, "execve");
1143798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich}
1144798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich
11450965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_execv(JNIEnv* env, jobject, jstring javaFilename, jobjectArray javaArgv) {
1146798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    ScopedUtfChars path(env, javaFilename);
1147798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    if (path.c_str() == NULL) {
1148798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich        return;
1149798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    }
1150798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich
1151ad9208affa02f92a6b85354a33123d51d80febe1Elliott Hughes    ExecStrings argv(env, javaArgv);
1152fa542091e45db699a937c5ac0191194405107827Elliott Hughes    TEMP_FAILURE_RETRY(execv(path.c_str(), argv.get()));
1153798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich
1154798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich    throwErrnoException(env, "execv");
1155798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich}
1156798f855f67b74d481346d9dc2293ba0eedd8daf9Nick Kralevich
11570965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_fchmod(JNIEnv* env, jobject, jobject javaFd, jint mode) {
115844f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
115944f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    throwIfMinusOne(env, "fchmod", TEMP_FAILURE_RETRY(fchmod(fd, mode)));
116044f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes}
116144f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes
11620965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_fchown(JNIEnv* env, jobject, jobject javaFd, jint uid, jint gid) {
116344f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
116444f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    throwIfMinusOne(env, "fchown", TEMP_FAILURE_RETRY(fchown(fd, uid, gid)));
116544f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes}
116644f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes
11670965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_fcntlFlock(JNIEnv* env, jobject, jobject javaFd, jint cmd, jobject javaFlock) {
1168fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    static jfieldID typeFid = env->GetFieldID(JniConstants::structFlockClass, "l_type", "S");
1169fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    static jfieldID whenceFid = env->GetFieldID(JniConstants::structFlockClass, "l_whence", "S");
1170fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    static jfieldID startFid = env->GetFieldID(JniConstants::structFlockClass, "l_start", "J");
1171fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    static jfieldID lenFid = env->GetFieldID(JniConstants::structFlockClass, "l_len", "J");
1172fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    static jfieldID pidFid = env->GetFieldID(JniConstants::structFlockClass, "l_pid", "I");
1173fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes
1174fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    struct flock64 lock;
1175fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    memset(&lock, 0, sizeof(lock));
1176fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    lock.l_type = env->GetShortField(javaFlock, typeFid);
1177fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    lock.l_whence = env->GetShortField(javaFlock, whenceFid);
1178fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    lock.l_start = env->GetLongField(javaFlock, startFid);
1179fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    lock.l_len = env->GetLongField(javaFlock, lenFid);
1180fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    lock.l_pid = env->GetIntField(javaFlock, pidFid);
1181fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes
11828add3229ceb13f2aa5d15b84cc59f5ecc6b90214Neil Fuller    int rc = IO_FAILURE_RETRY(env, int, fcntl, javaFd, cmd, &lock);
1183fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    if (rc != -1) {
1184fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes        env->SetShortField(javaFlock, typeFid, lock.l_type);
1185fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes        env->SetShortField(javaFlock, whenceFid, lock.l_whence);
1186fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes        env->SetLongField(javaFlock, startFid, lock.l_start);
1187fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes        env->SetLongField(javaFlock, lenFid, lock.l_len);
1188fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes        env->SetIntField(javaFlock, pidFid, lock.l_pid);
1189fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    }
1190fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes    return rc;
1191fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes}
1192fc549a0b0388987b26dea524894d75a63d14783bElliott Hughes
11930965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_fcntlInt(JNIEnv* env, jobject, jobject javaFd, jint cmd, jint arg) {
1194c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1195c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath    return throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, cmd, arg)));
1196c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath}
1197c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath
11980965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_fcntlVoid(JNIEnv* env, jobject, jobject javaFd, jint cmd) {
1199c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1200c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath    return throwIfMinusOne(env, "fcntl", TEMP_FAILURE_RETRY(fcntl(fd, cmd)));
1201c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath}
1202c8d9ea662de6f4856b28907b4119087cfc5a44d2Narayan Kamath
12030965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_fdatasync(JNIEnv* env, jobject, jobject javaFd) {
120452724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
12057e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    throwIfMinusOne(env, "fdatasync", TEMP_FAILURE_RETRY(fdatasync(fd)));
120652724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes}
120752724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes
12080965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_fstat(JNIEnv* env, jobject, jobject javaFd) {
120947cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
121013a70e6c04157064fc8a61ecfcb1d863f29c239dYi Kong    struct stat64 sb;
121113a70e6c04157064fc8a61ecfcb1d863f29c239dYi Kong    int rc = TEMP_FAILURE_RETRY(fstat64(fd, &sb));
1212dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    if (rc == -1) {
12137e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes        throwErrnoException(env, "fstat");
121447cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes        return NULL;
121547cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    }
121647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    return makeStructStat(env, sb);
121747cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes}
121847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes
12190965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_fstatvfs(JNIEnv* env, jobject, jobject javaFd) {
122059fa7163774d6930a174bc038414a4b780581957Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1221721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    struct statvfs sb;
1222721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    int rc = TEMP_FAILURE_RETRY(fstatvfs(fd, &sb));
122359fa7163774d6930a174bc038414a4b780581957Elliott Hughes    if (rc == -1) {
1224721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes        throwErrnoException(env, "fstatvfs");
122559fa7163774d6930a174bc038414a4b780581957Elliott Hughes        return NULL;
122659fa7163774d6930a174bc038414a4b780581957Elliott Hughes    }
1227721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    return makeStructStatVfs(env, sb);
122859fa7163774d6930a174bc038414a4b780581957Elliott Hughes}
122959fa7163774d6930a174bc038414a4b780581957Elliott Hughes
12300965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_fsync(JNIEnv* env, jobject, jobject javaFd) {
123152724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
12327e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    throwIfMinusOne(env, "fsync", TEMP_FAILURE_RETRY(fsync(fd)));
1233f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes}
1234f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes
12350965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_ftruncate(JNIEnv* env, jobject, jobject javaFd, jlong length) {
1236f5333fd2094bdac4d6506177b1964b79afa64d77Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
12377e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    throwIfMinusOne(env, "ftruncate", TEMP_FAILURE_RETRY(ftruncate64(fd, length)));
123852724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes}
123952724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes
12400965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_gai_strerror(JNIEnv* env, jobject, jint error) {
12414f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    return env->NewStringUTF(gai_strerror(error));
12424f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes}
12434f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes
12440965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobjectArray Linux_android_getaddrinfo(JNIEnv* env, jobject, jstring javaNode,
12453e58734d651080009c9190c7062837fca5c7cf4ePaul Jensen        jobject javaHints, jint netId) {
12461c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    ScopedUtfChars node(env, javaNode);
12471c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    if (node.c_str() == NULL) {
12481c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        return NULL;
12491c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
12501c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
12511c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    static jfieldID flagsFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_flags", "I");
12521c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    static jfieldID familyFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_family", "I");
12531c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    static jfieldID socktypeFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_socktype", "I");
12541c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    static jfieldID protocolFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_protocol", "I");
12551c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
12561c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    addrinfo hints;
12571c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    memset(&hints, 0, sizeof(hints));
12581c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    hints.ai_flags = env->GetIntField(javaHints, flagsFid);
12591c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    hints.ai_family = env->GetIntField(javaHints, familyFid);
12601c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    hints.ai_socktype = env->GetIntField(javaHints, socktypeFid);
12611c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    hints.ai_protocol = env->GetIntField(javaHints, protocolFid);
12621c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
12631c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    addrinfo* addressList = NULL;
126475cf14944d476670f6f915e5efd849e238a16250Elliott Hughes    errno = 0;
12653e58734d651080009c9190c7062837fca5c7cf4ePaul Jensen    int rc = android_getaddrinfofornet(node.c_str(), NULL, &hints, netId, 0, &addressList);
1266b3aacde3d8af759ee4a7b395c636ea360547d92dIan Rogers    std::unique_ptr<addrinfo, addrinfo_deleter> addressListDeleter(addressList);
12671c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    if (rc != 0) {
12683e58734d651080009c9190c7062837fca5c7cf4ePaul Jensen        throwGaiException(env, "android_getaddrinfo", rc);
12691c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        return NULL;
12701c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
12711c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
12721c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    // Count results so we know how to size the output array.
12731c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    int addressCount = 0;
12741c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    for (addrinfo* ai = addressList; ai != NULL; ai = ai->ai_next) {
12751c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
12761c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes            ++addressCount;
12771c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        } else {
12783e58734d651080009c9190c7062837fca5c7cf4ePaul Jensen            ALOGE("android_getaddrinfo unexpected ai_family %i", ai->ai_family);
12791c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        }
12801c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
12811c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    if (addressCount == 0) {
12821c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        return NULL;
12831c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
12841c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
12851c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    // Prepare output array.
12861c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    jobjectArray result = env->NewObjectArray(addressCount, JniConstants::inetAddressClass, NULL);
12871c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    if (result == NULL) {
12881c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        return NULL;
12891c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
12901c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
12911c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    // Examine returned addresses one by one, save them in the output array.
12921c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    int index = 0;
12931c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    for (addrinfo* ai = addressList; ai != NULL; ai = ai->ai_next) {
12941c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
12951c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes            // Unknown address family. Skip this address.
12963e58734d651080009c9190c7062837fca5c7cf4ePaul Jensen            ALOGE("android_getaddrinfo unexpected ai_family %i", ai->ai_family);
12971c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes            continue;
12981c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        }
12991c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
13001c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        // Convert each IP address into a Java byte array.
1301482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes        sockaddr_storage& address = *reinterpret_cast<sockaddr_storage*>(ai->ai_addr);
130223ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        ScopedLocalRef<jobject> inetAddress(env, sockaddrToInetAddress(env, address, NULL));
13031c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        if (inetAddress.get() == NULL) {
13041c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes            return NULL;
13051c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        }
13061c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        env->SetObjectArrayElement(result, index, inetAddress.get());
13071c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        ++index;
13081c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
13091c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    return result;
13101c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes}
13111c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
13120965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getegid(JNIEnv*, jobject) {
1313564312855784c9ae57e2af73affc48b0807b13eeElliott Hughes    return getegid();
1314396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1315396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
13160965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_geteuid(JNIEnv*, jobject) {
1317564312855784c9ae57e2af73affc48b0807b13eeElliott Hughes    return geteuid();
1318396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1319396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
13200965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getgid(JNIEnv*, jobject) {
1321564312855784c9ae57e2af73affc48b0807b13eeElliott Hughes    return getgid();
1322396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1323396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
13240965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_getenv(JNIEnv* env, jobject, jstring javaName) {
1325ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes    ScopedUtfChars name(env, javaName);
1326ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes    if (name.c_str() == NULL) {
1327ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes        return NULL;
1328ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes    }
1329ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes    return env->NewStringUTF(getenv(name.c_str()));
1330ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes}
1331ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes
13320965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_getnameinfo(JNIEnv* env, jobject, jobject javaAddress, jint flags) {
13334f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    sockaddr_storage ss;
1334482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    socklen_t sa_len;
1335482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    if (!inetAddressToSockaddrVerbatim(env, javaAddress, 0, ss, sa_len)) {
13364f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        return NULL;
13374f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    }
13384f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    char buf[NI_MAXHOST]; // NI_MAXHOST is longer than INET6_ADDRSTRLEN.
133975cf14944d476670f6f915e5efd849e238a16250Elliott Hughes    errno = 0;
1340482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    int rc = getnameinfo(reinterpret_cast<sockaddr*>(&ss), sa_len, buf, sizeof(buf), NULL, 0, flags);
13414f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    if (rc != 0) {
13424f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        throwGaiException(env, "getnameinfo", rc);
13434f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes        return NULL;
13444f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    }
13454f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes    return env->NewStringUTF(buf);
13464f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes}
13474f11ebea266eada830d507b8f011e811a8e5d7bcElliott Hughes
13480965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getpeername(JNIEnv* env, jobject, jobject javaFd) {
1349482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  return doGetSockName(env, javaFd, false);
1350482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes}
1351482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes
13520965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getpgid(JNIEnv* env, jobject, jint pid) {
13538f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes    return throwIfMinusOne(env, "getpgid", TEMP_FAILURE_RETRY(getpgid(pid)));
13548f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes}
13558f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes
13560965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getpid(JNIEnv*, jobject) {
1357fa542091e45db699a937c5ac0191194405107827Elliott Hughes    return TEMP_FAILURE_RETRY(getpid());
1358396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1359396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
13600965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getppid(JNIEnv*, jobject) {
1361fa542091e45db699a937c5ac0191194405107827Elliott Hughes    return TEMP_FAILURE_RETRY(getppid());
1362396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1363396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
13640965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getpwnam(JNIEnv* env, jobject, jstring javaName) {
1365d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    ScopedUtfChars name(env, javaName);
1366d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    if (name.c_str() == NULL) {
1367d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes        return NULL;
1368d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    }
1369d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    return Passwd(env).getpwnam(name.c_str());
1370d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes}
1371d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
13720965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getpwuid(JNIEnv* env, jobject, jint uid) {
1373d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes    return Passwd(env).getpwuid(uid);
1374d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes}
1375d4419fce71d11ec8494525eca65e54d1aab51de6Elliott Hughes
1376e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamathstatic jobject Linux_getrlimit(JNIEnv* env, jobject, jint resource) {
1377e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath    struct rlimit r;
1378e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath    if (throwIfMinusOne(env, "getrlimit", TEMP_FAILURE_RETRY(getrlimit(resource, &r))) == -1) {
1379e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath        return nullptr;
1380e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath    }
1381e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath
1382e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath    ScopedLocalRef<jclass> rlimit_class(env, env->FindClass("android/system/StructRlimit"));
1383e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath    jmethodID ctor = env->GetMethodID(rlimit_class.get(), "<init>", "(JJ)V");
138493a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
138593a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
138693a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
1387e785612bdf3b0112b5a1854bdf241f0ef87a3171Narayan Kamath    return env->NewObject(rlimit_class.get(), ctor,
1388e785612bdf3b0112b5a1854bdf241f0ef87a3171Narayan Kamath                          static_cast<jlong>(r.rlim_cur),
1389e785612bdf3b0112b5a1854bdf241f0ef87a3171Narayan Kamath                          static_cast<jlong>(r.rlim_max));
1390e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath}
1391e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath
13920965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getsockname(JNIEnv* env, jobject, jobject javaFd) {
1393482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  return doGetSockName(env, javaFd, true);
13940a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
13950a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
13960965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getsockoptByte(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) {
13970a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
13980a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    u_char result = 0;
13990a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    socklen_t size = sizeof(result);
14000a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    throwIfMinusOne(env, "getsockopt", TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &result, &size)));
14010a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    return result;
14020a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
14030a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
14040965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getsockoptInAddr(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) {
14050a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
14060a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    sockaddr_storage ss;
14070a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    memset(&ss, 0, sizeof(ss));
14080a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    ss.ss_family = AF_INET; // This is only for the IPv4-only IP_MULTICAST_IF.
14090a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(&ss);
14100a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    socklen_t size = sizeof(sa->sin_addr);
14110a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int rc = TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &sa->sin_addr, &size));
14120a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    if (rc == -1) {
14130a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        throwErrnoException(env, "getsockopt");
14140a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        return NULL;
14150a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    }
1416482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    return sockaddrToInetAddress(env, ss, NULL);
14170a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
14180a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
14190965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getsockoptInt(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) {
14200a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
14210a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    jint result = 0;
14220a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    socklen_t size = sizeof(result);
14230a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    throwIfMinusOne(env, "getsockopt", TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &result, &size)));
14240a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    return result;
14250a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
14260a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
14270965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getsockoptLinger(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) {
14280a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
14290a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    struct linger l;
14300a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    socklen_t size = sizeof(l);
14310a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    memset(&l, 0, size);
14320a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int rc = TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &l, &size));
14330a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    if (rc == -1) {
14340a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        throwErrnoException(env, "getsockopt");
14350a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        return NULL;
14360a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    }
14370a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    return makeStructLinger(env, l);
14380a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
14390a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
14400965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getsockoptTimeval(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) {
14410a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
14420a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    struct timeval tv;
14430a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    socklen_t size = sizeof(tv);
14440a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    memset(&tv, 0, size);
14450a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    int rc = TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &tv, &size));
14460a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    if (rc == -1) {
14470a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        throwErrnoException(env, "getsockopt");
14480a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes        return NULL;
14490a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    }
14500a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes    return makeStructTimeval(env, tv);
14510a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes}
14520a9d1ee45a9884a9616624d747172e18734e8fe0Elliott Hughes
14530965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_getsockoptUcred(JNIEnv* env, jobject, jobject javaFd, jint level, jint option) {
1454482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  int fd = jniGetFDFromFileDescriptor(env, javaFd);
1455482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  struct ucred u;
1456482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  socklen_t size = sizeof(u);
1457482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  memset(&u, 0, size);
1458482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  int rc = TEMP_FAILURE_RETRY(getsockopt(fd, level, option, &u, &size));
1459482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  if (rc == -1) {
1460482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    throwErrnoException(env, "getsockopt");
1461482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    return NULL;
1462482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  }
1463482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes  return makeStructUcred(env, u);
1464482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes}
1465482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes
14660965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_gettid(JNIEnv* env __unused, jobject) {
1467efe42934a8523f2b051a351e5eceebf6216454aeElliott Hughes#if defined(__BIONIC__)
1468fa542091e45db699a937c5ac0191194405107827Elliott Hughes  return TEMP_FAILURE_RETRY(gettid());
14693deabd220cf7b1ca0824987e90b8ecc07087f05aIan Rogers#else
1470069525a39125c203b658c805685b6045a7d4dfebElliott Hughes  return syscall(__NR_gettid);
14713deabd220cf7b1ca0824987e90b8ecc07087f05aIan Rogers#endif
1472069525a39125c203b658c805685b6045a7d4dfebElliott Hughes}
1473069525a39125c203b658c805685b6045a7d4dfebElliott Hughes
14740965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_getuid(JNIEnv*, jobject) {
1475564312855784c9ae57e2af73affc48b0807b13eeElliott Hughes    return getuid();
1476396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
1477396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
14780965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jbyteArray Linux_getxattr(JNIEnv* env, jobject, jstring javaPath,
147940afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        jstring javaName) {
148090246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    ScopedUtfChars path(env, javaPath);
148190246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (path.c_str() == NULL) {
148240afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        return NULL;
148390246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
148490246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    ScopedUtfChars name(env, javaName);
148590246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (name.c_str() == NULL) {
148640afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        return NULL;
148790246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
148840afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong
148940afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong    while (true) {
149040afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        // Get the current size of the named extended attribute.
149140afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        ssize_t valueLength;
149240afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        if ((valueLength = getxattr(path.c_str(), name.c_str(), NULL, 0)) < 0) {
149340afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong            throwErrnoException(env, "getxattr");
149440afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong            return NULL;
149540afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        }
149640afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong
149740afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        // Create the actual byte array.
149840afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        std::vector<char> buf(valueLength);
149940afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        if ((valueLength = getxattr(path.c_str(), name.c_str(), buf.data(), valueLength)) < 0) {
150040afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong            if (errno == ERANGE) {
150140afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong                // The attribute value has changed since last getxattr call and buf no longer fits,
150240afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong                // try again.
150340afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong                continue;
150440afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong            }
150540afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong            throwErrnoException(env, "getxattr");
150640afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong            return NULL;
150740afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        }
150840afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        jbyteArray array = env->NewByteArray(valueLength);
150940afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        if (array == NULL) {
151040afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong            return NULL;
151140afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        }
151240afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        env->SetByteArrayRegion(array, 0, valueLength, reinterpret_cast<const jbyte*>(buf.data()));
151340afa6bcd4652a16fe461a59f205dd0d65652118Yi Kong        return array;
151490246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
151590246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey}
151690246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey
15170965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobjectArray Linux_getifaddrs(JNIEnv* env, jobject) {
15186d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    static jmethodID ctor = env->GetMethodID(JniConstants::structIfaddrs, "<init>",
15196d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            "(Ljava/lang/String;ILjava/net/InetAddress;Ljava/net/InetAddress;Ljava/net/InetAddress;[B)V");
152093a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    if (ctor == NULL) {
152193a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        return NULL;
152293a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak    }
15236d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
15246d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    ifaddrs* ifaddr;
15256d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    int rc = TEMP_FAILURE_RETRY(getifaddrs(&ifaddr));
15266d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    if (rc == -1) {
15276d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        throwErrnoException(env, "getifaddrs");
15286d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        return NULL;
15296d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    }
15306d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    std::unique_ptr<ifaddrs, decltype(&freeifaddrs)> ifaddrPtr(ifaddr, freeifaddrs);
15316d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
15326d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    // Count results so we know how to size the output array.
15336d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    jint ifCount = 0;
15346d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    for (ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
15356d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        ++ifCount;
15366d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    }
15376d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
15386d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    // Prepare output array.
15396d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    jobjectArray result = env->NewObjectArray(ifCount, JniConstants::structIfaddrs, NULL);
15406d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    if (result == NULL) {
15416d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        return NULL;
15426d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    }
15436d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
15446d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    // Traverse the list and populate the output array.
15456d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    int index = 0;
15466d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    for (ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next, ++index) {
15476d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        TO_JAVA_STRING(name, ifa->ifa_name);
15486d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        jint flags = ifa->ifa_flags;
15496d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        sockaddr_storage* interfaceAddr =
15506d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr);
15516d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        sockaddr_storage* netmaskAddr =
15526d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            reinterpret_cast<sockaddr_storage*>(ifa->ifa_netmask);
15536d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        sockaddr_storage* broadAddr =
15546d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            reinterpret_cast<sockaddr_storage*>(ifa->ifa_broadaddr);
15556d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
15566d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        jobject addr, netmask, broad;
15576d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        jbyteArray hwaddr = NULL;
15586d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        if (interfaceAddr != NULL) {
15596d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            switch (interfaceAddr->ss_family) {
15606d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            case AF_INET:
15616d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            case AF_INET6:
15626d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                // IPv4 / IPv6.
15636d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                // interfaceAddr and netmaskAddr are never null.
15646d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                if ((addr = sockaddrToInetAddress(env, *interfaceAddr, NULL)) == NULL) {
15656d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    return NULL;
15666d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                }
15676d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                if ((netmask = sockaddrToInetAddress(env, *netmaskAddr, NULL)) == NULL) {
15686d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    return NULL;
15696d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                }
15706d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                if (broadAddr != NULL && (ifa->ifa_flags & IFF_BROADCAST)) {
15716d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    if ((broad = sockaddrToInetAddress(env, *broadAddr, NULL)) == NULL) {
15726d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                        return NULL;
15736d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    }
15746d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                } else {
15756d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    broad = NULL;
15766d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                }
15776d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                break;
15786d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            case AF_PACKET:
15796d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                // Raw Interface.
15806d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                sockaddr_ll* sll = reinterpret_cast<sockaddr_ll*>(ifa->ifa_addr);
15816d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
15826d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                bool allZero = true;
15836d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                for (int i = 0; i < sll->sll_halen; ++i) {
15846d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    if (sll->sll_addr[i] != 0) {
15856d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                        allZero = false;
15866d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                        break;
15876d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    }
15886d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                }
15896d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
15906d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                if (!allZero) {
15916d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    hwaddr = env->NewByteArray(sll->sll_halen);
15926d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    if (hwaddr == NULL) {
15936d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                        return NULL;
15946d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    }
15956d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                    env->SetByteArrayRegion(hwaddr, 0, sll->sll_halen,
15966d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                                            reinterpret_cast<const jbyte*>(sll->sll_addr));
15976d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                }
15986d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                addr = netmask = broad = NULL;
15996d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                break;
16006d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            }
16016d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        } else {
16026d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            // Preserve the entry even if the interface has no interface address.
16036d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            // http://b/29243557/
16046d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong            addr = netmask = broad = NULL;
16056d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        }
16066d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
16076d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        jobject o = env->NewObject(JniConstants::structIfaddrs, ctor, name, flags, addr, netmask,
16086d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong                                   broad, hwaddr);
160993a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        if (o == NULL) {
161093a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak            return NULL;
161193a973589d69b7e4a725c058761b79a5d6600796Przemyslaw Szczepaniak        }
16126d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong        env->SetObjectArrayElement(result, index, o);
16136d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    }
16146d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
16156d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    return result;
16166d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong}
16176d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
16180965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_if_indextoname(JNIEnv* env, jobject, jint index) {
1619a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    char buf[IF_NAMESIZE];
1620a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    char* name = if_indextoname(index, buf);
1621a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    // if_indextoname(3) returns NULL on failure, which will come out of NewStringUTF unscathed.
1622a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    // There's no useful information in errno, so we don't bother throwing. Callers can null-check.
1623a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    return env->NewStringUTF(name);
1624a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes}
1625a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes
16260965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_if_nametoindex(JNIEnv* env, jobject, jstring name) {
16276d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    ScopedUtfChars cname(env, name);
1628507ae71a0387dbf4ec17e5eef27b9d3d6d691986Yi Kong    if (cname.c_str() == NULL) {
1629507ae71a0387dbf4ec17e5eef27b9d3d6d691986Yi Kong        return 0;
1630507ae71a0387dbf4ec17e5eef27b9d3d6d691986Yi Kong    }
1631507ae71a0387dbf4ec17e5eef27b9d3d6d691986Yi Kong
16326d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    // There's no useful information in errno, so we don't bother throwing. Callers can zero-check.
16336d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong    return if_nametoindex(cname.c_str());
16346d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong}
16356d1649c5b37b21ef2b690bc0f86306e19a32db02Yi Kong
16360965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_inet_pton(JNIEnv* env, jobject, jint family, jstring javaName) {
16371c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    ScopedUtfChars name(env, javaName);
16381c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    if (name.c_str() == NULL) {
16391c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        return NULL;
16401c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
16411c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    sockaddr_storage ss;
16421c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    memset(&ss, 0, sizeof(ss));
1643fc041ff241f9a7556e72236f130de0215ecd17dbElliott Hughes    // sockaddr_in and sockaddr_in6 are at the same address, so we can use either here.
1644fc041ff241f9a7556e72236f130de0215ecd17dbElliott Hughes    void* dst = &reinterpret_cast<sockaddr_in*>(&ss)->sin_addr;
1645fc041ff241f9a7556e72236f130de0215ecd17dbElliott Hughes    if (inet_pton(family, name.c_str(), dst) != 1) {
16461c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes        return NULL;
16471c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes    }
1648fc041ff241f9a7556e72236f130de0215ecd17dbElliott Hughes    ss.ss_family = family;
1649482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    return sockaddrToInetAddress(env, ss, NULL);
16501c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes}
16511c039d71d3879f39e3a75b8788e656f7b4f88f08Elliott Hughes
16520965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_ioctlFlags(JNIEnv* env, jobject, jobject javaFd, jstring javaInterfaceName) {
165345348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     struct ifreq req;
165445348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     if (!fillIfreq(env, javaInterfaceName, req)) {
165545348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong        return 0;
165645348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     }
165745348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     int fd = jniGetFDFromFileDescriptor(env, javaFd);
165845348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     throwIfMinusOne(env, "ioctl", TEMP_FAILURE_RETRY(ioctl(fd, SIOCGIFFLAGS, &req)));
165945348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     return req.ifr_flags;
166045348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong}
166145348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong
16620965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_ioctlInetAddress(JNIEnv* env, jobject, jobject javaFd, jint cmd, jstring javaInterfaceName) {
1663a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    struct ifreq req;
1664a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    if (!fillIfreq(env, javaInterfaceName, req)) {
1665a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes        return NULL;
1666a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    }
1667a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1668a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    int rc = throwIfMinusOne(env, "ioctl", TEMP_FAILURE_RETRY(ioctl(fd, cmd, &req)));
1669a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    if (rc == -1) {
1670a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes        return NULL;
1671a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    }
1672482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    return sockaddrToInetAddress(env, reinterpret_cast<sockaddr_storage&>(req.ifr_addr), NULL);
1673a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes}
1674a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes
16750965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_ioctlInt(JNIEnv* env, jobject, jobject javaFd, jint cmd, jobject javaArg) {
16768b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    // This is complicated because ioctls may return their result by updating their argument
16778b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    // or via their return value, so we need to support both.
1678461d0d860814c68154d8dd06d24f94118f33d28aElliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1679e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    jint arg = env->GetIntField(javaArg, int32RefValueFid);
16808b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    int rc = throwIfMinusOne(env, "ioctl", TEMP_FAILURE_RETRY(ioctl(fd, cmd, &arg)));
16818b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    if (!env->ExceptionCheck()) {
1682e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer        env->SetIntField(javaArg, int32RefValueFid, arg);
16838b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    }
16848b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    return rc;
1685461d0d860814c68154d8dd06d24f94118f33d28aElliott Hughes}
1686461d0d860814c68154d8dd06d24f94118f33d28aElliott Hughes
16870965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_ioctlMTU(JNIEnv* env, jobject, jobject javaFd, jstring javaInterfaceName) {
168845348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     struct ifreq req;
168945348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     if (!fillIfreq(env, javaInterfaceName, req)) {
169045348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong        return 0;
169145348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     }
169245348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     int fd = jniGetFDFromFileDescriptor(env, javaFd);
169345348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     throwIfMinusOne(env, "ioctl", TEMP_FAILURE_RETRY(ioctl(fd, SIOCGIFMTU, &req)));
169445348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong     return req.ifr_mtu;
169545348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong}
169645348e170536651c0e5f8d5cb0319ba232a1b833Yi Kong
16970965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jboolean Linux_isatty(JNIEnv* env, jobject, jobject javaFd) {
16989a3f363523000704205df288f8b6f2f48c0d8563Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1699bb5816aa1626eb2f6263bd21479600b114c8a1bdJohan Redestig    return TEMP_FAILURE_RETRY(isatty(fd)) == 1;
17009a3f363523000704205df288f8b6f2f48c0d8563Elliott Hughes}
17019a3f363523000704205df288f8b6f2f48c0d8563Elliott Hughes
17020965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_kill(JNIEnv* env, jobject, jint pid, jint sig) {
1703a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes    throwIfMinusOne(env, "kill", TEMP_FAILURE_RETRY(kill(pid, sig)));
1704a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes}
1705a5fb706fe4a6dbeaaf4cb1f8bbc2c68b0a2a3f3cElliott Hughes
17060965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_lchown(JNIEnv* env, jobject, jstring javaPath, jint uid, jint gid) {
170744f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    ScopedUtfChars path(env, javaPath);
170844f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    if (path.c_str() == NULL) {
170944f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes        return;
171044f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    }
171144f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    throwIfMinusOne(env, "lchown", TEMP_FAILURE_RETRY(lchown(path.c_str(), uid, gid)));
171244f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes}
171344f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes
17140965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_link(JNIEnv* env, jobject, jstring javaOldPath, jstring javaNewPath) {
171504428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes    ScopedUtfChars oldPath(env, javaOldPath);
171604428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes    if (oldPath.c_str() == NULL) {
171704428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes        return;
171804428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes    }
171904428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes    ScopedUtfChars newPath(env, javaNewPath);
172004428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes    if (newPath.c_str() == NULL) {
172104428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes        return;
172204428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes    }
172304428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes    throwIfMinusOne(env, "link", TEMP_FAILURE_RETRY(link(oldPath.c_str(), newPath.c_str())));
172404428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes}
172504428d61d7000e17ab21d08a1d672c34eb68f6e2Elliott Hughes
17260965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_listen(JNIEnv* env, jobject, jobject javaFd, jint backlog) {
1727e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1728e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes    throwIfMinusOne(env, "listen", TEMP_FAILURE_RETRY(listen(fd, backlog)));
1729e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes}
1730e1502d64e937001636fca3d62b2552ef2a34d05fElliott Hughes
17310965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobjectArray Linux_listxattr(JNIEnv* env, jobject, jstring javaPath) {
173255dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong    ScopedUtfChars path(env, javaPath);
173355dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong    if (path.c_str() == NULL) {
173455dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        return NULL;
173555dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong    }
173655dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong
173755dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong    while (true) {
173855dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        // Get the current size of the named extended attribute.
173955dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        ssize_t valueLength;
174055dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        if ((valueLength = listxattr(path.c_str(), NULL, 0)) < 0) {
174155dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong            throwErrnoException(env, "listxattr");
174255dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong            return NULL;
174355dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        }
174455dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong
174555dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        // Create the actual byte array.
174655dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        std::string buf(valueLength, '\0');
174755dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        if ((valueLength = listxattr(path.c_str(), &buf[0], valueLength)) < 0) {
174855dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong            if (errno == ERANGE) {
174955dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong                // The attribute value has changed since last listxattr call and buf no longer fits,
175055dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong                // try again.
175155dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong                continue;
175255dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong            }
175355dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong            throwErrnoException(env, "listxattr");
175455dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong            return NULL;
175555dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        }
175655dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong
175755dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        // Split the output by '\0'.
175855dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        buf.resize(valueLength > 0 ? valueLength - 1 : 0); // Remove the trailing NULL character.
175955dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        std::string delim("\0", 1);
176055dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        auto xattrs = android::base::Split(buf, delim);
176155dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong
176255dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong        return toStringArray(env, xattrs);
176355dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong    }
176455dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong}
176555dd377d62cf780df94d8e0198b66e99456b6f50Yi Kong
17660965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jlong Linux_lseek(JNIEnv* env, jobject, jobject javaFd, jlong offset, jint whence) {
1767dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
17687e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    return throwIfMinusOne(env, "lseek", TEMP_FAILURE_RETRY(lseek64(fd, offset, whence)));
1769dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes}
1770dedaccdfa07c370a58cba08b096133ad9eec0ec3Elliott Hughes
17710965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_lstat(JNIEnv* env, jobject, jstring javaPath) {
177247cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    return doStat(env, javaPath, true);
177347cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes}
177447cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes
17750965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_mincore(JNIEnv* env, jobject, jlong address, jlong byteCount, jbyteArray javaVector) {
17760f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes    ScopedByteArrayRW vector(env, javaVector);
17770f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes    if (vector.get() == NULL) {
17780f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes        return;
17790f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes    }
17800f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
17810f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes    unsigned char* vec = reinterpret_cast<unsigned char*>(vector.get());
17820f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes    throwIfMinusOne(env, "mincore", TEMP_FAILURE_RETRY(mincore(ptr, byteCount, vec)));
17830f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes}
17840f746ff511162add42eeabaf14ba70ace874c6f4Elliott Hughes
17850965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_mkdir(JNIEnv* env, jobject, jstring javaPath, jint mode) {
1786c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    ScopedUtfChars path(env, javaPath);
1787c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    if (path.c_str() == NULL) {
1788c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes        return;
1789c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    }
1790c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    throwIfMinusOne(env, "mkdir", TEMP_FAILURE_RETRY(mkdir(path.c_str(), mode)));
1791c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes}
1792c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes
17930965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_mkfifo(JNIEnv* env, jobject, jstring javaPath, jint mode) {
1794f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    ScopedUtfChars path(env, javaPath);
1795f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    if (path.c_str() == NULL) {
1796f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        return;
1797f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    }
1798f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    throwIfMinusOne(env, "mkfifo", TEMP_FAILURE_RETRY(mkfifo(path.c_str(), mode)));
1799f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller}
1800f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller
18010965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_mlock(JNIEnv* env, jobject, jlong address, jlong byteCount) {
18027e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
18037e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes    throwIfMinusOne(env, "mlock", TEMP_FAILURE_RETRY(mlock(ptr, byteCount)));
18047e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes}
18057e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes
18060965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jlong Linux_mmap(JNIEnv* env, jobject, jlong address, jlong byteCount, jint prot, jint flags, jobject javaFd, jlong offset) {
18077e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
18087e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    void* suggestedPtr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
180913a70e6c04157064fc8a61ecfcb1d863f29c239dYi Kong    void* ptr = mmap64(suggestedPtr, byteCount, prot, flags, fd, offset);
18107e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    if (ptr == MAP_FAILED) {
18117e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes        throwErrnoException(env, "mmap");
18127e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    }
18137e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    return static_cast<jlong>(reinterpret_cast<uintptr_t>(ptr));
18147e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes}
18157e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes
18160965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_msync(JNIEnv* env, jobject, jlong address, jlong byteCount, jint flags) {
18177e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
18187e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    throwIfMinusOne(env, "msync", TEMP_FAILURE_RETRY(msync(ptr, byteCount, flags)));
18197e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes}
18207e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes
18210965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_munlock(JNIEnv* env, jobject, jlong address, jlong byteCount) {
18227e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
18237e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes    throwIfMinusOne(env, "munlock", TEMP_FAILURE_RETRY(munlock(ptr, byteCount)));
18247e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes}
18257e13c0f05ac9e7c55682d10e953dd4cbd5e6107cElliott Hughes
18260965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_munmap(JNIEnv* env, jobject, jlong address, jlong byteCount) {
18277e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    void* ptr = reinterpret_cast<void*>(static_cast<uintptr_t>(address));
18287e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes    throwIfMinusOne(env, "munmap", TEMP_FAILURE_RETRY(munmap(ptr, byteCount)));
18297e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes}
18307e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes
18310965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_open(JNIEnv* env, jobject, jstring javaPath, jint flags, jint mode) {
18320ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes    ScopedUtfChars path(env, javaPath);
18330ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes    if (path.c_str() == NULL) {
18340ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes        return NULL;
18350ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes    }
18360ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes    int fd = throwIfMinusOne(env, "open", TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode)));
18370ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes    return fd != -1 ? jniCreateFileDescriptor(env, fd) : NULL;
18380ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes}
18390ac77ac8e915bff1a863e371f9b363033f9cf759Elliott Hughes
18400965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobjectArray Linux_pipe2(JNIEnv* env, jobject, jint flags __unused) {
184141f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes    int fds[2];
184257a65ad7f0be5b9d0364d36208752f66e9f13596Przemyslaw Szczepaniak    int pipe2_result = throwIfMinusOne(env, "pipe2", TEMP_FAILURE_RETRY(pipe2(&fds[0], flags)));
184357a65ad7f0be5b9d0364d36208752f66e9f13596Przemyslaw Szczepaniak    if (pipe2_result == -1) {
184457a65ad7f0be5b9d0364d36208752f66e9f13596Przemyslaw Szczepaniak        return NULL;
184557a65ad7f0be5b9d0364d36208752f66e9f13596Przemyslaw Szczepaniak    }
184641f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes    jobjectArray result = env->NewObjectArray(2, JniConstants::fileDescriptorClass, NULL);
184741f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes    if (result == NULL) {
184841f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        return NULL;
184941f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes    }
185041f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes    for (int i = 0; i < 2; ++i) {
185141f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        ScopedLocalRef<jobject> fd(env, jniCreateFileDescriptor(env, fds[i]));
185241f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        if (fd.get() == NULL) {
185341f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes            return NULL;
185441f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        }
185541f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        env->SetObjectArrayElement(result, i, fd.get());
185641f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        if (env->ExceptionCheck()) {
185741f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes            return NULL;
185841f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        }
185941f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes    }
186041f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes    return result;
186141f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes}
186241f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes
18630965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_poll(JNIEnv* env, jobject, jobjectArray javaStructs, jint timeoutMs) {
186470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    static jfieldID fdFid = env->GetFieldID(JniConstants::structPollfdClass, "fd", "Ljava/io/FileDescriptor;");
186570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    static jfieldID eventsFid = env->GetFieldID(JniConstants::structPollfdClass, "events", "S");
186670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    static jfieldID reventsFid = env->GetFieldID(JniConstants::structPollfdClass, "revents", "S");
186770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
18685d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughes    // Turn the Java android.system.StructPollfd[] into a C++ struct pollfd[].
186970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    size_t arrayLength = env->GetArrayLength(javaStructs);
1870b3aacde3d8af759ee4a7b395c636ea360547d92dIan Rogers    std::unique_ptr<struct pollfd[]> fds(new struct pollfd[arrayLength]);
187170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    memset(fds.get(), 0, sizeof(struct pollfd) * arrayLength);
187270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    size_t count = 0; // Some trailing array elements may be irrelevant. (See below.)
187370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    for (size_t i = 0; i < arrayLength; ++i) {
187470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        ScopedLocalRef<jobject> javaStruct(env, env->GetObjectArrayElement(javaStructs, i));
187570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        if (javaStruct.get() == NULL) {
187670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            break; // We allow trailing nulls in the array for caller convenience.
187770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        }
187870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        ScopedLocalRef<jobject> javaFd(env, env->GetObjectField(javaStruct.get(), fdFid));
187970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        if (javaFd.get() == NULL) {
188070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            break; // We also allow callers to just clear the fd field (this is what Selector does).
188170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        }
188270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        fds[count].fd = jniGetFDFromFileDescriptor(env, javaFd.get());
188370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        fds[count].events = env->GetShortField(javaStruct.get(), eventsFid);
188470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        ++count;
188570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    }
188670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
1887f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    std::vector<AsynchronousCloseMonitor*> monitors;
1888796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes    for (size_t i = 0; i < count; ++i) {
1889f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        monitors.push_back(new AsynchronousCloseMonitor(fds[i].fd));
1890796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes    }
1891fa542091e45db699a937c5ac0191194405107827Elliott Hughes
1892fa542091e45db699a937c5ac0191194405107827Elliott Hughes    int rc;
1893fa542091e45db699a937c5ac0191194405107827Elliott Hughes    while (true) {
1894fa542091e45db699a937c5ac0191194405107827Elliott Hughes        timespec before;
1895fa542091e45db699a937c5ac0191194405107827Elliott Hughes        clock_gettime(CLOCK_MONOTONIC, &before);
1896fa542091e45db699a937c5ac0191194405107827Elliott Hughes
1897fa542091e45db699a937c5ac0191194405107827Elliott Hughes        rc = poll(fds.get(), count, timeoutMs);
1898fa542091e45db699a937c5ac0191194405107827Elliott Hughes        if (rc >= 0 || errno != EINTR) {
1899fa542091e45db699a937c5ac0191194405107827Elliott Hughes            break;
1900fa542091e45db699a937c5ac0191194405107827Elliott Hughes        }
1901fa542091e45db699a937c5ac0191194405107827Elliott Hughes
1902fa542091e45db699a937c5ac0191194405107827Elliott Hughes        // We got EINTR. Work out how much of the original timeout is still left.
1903fa542091e45db699a937c5ac0191194405107827Elliott Hughes        if (timeoutMs > 0) {
1904fa542091e45db699a937c5ac0191194405107827Elliott Hughes            timespec now;
1905fa542091e45db699a937c5ac0191194405107827Elliott Hughes            clock_gettime(CLOCK_MONOTONIC, &now);
1906fa542091e45db699a937c5ac0191194405107827Elliott Hughes
1907fa542091e45db699a937c5ac0191194405107827Elliott Hughes            timespec diff;
1908fa542091e45db699a937c5ac0191194405107827Elliott Hughes            diff.tv_sec = now.tv_sec - before.tv_sec;
1909fa542091e45db699a937c5ac0191194405107827Elliott Hughes            diff.tv_nsec = now.tv_nsec - before.tv_nsec;
1910fa542091e45db699a937c5ac0191194405107827Elliott Hughes            if (diff.tv_nsec < 0) {
1911fa542091e45db699a937c5ac0191194405107827Elliott Hughes                --diff.tv_sec;
1912fa542091e45db699a937c5ac0191194405107827Elliott Hughes                diff.tv_nsec += 1000000000;
1913fa542091e45db699a937c5ac0191194405107827Elliott Hughes            }
1914fa542091e45db699a937c5ac0191194405107827Elliott Hughes
1915fa542091e45db699a937c5ac0191194405107827Elliott Hughes            jint diffMs = diff.tv_sec * 1000 + diff.tv_nsec / 1000000;
1916fa542091e45db699a937c5ac0191194405107827Elliott Hughes            if (diffMs >= timeoutMs) {
1917fa542091e45db699a937c5ac0191194405107827Elliott Hughes                rc = 0; // We have less than 1ms left anyway, so just time out.
1918fa542091e45db699a937c5ac0191194405107827Elliott Hughes                break;
1919fa542091e45db699a937c5ac0191194405107827Elliott Hughes            }
1920fa542091e45db699a937c5ac0191194405107827Elliott Hughes
1921fa542091e45db699a937c5ac0191194405107827Elliott Hughes            timeoutMs -= diffMs;
1922fa542091e45db699a937c5ac0191194405107827Elliott Hughes        }
1923fa542091e45db699a937c5ac0191194405107827Elliott Hughes    }
1924fa542091e45db699a937c5ac0191194405107827Elliott Hughes
1925796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes    for (size_t i = 0; i < monitors.size(); ++i) {
1926796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes        delete monitors[i];
1927796f0d5a4e7b83c3efc5e587b6766977dc20b0c3Elliott Hughes    }
192870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    if (rc == -1) {
192970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        throwErrnoException(env, "poll");
193070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        return -1;
193170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    }
193270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
19335d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughes    // Update the revents fields in the Java android.system.StructPollfd[].
193498b23d4d9894d21be1eacf498f48aeb707ca1e41Elliott Hughes    for (size_t i = 0; i < count; ++i) {
193570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        ScopedLocalRef<jobject> javaStruct(env, env->GetObjectArrayElement(javaStructs, i));
193698b23d4d9894d21be1eacf498f48aeb707ca1e41Elliott Hughes        if (javaStruct.get() == NULL) {
193798b23d4d9894d21be1eacf498f48aeb707ca1e41Elliott Hughes            return -1;
193898b23d4d9894d21be1eacf498f48aeb707ca1e41Elliott Hughes        }
193970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        env->SetShortField(javaStruct.get(), reventsFid, fds[i].revents);
194070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    }
194170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    return rc;
194270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes}
194370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
19440965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_posix_fallocate(JNIEnv* env, jobject, jobject javaFd __unused,
19453deabd220cf7b1ca0824987e90b8ecc07087f05aIan Rogers                                  jlong offset __unused, jlong length __unused) {
194611f07d30d2e344b48f132ec6ed105d85423052c2Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
1947fa542091e45db699a937c5ac0191194405107827Elliott Hughes    while ((errno = posix_fallocate64(fd, offset, length)) == EINTR) {
1948fa542091e45db699a937c5ac0191194405107827Elliott Hughes    }
194911f07d30d2e344b48f132ec6ed105d85423052c2Elliott Hughes    if (errno != 0) {
195011f07d30d2e344b48f132ec6ed105d85423052c2Elliott Hughes        throwErrnoException(env, "posix_fallocate");
195111f07d30d2e344b48f132ec6ed105d85423052c2Elliott Hughes    }
195211f07d30d2e344b48f132ec6ed105d85423052c2Elliott Hughes}
195311f07d30d2e344b48f132ec6ed105d85423052c2Elliott Hughes
19540965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_prctl(JNIEnv* env, jobject, jint option __unused, jlong arg2 __unused,
19553deabd220cf7b1ca0824987e90b8ecc07087f05aIan Rogers                        jlong arg3 __unused, jlong arg4 __unused, jlong arg5 __unused) {
1956fa542091e45db699a937c5ac0191194405107827Elliott Hughes    int result = TEMP_FAILURE_RETRY(prctl(static_cast<int>(option),
1957fa542091e45db699a937c5ac0191194405107827Elliott Hughes                                          static_cast<unsigned long>(arg2),
1958fa542091e45db699a937c5ac0191194405107827Elliott Hughes                                          static_cast<unsigned long>(arg3),
1959fa542091e45db699a937c5ac0191194405107827Elliott Hughes                                          static_cast<unsigned long>(arg4),
1960fa542091e45db699a937c5ac0191194405107827Elliott Hughes                                          static_cast<unsigned long>(arg5)));
19615215e4c0db7530519981f1e505e6db82401802f2Nick Kralevich    return throwIfMinusOne(env, "prctl", result);
19625215e4c0db7530519981f1e505e6db82401802f2Nick Kralevich}
19635215e4c0db7530519981f1e505e6db82401802f2Nick Kralevich
19640965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_preadBytes(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount, jlong offset) {
1965e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    ScopedBytesRW bytes(env, javaBytes);
1966e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    if (bytes.get() == NULL) {
1967e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes        return -1;
1968e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    }
1969f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    return IO_FAILURE_RETRY(env, ssize_t, pread64, javaFd, bytes.get() + byteOffset, byteCount, offset);
1970e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes}
1971e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes
19720965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_pwriteBytes(JNIEnv* env, jobject, jobject javaFd, jbyteArray javaBytes, jint byteOffset, jint byteCount, jlong offset) {
1973e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    ScopedBytesRO bytes(env, javaBytes);
1974e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    if (bytes.get() == NULL) {
1975e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes        return -1;
1976e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes    }
1977f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    return IO_FAILURE_RETRY(env, ssize_t, pwrite64, javaFd, bytes.get() + byteOffset, byteCount, offset);
1978e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes}
1979e3b6fa2bf357f2712ab2ee9e8487f157595ea0c7Elliott Hughes
19800965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_readBytes(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount) {
19810568a63ba1086a78ffb4cff68dd2eac4f9908e13Elliott Hughes    ScopedBytesRW bytes(env, javaBytes);
198226c7025a7a919044771fb89031161bd26fe03032Elliott Hughes    if (bytes.get() == NULL) {
198326c7025a7a919044771fb89031161bd26fe03032Elliott Hughes        return -1;
198426c7025a7a919044771fb89031161bd26fe03032Elliott Hughes    }
1985f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    return IO_FAILURE_RETRY(env, ssize_t, read, javaFd, bytes.get() + byteOffset, byteCount);
198626c7025a7a919044771fb89031161bd26fe03032Elliott Hughes}
198726c7025a7a919044771fb89031161bd26fe03032Elliott Hughes
19880965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_readlink(JNIEnv* env, jobject, jstring javaPath) {
19890b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes    ScopedUtfChars path(env, javaPath);
19900b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes    if (path.c_str() == NULL) {
19910b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes        return NULL;
19920b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes    }
19930b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes
19940b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes    std::string result;
19952cb2851f4a528e3e6e3e59cf3e854c2abf9f1811Elliott Hughes    if (!android::base::Readlink(path.c_str(), &result)) {
19960b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes        throwErrnoException(env, "readlink");
19970b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes        return NULL;
19980b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes    }
19990b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes    return env->NewStringUTF(result.c_str());
20000b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes}
20010b6b3e10459fc3a3f4dd280dab8d4a145f7bf2f0Elliott Hughes
20020965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_realpath(JNIEnv* env, jobject, jstring javaPath) {
20035d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    ScopedUtfChars path(env, javaPath);
20045d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    if (path.c_str() == NULL) {
20055d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath        return NULL;
20065d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    }
20075d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath
20085d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    std::unique_ptr<char, c_deleter> real_path(realpath(path.c_str(), nullptr));
20095d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    if (real_path.get() == nullptr) {
20105d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath        throwErrnoException(env, "realpath");
20115d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath        return NULL;
20125d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    }
20135d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath
20145d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath    return env->NewStringUTF(real_path.get());
20155d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath}
20165d45c289afe04d12f41612e33e8df83e5db650d8Narayan Kamath
20170965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_readv(JNIEnv* env, jobject, jobject javaFd, jobjectArray buffers, jintArray offsets, jintArray byteCounts) {
20188dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughes    IoVec<ScopedBytesRW> ioVec(env, env->GetArrayLength(buffers));
2019bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    if (!ioVec.init(buffers, offsets, byteCounts)) {
2020bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        return -1;
2021bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
2022f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    return IO_FAILURE_RETRY(env, ssize_t, readv, javaFd, ioVec.get(), ioVec.size());
2023bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes}
2024bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
20250965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_recvfromBytes(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount, jint flags, jobject javaInetSocketAddress) {
202623ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    ScopedBytesRW bytes(env, javaBytes);
202723ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    if (bytes.get() == NULL) {
202823ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes        return -1;
202923ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    }
203023ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    sockaddr_storage ss;
203123ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    socklen_t sl = sizeof(ss);
203223ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    memset(&ss, 0, sizeof(ss));
203323ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    sockaddr* from = (javaInetSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;
203423ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    socklen_t* fromLength = (javaInetSocketAddress != NULL) ? &sl : 0;
20351124a814d698ed6fd68ac501f5dddfa103d656fdElliott Hughes    jint recvCount = NET_FAILURE_RETRY(env, ssize_t, recvfrom, javaFd, bytes.get() + byteOffset, byteCount, flags, from, fromLength);
20366dd21e692ae87b75e49b23ffbecc6964604f466aYi Kong    if (recvCount >= 0) {
20376dd21e692ae87b75e49b23ffbecc6964604f466aYi Kong        // The socket may have performed orderly shutdown and recvCount would return 0 (see man 2
20386dd21e692ae87b75e49b23ffbecc6964604f466aYi Kong        // recvfrom), in which case ss.ss_family == AF_UNIX and fillInetSocketAddress would fail.
20396dd21e692ae87b75e49b23ffbecc6964604f466aYi Kong        // Don't fill in the address if recvfrom didn't succeed. http://b/33483694
20406dd21e692ae87b75e49b23ffbecc6964604f466aYi Kong        if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
20416dd21e692ae87b75e49b23ffbecc6964604f466aYi Kong            fillInetSocketAddress(env, javaInetSocketAddress, ss);
20426dd21e692ae87b75e49b23ffbecc6964604f466aYi Kong        }
20430ab1a26ca767ae36fbbe27b62893670b208fa494Neil Fuller    }
204423ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes    return recvCount;
204523ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes}
204623ec09188303a874b3b391f96ae0a29af002bff9Elliott Hughes
20470965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_remove(JNIEnv* env, jobject, jstring javaPath) {
2048c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    ScopedUtfChars path(env, javaPath);
2049c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    if (path.c_str() == NULL) {
2050c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes        return;
2051c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    }
2052c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes    throwIfMinusOne(env, "remove", TEMP_FAILURE_RETRY(remove(path.c_str())));
2053c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes}
2054c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes
20550965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_removexattr(JNIEnv* env, jobject, jstring javaPath, jstring javaName) {
205690246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    ScopedUtfChars path(env, javaPath);
205790246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (path.c_str() == NULL) {
205890246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        return;
205990246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
206090246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    ScopedUtfChars name(env, javaName);
206190246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (name.c_str() == NULL) {
206290246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        return;
206390246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
206490246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey
206590246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    int res = removexattr(path.c_str(), name.c_str());
206690246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (res < 0) {
206790246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        throwErrnoException(env, "removexattr");
206890246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
206990246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey}
207090246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey
20710965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_rename(JNIEnv* env, jobject, jstring javaOldPath, jstring javaNewPath) {
2072a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    ScopedUtfChars oldPath(env, javaOldPath);
2073a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    if (oldPath.c_str() == NULL) {
2074a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes        return;
2075a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    }
2076a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    ScopedUtfChars newPath(env, javaNewPath);
2077a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    if (newPath.c_str() == NULL) {
2078a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes        return;
2079a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    }
2080a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    throwIfMinusOne(env, "rename", TEMP_FAILURE_RETRY(rename(oldPath.c_str(), newPath.c_str())));
2081a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes}
2082a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes
20830965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jlong Linux_sendfile(JNIEnv* env, jobject, jobject javaOutFd, jobject javaInFd, jobject javaOffset, jlong byteCount) {
20848b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    int outFd = jniGetFDFromFileDescriptor(env, javaOutFd);
20858b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    int inFd = jniGetFDFromFileDescriptor(env, javaInFd);
20868b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    off_t offset = 0;
20878b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    off_t* offsetPtr = NULL;
20888b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    if (javaOffset != NULL) {
20898b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes        // TODO: fix bionic so we can have a 64-bit off_t!
2090e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer        offset = env->GetLongField(javaOffset, int64RefValueFid);
20918b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes        offsetPtr = &offset;
20928b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    }
20938b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    jlong result = throwIfMinusOne(env, "sendfile", TEMP_FAILURE_RETRY(sendfile(outFd, inFd, offsetPtr, byteCount)));
209457a65ad7f0be5b9d0364d36208752f66e9f13596Przemyslaw Szczepaniak    if (result == -1) {
209557a65ad7f0be5b9d0364d36208752f66e9f13596Przemyslaw Szczepaniak        return -1;
209657a65ad7f0be5b9d0364d36208752f66e9f13596Przemyslaw Szczepaniak    }
20978b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    if (javaOffset != NULL) {
2098e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer        env->SetLongField(javaOffset, int64RefValueFid, offset);
20998b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    }
21008b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes    return result;
21018b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes}
21028b15dcc5890963edad4dfcf558cc16027c7985e5Elliott Hughes
21030965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_sendtoBytes(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount, jint flags, jobject javaInetAddress, jint port) {
210490d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    ScopedBytesRO bytes(env, javaBytes);
210590d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    if (bytes.get() == NULL) {
210690d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes        return -1;
210790d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes    }
2108b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti
2109b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti    return NET_IPV4_FALLBACK(env, ssize_t, sendto, javaFd, javaInetAddress, port,
2110b2a9923fa2006e384013734d3e1c6a7fbe3d9074Lorenzo Colitti                             NULL_ADDR_OK, bytes.get() + byteOffset, byteCount, flags);
211190d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes}
211290d96a4f168b7e56cff54dc94dca2f3cde60ebcdElliott Hughes
21130965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_sendtoBytesSocketAddress(JNIEnv* env, jobject, jobject javaFd, jobject javaBytes, jint byteOffset, jint byteCount, jint flags, jobject javaSocketAddress) {
2114f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti    if (env->IsInstanceOf(javaSocketAddress, JniConstants::inetSocketAddressClass)) {
2115f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti        // Use the InetAddress version so we get the benefit of NET_IPV4_FALLBACK.
2116f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti        jobject javaInetAddress;
2117f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti        jint port;
2118f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti        javaInetSocketAddressToInetAddressAndPort(env, javaSocketAddress, javaInetAddress, port);
21190965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe        return Linux_sendtoBytes(env, NULL, javaFd, javaBytes, byteOffset, byteCount, flags,
2120f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti                                 javaInetAddress, port);
2121f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti    }
2122f5fc4ade3ab082f545e2aafdb1942c1f14e0df5dLorenzo Colitti
2123a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    ScopedBytesRO bytes(env, javaBytes);
2124a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    if (bytes.get() == NULL) {
2125a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti        return -1;
2126a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    }
2127a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti
2128a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    sockaddr_storage ss;
2129a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    socklen_t sa_len;
2130a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    if (!javaSocketAddressToSockaddr(env, javaSocketAddress, ss, sa_len)) {
2131a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti        return -1;
2132a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    }
2133a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti
2134a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    const sockaddr* sa = reinterpret_cast<const sockaddr*>(&ss);
2135a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    // We don't need the return value because we'll already have thrown.
2136a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti    return NET_FAILURE_RETRY(env, ssize_t, sendto, javaFd, bytes.get() + byteOffset, byteCount, flags, sa, sa_len);
2137a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti}
2138a8b7587c5001db3489c64ac1d16c254a683f76bdLorenzo Colitti
21390965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setegid(JNIEnv* env, jobject, jint egid) {
2140396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    throwIfMinusOne(env, "setegid", TEMP_FAILURE_RETRY(setegid(egid)));
2141396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
2142396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
21430965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setenv(JNIEnv* env, jobject, jstring javaName, jstring javaValue, jboolean overwrite) {
2144895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    ScopedUtfChars name(env, javaName);
2145895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    if (name.c_str() == NULL) {
2146895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes        return;
2147895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    }
2148895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    ScopedUtfChars value(env, javaValue);
2149895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    if (value.c_str() == NULL) {
2150895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes        return;
2151895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    }
2152895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    throwIfMinusOne(env, "setenv", setenv(name.c_str(), value.c_str(), overwrite));
2153895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes}
2154895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes
21550965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_seteuid(JNIEnv* env, jobject, jint euid) {
2156396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    throwIfMinusOne(env, "seteuid", TEMP_FAILURE_RETRY(seteuid(euid)));
2157396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
2158396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
21590965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setgid(JNIEnv* env, jobject, jint gid) {
2160396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    throwIfMinusOne(env, "setgid", TEMP_FAILURE_RETRY(setgid(gid)));
2161396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
2162396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
21630965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setpgid(JNIEnv* env, jobject, jint pid, int pgid) {
21648f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes    throwIfMinusOne(env, "setpgid", TEMP_FAILURE_RETRY(setpgid(pid, pgid)));
21658f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes}
21668f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes
21670965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setregid(JNIEnv* env, jobject, jint rgid, int egid) {
21688f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes    throwIfMinusOne(env, "setregid", TEMP_FAILURE_RETRY(setregid(rgid, egid)));
21698f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes}
21708f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes
21710965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setreuid(JNIEnv* env, jobject, jint ruid, int euid) {
21728f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes    throwIfMinusOne(env, "setreuid", TEMP_FAILURE_RETRY(setreuid(ruid, euid)));
21738f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes}
21748f0f2ac7fcd8f366a78cc51181d065ab93385e46Elliott Hughes
21750965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_setsid(JNIEnv* env, jobject) {
21766c9b5377550a9649ed1532d1fcdfeba116c74eadElliott Hughes    return throwIfMinusOne(env, "setsid", TEMP_FAILURE_RETRY(setsid()));
21776c9b5377550a9649ed1532d1fcdfeba116c74eadElliott Hughes}
21786c9b5377550a9649ed1532d1fcdfeba116c74eadElliott Hughes
21790965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setsockoptByte(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jint value) {
2180c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
2181c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    u_char byte = value;
2182c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    throwIfMinusOne(env, "setsockopt", TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &byte, sizeof(byte))));
2183c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes}
2184c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes
21850965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setsockoptIfreq(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jstring javaInterfaceName) {
2186a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    struct ifreq req;
2187a37e971343883bb582a93ffbd9f0ba84f10e55baElliott Hughes    if (!fillIfreq(env, javaInterfaceName, req)) {
2188b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes        return;
2189b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    }
2190b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
2191b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    throwIfMinusOne(env, "setsockopt", TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &req, sizeof(req))));
2192b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes}
2193b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes
21940965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setsockoptInt(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jint value) {
2195454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
2196454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes    throwIfMinusOne(env, "setsockopt", TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &value, sizeof(value))));
2197454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes}
2198454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes
21990965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setsockoptIpMreqn(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jint value) {
2200b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    ip_mreqn req;
2201b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    memset(&req, 0, sizeof(req));
2202b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    req.imr_ifindex = value;
2203b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
2204b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes    throwIfMinusOne(env, "setsockopt", TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &req, sizeof(req))));
2205b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes}
2206b974666d79ebc392b37ec1ae83aae57ae6331c08Elliott Hughes
22070965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setsockoptGroupReq(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jobject javaGroupReq) {
22088ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes    struct group_req req;
22098ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes    memset(&req, 0, sizeof(req));
2210438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes
2211438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    static jfieldID grInterfaceFid = env->GetFieldID(JniConstants::structGroupReqClass, "gr_interface", "I");
22128ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes    req.gr_interface = env->GetIntField(javaGroupReq, grInterfaceFid);
2213438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    // Get the IPv4 or IPv6 multicast address to join or leave.
2214438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    static jfieldID grGroupFid = env->GetFieldID(JniConstants::structGroupReqClass, "gr_group", "Ljava/net/InetAddress;");
2215e9f12043a1e2a29c60779cdb55c58eb156963570Elliott Hughes    ScopedLocalRef<jobject> javaGroup(env, env->GetObjectField(javaGroupReq, grGroupFid));
2216482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    socklen_t sa_len;
2217482a3fc5635ac431b8a7476d7fe3397af4c2e8ecElliott Hughes    if (!inetAddressToSockaddrVerbatim(env, javaGroup.get(), 0, req.gr_group, sa_len)) {
2218438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes        return;
2219438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    }
2220438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes
2221438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
22228ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes    int rc = TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &req, sizeof(req)));
2223438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    if (rc == -1 && errno == EINVAL) {
2224438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes        // Maybe we're a 32-bit binary talking to a 64-bit kernel?
2225438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes        // glibc doesn't automatically handle this.
2226df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller        // http://sourceware.org/bugzilla/show_bug.cgi?id=12080
22279634b569a92841f32268907c88c408f22cb00486Elliott Hughes        struct group_req64 {
2228438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes            uint32_t gr_interface;
2229438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes            uint32_t my_padding;
2230438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes            sockaddr_storage gr_group;
2231438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes        };
22328ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes        group_req64 req64;
22338ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes        req64.gr_interface = req.gr_interface;
22348ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes        memcpy(&req64.gr_group, &req.gr_group, sizeof(req.gr_group));
22358ecbb3f6a89983adb1a085469befc70488f4f04fElliott Hughes        rc = TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &req64, sizeof(req64)));
2236438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    }
2237438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes    throwIfMinusOne(env, "setsockopt", rc);
2238438cb9e440d250c8aa5daf4fae0c400dce8b1499Elliott Hughes}
2239df29508a7aa622f265aaebdc472eb7d679185ebbNeil Fuller
22400965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setsockoptLinger(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jobject javaLinger) {
2241c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    static jfieldID lOnoffFid = env->GetFieldID(JniConstants::structLingerClass, "l_onoff", "I");
2242c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    static jfieldID lLingerFid = env->GetFieldID(JniConstants::structLingerClass, "l_linger", "I");
2243c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
2244c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    struct linger value;
2245c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    value.l_onoff = env->GetIntField(javaLinger, lOnoffFid);
2246c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    value.l_linger = env->GetIntField(javaLinger, lLingerFid);
2247c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    throwIfMinusOne(env, "setsockopt", TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &value, sizeof(value))));
2248c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes}
2249c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes
22500965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setsockoptTimeval(JNIEnv* env, jobject, jobject javaFd, jint level, jint option, jobject javaTimeval) {
2251c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    static jfieldID tvSecFid = env->GetFieldID(JniConstants::structTimevalClass, "tv_sec", "J");
2252c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    static jfieldID tvUsecFid = env->GetFieldID(JniConstants::structTimevalClass, "tv_usec", "J");
2253c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
2254c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    struct timeval value;
225539fd5e164f93ab821841aa4d1fac09055c102b8bElliott Hughes    value.tv_sec = env->GetLongField(javaTimeval, tvSecFid);
225639fd5e164f93ab821841aa4d1fac09055c102b8bElliott Hughes    value.tv_usec = env->GetLongField(javaTimeval, tvUsecFid);
2257c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes    throwIfMinusOne(env, "setsockopt", TEMP_FAILURE_RETRY(setsockopt(fd, level, option, &value, sizeof(value))));
2258c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes}
2259c63f0d4e80a9fd3bdf99cd438d108b750226736aElliott Hughes
22600965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setuid(JNIEnv* env, jobject, jint uid) {
2261396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes    throwIfMinusOne(env, "setuid", TEMP_FAILURE_RETRY(setuid(uid)));
2262396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes}
2263396a9c666da353b910b515d12eb1c43adfddb0c8Elliott Hughes
22640965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_setxattr(JNIEnv* env, jobject, jstring javaPath, jstring javaName,
226590246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        jbyteArray javaValue, jint flags) {
226690246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    ScopedUtfChars path(env, javaPath);
226790246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (path.c_str() == NULL) {
226890246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        return;
226990246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
227090246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    ScopedUtfChars name(env, javaName);
227190246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (name.c_str() == NULL) {
227290246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        return;
227390246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
227490246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    ScopedBytesRO value(env, javaValue);
227590246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (value.get() == NULL) {
227690246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        return;
227790246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
227890246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    size_t valueLength = env->GetArrayLength(javaValue);
227990246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    int res = setxattr(path.c_str(), name.c_str(), value.get(), valueLength, flags);
228090246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    if (res < 0) {
228190246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey        throwErrnoException(env, "setxattr");
228290246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey    }
228390246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey}
228490246a0ae7117d780e077c9e84cdb73ff5b44af7Jeff Sharkey
22850965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_shutdown(JNIEnv* env, jobject, jobject javaFd, jint how) {
228659e4744d27231f260271dbbca406e0cc39768116Elliott Hughes    int fd = jniGetFDFromFileDescriptor(env, javaFd);
228759e4744d27231f260271dbbca406e0cc39768116Elliott Hughes    throwIfMinusOne(env, "shutdown", TEMP_FAILURE_RETRY(shutdown(fd, how)));
228859e4744d27231f260271dbbca406e0cc39768116Elliott Hughes}
228959e4744d27231f260271dbbca406e0cc39768116Elliott Hughes
22900965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_socket(JNIEnv* env, jobject, jint domain, jint type, jint protocol) {
229100bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    if (domain == AF_PACKET) {
229200bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti        protocol = htons(protocol);  // Packet sockets specify the protocol in host byte order.
229300bb2a5e5d619cbfd172793ca9bf7130192765ebLorenzo Colitti    }
2294454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes    int fd = throwIfMinusOne(env, "socket", TEMP_FAILURE_RETRY(socket(domain, type, protocol)));
2295454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes    return fd != -1 ? jniCreateFileDescriptor(env, fd) : NULL;
2296454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes}
2297454a95f6a28855aa3c88d168b15a45bf315efc99Elliott Hughes
22980965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_socketpair(JNIEnv* env, jobject, jint domain, jint type, jint protocol, jobject javaFd1, jobject javaFd2) {
22993218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes    int fds[2];
23003218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes    int rc = throwIfMinusOne(env, "socketpair", TEMP_FAILURE_RETRY(socketpair(domain, type, protocol, fds)));
23013218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes    if (rc != -1) {
23023218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes        jniSetFileDescriptorOfFD(env, javaFd1, fds[0]);
23033218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes        jniSetFileDescriptorOfFD(env, javaFd2, fds[1]);
23043218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes    }
23053218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes}
23063218082325b6b8713a8ac15731482e3da86a7df9Elliott Hughes
23075310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniakstatic jlong Linux_splice(JNIEnv* env, jobject, jobject javaFdIn, jobject javaOffIn, jobject javaFdOut, jobject javaOffOut, jlong len, jint flags) {
23085310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak    int fdIn = jniGetFDFromFileDescriptor(env, javaFdIn);
23095310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak    int fdOut = jniGetFDFromFileDescriptor(env, javaFdOut);
23105310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak    int spliceErrno;
23115310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak
23125310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak    jlong offIn = (javaOffIn == NULL ? 0 : env->GetLongField(javaOffIn, int64RefValueFid));
23135310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak    jlong offOut = (javaOffOut == NULL ? 0 : env->GetLongField(javaOffOut, int64RefValueFid));
23145310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak    jlong ret = -1;
23155310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak    do {
23165310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak        bool wasSignaled = false;
23175310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak        {
23185310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak            AsynchronousCloseMonitor monitorIn(fdIn);
23195310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak            AsynchronousCloseMonitor monitorOut(fdOut);
23205310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak            ret = splice(fdIn, (javaOffIn == NULL ? NULL : &offIn),
23215310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak                   fdOut, (javaOffOut == NULL ? NULL : &offOut),
23225310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak                   len, flags);
23235310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak            spliceErrno = errno;
23245310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak            wasSignaled = monitorIn.wasSignaled() || monitorOut.wasSignaled();
23255310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak        }
23265310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak        if (wasSignaled) {
23275310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak            jniThrowException(env, "java/io/InterruptedIOException", "splice interrupted");
23285310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak            ret = -1;
23295310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak            break;
23305310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak        }
23315310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak        if (ret == -1 && spliceErrno != EINTR) {
23325310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak            throwErrnoException(env, "splice");
23335310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak            break;
23345310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak        }
23355310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak    } while (ret == -1);
23365310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak    if (ret == -1) {
23375310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak        /* If the syscall failed, re-set errno: throwing an exception might have modified it. */
23385310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak        errno = spliceErrno;
23395310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak    } else {
23405310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak        if (javaOffIn != NULL) {
23415310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak            env->SetLongField(javaOffIn, int64RefValueFid, offIn);
23425310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak        }
23435310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak        if (javaOffOut != NULL) {
23445310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak            env->SetLongField(javaOffOut, int64RefValueFid, offOut);
23455310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak        }
23465310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak    }
23475310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak    return ret;
23485310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak}
23495310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak
23505310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak
23510965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_stat(JNIEnv* env, jobject, jstring javaPath) {
235247cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes    return doStat(env, javaPath, false);
235347cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes}
235447cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes
23550965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_statvfs(JNIEnv* env, jobject, jstring javaPath) {
235659fa7163774d6930a174bc038414a4b780581957Elliott Hughes    ScopedUtfChars path(env, javaPath);
235759fa7163774d6930a174bc038414a4b780581957Elliott Hughes    if (path.c_str() == NULL) {
235859fa7163774d6930a174bc038414a4b780581957Elliott Hughes        return NULL;
235959fa7163774d6930a174bc038414a4b780581957Elliott Hughes    }
2360721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    struct statvfs sb;
2361721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    int rc = TEMP_FAILURE_RETRY(statvfs(path.c_str(), &sb));
236259fa7163774d6930a174bc038414a4b780581957Elliott Hughes    if (rc == -1) {
2363721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes        throwErrnoException(env, "statvfs");
236459fa7163774d6930a174bc038414a4b780581957Elliott Hughes        return NULL;
236559fa7163774d6930a174bc038414a4b780581957Elliott Hughes    }
2366721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes    return makeStructStatVfs(env, sb);
236759fa7163774d6930a174bc038414a4b780581957Elliott Hughes}
236859fa7163774d6930a174bc038414a4b780581957Elliott Hughes
23690965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_strerror(JNIEnv* env, jobject, jint errnum) {
237052724d3ebd4ccaaa4b9f5576e329d4272cde8ea9Elliott Hughes    char buffer[BUFSIZ];
2371ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    const char* message = jniStrError(errnum, buffer, sizeof(buffer));
2372ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    return env->NewStringUTF(message);
2373ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes}
2374ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes
23750965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jstring Linux_strsignal(JNIEnv* env, jobject, jint signal) {
2376763f8ed6195707d0c30bfae1ca8a3bb886b746ccElliott Hughes    return env->NewStringUTF(strsignal(signal));
2377763f8ed6195707d0c30bfae1ca8a3bb886b746ccElliott Hughes}
2378763f8ed6195707d0c30bfae1ca8a3bb886b746ccElliott Hughes
23790965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_symlink(JNIEnv* env, jobject, jstring javaOldPath, jstring javaNewPath) {
2380a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    ScopedUtfChars oldPath(env, javaOldPath);
2381a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    if (oldPath.c_str() == NULL) {
2382a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes        return;
2383a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    }
2384a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    ScopedUtfChars newPath(env, javaNewPath);
2385a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    if (newPath.c_str() == NULL) {
2386a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes        return;
2387a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    }
2388a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes    throwIfMinusOne(env, "symlink", TEMP_FAILURE_RETRY(symlink(oldPath.c_str(), newPath.c_str())));
2389a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes}
2390a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes
23910965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jlong Linux_sysconf(JNIEnv* env, jobject, jint name) {
23926fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes    // Since -1 is a valid result from sysconf(3), detecting failure is a little more awkward.
23936fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes    errno = 0;
23946fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes    long result = sysconf(name);
23956fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes    if (result == -1L && errno == EINVAL) {
23967e25eff38a191d9c19e45093f4fde5102fb09d78Elliott Hughes        throwErrnoException(env, "sysconf");
23976fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes    }
23986fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes    return result;
23996fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes}
24006fc1a0e1e68dc2e0d12341548e58fa7f1c5dafc4Elliott Hughes
24010965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_tcdrain(JNIEnv* env, jobject, jobject javaFd) {
2402bb5816aa1626eb2f6263bd21479600b114c8a1bdJohan Redestig    int fd = jniGetFDFromFileDescriptor(env, javaFd);
2403bb5816aa1626eb2f6263bd21479600b114c8a1bdJohan Redestig    throwIfMinusOne(env, "tcdrain", TEMP_FAILURE_RETRY(tcdrain(fd)));
2404bb5816aa1626eb2f6263bd21479600b114c8a1bdJohan Redestig}
2405bb5816aa1626eb2f6263bd21479600b114c8a1bdJohan Redestig
24060965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_tcsendbreak(JNIEnv* env, jobject, jobject javaFd, jint duration) {
2407039f7599559fd7e48c354b99dcb94ff391f53349Elliott Hughes  int fd = jniGetFDFromFileDescriptor(env, javaFd);
2408039f7599559fd7e48c354b99dcb94ff391f53349Elliott Hughes  throwIfMinusOne(env, "tcsendbreak", TEMP_FAILURE_RETRY(tcsendbreak(fd, duration)));
2409039f7599559fd7e48c354b99dcb94ff391f53349Elliott Hughes}
2410039f7599559fd7e48c354b99dcb94ff391f53349Elliott Hughes
24110965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_umaskImpl(JNIEnv*, jobject, jint mask) {
241244f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes    return umask(mask);
241344f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes}
241444f7875f2985d7944c5afecc8394ad9f2219c806Elliott Hughes
24150965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jobject Linux_uname(JNIEnv* env, jobject) {
24167341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes    struct utsname buf;
24179b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes    if (TEMP_FAILURE_RETRY(uname(&buf)) == -1) {
24189b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes        return NULL; // Can't happen.
24197341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes    }
24207341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes    return makeStructUtsname(env, buf);
24217341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes}
24227341b9ed7157a1e37a3e69a0974676da358b735aElliott Hughes
24230965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_unlink(JNIEnv* env, jobject, jstring javaPathname) {
24245e8f82f2592498e75ac4685ccd0d31d601d37bdcNeil Fuller    ScopedUtfChars pathname(env, javaPathname);
24255e8f82f2592498e75ac4685ccd0d31d601d37bdcNeil Fuller    if (pathname.c_str() == NULL) {
24265e8f82f2592498e75ac4685ccd0d31d601d37bdcNeil Fuller        return;
24275e8f82f2592498e75ac4685ccd0d31d601d37bdcNeil Fuller    }
24285e8f82f2592498e75ac4685ccd0d31d601d37bdcNeil Fuller    throwIfMinusOne(env, "unlink", unlink(pathname.c_str()));
24295e8f82f2592498e75ac4685ccd0d31d601d37bdcNeil Fuller}
24305e8f82f2592498e75ac4685ccd0d31d601d37bdcNeil Fuller
24310965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic void Linux_unsetenv(JNIEnv* env, jobject, jstring javaName) {
2432895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    ScopedUtfChars name(env, javaName);
2433895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    if (name.c_str() == NULL) {
2434895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes        return;
2435895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    }
2436895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes    throwIfMinusOne(env, "unsetenv", unsetenv(name.c_str()));
2437895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes}
2438895a613aa2aec6aa6d03b29755cf2fea584909adElliott Hughes
24390965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_waitpid(JNIEnv* env, jobject, jint pid, jobject javaStatus, jint options) {
24409e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes    int status;
24419e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes    int rc = throwIfMinusOne(env, "waitpid", TEMP_FAILURE_RETRY(waitpid(pid, &status, options)));
244250e20daf19d19acd61bb2ac0fddf4be09814defbTobias Thierer    if (javaStatus != NULL && rc != -1) {
2443e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer        env->SetIntField(javaStatus, int32RefValueFid, status);
24449e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes    }
24459e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes    return rc;
24469e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes}
24479e67ca71d3d4a489a157abadc5ba519ced7a0b50Elliott Hughes
24480965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_writeBytes(JNIEnv* env, jobject, jobject javaFd, jbyteArray javaBytes, jint byteOffset, jint byteCount) {
24490568a63ba1086a78ffb4cff68dd2eac4f9908e13Elliott Hughes    ScopedBytesRO bytes(env, javaBytes);
245078c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes    if (bytes.get() == NULL) {
245178c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes        return -1;
245278c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes    }
2453f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    return IO_FAILURE_RETRY(env, ssize_t, write, javaFd, bytes.get() + byteOffset, byteCount);
245478c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes}
245578c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes
24560965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampestatic jint Linux_writev(JNIEnv* env, jobject, jobject javaFd, jobjectArray buffers, jintArray offsets, jintArray byteCounts) {
24578dc754726bb5303c25e2c48decdf76d9323ee231Elliott Hughes    IoVec<ScopedBytesRO> ioVec(env, env->GetArrayLength(buffers));
2458bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    if (!ioVec.init(buffers, offsets, byteCounts)) {
2459bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes        return -1;
2460bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes    }
2461f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller    return IO_FAILURE_RETRY(env, ssize_t, writev, javaFd, ioVec.get(), ioVec.size());
2462bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes}
2463bbac92e691de7d570928ddfba639067978e55b06Elliott Hughes
24648f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline#define NATIVE_METHOD_OVERLOAD(className, functionName, signature, variant) \
24658f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline    { #functionName, signature, reinterpret_cast<void*>(className ## _ ## functionName ## variant) }
24668f5b46d72e5c1b1b1dd4357580c4fb5a60e3f4deErik Kline
2467ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughesstatic JNINativeMethod gMethods[] = {
24680965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, accept, "(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)Ljava/io/FileDescriptor;"),
24690965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, access, "(Ljava/lang/String;I)Z"),
24700965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, android_getaddrinfo, "(Ljava/lang/String;Landroid/system/StructAddrinfo;I)[Ljava/net/InetAddress;"),
24710965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, bind, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
24720965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD_OVERLOAD(Linux, bind, "(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)V", SocketAddress),
24735744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    NATIVE_METHOD(Linux, capget,
24745744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe                  "(Landroid/system/StructCapUserHeader;)[Landroid/system/StructCapUserData;"),
24755744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe    NATIVE_METHOD(Linux, capset,
24765744e4a762ca12243b47dd8aed24d87d963b4d3bAndreas Gampe                  "(Landroid/system/StructCapUserHeader;[Landroid/system/StructCapUserData;)V"),
24770965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, chmod, "(Ljava/lang/String;I)V"),
24780965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, chown, "(Ljava/lang/String;II)V"),
24790965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, close, "(Ljava/io/FileDescriptor;)V"),
24800965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, connect, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
24810965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD_OVERLOAD(Linux, connect, "(Ljava/io/FileDescriptor;Ljava/net/SocketAddress;)V", SocketAddress),
24820965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, dup, "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;"),
24830965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, dup2, "(Ljava/io/FileDescriptor;I)Ljava/io/FileDescriptor;"),
24840965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, environ, "()[Ljava/lang/String;"),
24850965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, execv, "(Ljava/lang/String;[Ljava/lang/String;)V"),
24860965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, execve, "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V"),
24870965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fchmod, "(Ljava/io/FileDescriptor;I)V"),
24880965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fchown, "(Ljava/io/FileDescriptor;II)V"),
24890965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fcntlFlock, "(Ljava/io/FileDescriptor;ILandroid/system/StructFlock;)I"),
24900965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fcntlInt, "(Ljava/io/FileDescriptor;II)I"),
24910965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fcntlVoid, "(Ljava/io/FileDescriptor;I)I"),
24920965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fdatasync, "(Ljava/io/FileDescriptor;)V"),
24930965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fstat, "(Ljava/io/FileDescriptor;)Landroid/system/StructStat;"),
24940965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fstatvfs, "(Ljava/io/FileDescriptor;)Landroid/system/StructStatVfs;"),
24950965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, fsync, "(Ljava/io/FileDescriptor;)V"),
24960965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, ftruncate, "(Ljava/io/FileDescriptor;J)V"),
24970965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, gai_strerror, "(I)Ljava/lang/String;"),
24980965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getegid, "()I"),
24990965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, geteuid, "()I"),
25000965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getgid, "()I"),
25010965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getenv, "(Ljava/lang/String;)Ljava/lang/String;"),
25020965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getnameinfo, "(Ljava/net/InetAddress;I)Ljava/lang/String;"),
25030965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getpeername, "(Ljava/io/FileDescriptor;)Ljava/net/SocketAddress;"),
25040965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getpgid, "(I)I"),
25050965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getpid, "()I"),
25060965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getppid, "()I"),
25070965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getpwnam, "(Ljava/lang/String;)Landroid/system/StructPasswd;"),
25080965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getpwuid, "(I)Landroid/system/StructPasswd;"),
2509e873cd1285c04da110758df066b4bd40ad6eb93dNarayan Kamath    NATIVE_METHOD(Linux, getrlimit, "(I)Landroid/system/StructRlimit;"),
25100965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getsockname, "(Ljava/io/FileDescriptor;)Ljava/net/SocketAddress;"),
25110965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getsockoptByte, "(Ljava/io/FileDescriptor;II)I"),
25120965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getsockoptInAddr, "(Ljava/io/FileDescriptor;II)Ljava/net/InetAddress;"),
25130965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getsockoptInt, "(Ljava/io/FileDescriptor;II)I"),
25140965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getsockoptLinger, "(Ljava/io/FileDescriptor;II)Landroid/system/StructLinger;"),
25150965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getsockoptTimeval, "(Ljava/io/FileDescriptor;II)Landroid/system/StructTimeval;"),
25160965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getsockoptUcred, "(Ljava/io/FileDescriptor;II)Landroid/system/StructUcred;"),
25170965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, gettid, "()I"),
25180965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getuid, "()I"),
25190965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getxattr, "(Ljava/lang/String;Ljava/lang/String;)[B"),
25200965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, getifaddrs, "()[Landroid/system/StructIfaddrs;"),
25210965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, if_indextoname, "(I)Ljava/lang/String;"),
25220965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, if_nametoindex, "(Ljava/lang/String;)I"),
25230965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, inet_pton, "(ILjava/lang/String;)Ljava/net/InetAddress;"),
25240965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, ioctlFlags, "(Ljava/io/FileDescriptor;Ljava/lang/String;)I"),
25250965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, ioctlInetAddress, "(Ljava/io/FileDescriptor;ILjava/lang/String;)Ljava/net/InetAddress;"),
2526e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    NATIVE_METHOD(Linux, ioctlInt, "(Ljava/io/FileDescriptor;ILandroid/system/Int32Ref;)I"),
25270965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, ioctlMTU, "(Ljava/io/FileDescriptor;Ljava/lang/String;)I"),
25280965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, isatty, "(Ljava/io/FileDescriptor;)Z"),
25290965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, kill, "(II)V"),
25300965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, lchown, "(Ljava/lang/String;II)V"),
25310965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, link, "(Ljava/lang/String;Ljava/lang/String;)V"),
25320965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, listen, "(Ljava/io/FileDescriptor;I)V"),
25330965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, listxattr, "(Ljava/lang/String;)[Ljava/lang/String;"),
25340965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, lseek, "(Ljava/io/FileDescriptor;JI)J"),
25350965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, lstat, "(Ljava/lang/String;)Landroid/system/StructStat;"),
25360965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, mincore, "(JJ[B)V"),
25370965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, mkdir, "(Ljava/lang/String;I)V"),
25380965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, mkfifo, "(Ljava/lang/String;I)V"),
25390965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, mlock, "(JJ)V"),
25400965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, mmap, "(JJIILjava/io/FileDescriptor;J)J"),
25410965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, msync, "(JJI)V"),
25420965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, munlock, "(JJ)V"),
25430965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, munmap, "(JJ)V"),
25440965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, open, "(Ljava/lang/String;II)Ljava/io/FileDescriptor;"),
25450965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, pipe2, "(I)[Ljava/io/FileDescriptor;"),
25460965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, poll, "([Landroid/system/StructPollfd;I)I"),
25470965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, posix_fallocate, "(Ljava/io/FileDescriptor;JJ)V"),
25480965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, prctl, "(IJJJJ)I"),
25490965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, preadBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;IIJ)I"),
25500965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, pwriteBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;IIJ)I"),
25510965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, readBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;II)I"),
25520965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, readlink, "(Ljava/lang/String;)Ljava/lang/String;"),
25530965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, realpath, "(Ljava/lang/String;)Ljava/lang/String;"),
25540965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, readv, "(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I"),
25550965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, recvfromBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;IIILjava/net/InetSocketAddress;)I"),
25560965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, remove, "(Ljava/lang/String;)V"),
25570965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, removexattr, "(Ljava/lang/String;Ljava/lang/String;)V"),
25580965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, rename, "(Ljava/lang/String;Ljava/lang/String;)V"),
2559e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    NATIVE_METHOD(Linux, sendfile, "(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Landroid/system/Int64Ref;J)J"),
25600965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, sendtoBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;IIILjava/net/InetAddress;I)I"),
25610965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD_OVERLOAD(Linux, sendtoBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;IIILjava/net/SocketAddress;)I", SocketAddress),
25620965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setegid, "(I)V"),
25630965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setenv, "(Ljava/lang/String;Ljava/lang/String;Z)V"),
25640965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, seteuid, "(I)V"),
25650965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setgid, "(I)V"),
25660965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setpgid, "(II)V"),
25670965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setregid, "(II)V"),
25680965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setreuid, "(II)V"),
25690965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsid, "()I"),
25700965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsockoptByte, "(Ljava/io/FileDescriptor;III)V"),
25710965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsockoptIfreq, "(Ljava/io/FileDescriptor;IILjava/lang/String;)V"),
25720965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsockoptInt, "(Ljava/io/FileDescriptor;III)V"),
25730965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsockoptIpMreqn, "(Ljava/io/FileDescriptor;III)V"),
25740965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsockoptGroupReq, "(Ljava/io/FileDescriptor;IILandroid/system/StructGroupReq;)V"),
25750965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsockoptLinger, "(Ljava/io/FileDescriptor;IILandroid/system/StructLinger;)V"),
25760965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setsockoptTimeval, "(Ljava/io/FileDescriptor;IILandroid/system/StructTimeval;)V"),
25770965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setuid, "(I)V"),
25780965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, setxattr, "(Ljava/lang/String;Ljava/lang/String;[BI)V"),
25790965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, shutdown, "(Ljava/io/FileDescriptor;I)V"),
25800965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, socket, "(III)Ljava/io/FileDescriptor;"),
25810965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, socketpair, "(IIILjava/io/FileDescriptor;Ljava/io/FileDescriptor;)V"),
25825310ea4af51082e4a775d31615daaa59754d003ePrzemyslaw Szczepaniak    NATIVE_METHOD(Linux, splice, "(Ljava/io/FileDescriptor;Landroid/system/Int64Ref;Ljava/io/FileDescriptor;Landroid/system/Int64Ref;JI)J"),
25830965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, stat, "(Ljava/lang/String;)Landroid/system/StructStat;"),
25840965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, statvfs, "(Ljava/lang/String;)Landroid/system/StructStatVfs;"),
25850965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, strerror, "(I)Ljava/lang/String;"),
25860965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, strsignal, "(I)Ljava/lang/String;"),
25870965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, symlink, "(Ljava/lang/String;Ljava/lang/String;)V"),
25880965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, sysconf, "(I)J"),
25890965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, tcdrain, "(Ljava/io/FileDescriptor;)V"),
25900965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, tcsendbreak, "(Ljava/io/FileDescriptor;I)V"),
25910965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, umaskImpl, "(I)I"),
25920965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, uname, "()Landroid/system/StructUtsname;"),
25930965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, unlink, "(Ljava/lang/String;)V"),
25940965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, unsetenv, "(Ljava/lang/String;)V"),
2595e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    NATIVE_METHOD(Linux, waitpid, "(ILandroid/system/Int32Ref;I)I"),
25960965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, writeBytes, "(Ljava/io/FileDescriptor;Ljava/lang/Object;II)I"),
25970965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    NATIVE_METHOD(Linux, writev, "(Ljava/io/FileDescriptor;[Ljava/lang/Object;[I[I)I"),
2598ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes};
25990965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampevoid register_libcore_io_Linux(JNIEnv* env) {
26002c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe    // Note: it is safe to only cache the fields as boot classpath classes are never
26012c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe    //       unloaded.
2602e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    ScopedLocalRef<jclass> int32RefClass(env, env->FindClass("android/system/Int32Ref"));
2603e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    CHECK(int32RefClass != nullptr);
2604e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    int32RefValueFid = env->GetFieldID(int32RefClass.get(), "value", "I");
2605e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    CHECK(int32RefValueFid != nullptr);
2606e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer
2607e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    ScopedLocalRef<jclass> int64RefClass(env, env->FindClass("android/system/Int64Ref"));
2608e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    CHECK(int64RefClass != nullptr);
2609e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    int64RefValueFid = env->GetFieldID(int64RefClass.get(), "value", "J");
2610e3a3a06a94a50d31b7033e496f23becb0f1329c7Tobias Thierer    CHECK(int64RefValueFid != nullptr);
26112c549f1ba3fb683ab1c4ede75bdcb312e8769672Andreas Gampe
26120965ac3ceff49f3c090c417c0e30ea51c6f294a7Andreas Gampe    jniRegisterNativeMethods(env, "libcore/io/Linux", gMethods, NELEM(gMethods));
2613ec617e2cb4a374f0fd8fbda4a633214cf23a59a9Elliott Hughes}
2614