• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package libcore.android.system;
18 
19 import android.system.ErrnoException;
20 import android.system.Int64Ref;
21 import android.system.NetlinkSocketAddress;
22 import android.system.Os;
23 import android.system.OsConstants;
24 import android.system.PacketSocketAddress;
25 import android.system.StructCmsghdr;
26 import android.system.StructMsghdr;
27 import android.system.StructRlimit;
28 import android.system.StructStat;
29 import android.system.StructTimespec;
30 import android.system.StructTimeval;
31 import android.system.StructUcred;
32 import android.system.UnixSocketAddress;
33 import android.system.VmSocketAddress;
34 
35 import java.io.BufferedReader;
36 import java.io.File;
37 import java.io.FileDescriptor;
38 import java.io.FileInputStream;
39 import java.io.FileOutputStream;
40 import java.io.FileWriter;
41 import java.io.IOException;
42 import java.io.InputStreamReader;
43 import java.net.DatagramPacket;
44 import java.net.DatagramSocket;
45 import java.net.Inet4Address;
46 import java.net.Inet6Address;
47 import java.net.InetAddress;
48 import java.net.InetSocketAddress;
49 import java.net.NetworkInterface;
50 import java.net.ServerSocket;
51 import java.net.SocketAddress;
52 import java.net.SocketException;
53 import java.nio.ByteBuffer;
54 import java.nio.ByteOrder;
55 import java.nio.charset.StandardCharsets;
56 import java.nio.file.Files;
57 import java.nio.file.Path;
58 import java.time.Duration;
59 import java.util.Arrays;
60 import java.util.Collections;
61 import java.util.Enumeration;
62 import java.util.List;
63 import java.util.Locale;
64 import java.util.Map;
65 import java.util.concurrent.atomic.AtomicReference;
66 import java.util.regex.Matcher;
67 import java.util.regex.Pattern;
68 
69 import java.util.stream.Collectors;
70 import java.util.stream.Stream;
71 
72 import libcore.io.IoUtils;
73 import libcore.testing.io.TestIoUtils;
74 
75 import org.junit.Assert;
76 import org.junit.Test;
77 import org.junit.runner.RunWith;
78 import org.junit.runners.JUnit4;
79 
80 import static android.system.OsConstants.*;
81 import static org.junit.Assert.assertArrayEquals;
82 import static org.junit.Assert.assertEquals;
83 import static org.junit.Assert.assertFalse;
84 import static org.junit.Assert.assertNotEquals;
85 import static org.junit.Assert.assertNotNull;
86 import static org.junit.Assert.assertNull;
87 import static org.junit.Assert.assertThrows;
88 import static org.junit.Assert.assertTrue;
89 import static org.junit.Assert.fail;
90 import static org.junit.Assume.assumeNoException;
91 import static org.junit.Assume.assumeTrue;
92 
93 import jdk.internal.misc.Unsafe;
94 
95 @RunWith(JUnit4.class)
96 public class OsTest {
97 
98     @Test
testIsSocket()99     public void testIsSocket() throws Exception {
100         File f = new File("/dev/null");
101         FileInputStream fis = new FileInputStream(f);
102         assertFalse(S_ISSOCK(Os.fstat(fis.getFD()).st_mode));
103         fis.close();
104 
105         ServerSocket s = new ServerSocket();
106         assertTrue(S_ISSOCK(Os.fstat(s.getImpl().getFD$()).st_mode));
107         s.close();
108     }
109 
110     @Test
testFcntlInt()111     public void testFcntlInt() throws Exception {
112         File f = File.createTempFile("OsTest", "tst");
113         FileInputStream fis = null;
114         try {
115             fis = new FileInputStream(f);
116             Os.fcntlInt(fis.getFD(), F_SETFD, FD_CLOEXEC);
117             int flags = Os.fcntlVoid(fis.getFD(), F_GETFD);
118             assertTrue((flags & FD_CLOEXEC) != 0);
119         } finally {
120             TestIoUtils.closeQuietly(fis);
121             f.delete();
122         }
123     }
124 
125     @Test
testFcntlInt_udpSocket()126     public void testFcntlInt_udpSocket() throws Exception {
127         final FileDescriptor fd = Os.socket(AF_INET, SOCK_DGRAM, 0);
128         try {
129             assertEquals(0, (Os.fcntlVoid(fd, F_GETFL) & O_NONBLOCK));
130 
131             // Verify that we can set file descriptor flags on sockets
132             Os.fcntlInt(fd, F_SETFL, SOCK_DGRAM | O_NONBLOCK);
133             assertTrue((Os.fcntlVoid(fd, F_GETFL) & O_NONBLOCK) != 0);
134 
135             // Check that we can turn it off also.
136             Os.fcntlInt(fd, F_SETFL, SOCK_DGRAM);
137             assertEquals(0, (Os.fcntlVoid(fd, F_GETFL) & O_NONBLOCK));
138         } finally {
139             Os.close(fd);
140         }
141     }
142 
143     @Test
testFcntlInt_invalidCmd()144     public void testFcntlInt_invalidCmd() throws Exception {
145         final FileDescriptor fd = Os.socket(AF_INET, SOCK_DGRAM, 0);
146         try {
147             final int unknownCmd = -1;
148             Os.fcntlInt(fd, unknownCmd, 0);
149             fail("Expected failure due to invalid cmd");
150         } catch (ErrnoException expected) {
151             assertEquals(EINVAL, expected.errno);
152         } finally {
153             Os.close(fd);
154         }
155     }
156 
157     @Test
testFcntlInt_nullFd()158     public void testFcntlInt_nullFd() {
159         try {
160             Os.fcntlInt(null, F_SETFL, O_NONBLOCK);
161             fail("Expected failure due to null file descriptor");
162         } catch (ErrnoException expected) {
163             assertEquals(EBADF, expected.errno);
164         }
165     }
166 
167     @Test
testUnixDomainSockets_in_file_system()168     public void testUnixDomainSockets_in_file_system() throws Exception {
169         String path = System.getProperty("java.io.tmpdir") + "/test_unix_socket";
170         new File(path).delete();
171         checkUnixDomainSocket(UnixSocketAddress.createFileSystem(path), false);
172     }
173 
174     @Test
testUnixDomainSocket_abstract_name()175     public void testUnixDomainSocket_abstract_name() throws Exception {
176         // Linux treats a sun_path starting with a NUL byte as an abstract name. See unix(7).
177         checkUnixDomainSocket(UnixSocketAddress.createAbstract("/abstract_name_unix_socket"), true);
178     }
179 
180     @Test
testUnixDomainSocket_unnamed()181     public void testUnixDomainSocket_unnamed() throws Exception {
182         final FileDescriptor fd = Os.socket(AF_UNIX, SOCK_STREAM, 0);
183         // unix(7) says an unbound socket is unnamed.
184         checkNoSockName(fd);
185         Os.close(fd);
186     }
187 
checkUnixDomainSocket(final UnixSocketAddress address, final boolean isAbstract)188     private void checkUnixDomainSocket(final UnixSocketAddress address, final boolean isAbstract)
189             throws Exception {
190         final FileDescriptor serverFd = Os.socket(AF_UNIX, SOCK_STREAM, 0);
191         Os.bind(serverFd, address);
192         Os.listen(serverFd, 5);
193 
194         checkSockName(serverFd, isAbstract, address);
195 
196         Thread server = new Thread(new Runnable() {
197             public void run() {
198                 try {
199                     UnixSocketAddress peerAddress = UnixSocketAddress.createUnnamed();
200                     FileDescriptor clientFd = Os.accept(serverFd, peerAddress);
201                     checkSockName(clientFd, isAbstract, address);
202                     checkNoName(peerAddress);
203 
204                     checkNoPeerName(clientFd);
205 
206                     StructUcred credentials = Os.getsockoptUcred(clientFd, SOL_SOCKET, SO_PEERCRED);
207                     assertEquals(Os.getpid(), credentials.pid);
208                     assertEquals(Os.getuid(), credentials.uid);
209                     assertEquals(Os.getgid(), credentials.gid);
210 
211                     byte[] request = new byte[256];
212                     Os.read(clientFd, request, 0, request.length);
213 
214                     String s = new String(request, StandardCharsets.UTF_8);
215                     byte[] response = s.toUpperCase(Locale.ROOT).getBytes(StandardCharsets.UTF_8);
216                     Os.write(clientFd, response, 0, response.length);
217 
218                     Os.close(clientFd);
219                 } catch (Exception ex) {
220                     throw new RuntimeException(ex);
221                 }
222             }
223         });
224         server.start();
225 
226         FileDescriptor clientFd = Os.socket(AF_UNIX, SOCK_STREAM, 0);
227 
228         Os.connect(clientFd, address);
229         checkNoSockName(clientFd);
230 
231         String string = "hello, world!";
232 
233         byte[] request = string.getBytes(StandardCharsets.UTF_8);
234         assertEquals(request.length, Os.write(clientFd, request, 0, request.length));
235 
236         byte[] response = new byte[request.length];
237         assertEquals(response.length, Os.read(clientFd, response, 0, response.length));
238 
239         assertEquals(string.toUpperCase(Locale.ROOT), new String(response, StandardCharsets.UTF_8));
240 
241         Os.close(clientFd);
242     }
243 
checkSockName(FileDescriptor fd, boolean isAbstract, UnixSocketAddress address)244     private static void checkSockName(FileDescriptor fd, boolean isAbstract,
245             UnixSocketAddress address) throws Exception {
246         UnixSocketAddress isa = (UnixSocketAddress) Os.getsockname(fd);
247         assertEquals(address, isa);
248         if (isAbstract) {
249             assertEquals(0, isa.getSunPath()[0]);
250         }
251     }
252 
checkNoName(UnixSocketAddress usa)253     private void checkNoName(UnixSocketAddress usa) {
254         assertEquals(0, usa.getSunPath().length);
255     }
256 
checkNoPeerName(FileDescriptor fd)257     private void checkNoPeerName(FileDescriptor fd) throws Exception {
258         checkNoName((UnixSocketAddress) Os.getpeername(fd));
259     }
260 
checkNoSockName(FileDescriptor fd)261     private void checkNoSockName(FileDescriptor fd) throws Exception {
262         checkNoName((UnixSocketAddress) Os.getsockname(fd));
263     }
264 
265     @Test
test_strsignal()266     public void test_strsignal() {
267         assertEquals("Killed", Os.strsignal(9));
268         assertEquals("Unknown signal -1", Os.strsignal(-1));
269     }
270 
271     @Test
test_byteBufferPositions_write_pwrite()272     public void test_byteBufferPositions_write_pwrite() throws Exception {
273         FileOutputStream fos = new FileOutputStream(new File("/dev/null"));
274         FileDescriptor fd = fos.getFD();
275         final byte[] contents = "goodbye, cruel world".getBytes(StandardCharsets.US_ASCII);
276         ByteBuffer byteBuffer = ByteBuffer.wrap(contents);
277 
278         byteBuffer.position(0);
279         int written = Os.write(fd, byteBuffer);
280         assertTrue(written > 0);
281         assertEquals(written, byteBuffer.position());
282 
283         byteBuffer.position(4);
284         written = Os.write(fd, byteBuffer);
285         assertTrue(written > 0);
286         assertEquals(written + 4, byteBuffer.position());
287 
288         byteBuffer.position(0);
289         written = Os.pwrite(fd, byteBuffer, 64 /* offset */);
290         assertTrue(written > 0);
291         assertEquals(written, byteBuffer.position());
292 
293         byteBuffer.position(4);
294         written = Os.pwrite(fd, byteBuffer, 64 /* offset */);
295         assertTrue(written > 0);
296         assertEquals(written + 4, byteBuffer.position());
297 
298         fos.close();
299     }
300 
301     @Test
test_byteBufferPositions_read_pread()302     public void test_byteBufferPositions_read_pread() throws Exception {
303         FileInputStream fis = new FileInputStream(new File("/dev/zero"));
304         FileDescriptor fd = fis.getFD();
305         ByteBuffer byteBuffer = ByteBuffer.allocate(64);
306 
307         byteBuffer.position(0);
308         int read = Os.read(fd, byteBuffer);
309         assertTrue(read > 0);
310         assertEquals(read, byteBuffer.position());
311 
312         byteBuffer.position(4);
313         read = Os.read(fd, byteBuffer);
314         assertTrue(read > 0);
315         assertEquals(read + 4, byteBuffer.position());
316 
317         byteBuffer.position(0);
318         read = Os.pread(fd, byteBuffer, 64 /* offset */);
319         assertTrue(read > 0);
320         assertEquals(read, byteBuffer.position());
321 
322         byteBuffer.position(4);
323         read = Os.pread(fd, byteBuffer, 64 /* offset */);
324         assertTrue(read > 0);
325         assertEquals(read + 4, byteBuffer.position());
326 
327         fis.close();
328     }
329 
checkByteBufferPositions_sendto_recvfrom( int family, InetAddress loopback)330     private static void checkByteBufferPositions_sendto_recvfrom(
331             int family, InetAddress loopback) throws Exception {
332         final FileDescriptor serverFd = Os.socket(family, SOCK_STREAM, 0);
333         Os.bind(serverFd, loopback, 0);
334         Os.listen(serverFd, 5);
335 
336         InetSocketAddress address = (InetSocketAddress) Os.getsockname(serverFd);
337 
338         final Thread server = new Thread(() -> {
339             try {
340                 InetSocketAddress peerAddress = new InetSocketAddress();
341                 FileDescriptor clientFd = Os.accept(serverFd, peerAddress);
342 
343                 // Attempt to receive a maximum of 24 bytes from the client, and then
344                 // close the connection.
345                 ByteBuffer buffer = ByteBuffer.allocate(16);
346                 int received = Os.recvfrom(clientFd, buffer, 0, null);
347                 assertTrue(received > 0);
348                 assertEquals(received, buffer.position());
349 
350                 ByteBuffer buffer2 = ByteBuffer.allocate(16);
351                 buffer2.position(8);
352                 received = Os.recvfrom(clientFd, buffer2, 0, null);
353                 assertTrue(received > 0);
354                 assertEquals(received + 8, buffer.position());
355 
356                 Os.close(clientFd);
357             } catch (Exception ex) {
358                 throw new RuntimeException(ex);
359             }
360         });
361 
362         server.start();
363 
364         FileDescriptor clientFd = Os.socket(family, SOCK_STREAM, 0);
365         Os.connect(clientFd, address.getAddress(), address.getPort());
366 
367         final byte[] bytes = "good bye, cruel black hole with fancy distortion"
368                 .getBytes(StandardCharsets.US_ASCII);
369         assertTrue(bytes.length > 24);
370 
371         ByteBuffer input = ByteBuffer.wrap(bytes);
372         input.position(0);
373         input.limit(16);
374 
375         int sent = Os.sendto(clientFd, input, 0, address.getAddress(), address.getPort());
376         assertTrue(sent > 0);
377         assertEquals(sent, input.position());
378 
379         input.position(16);
380         input.limit(24);
381         sent = Os.sendto(clientFd, input, 0, address.getAddress(), address.getPort());
382         assertTrue(sent > 0);
383         assertEquals(sent + 16, input.position());
384 
385         Os.close(clientFd);
386     }
387 
388     private interface ExceptionalRunnable {
run()389         void run() throws Exception;
390     }
391 
392     /**
393      * Expects that the given Runnable will throw an exception of the specified class. If the class
394      * is ErrnoException, and expectedErrno is non-null, also checks that the errno is equal to
395      * expectedErrno.
396      */
expectException(ExceptionalRunnable r, Class<? extends Exception> exClass, Integer expectedErrno, String msg)397     private static void expectException(ExceptionalRunnable r, Class<? extends Exception> exClass,
398             Integer expectedErrno, String msg) {
399         try {
400             r.run();
401             fail(msg + " did not throw exception");
402         } catch (Exception e) {
403             assertEquals(msg + " threw unexpected exception", exClass, e.getClass());
404 
405             if (expectedErrno != null) {
406                 if (e instanceof ErrnoException) {
407                     assertEquals(msg + "threw ErrnoException with unexpected error number",
408                             (int) expectedErrno, ((ErrnoException) e).errno);
409                 } else {
410                     fail("Can only pass expectedErrno when expecting ErrnoException");
411                 }
412             }
413 
414         }
415     }
416 
expectBindException(FileDescriptor socket, SocketAddress addr, Class<? extends Exception> exClass, Integer expectedErrno)417     private static void expectBindException(FileDescriptor socket, SocketAddress addr,
418             Class<? extends Exception> exClass, Integer expectedErrno) {
419         String msg = String.format("bind(%s, %s)", socket, addr);
420         expectException(() -> {
421             Os.bind(socket, addr);
422         }, exClass, expectedErrno, msg);
423     }
424 
expectConnectException(FileDescriptor socket, SocketAddress addr, Class<? extends Exception> exClass, Integer expectedErrno)425     private static void expectConnectException(FileDescriptor socket, SocketAddress addr,
426             Class<? extends Exception> exClass, Integer expectedErrno) {
427         String msg = String.format("connect(%s, %s)", socket, addr);
428         expectException(() -> {
429             Os.connect(socket, addr);
430         }, exClass, expectedErrno, msg);
431     }
432 
expectSendtoException(FileDescriptor socket, SocketAddress addr, Integer expectedErrno)433     private static void expectSendtoException(FileDescriptor socket, SocketAddress addr,
434         Integer expectedErrno) {
435         String msg = String.format("sendto(%s, %s)", socket, addr);
436         byte[] packet = new byte[42];
437         expectException(() -> {
438                     Os.sendto(socket, packet, 0, packet.length, 0, addr);
439                 },
440             ErrnoException.class, expectedErrno, msg);
441     }
442 
expectBindConnectSendtoSuccess(FileDescriptor socket, String socketDesc, SocketAddress addr)443     private static void expectBindConnectSendtoSuccess(FileDescriptor socket, String socketDesc,
444             SocketAddress addr) {
445         String msg = socketDesc + " socket to " + addr.toString();
446 
447         try {
448             try {
449                 // Expect that bind throws when any of its arguments are null.
450                 expectBindException(null, addr, ErrnoException.class, EBADF);
451                 expectBindException(socket, null, NullPointerException.class, null);
452                 expectBindException(null, null, NullPointerException.class, null);
453 
454                 // Expect bind to succeed.
455                 Os.bind(socket, addr);
456 
457                 // Find out which port we're actually bound to, and use that in subsequent connect()
458                 // and send() calls. We can't send to addr because that has a port of 0.
459                 if (addr instanceof InetSocketAddress) {
460                     InetSocketAddress addrISA = (InetSocketAddress) addr;
461                     InetSocketAddress socknameISA = (InetSocketAddress) Os.getsockname(socket);
462 
463                     assertEquals(addrISA.getAddress(), socknameISA.getAddress());
464                     assertEquals(0, addrISA.getPort());
465                     assertNotEquals(0, socknameISA.getPort());
466                     addr = socknameISA;
467                 }
468 
469                 // Expect sendto with a null address to throw because the socket is not connected,
470                 // but to succeed with a non-null address.
471                 byte[] packet = new byte[42];
472                 Os.sendto(socket, packet, 0, packet.length, 0, addr);
473                 // UNIX and IP sockets return different errors for this operation, so we can't check
474                 // errno.
475                 expectSendtoException(socket, null, null);
476                 expectSendtoException(null, null, EBADF);
477                 expectSendtoException(null, addr, EBADF);
478 
479                 // Expect that connect throws when any of its arguments are null.
480                 expectConnectException(null, addr, ErrnoException.class, EBADF);
481                 expectConnectException(socket, null, NullPointerException.class, null);
482                 expectConnectException(null, null, NullPointerException.class, null);
483 
484                 // Expect connect to succeed.
485                 Os.connect(socket, addr);
486                 assertEquals(Os.getsockname(socket), Os.getpeername(socket));
487 
488                 // Expect sendto to succeed both when given an explicit address and a null address.
489                 Os.sendto(socket, packet, 0, packet.length, 0, addr);
490                 Os.sendto(socket, packet, 0, packet.length, 0, null);
491             } catch (SocketException | ErrnoException e) {
492                 fail("Expected success for " + msg + ", but got: " + e);
493             }
494 
495         } finally {
496             IoUtils.closeQuietly(socket);
497         }
498     }
499 
expectBindConnectSendtoErrno(int bindErrno, int connectErrno, int sendtoErrno, FileDescriptor socket, String socketDesc, SocketAddress addr)500     private static void expectBindConnectSendtoErrno(int bindErrno, int connectErrno,
501             int sendtoErrno, FileDescriptor socket, String socketDesc, SocketAddress addr) {
502         try {
503 
504             // Expect bind to fail with bindErrno.
505             String msg = "bind " + socketDesc + " socket to " + addr.toString();
506             try {
507                 Os.bind(socket, addr);
508                 fail("Expected to fail " + msg);
509             } catch (ErrnoException e) {
510                 assertEquals("Expected errno " + bindErrno + " " + msg, bindErrno, e.errno);
511             } catch (SocketException e) {
512                 fail("Unexpected SocketException " + msg);
513             }
514 
515             // Expect connect to fail with connectErrno.
516             msg = "connect " + socketDesc + " socket to " + addr.toString();
517             try {
518                 Os.connect(socket, addr);
519                 fail("Expected to fail " + msg);
520             } catch (ErrnoException e) {
521                 assertEquals("Expected errno " + connectErrno + " " + msg, connectErrno, e.errno);
522             } catch (SocketException e) {
523                 fail("Unexpected SocketException " + msg);
524             }
525 
526             // Expect sendto to fail with sendtoErrno.
527             byte[] packet = new byte[42];
528             msg = "sendto " + socketDesc + " socket to " + addr.toString();
529             try {
530                 Os.sendto(socket, packet, 0, packet.length, 0, addr);
531                 fail("Expected to fail " + msg);
532             } catch (ErrnoException e) {
533                 assertEquals("Expected errno " + sendtoErrno + " " + msg, sendtoErrno, e.errno);
534             } catch (SocketException e) {
535                 fail("Unexpected SocketException " + msg);
536             }
537 
538         } finally {
539             // No matter what happened, close the socket.
540             IoUtils.closeQuietly(socket);
541         }
542     }
543 
makeIpv4Socket()544     private FileDescriptor makeIpv4Socket() throws Exception {
545         return Os.socket(AF_INET, SOCK_DGRAM, 0);
546     }
547 
makeIpv6Socket()548     private FileDescriptor makeIpv6Socket() throws Exception {
549         return Os.socket(AF_INET6, SOCK_DGRAM, 0);
550     }
551 
makeUnixSocket()552     private FileDescriptor makeUnixSocket() throws Exception {
553         return Os.socket(AF_UNIX, SOCK_DGRAM, 0);
554     }
555 
556     @Test
testCrossFamilyBindConnectSendto()557     public void testCrossFamilyBindConnectSendto() throws Exception {
558         SocketAddress addrIpv4 = new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0);
559         SocketAddress addrIpv6 = new InetSocketAddress(InetAddress.getByName("::1"), 0);
560         SocketAddress addrUnix = UnixSocketAddress.createAbstract("/abstract_name_unix_socket");
561 
562         expectBindConnectSendtoSuccess(makeIpv4Socket(), "ipv4", addrIpv4);
563         expectBindConnectSendtoErrno(EAFNOSUPPORT, EAFNOSUPPORT, EAFNOSUPPORT,
564                 makeIpv4Socket(), "ipv4", addrIpv6);
565         expectBindConnectSendtoErrno(EAFNOSUPPORT, EAFNOSUPPORT, EAFNOSUPPORT,
566                 makeIpv4Socket(), "ipv4", addrUnix);
567 
568         // This succeeds because Java always uses dual-stack sockets and all InetAddress and
569         // InetSocketAddress objects represent IPv4 addresses using IPv4-mapped IPv6 addresses.
570         expectBindConnectSendtoSuccess(makeIpv6Socket(), "ipv6", addrIpv4);
571         expectBindConnectSendtoSuccess(makeIpv6Socket(), "ipv6", addrIpv6);
572         expectBindConnectSendtoErrno(EAFNOSUPPORT, EAFNOSUPPORT, EINVAL,
573                 makeIpv6Socket(), "ipv6", addrUnix);
574 
575         expectBindConnectSendtoErrno(EINVAL, EINVAL, EINVAL,
576                 makeUnixSocket(), "unix", addrIpv4);
577         expectBindConnectSendtoErrno(EINVAL, EINVAL, EINVAL,
578                 makeUnixSocket(), "unix", addrIpv6);
579         expectBindConnectSendtoSuccess(makeUnixSocket(), "unix", addrUnix);
580     }
581 
582     @Test
testUnknownSocketAddressSubclass()583     public void testUnknownSocketAddressSubclass() throws Exception {
584         class MySocketAddress extends SocketAddress {
585 
586         }
587         MySocketAddress myaddr = new MySocketAddress();
588 
589         for (int family : new int[] { AF_INET, AF_INET6, AF_NETLINK }) {
590             FileDescriptor s = Os.socket(family, SOCK_DGRAM, 0);
591             try {
592 
593                 try {
594                     Os.bind(s, myaddr);
595                     fail("bind socket family " + family
596                             + " to unknown SocketAddress subclass succeeded");
597                 } catch (UnsupportedOperationException expected) {
598                 }
599 
600                 try {
601                     Os.connect(s, myaddr);
602                     fail("connect socket family " + family
603                             + " to unknown SocketAddress subclass succeeded");
604                 } catch (UnsupportedOperationException expected) {
605                 }
606 
607                 byte[] msg = new byte[42];
608                 try {
609                     Os.sendto(s, msg, 0, msg.length, 0, myaddr);
610                     fail("sendto socket family " + family
611                             + " to unknown SocketAddress subclass succeeded");
612                 } catch (UnsupportedOperationException expected) {
613                 }
614 
615             } finally {
616                 Os.close(s);
617             }
618         }
619     }
620 
621     @Test
test_NetlinkSocket()622     public void test_NetlinkSocket() throws Exception {
623         FileDescriptor nlSocket = Os.socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
624         try {
625             Os.bind(nlSocket, new NetlinkSocketAddress());
626             // Non-system processes should not be allowed to bind() to NETLINK_ROUTE sockets.
627             // http://b/141455849
628             fail("bind() on NETLINK_ROUTE socket succeeded");
629         } catch (ErrnoException expectedException) {
630             assertEquals(expectedException.errno, EACCES);
631         }
632 
633         NetlinkSocketAddress nlKernel = new NetlinkSocketAddress();
634         Os.connect(nlSocket, nlKernel);
635         NetlinkSocketAddress nlPeer = (NetlinkSocketAddress) Os.getpeername(nlSocket);
636         assertEquals(0, nlPeer.getPortId());
637         assertEquals(0, nlPeer.getGroupsMask());
638         Os.close(nlSocket);
639     }
640 
641     // This test is excluded from CTS via the knownfailures.txt because it requires extra
642     // permissions not available in CTS. To run it you have to use an -eng build and use a tool like
643     // vogar that runs the Android runtime as a privileged user.
644     @Test
test_PacketSocketAddress()645     public void test_PacketSocketAddress() throws Exception {
646         NetworkInterface lo = NetworkInterface.getByName("lo");
647         assertNotNull(lo);
648         FileDescriptor fd = Os.socket(AF_PACKET, SOCK_DGRAM, ETH_P_IPV6);
649         PacketSocketAddress addr =
650                 new PacketSocketAddress(ETH_P_IPV6, lo.getIndex(), null /* sll_addr */);
651         Os.bind(fd, addr);
652 
653         PacketSocketAddress bound = (PacketSocketAddress) Os.getsockname(fd);
654         assertEquals(ETH_P_IPV6, bound.sll_protocol);
655         assertEquals(lo.getIndex(), bound.sll_ifindex);
656         assertEquals(ARPHRD_LOOPBACK, bound.sll_hatype);
657         assertEquals(0, bound.sll_pkttype);
658 
659         // The loopback address is ETH_ALEN bytes long and is all zeros.
660         // http://lxr.free-electrons.com/source/drivers/net/loopback.c?v=3.10#L167
661         assertNotNull(bound.sll_addr);
662         assertEquals(6, bound.sll_addr.length);
663         for (int i = 0; i < 6; i++) {
664             assertEquals(0, bound.sll_addr[i]);
665         }
666 
667         // The following checks that the packet socket address was constructed correctly in a form
668         // that the kernel understands. If the address is correct, the bind should result in a
669         // socket that is listening only for IPv6 packets, and only on loopback.
670 
671         // Send an IPv4 packet on loopback.
672         // We send ourselves an IPv4 packet first. If we don't receive it, that (with high
673         // probability) ensures that the packet socket does not see IPv4 packets.
674         try (DatagramSocket s = new DatagramSocket()) {
675             byte[] packet = new byte[64];
676             s.send(new DatagramPacket(packet, 0, packet.length, Inet4Address.LOOPBACK,
677                     53 /* arbitrary port */));
678         }
679 
680         // Send an IPv6 packet on loopback.
681         // Sending ourselves an IPv6 packet should cause the socket to receive a packet.
682         // The idea is that if the code gets sll_protocol wrong, then the packet socket will receive
683         // no packets and the test will fail.
684         try (DatagramSocket s = new DatagramSocket()) {
685             byte[] packet = new byte[64];
686             s.send(new DatagramPacket(packet, 0, packet.length, Inet6Address.LOOPBACK,
687                     53 /* arbitrary port */));
688         }
689 
690         // Check that the socket associated with fd has received an IPv6 packet, not necessarily the
691         // UDP one we sent above. IPv6 packets always begin with the nibble 6. If we get anything
692         // else it means we're catching non-IPv6 or non-loopback packets unexpectedly. Since the
693         // socket is not discriminating it may catch packets unrelated to this test from things
694         // happening on the device at the same time, so we can't assert too much about the received
695         // packet, i.e. no length / content check.
696         {
697             byte[] receivedPacket = new byte[4096];
698             Os.read(fd, receivedPacket, 0, receivedPacket.length);
699             assertEquals(6, (receivedPacket[0] & 0xf0) >> 4);
700 
701             byte[] sourceAddress = getIPv6AddressBytesAtOffset(receivedPacket, 8);
702             assertArrayEquals(Inet6Address.LOOPBACK.getAddress(), sourceAddress);
703 
704             byte[] destAddress = getIPv6AddressBytesAtOffset(receivedPacket, 24);
705             assertArrayEquals(Inet6Address.LOOPBACK.getAddress(), destAddress);
706         }
707 
708         Os.close(fd);
709     }
710 
711     @Test
test_VmSocketAddress()712     public void test_VmSocketAddress() {
713         try {
714             final VmSocketAddress addr = new VmSocketAddress(111, 222);
715             assertEquals(111, addr.getSvmPort());
716             assertEquals(222, addr.getSvmCid());
717         } catch (UnsupportedOperationException ignore) {
718             assumeNoException(ignore);  // the platform does not support virtio-vsock
719         }
720     }
721 
createVmSocketEchoServer(final FileDescriptor serverFd)722     private static Thread createVmSocketEchoServer(final FileDescriptor serverFd) {
723         return new Thread(new Runnable() {
724             public void run() {
725                 final VmSocketAddress peer =
726                     new VmSocketAddress(VMADDR_PORT_ANY, VMADDR_CID_ANY);
727 
728                 try {
729                     final FileDescriptor clientFd = Os.accept(serverFd, peer);
730                     try {
731                         final byte[] requestBuf = new byte[256];
732                         final int len = Os.read(clientFd, requestBuf, 0, requestBuf.length);
733                         final String request =
734                             new String(requestBuf, 0, len, StandardCharsets.UTF_8);
735                         final byte[] responseBuf =
736                             request.toUpperCase(Locale.ROOT).getBytes(StandardCharsets.UTF_8);
737                         Os.write(clientFd, responseBuf, 0, responseBuf.length);
738                     } finally {
739                         Os.close(clientFd);
740                     }
741                 } catch (Exception e) {
742                     throw new RuntimeException(e);
743                 }
744             }
745         });
746     }
747 
748     @Test
749     public void test_VmSocket() throws Exception {
750         try {
751             final VmSocketAddress serverAddr = new VmSocketAddress(12345, VMADDR_CID_LOCAL);
752 
753             final FileDescriptor serverFd = Os.socket(AF_VSOCK, SOCK_STREAM, 0);
754 
755             try {
756                 Os.bind(serverFd, serverAddr);
757                 Os.listen(serverFd, 3);
758 
759                 final Thread server = createVmSocketEchoServer(serverFd);
760                 server.start();
761 
762                 final FileDescriptor clientFd = Os.socket(AF_VSOCK, SOCK_STREAM, 0);
763                 try {
764                     Os.connect(clientFd, serverAddr);
765 
766                     final String request = "hello, world!";
767                     final byte[] requestBuf = request.getBytes(StandardCharsets.UTF_8);
768 
769                     assertEquals(requestBuf.length,
770                                  Os.write(clientFd, requestBuf, 0, requestBuf.length));
771 
772                     final byte[] responseBuf = new byte[requestBuf.length];
773                     assertEquals(responseBuf.length,
774                                  Os.read(clientFd, responseBuf, 0, responseBuf.length));
775 
776                     final String response = new String(responseBuf, StandardCharsets.UTF_8);
777 
778                     assertEquals(request.toUpperCase(Locale.ROOT), response);
779                 } finally {
780                     Os.close(clientFd);
781                 }
782             } finally {
783                 Os.close(serverFd);
784             }
785         } catch (UnsupportedOperationException ignore) {
786             assumeNoException(ignore);  // the platform does not support virtio-vsock
787         } catch (ErrnoException e) {
788             // the platform does not support vsock
789             assumeTrue(e.errno != EAFNOSUPPORT && e.errno != EACCES);
790             throw e;
791         }
792     }
793 
794     private static byte[] getIPv6AddressBytesAtOffset(byte[] packet, int offsetIndex) {
795         byte[] address = new byte[16];
796         System.arraycopy(packet, offsetIndex, address, 0, 16);
797         return address;
798     }
799 
800     @Test
801     public void test_byteBufferPositions_sendto_recvfrom_af_inet() throws Exception {
802         checkByteBufferPositions_sendto_recvfrom(AF_INET, InetAddress.getByName("127.0.0.1"));
803     }
804 
805     @Test
806     public void test_byteBufferPositions_sendto_recvfrom_af_inet6() throws Exception {
807         checkByteBufferPositions_sendto_recvfrom(AF_INET6, InetAddress.getByName("::1"));
808     }
809 
810     private void checkSendToSocketAddress(int family, InetAddress loopback) throws Exception {
811         FileDescriptor recvFd = Os.socket(family, SOCK_DGRAM, 0);
812         Os.bind(recvFd, loopback, 0);
813         StructTimeval tv = StructTimeval.fromMillis(20);
814         Os.setsockoptTimeval(recvFd, SOL_SOCKET, SO_RCVTIMEO, tv);
815 
816         InetSocketAddress to = ((InetSocketAddress) Os.getsockname(recvFd));
817         FileDescriptor sendFd = Os.socket(family, SOCK_DGRAM, 0);
818         byte[] msg = ("Hello, I'm going to a socket address: " + to.toString()).getBytes(
819             StandardCharsets.UTF_8);
820         int len = msg.length;
821 
822         assertEquals(len, Os.sendto(sendFd, msg, 0, len, 0, to));
823         byte[] received = new byte[msg.length + 42];
824         InetSocketAddress from = new InetSocketAddress();
825         assertEquals(len, Os.recvfrom(recvFd, received, 0, received.length, 0, from));
826         assertEquals(loopback, from.getAddress());
827     }
828 
829     @Test
830     public void test_sendtoSocketAddress_af_inet() throws Exception {
831         checkSendToSocketAddress(AF_INET, InetAddress.getByName("127.0.0.1"));
832     }
833 
834     @Test
835     public void test_sendtoSocketAddress_af_inet6() throws Exception {
836         checkSendToSocketAddress(AF_INET6, InetAddress.getByName("::1"));
837     }
838 
839     private static short asShort(StructCmsghdr cmsg) {
840         ByteBuffer buf = ByteBuffer.wrap(cmsg.cmsg_data).order(ByteOrder.nativeOrder());
841         assertEquals(Short.BYTES, buf.capacity());
842         return buf.getShort();
843     }
844 
845     private static int asInt(StructCmsghdr cmsg) {
846         ByteBuffer buf = ByteBuffer.wrap(cmsg.cmsg_data).order(ByteOrder.nativeOrder());
847         assertEquals(Integer.BYTES, buf.capacity());
848         return buf.getInt();
849     }
850 
851     @Test
852     public void test_StructCmsgHdrConstructors() throws Exception {
853         final StructCmsghdr cmsg1 = new StructCmsghdr(1, 2, (short) 32005);
854         assertEquals(1, cmsg1.cmsg_level);
855         assertEquals(2, cmsg1.cmsg_type);
856         assertEquals(32005, asShort(cmsg1));
857 
858         ByteBuffer buf = ByteBuffer.allocate(Short.BYTES);
859         buf.order(ByteOrder.nativeOrder());
860         buf.putShort((short) 32005);
861         assertArrayEquals(cmsg1.cmsg_data, buf.array());
862 
863         buf = ByteBuffer.allocate(Integer.BYTES);
864         buf.order(ByteOrder.nativeOrder());
865         buf.putInt(1000042);
866 
867         final StructCmsghdr cmsg2 = new StructCmsghdr(456789, 123456, buf.array());
868         assertEquals(456789, cmsg2.cmsg_level);
869         assertEquals(123456, cmsg2.cmsg_type);
870         assertEquals(1000042, asInt(cmsg2));
871         assertArrayEquals(buf.array(), cmsg2.cmsg_data);
872     }
873 
874     /*
875      * Test case for sendmsg with/without GSO in loopback iface,
876      * recvmsg/gro would not happen since in loopback
877      */
878     private void checkSendmsgSocketAddress(int family, InetSocketAddress loopbackAddr,
879             StructMsghdr sendmsgHdr, StructMsghdr recvmsgHdr, int sendSize) throws Exception {
880 
881         FileDescriptor sendFd = Os.socket(family, SOCK_DGRAM, 0);
882         FileDescriptor recvFd = Os.socket(family, SOCK_DGRAM, 0);
883         int rc = 0;
884 
885         //recvmsg cleanup data
886         if (loopbackAddr.getAddress() instanceof Inet6Address) {
887             Os.bind(recvFd, Inet6Address.ANY, loopbackAddr.getPort());
888         } else {
889             Os.bind(recvFd, Inet4Address.ANY, loopbackAddr.getPort());
890         }
891 
892         StructTimeval tv = StructTimeval.fromMillis(20);
893         Os.setsockoptTimeval(recvFd, SOL_SOCKET, SO_RCVTIMEO, tv);
894         Os.setsockoptInt(recvFd, IPPROTO_UDP, UDP_GRO, 1); //enable GRO
895         Os.setsockoptInt(recvFd, SOL_SOCKET, SO_RCVBUF, 1024 * 1024);
896 
897         try {
898             assertEquals(sendSize, Os.sendmsg(sendFd, sendmsgHdr, 0));
899             rc = 0;
900             do {
901                 int temp_rc = Os.recvmsg(recvFd, recvmsgHdr, OsConstants.MSG_TRUNC);
902                 rc += temp_rc;
903                 if (recvmsgHdr.msg_control != null && recvmsgHdr.msg_control.length > 0) {
904                     byte[] sendCmsgByte = sendmsgHdr.msg_control[0].cmsg_data;
905                     byte[] recvCmsgByte = recvmsgHdr.msg_control[0].cmsg_data;
906                     /* Note:
907                      * GSO: is set with Short(2Byte) values;
908                      * GRO: IP stack return with Int(4Bytes) value;
909                      */
910                     assertEquals(
911                             ByteBuffer.wrap(sendCmsgByte).order(
912                                     ByteOrder.nativeOrder()).getShort(0),
913                             ByteBuffer.wrap(recvCmsgByte).order(
914                                     ByteOrder.nativeOrder()).getInt(0));
915                 }
916 
917                 recvmsgHdr = new StructMsghdr(recvmsgHdr.msg_name, recvmsgHdr.msg_iov,
918                                               null,
919                                               recvmsgHdr.msg_flags);
920             }while(rc < sendSize);
921         } finally {
922             Os.close(sendFd);
923             Os.close(recvFd);
924         }
925     }
926 
927     @Test
928     public void test_sendmsg_af_inet_4K() throws Exception {
929         // UDP GRO not required to be enabled on kernels prior to 5.4
930         assumeTrue(kernelIsAtLeast(5, 4));
931 
932         InetSocketAddress loopbackAddr = new InetSocketAddress(InetAddress.getByName("127.0.0.1"),
933                 10234);
934         StructCmsghdr[] cmsg = new StructCmsghdr[1];
935         cmsg[0] = new StructCmsghdr(SOL_UDP, UDP_SEGMENT, (short) 1400);
936 
937         //sendmsg/recvmsg with 1*4K ByteBuffer
938         ByteBuffer[] bufferArray = new ByteBuffer[1];
939         ByteBuffer[] bufferArrayRecv = new ByteBuffer[1];
940         bufferArray[0] = ByteBuffer.allocate(4096);
941         bufferArrayRecv[0] = ByteBuffer.allocate(4096);
942 
943         StructMsghdr sendmsgHdr = new StructMsghdr(loopbackAddr,
944                                                    bufferArray,
945                                                    cmsg, 0);
946         StructMsghdr recvmsgHdr = new StructMsghdr(new InetSocketAddress(),
947                                                    bufferArrayRecv,
948                                                    null, 0);
949 
950         checkSendmsgSocketAddress(AF_INET, loopbackAddr, sendmsgHdr, recvmsgHdr, 4096);
951     }
952 
953     @Test
954     public void test_sendmsg_af_inet6_4K() throws Exception {
955         // UDP GRO not required to be enabled on kernels prior to 5.4
956         assumeTrue(kernelIsAtLeast(5, 4));
957 
958         InetSocketAddress loopbackAddr = new InetSocketAddress(InetAddress.getByName("::1"), 10234);
959         StructCmsghdr[] cmsg = new StructCmsghdr[1];
960         cmsg[0] = new StructCmsghdr(SOL_UDP, UDP_SEGMENT, (short) 1400);
961 
962         //sendmsg/recvmsg with 1*4K ByteBuffer
963         ByteBuffer[] bufferArray = new ByteBuffer[1];
964         ByteBuffer[] bufferArrayRecv = new ByteBuffer[1];
965         bufferArray[0] = ByteBuffer.allocate(4096);
966         bufferArrayRecv[0] = ByteBuffer.allocate(4096);
967 
968         StructMsghdr sendmsgHdr = new StructMsghdr(loopbackAddr,
969                                                    bufferArray,
970                                                    cmsg, 0);
971         StructMsghdr recvmsgHdr = new StructMsghdr(new InetSocketAddress(),
972                                                    bufferArrayRecv,
973                                                    null, 0);
974 
975         checkSendmsgSocketAddress(AF_INET6, loopbackAddr, sendmsgHdr, recvmsgHdr, 4096);
976     }
977 
978     @Test
979     public void test_sendmsg_af_inet6_4K_directBuffer() throws Exception {
980         // UDP GRO not required to be enabled on kernels prior to 5.4
981         assumeTrue(kernelIsAtLeast(5, 4));
982 
983         InetSocketAddress loopbackAddr = new InetSocketAddress(InetAddress.getByName("127.0.0.1"),
984                                                                10234);
985         StructCmsghdr[] cmsg = new StructCmsghdr[1];
986         cmsg[0] = new StructCmsghdr(SOL_UDP, UDP_SEGMENT, (short) 1400);
987 
988         //sendmsg/recvmsg with 1*4K ByteBuffer
989         ByteBuffer[] bufferArray = new ByteBuffer[1];
990         ByteBuffer[] bufferArrayRecv = new ByteBuffer[1];
991         bufferArray[0] = ByteBuffer.allocateDirect(4096); // DirectBuffer
992         bufferArrayRecv[0] = ByteBuffer.allocateDirect(4096); // DirectBuffer
993 
994         StructMsghdr sendmsgHdr = new StructMsghdr(loopbackAddr,
995                                                    bufferArray,
996                                                    cmsg, 0);
997         StructMsghdr recvmsgHdr = new StructMsghdr(new InetSocketAddress(),
998                                                    bufferArrayRecv,
999                                                    null, 0);
1000 
1001         checkSendmsgSocketAddress(AF_INET6, loopbackAddr, sendmsgHdr, recvmsgHdr, 4096);
1002     }
1003 
1004     @Test
1005     public void test_sendmsg_af_inet_16K_recvparts() throws Exception {
1006         // UDP GRO not required to be enabled on kernels prior to 5.4
1007         assumeTrue(kernelIsAtLeast(5, 4));
1008 
1009         InetSocketAddress loopbackAddr = new InetSocketAddress(InetAddress.getByName("127.0.0.1"),
1010                                                                10234);
1011         StructCmsghdr[] cmsg = new StructCmsghdr[1];
1012         cmsg[0] = new StructCmsghdr(SOL_UDP, UDP_SEGMENT, (short) 1400);
1013 
1014         //sendmsg with 4*4K ByteBuffer, recv with 1*4K ByteBuffer(already with MSG_TRUNC option)
1015         ByteBuffer[] bufferArray = new ByteBuffer[4];
1016         ByteBuffer[] bufferArrayRecv = new ByteBuffer[1];
1017         bufferArray[0] = ByteBuffer.allocate(4096);
1018         bufferArray[1] = ByteBuffer.allocate(4096);
1019         bufferArray[2] = ByteBuffer.allocate(4096);
1020         bufferArray[3] = ByteBuffer.allocate(4096);
1021         bufferArrayRecv[0] = ByteBuffer.allocate(4096); //receive only part of data
1022 
1023         StructMsghdr sendmsgHdr = new StructMsghdr(loopbackAddr,
1024                                                    bufferArray,
1025                                                    cmsg, 0);
1026         StructMsghdr recvmsgHdr = new StructMsghdr(new InetSocketAddress(),
1027                                                    bufferArrayRecv,
1028                                                    null, 0);
1029 
1030         checkSendmsgSocketAddress(AF_INET, loopbackAddr, sendmsgHdr, recvmsgHdr, 4096 * 4);
1031     }
1032 
1033     @Test
1034     public void test_sendmsg_af_inet_16K_reciveall() throws Exception {
1035         // UDP GRO not required to be enabled on kernels prior to 5.4
1036         assumeTrue(kernelIsAtLeast(5, 4));
1037 
1038         InetSocketAddress loopbackAddr = new InetSocketAddress(InetAddress.getByName("127.0.0.1"),
1039                                                                10234);
1040         StructCmsghdr[] cmsg = new StructCmsghdr[1];
1041         cmsg[0] = new StructCmsghdr(SOL_UDP, UDP_SEGMENT, (short) 1400);
1042 
1043         // Create sendmsg/recvmsg with 4*4K ByteBuffer
1044         ByteBuffer[] bufferArray = new ByteBuffer[4];
1045         bufferArray[0] = ByteBuffer.allocate(4096);
1046         bufferArray[1] = ByteBuffer.allocate(4096);
1047         bufferArray[2] = ByteBuffer.allocate(4096);
1048         bufferArray[3] = ByteBuffer.allocate(4096);
1049 
1050         StructMsghdr sendmsgHdr = new StructMsghdr(loopbackAddr, bufferArray, cmsg, 0);
1051         StructMsghdr recvmsgHdr = new StructMsghdr(new InetSocketAddress(), bufferArray, null, 0);
1052 
1053         checkSendmsgSocketAddress(AF_INET, loopbackAddr, sendmsgHdr, recvmsgHdr, 4096 * 4);
1054     }
1055 
1056     @Test
1057     public void test_sendmsg_af_inet_16K_receiveall_without_recv_msgname() throws Exception {
1058         // UDP GRO not required to be enabled on kernels prior to 5.4
1059         assumeTrue(kernelIsAtLeast(5, 4));
1060 
1061         InetSocketAddress loopbackAddr = new InetSocketAddress(InetAddress.getByName("127.0.0.1"),
1062                                                                10234);
1063         StructCmsghdr[] cmsg = new StructCmsghdr[1];
1064         cmsg[0] = new StructCmsghdr(SOL_UDP, UDP_SEGMENT, (short) 1400);
1065 
1066         // Create sendmsg/recvmsg with 4*4K ByteBuffer
1067         ByteBuffer[] bufferArray = new ByteBuffer[4];
1068         bufferArray[0] = ByteBuffer.allocate(4096);
1069         bufferArray[1] = ByteBuffer.allocate(4096);
1070         bufferArray[2] = ByteBuffer.allocate(4096);
1071         bufferArray[3] = ByteBuffer.allocate(4096);
1072 
1073         StructMsghdr sendmsgHdr = new StructMsghdr(loopbackAddr, bufferArray, cmsg, 0);
1074         // msg_name is unnecessary.
1075         StructMsghdr recvmsgHdr = new StructMsghdr(null, bufferArray, null, 0);
1076 
1077         checkSendmsgSocketAddress(AF_INET, loopbackAddr, sendmsgHdr, recvmsgHdr, 4096 * 4);
1078     }
1079 
1080     @Test
1081     public void test_sendmsg_af_inet_16K_without_send_msgcontrl() throws Exception {
1082         // UDP GRO not required to be enabled on kernels prior to 5.4
1083         assumeTrue(kernelIsAtLeast(5, 4));
1084 
1085         InetSocketAddress loopbackAddr = new InetSocketAddress(InetAddress.getByName("127.0.0.1"),
1086                                                                10234);
1087 
1088         // Create sendmsg/recvmsg with 4*4K ByteBuffer
1089         ByteBuffer[] bufferArray = new ByteBuffer[4];
1090         bufferArray[0] = ByteBuffer.allocate(4096);
1091         bufferArray[1] = ByteBuffer.allocate(4096);
1092         bufferArray[2] = ByteBuffer.allocate(4096);
1093         bufferArray[3] = ByteBuffer.allocate(4096);
1094 
1095         // GSO will not happen without msgcontrol.
1096         StructMsghdr sendmsgHdr = new StructMsghdr(loopbackAddr, bufferArray, null, 0);
1097         StructMsghdr recvmsgHdr = new StructMsghdr(null, bufferArray, null, 0);
1098 
1099         checkSendmsgSocketAddress(AF_INET, loopbackAddr, sendmsgHdr, recvmsgHdr, 4096 * 4);
1100     }
1101 
1102     @Test
1103     public void test_sendmsg_af_inet_abnormal() throws Exception {
1104         //sendmsg socket set
1105         InetSocketAddress address = new InetSocketAddress(InetAddress.getByName("127.0.0.1"),
1106                                                           10234);
1107         FileDescriptor sendFd = Os.socket(AF_INET, SOCK_DGRAM, 0);
1108 
1109         ByteBuffer[] bufferArray = new ByteBuffer[1];
1110         bufferArray[0] = ByteBuffer.allocate(8192);
1111 
1112         try {
1113             StructMsghdr msgHdr = new StructMsghdr(address, null, null, 0);
1114             Os.sendmsg(sendFd, msgHdr, 0);
1115             fail("Expected NullPointerException due to invalid StructMsghdr.msg_iov(NULL)");
1116         } catch (NullPointerException expected) {
1117         }
1118 
1119         try {
1120             StructMsghdr msgHdr = new StructMsghdr(null, bufferArray, null, 0);
1121             Os.sendmsg(sendFd, msgHdr, 0);
1122             fail("Expected ErrnoException due to invalid StructMsghdr.msg_name(NULL)");
1123         } catch (ErrnoException expected) {
1124             assertEquals("Expected EDESTADDRREQ binding IPv4 socket to ::", EDESTADDRREQ,
1125                     expected.errno);
1126         }
1127 
1128     }
1129 
1130     @Test
1131     public void test_socketFamilies() throws Exception {
1132         FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0);
1133         Os.bind(fd, InetAddress.getByName("::"), 0);
1134         InetSocketAddress localSocketAddress = (InetSocketAddress) Os.getsockname(fd);
1135         assertEquals(Inet6Address.ANY, localSocketAddress.getAddress());
1136 
1137         fd = Os.socket(AF_INET6, SOCK_STREAM, 0);
1138         Os.bind(fd, InetAddress.getByName("0.0.0.0"), 0);
1139         localSocketAddress = (InetSocketAddress) Os.getsockname(fd);
1140         assertEquals(Inet6Address.ANY, localSocketAddress.getAddress());
1141 
1142         fd = Os.socket(AF_INET, SOCK_STREAM, 0);
1143         Os.bind(fd, InetAddress.getByName("0.0.0.0"), 0);
1144         localSocketAddress = (InetSocketAddress) Os.getsockname(fd);
1145         assertEquals(Inet4Address.ANY, localSocketAddress.getAddress());
1146         try {
1147             Os.bind(fd, InetAddress.getByName("::"), 0);
1148             fail("Expected ErrnoException binding IPv4 socket to ::");
1149         } catch (ErrnoException expected) {
1150             assertEquals("Expected EAFNOSUPPORT binding IPv4 socket to ::", EAFNOSUPPORT,
1151                     expected.errno);
1152         }
1153     }
1154 
1155     private static void checkSocketPing(FileDescriptor fd, InetAddress to, byte[] packet,
1156             byte type, byte responseType, boolean useSendto) throws Exception {
1157         int len = packet.length;
1158         packet[0] = type;
1159         if (useSendto) {
1160             assertEquals(len, Os.sendto(fd, packet, 0, len, 0, to, 0));
1161         } else {
1162             Os.connect(fd, to, 0);
1163             assertEquals(len, Os.sendto(fd, packet, 0, len, 0, null, 0));
1164         }
1165 
1166         int icmpId = ((InetSocketAddress) Os.getsockname(fd)).getPort();
1167         byte[] received = new byte[4096];
1168         InetSocketAddress srcAddress = new InetSocketAddress();
1169         assertEquals(len, Os.recvfrom(fd, received, 0, received.length, 0, srcAddress));
1170         assertEquals(to, srcAddress.getAddress());
1171         assertEquals(responseType, received[0]);
1172         assertEquals(received[4], (byte) (icmpId >> 8));
1173         assertEquals(received[5], (byte) (icmpId & 0xff));
1174 
1175         received = Arrays.copyOf(received, len);
1176         received[0] = type;
1177         received[2] = received[3] = 0;  // Checksum.
1178         received[4] = received[5] = 0;  // ICMP ID.
1179         assertArrayEquals(packet, received);
1180     }
1181 
1182     @Test
1183     public void test_socketPing() throws Exception {
1184         final byte ICMP_ECHO = 8, ICMP_ECHOREPLY = 0;
1185         final byte ICMPV6_ECHO_REQUEST = (byte) 128, ICMPV6_ECHO_REPLY = (byte) 129;
1186         final byte[] packet = ("\000\000\000\000" +  // ICMP type, code.
1187                 "\000\000\000\003" +  // ICMP ID (== port), sequence number.
1188                 "Hello myself").getBytes(StandardCharsets.US_ASCII);
1189 
1190         FileDescriptor fd = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
1191         InetAddress ipv6Loopback = InetAddress.getByName("::1");
1192         checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, true);
1193         checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, false);
1194 
1195         fd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
1196         InetAddress ipv4Loopback = InetAddress.getByName("127.0.0.1");
1197         checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, true);
1198         checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, false);
1199     }
1200 
1201     @Test
1202     public void test_Ipv4Fallback() throws Exception {
1203         // This number of iterations gives a ~60% chance of creating the conditions that caused
1204         // http://b/23088314 without making test times too long. On a hammerhead running MRZ37C
1205         // using vogar, this test takes about 4s.
1206         final int ITERATIONS = 10000;
1207         for (int i = 0; i < ITERATIONS; i++) {
1208             FileDescriptor mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1209             try {
1210                 Os.bind(mUdpSock, Inet4Address.ANY, 0);
1211             } catch (ErrnoException e) {
1212                 fail("ErrnoException after " + i + " iterations: " + e);
1213             } finally {
1214                 Os.close(mUdpSock);
1215             }
1216         }
1217     }
1218 
1219     @Test
1220     public void test_unlink() throws Exception {
1221         File f = File.createTempFile("OsTest", "tst");
1222         assertTrue(f.exists());
1223         Os.unlink(f.getAbsolutePath());
1224         assertFalse(f.exists());
1225 
1226         try {
1227             Os.unlink(f.getAbsolutePath());
1228             fail();
1229         } catch (ErrnoException e) {
1230             assertEquals(OsConstants.ENOENT, e.errno);
1231         }
1232     }
1233 
1234     // b/27294715
1235     @Test
1236     public void test_recvfrom_concurrentShutdown() throws Exception {
1237         final FileDescriptor serverFd = Os.socket(AF_INET, SOCK_DGRAM, 0);
1238         Os.bind(serverFd, InetAddress.getByName("127.0.0.1"), 0);
1239         // Set 4s timeout
1240         StructTimeval tv = StructTimeval.fromMillis(4000);
1241         Os.setsockoptTimeval(serverFd, SOL_SOCKET, SO_RCVTIMEO, tv);
1242 
1243         final AtomicReference<Exception> killerThreadException = new AtomicReference<>(
1244             null);
1245         final Thread killer = new Thread(() -> {
1246             try {
1247                 Thread.sleep(2000);
1248                 try {
1249                     Os.shutdown(serverFd, SHUT_RDWR);
1250                 } catch (ErrnoException expected) {
1251                     if (OsConstants.ENOTCONN != expected.errno) {
1252                         killerThreadException.set(expected);
1253                     }
1254                 }
1255             } catch (Exception ex) {
1256                 killerThreadException.set(ex);
1257             }
1258         });
1259         killer.start();
1260 
1261         ByteBuffer buffer = ByteBuffer.allocate(16);
1262         InetSocketAddress srcAddress = new InetSocketAddress();
1263         int received = Os.recvfrom(serverFd, buffer, 0, srcAddress);
1264         assertEquals(0, received);
1265         Os.close(serverFd);
1266 
1267         killer.join();
1268         assertNull(killerThreadException.get());
1269     }
1270 
1271     @Test
1272     public void test_xattr() throws Exception {
1273         final String NAME_TEST = "user.meow";
1274 
1275         final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
1276         final byte[] VALUE_PIE = "pie".getBytes(StandardCharsets.UTF_8);
1277 
1278         File file = File.createTempFile("xattr", "test");
1279         String path = file.getAbsolutePath();
1280 
1281         try {
1282             try {
1283                 Os.getxattr(path, NAME_TEST);
1284                 fail("Expected ENODATA");
1285             } catch (ErrnoException e) {
1286                 assertEquals(OsConstants.ENODATA, e.errno);
1287             }
1288             assertFalse(Arrays.asList(Os.listxattr(path)).contains(NAME_TEST));
1289 
1290             Os.setxattr(path, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
1291             byte[] xattr_create = Os.getxattr(path, NAME_TEST);
1292             assertTrue(Arrays.asList(Os.listxattr(path)).contains(NAME_TEST));
1293             assertEquals(VALUE_CAKE.length, xattr_create.length);
1294             assertStartsWith(VALUE_CAKE, xattr_create);
1295 
1296             try {
1297                 Os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_CREATE);
1298                 fail("Expected EEXIST");
1299             } catch (ErrnoException e) {
1300                 assertEquals(OsConstants.EEXIST, e.errno);
1301             }
1302 
1303             Os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_REPLACE);
1304             byte[] xattr_replace = Os.getxattr(path, NAME_TEST);
1305             assertTrue(Arrays.asList(Os.listxattr(path)).contains(NAME_TEST));
1306             assertEquals(VALUE_PIE.length, xattr_replace.length);
1307             assertStartsWith(VALUE_PIE, xattr_replace);
1308 
1309             Os.removexattr(path, NAME_TEST);
1310             try {
1311                 Os.getxattr(path, NAME_TEST);
1312                 fail("Expected ENODATA");
1313             } catch (ErrnoException e) {
1314                 assertEquals(OsConstants.ENODATA, e.errno);
1315             }
1316             assertFalse(Arrays.asList(Os.listxattr(path)).contains(NAME_TEST));
1317 
1318         } finally {
1319             file.delete();
1320         }
1321     }
1322 
1323     @Test
1324     public void test_xattr_NPE() throws Exception {
1325         File file = File.createTempFile("xattr", "test");
1326         final String path = file.getAbsolutePath();
1327         final String NAME_TEST = "user.meow";
1328         final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
1329 
1330         // getxattr
1331         try {
1332             Os.getxattr(null, NAME_TEST);
1333             fail();
1334         } catch (NullPointerException expected) {
1335         }
1336         try {
1337             Os.getxattr(path, null);
1338             fail();
1339         } catch (NullPointerException expected) {
1340         }
1341 
1342         // listxattr
1343         try {
1344             Os.listxattr(null);
1345             fail();
1346         } catch (NullPointerException expected) {
1347         }
1348 
1349         // removexattr
1350         try {
1351             Os.removexattr(null, NAME_TEST);
1352             fail();
1353         } catch (NullPointerException expected) {
1354         }
1355         try {
1356             Os.removexattr(path, null);
1357             fail();
1358         } catch (NullPointerException expected) {
1359         }
1360 
1361         // setxattr
1362         try {
1363             Os.setxattr(null, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
1364             fail();
1365         } catch (NullPointerException expected) {
1366         }
1367         try {
1368             Os.setxattr(path, null, VALUE_CAKE, OsConstants.XATTR_CREATE);
1369             fail();
1370         } catch (NullPointerException expected) {
1371         }
1372         try {
1373             Os.setxattr(path, NAME_TEST, null, OsConstants.XATTR_CREATE);
1374             fail();
1375         } catch (NullPointerException expected) {
1376         }
1377     }
1378 
1379     @Test
1380     public void test_xattr_Errno() {
1381         final String NAME_TEST = "user.meow";
1382         final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
1383 
1384         // ENOENT, No such file or directory.
1385         try {
1386             Os.getxattr("", NAME_TEST);
1387             fail();
1388         } catch (ErrnoException e) {
1389             assertEquals(ENOENT, e.errno);
1390         }
1391         try {
1392             Os.listxattr("");
1393             fail();
1394         } catch (ErrnoException e) {
1395             assertEquals(ENOENT, e.errno);
1396         }
1397         try {
1398             Os.removexattr("", NAME_TEST);
1399             fail();
1400         } catch (ErrnoException e) {
1401             assertEquals(ENOENT, e.errno);
1402         }
1403         try {
1404             Os.setxattr("", NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
1405             fail();
1406         } catch (ErrnoException e) {
1407             assertEquals(ENOENT, e.errno);
1408         }
1409 
1410         // ENOTSUP, Extended attributes are not supported by the filesystem, or are disabled.
1411         // Since kernel version 4.9 (or some other version after 4.4), *xattr() methods
1412         // may set errno to EACCES instead. This behavior change is likely related to
1413         // https://patchwork.kernel.org/patch/9294421/ which reimplemented getxattr, setxattr,
1414         // and removexattr on top of generic handlers.
1415         final String path = "/proc/self/stat";
1416         try {
1417             Os.setxattr(path, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
1418             fail();
1419         } catch (ErrnoException e) {
1420             assertTrue("Unexpected errno: " + e.errno, e.errno == ENOTSUP || e.errno == EACCES);
1421         }
1422         try {
1423             Os.getxattr(path, NAME_TEST);
1424             fail();
1425         } catch (ErrnoException e) {
1426             assertEquals(ENOTSUP, e.errno);
1427         }
1428         try {
1429             // Linux listxattr does not set errno.
1430             Os.listxattr(path);
1431         } catch (ErrnoException e) {
1432             fail();
1433         }
1434         try {
1435             Os.removexattr(path, NAME_TEST);
1436             fail();
1437         } catch (ErrnoException e) {
1438             assertTrue("Unexpected errno: " + e.errno, e.errno == ENOTSUP || e.errno == EACCES);
1439         }
1440     }
1441 
1442     @Test
1443     public void test_realpath() throws Exception {
1444         File tmpDir = new File(System.getProperty("java.io.tmpdir"));
1445         // This is a chicken and egg problem. We have no way of knowing whether
1446         // the temporary directory or one of its path elements were symlinked, so
1447         // we'll need this call to realpath.
1448         String canonicalTmpDir = Os.realpath(tmpDir.getAbsolutePath());
1449 
1450         // Test that "." and ".." are resolved correctly.
1451         assertEquals(canonicalTmpDir,
1452                 Os.realpath(canonicalTmpDir + "/./../" + tmpDir.getName()));
1453 
1454         // Test that symlinks are resolved correctly.
1455         File target = new File(tmpDir, "target");
1456         File link = new File(tmpDir, "link");
1457         try {
1458             assertTrue(target.createNewFile());
1459             Os.symlink(target.getAbsolutePath(), link.getAbsolutePath());
1460 
1461             assertEquals(canonicalTmpDir + "/target",
1462                     Os.realpath(canonicalTmpDir + "/link"));
1463         } finally {
1464             boolean deletedTarget = target.delete();
1465             boolean deletedLink = link.delete();
1466             // Asserting this here to provide a definitive reason for
1467             // a subsequent failure on the same run.
1468             assertTrue("deletedTarget = " + deletedTarget + ", deletedLink =" + deletedLink,
1469                     deletedTarget && deletedLink);
1470         }
1471     }
1472 
1473     private int[] getKernelVersion() {
1474         // Example:
1475         // 4.9.29-g958411d --> 4.9
1476         String release = Os.uname().release;
1477         Matcher m = Pattern.compile("^(\\d+)\\.(\\d+)").matcher(release);
1478         assertTrue("No pattern in release string: " + release, m.find());
1479         return new int[]{ Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)) };
1480     }
1481 
1482     private boolean kernelIsAtLeast(int major, int minor) {
1483         int[] version = getKernelVersion();
1484         return version[0] > major || (version[0] == major && version[1] >= minor);
1485     }
1486 
1487     @Test
1488     public void test_socket_udpGro_setAndGet() throws Exception {
1489         // UDP GRO not required to be enabled on kernels prior to 5.4
1490         assumeTrue(kernelIsAtLeast(5, 4));
1491 
1492         final FileDescriptor fd = Os.socket(AF_INET6, SOCK_DGRAM, 0);
1493         try {
1494             final int setValue = 1;
1495             Os.setsockoptInt(fd, IPPROTO_UDP, UDP_GRO, setValue);
1496             // getsockopt(IPPROTO_UDP, UDP_GRO) is not implemented.
1497         } finally {
1498             Os.close(fd);
1499         }
1500     }
1501 
1502     @Test
1503     public void test_socket_udpGso_set() throws Exception {
1504         // UDP GSO not required to be enabled on kernels prior to 4.19.
1505         assumeTrue(kernelIsAtLeast(4, 19));
1506 
1507         final FileDescriptor fd = Os.socket(AF_INET, SOCK_DGRAM, 0);
1508         try {
1509             assertEquals(0, Os.getsockoptInt(fd, IPPROTO_UDP, UDP_SEGMENT));
1510 
1511             final int setValue = 1452;
1512             Os.setsockoptInt(fd, IPPROTO_UDP, UDP_SEGMENT, setValue);
1513             assertEquals(setValue, Os.getsockoptInt(fd, IPPROTO_UDP, UDP_SEGMENT));
1514         } finally {
1515             Os.close(fd);
1516         }
1517     }
1518 
1519     /**
1520      * Tests that TCP_USER_TIMEOUT can be set on a TCP socket, but doesn't test
1521      * that it behaves as expected.
1522      */
1523     @Test
1524     public void test_socket_tcpUserTimeout_setAndGet() throws Exception {
1525         final FileDescriptor fd = Os.socket(AF_INET, SOCK_STREAM, 0);
1526         try {
1527             int v = Os.getsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT);
1528             assertEquals(0, v); // system default value
1529             int newValue = 3000;
1530             Os.setsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT,
1531                     newValue);
1532             int actualValue = Os.getsockoptInt(fd, OsConstants.IPPROTO_TCP,
1533                     OsConstants.TCP_USER_TIMEOUT);
1534             // The kernel can round the requested value based on the HZ setting. We allow up to 10ms
1535             // difference.
1536             assertTrue("Returned incorrect timeout:" + actualValue,
1537                     Math.abs(newValue - actualValue) <= 10);
1538             // No need to reset the value to 0, since we're throwing the socket away
1539         } finally {
1540             Os.close(fd);
1541         }
1542     }
1543 
1544     @Test
1545     public void test_socket_tcpUserTimeout_doesNotWorkOnDatagramSocket() throws Exception {
1546         final FileDescriptor fd = Os.socket(AF_INET, SOCK_DGRAM, 0);
1547         try {
1548             Os.setsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT,
1549                     3000);
1550             fail("datagram (connectionless) sockets shouldn't support TCP_USER_TIMEOUT");
1551         } catch (ErrnoException expected) {
1552             // expected
1553         } finally {
1554             Os.close(fd);
1555         }
1556     }
1557 
1558     @Test
1559     public void test_socket_sockoptTimeval_readWrite() throws Exception {
1560         FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0);
1561         try {
1562             StructTimeval v = Os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO);
1563             assertEquals(0, v.toMillis()); // system default value
1564 
1565             StructTimeval newValue = StructTimeval.fromMillis(3000);
1566             Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, newValue);
1567 
1568             StructTimeval actualValue = Os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO);
1569 
1570             // The kernel can round the requested value based on the HZ setting. We allow up to 10ms
1571             // difference.
1572             assertTrue("Returned incorrect timeout:" + actualValue,
1573                     Math.abs(newValue.toMillis() - actualValue.toMillis()) <= 10);
1574             // No need to reset the value to 0, since we're throwing the socket away
1575         } finally {
1576             Os.close(fd);
1577         }
1578     }
1579 
1580     @Test
1581     public void test_socket_setSockoptTimeval_effective() throws Exception {
1582         final int TIMEOUT_VALUE_MILLIS = 250;
1583         final int ALLOWED_TIMEOUT_MILLIS = 3000;
1584         final int ROUNDING_ERROR_MILLIS = 10;
1585 
1586         FileDescriptor fd = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
1587         try {
1588             // Configure the receive timeout.
1589             StructTimeval tv = StructTimeval.fromMillis(TIMEOUT_VALUE_MILLIS);
1590             Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, tv);
1591 
1592             // Bind socket and wait for data (and timeout).
1593             Os.bind(fd, InetAddress.getByName("::1"), 0);
1594             byte[] request = new byte[1];
1595             long startTime = System.nanoTime();
1596             expectException(() -> Os.read(fd, request, 0, request.length),
1597                     ErrnoException.class, EAGAIN, "Expected timeout");
1598             long durationMillis = Duration.ofNanos(System.nanoTime() - startTime).toMillis();
1599 
1600             // Our requested timeout may be rounded by the kernel (b/176104885, b/216667550).
1601             // We allow up to 1 scheduling quantum difference (assuming HZ = 100).
1602             assertTrue("Timeout of " + tv.toMillis() + "ms returned after " + durationMillis + "ms",
1603                        durationMillis >= tv.toMillis() - ROUNDING_ERROR_MILLIS);
1604             assertTrue("Timeout of " + TIMEOUT_VALUE_MILLIS + "ms failed to return within "
1605                     + ALLOWED_TIMEOUT_MILLIS  + "ms",
1606                        durationMillis < ALLOWED_TIMEOUT_MILLIS);
1607         } finally {
1608             Os.close(fd);
1609         }
1610     }
1611 
1612     @Test
1613     public void test_socket_setSockoptTimeval_nullFd() {
1614         StructTimeval tv = StructTimeval.fromMillis(500);
1615         expectException(
1616                 () -> Os.setsockoptTimeval(null, SOL_SOCKET, SO_RCVTIMEO, tv),
1617                 ErrnoException.class, EBADF, "setsockoptTimeval(null, ...)");
1618     }
1619 
1620     @Test
1621     public void test_socket_setSockoptTimeval_fileFd() throws Exception {
1622         File testFile = createTempFile("test_socket_setSockoptTimeval_invalidFd", "");
1623         try (FileInputStream fis = new FileInputStream(testFile)) {
1624             final FileDescriptor fd = fis.getFD();
1625 
1626             StructTimeval tv = StructTimeval.fromMillis(500);
1627             expectException(
1628                     () -> Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, tv),
1629                     ErrnoException.class, ENOTSOCK, "setsockoptTimeval(<file fd>, ...)");
1630         }
1631     }
1632 
1633     @Test
1634     public void test_socket_setSockoptTimeval_badFd() throws Exception {
1635         StructTimeval tv = StructTimeval.fromMillis(500);
1636         FileDescriptor invalidFd = Os.socket(AF_INET6, SOCK_STREAM, 0);
1637         Os.close(invalidFd);
1638 
1639         expectException(
1640                 () -> Os.setsockoptTimeval(invalidFd, SOL_SOCKET, SO_RCVTIMEO, tv),
1641                 ErrnoException.class, EBADF, "setsockoptTimeval(<closed fd>, ...)");
1642     }
1643 
1644     @Test
1645     public void test_socket_setSockoptTimeval_invalidLevel() throws Exception {
1646         StructTimeval tv = StructTimeval.fromMillis(500);
1647         FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0);
1648         try {
1649             expectException(
1650                     () -> Os.setsockoptTimeval(fd, -1, SO_RCVTIMEO, tv),
1651                     ErrnoException.class, ENOPROTOOPT,
1652                     "setsockoptTimeval(fd, <invalid level>, ...)");
1653         } finally {
1654             Os.close(fd);
1655         }
1656     }
1657 
1658     @Test
1659     public void test_socket_setSockoptTimeval_invalidOpt() throws Exception {
1660         StructTimeval tv = StructTimeval.fromMillis(500);
1661         FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0);
1662         try {
1663             expectException(
1664                     () -> Os.setsockoptTimeval(fd, SOL_SOCKET, -1, tv),
1665                     ErrnoException.class, ENOPROTOOPT,
1666                     "setsockoptTimeval(fd, <invalid level>, ...)");
1667         } finally {
1668             Os.close(fd);
1669         }
1670     }
1671 
1672     @Test
1673     public void test_socket_setSockoptTimeval_nullTimeVal() throws Exception {
1674         FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0);
1675         try {
1676             expectException(
1677                     () -> Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, null),
1678                     NullPointerException.class, null, "setsockoptTimeval(..., null)");
1679         } finally {
1680             Os.close(fd);
1681         }
1682     }
1683 
1684     @Test
1685     public void test_socket_getSockoptTimeval_invalidOption() throws Exception {
1686         FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0);
1687         try {
1688             expectException(
1689                     () -> Os.getsockoptTimeval(fd, SOL_SOCKET, SO_DEBUG),
1690                     IllegalArgumentException.class, null,
1691                     "getsockoptTimeval(..., <non-timeval option>)");
1692         } finally {
1693             Os.close(fd);
1694         }
1695     }
1696 
1697     @Test
1698     public void test_if_nametoindex_if_indextoname() throws Exception {
1699         Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
1700         assertNotNull(networkInterfaces);
1701         List<NetworkInterface> nis = Collections.list(networkInterfaces);
1702 
1703         assertTrue(nis.size() > 0);
1704         for (NetworkInterface ni : nis) {
1705             int index = ni.getIndex();
1706             String name = ni.getName();
1707             assertEquals(index, Os.if_nametoindex(name));
1708             assertEquals(Os.if_indextoname(index), name);
1709         }
1710 
1711         assertEquals(0, Os.if_nametoindex("this-interface-does-not-exist"));
1712         assertNull(Os.if_indextoname(-1000));
1713 
1714         try {
1715             Os.if_nametoindex(null);
1716             fail();
1717         } catch (NullPointerException expected) {
1718         }
1719     }
1720 
1721     private static void assertStartsWith(byte[] expectedContents, byte[] container) {
1722         for (int i = 0; i < expectedContents.length; i++) {
1723             if (expectedContents[i] != container[i]) {
1724                 fail("Expected " + Arrays.toString(expectedContents) + " but found "
1725                         + Arrays.toString(expectedContents));
1726             }
1727         }
1728     }
1729 
1730     @Test
1731     public void test_readlink() throws Exception {
1732         File path = new File(TestIoUtils.createTemporaryDirectory("test_readlink"), "symlink");
1733 
1734         // ext2 and ext4 have PAGE_SIZE limits on symlink targets.
1735         // If file encryption is enabled, there's extra overhead to store the
1736         // size of the encrypted symlink target. There's also an off-by-one
1737         // in current kernels (and marlin/sailfish where we're seeing this
1738         // failure are still on 3.18, far from current). Given that we don't
1739         // really care here, just use 2048 instead. http://b/33306057.
1740         int size = 2048;
1741         StringBuilder xs = new StringBuilder();
1742         for (int i = 0; i < size - 1; ++i) {
1743             xs.append("x");
1744         }
1745 
1746         Os.symlink(xs.toString(), path.getPath());
1747 
1748         assertEquals(xs.toString(), Os.readlink(path.getPath()));
1749     }
1750 
1751     // Address should be correctly set for empty packets. http://b/33481605
1752     @Test
1753     public void test_recvfrom_EmptyPacket() throws Exception {
1754         try (DatagramSocket ds = new DatagramSocket();
1755              DatagramSocket srcSock = new DatagramSocket()) {
1756             srcSock.send(new DatagramPacket(new byte[0], 0, ds.getLocalSocketAddress()));
1757 
1758             byte[] recvBuf = new byte[16];
1759             InetSocketAddress address = new InetSocketAddress();
1760             int recvCount =
1761                     android.system.Os.recvfrom(ds.getFileDescriptor$(), recvBuf, 0, 16, 0, address);
1762             assertEquals(0, recvCount);
1763             assertTrue(address.getAddress().isLoopbackAddress());
1764             assertEquals(srcSock.getLocalPort(), address.getPort());
1765         }
1766     }
1767 
1768     @Test
1769     public void test_fstat_times() throws Exception {
1770         File file = File.createTempFile("OsTest", "fstattest");
1771         FileOutputStream fos = new FileOutputStream(file);
1772         StructStat structStat1 = Os.fstat(fos.getFD());
1773         assertEquals(structStat1.st_mtim.tv_sec, structStat1.st_mtime);
1774         assertEquals(structStat1.st_ctim.tv_sec, structStat1.st_ctime);
1775         assertEquals(structStat1.st_atim.tv_sec, structStat1.st_atime);
1776         Thread.sleep(100);
1777         fos.write(new byte[] { 1, 2, 3 });
1778         fos.flush();
1779         StructStat structStat2 = Os.fstat(fos.getFD());
1780         fos.close();
1781 
1782         assertEquals(-1, structStat1.st_mtim.compareTo(structStat2.st_mtim));
1783         assertEquals(-1, structStat1.st_ctim.compareTo(structStat2.st_ctim));
1784         assertEquals(0, structStat1.st_atim.compareTo(structStat2.st_atim));
1785     }
1786 
1787     @Test
1788     public void test_build_sruct_stat() {
1789       StructStat structStat1 = new StructStat(/*st_dev*/ 0L, /*st_ino*/ 0L, /*st_mode*/ 0,
1790           /*st_nlink*/ 1L, /*st_uid*/ 1000, /*st_gid*/ 1000, /*st_rdev*/ 0L, /*st_size*/ 0L,
1791           /*st_atime*/ 0L, /*st_mtime*/ 0L, /*st_ctime*/ 0L, /*st_blksize*/ 4096L,
1792           /*st_blocks*/ 1L);
1793       StructStat structStat2 = new StructStat(/*st_dev*/ 0L, /*st_ino*/ 0L, /*st_mode*/ 0,
1794           /*st_nlink*/ 1L, /*st_uid*/ 1000, /*st_gid*/ 1000, /*st_rdev*/ 0L, /*st_size*/ 0L,
1795           /*st_atim*/ new StructTimespec(0L, 0L), /*st_mtim*/ new StructTimespec(0L, 0L),
1796           /*st_ctim*/ new StructTimespec(0L, 0L), /*st_blksize*/ 4096L, /*st_blocks*/ 1L);
1797       assertStructStatsEqual(structStat1, structStat2);
1798     }
1799 
1800     @Test
1801     public void test_getrlimit() throws Exception {
1802         StructRlimit rlimit = Os.getrlimit(OsConstants.RLIMIT_NOFILE);
1803         // We can't really make any assertions about these values since they might vary from
1804         // device to device and even process to process. We do know that they will be greater
1805         // than zero, though.
1806         assertTrue(rlimit.rlim_cur > 0);
1807         assertTrue(rlimit.rlim_max > 0);
1808     }
1809 
1810     // http://b/65051835
1811     @Test
1812     public void test_pipe2_errno() {
1813         try {
1814             // flag=-1 is not a valid value for pip2, will EINVAL
1815             Os.pipe2(-1);
1816             fail();
1817         } catch (ErrnoException expected) {
1818         }
1819     }
1820 
1821     // http://b/65051835
1822     @Test
1823     public void test_sendfile_errno() throws Exception {
1824         File testFile = File.createTempFile("test_sendfile_errno", "");
1825         FileDescriptor fd = Os.open(testFile.toString(), O_WRONLY, S_IRUSR | S_IWUSR);
1826         assertNotNull(fd);
1827 
1828         try {
1829             // fd is not open for input, will cause EBADF
1830             Int64Ref offset = new Int64Ref(10);
1831             Os.sendfile(fd, fd, offset, 10);
1832             fail();
1833         } catch (ErrnoException expected) {
1834         } finally {
1835             Os.close(fd);
1836         }
1837     }
1838 
1839     @Test
1840     public void test_sendfile_null() throws Exception {
1841         File in = createTempFile("test_sendfile_null", "Hello, world!");
1842         try {
1843             int len = "Hello".length();
1844             assertEquals("Hello", checkSendfile(in, null, len, null));
1845         } finally {
1846             in.delete();
1847         }
1848     }
1849 
1850     @Test
1851     public void test_sendfile_offset() throws Exception {
1852         File in = createTempFile("test_sendfile_offset", "Hello, world!");
1853         try {
1854             // checkSendfile(sendFileImplToUse, in, startOffset, maxBytes, expectedEndOffset)
1855             assertEquals("Hello", checkSendfile(in, 0L, 5, 5L));
1856             assertEquals("ello,", checkSendfile(in, 1L, 5, 6L));
1857             // At offset 9, only 4 bytes/chars available, even though we're asking for 5.
1858             assertEquals("rld!", checkSendfile(in, 9L, 5, 13L));
1859             assertEquals("", checkSendfile(in, 1L, 0, 1L));
1860         } finally {
1861             in.delete();
1862         }
1863     }
1864 
1865     private static String checkSendfile(File in, Long startOffset,
1866             int maxBytes, Long expectedEndOffset) throws IOException, ErrnoException {
1867         File out = File.createTempFile(OsTest.class.getSimpleName() + "_checkSendFile", ".out");
1868         try (FileInputStream inStream = new FileInputStream(in)) {
1869             FileDescriptor inFd = inStream.getFD();
1870             try (FileOutputStream outStream = new FileOutputStream(out)) {
1871                 FileDescriptor outFd = outStream.getFD();
1872                 Int64Ref offset = (startOffset == null) ? null : new Int64Ref(startOffset);
1873                 android.system.Os.sendfile(outFd, inFd, offset, maxBytes);
1874                 assertEquals(expectedEndOffset, offset == null ? null : offset.value);
1875             }
1876             return TestIoUtils.readFileAsString(out.getPath());
1877         } finally {
1878             out.delete();
1879         }
1880     }
1881 
1882     private static File createTempFile(String namePart, String contents) throws IOException {
1883         File f = File.createTempFile(OsTest.class.getSimpleName() + namePart, ".in");
1884         try (FileWriter writer = new FileWriter(f)) {
1885             writer.write(contents);
1886         }
1887         return f;
1888     }
1889 
1890     @Test
1891     public void test_odirect() throws Exception {
1892         File testFile = createTempFile("test_odirect", "");
1893         try {
1894             FileDescriptor fd =
1895                     Os.open(testFile.toString(), O_WRONLY | O_DIRECT, S_IRUSR | S_IWUSR);
1896             assertNotNull(fd);
1897             assertTrue(fd.valid());
1898             int flags = Os.fcntlVoid(fd, F_GETFL);
1899             assertTrue("Expected file flags to include " + O_DIRECT + ", actual value: " + flags,
1900                     0 != (flags & O_DIRECT));
1901             Os.close(fd);
1902         } finally {
1903             testFile.delete();
1904         }
1905     }
1906 
1907     @Test
1908     public void test_oappend() throws Exception {
1909         File testFile = createTempFile("test_oappend", "");
1910         try {
1911             FileDescriptor fd =
1912                     Os.open(testFile.toString(), O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
1913             assertNotNull(fd);
1914             assertTrue(fd.valid());
1915             int flags = Os.fcntlVoid(fd, F_GETFL);
1916             assertTrue("Expected file flags to include " + O_APPEND + ", actual value: " + flags,
1917                     0 != (flags & O_APPEND));
1918             Os.close(fd);
1919         } finally {
1920             testFile.delete();
1921         }
1922     }
1923 
1924     @Test
1925     public void test_splice() throws Exception {
1926         FileDescriptor[] pipe = Os.pipe2(0);
1927         File in = createTempFile("splice1", "foobar");
1928         File out = createTempFile("splice2", "");
1929 
1930         Int64Ref offIn = new Int64Ref(1);
1931         Int64Ref offOut = new Int64Ref(0);
1932 
1933         // Splice into pipe
1934         try (FileInputStream streamIn = new FileInputStream(in)) {
1935             FileDescriptor fdIn = streamIn.getFD();
1936             long result = Os
1937                     .splice(fdIn, offIn, pipe[1], null /* offOut */, 10 /* len */, 0 /* flags */);
1938             assertEquals(5, result);
1939             assertEquals(6, offIn.value);
1940         }
1941 
1942         // Splice from pipe
1943         try (FileOutputStream streamOut = new FileOutputStream(out)) {
1944             FileDescriptor fdOut = streamOut.getFD();
1945             long result = Os
1946                     .splice(pipe[0], null /* offIn */, fdOut, offOut, 10 /* len */, 0 /* flags */);
1947             assertEquals(5, result);
1948             assertEquals(5, offOut.value);
1949         }
1950 
1951         assertEquals("oobar", TestIoUtils.readFileAsString(out.getPath()));
1952 
1953         Os.close(pipe[0]);
1954         Os.close(pipe[1]);
1955     }
1956 
1957     @Test
1958     public void test_splice_errors() throws Exception {
1959         File in = createTempFile("splice3", "");
1960         File out = createTempFile("splice4", "");
1961         FileDescriptor[] pipe = Os.pipe2(0);
1962 
1963         //.fdIn == null
1964         try {
1965             Os.splice(null /* fdIn */, null /* offIn */, pipe[1],
1966                     null /*offOut*/, 10 /* len */, 0 /* flags */);
1967             fail();
1968         } catch (ErrnoException expected) {
1969             assertEquals(EBADF, expected.errno);
1970         }
1971 
1972         //.fdOut == null
1973         try {
1974             Os.splice(pipe[0] /* fdIn */, null /* offIn */, null  /* fdOut */,
1975                     null /*offOut*/, 10 /* len */, 0 /* flags */);
1976             fail();
1977         } catch (ErrnoException expected) {
1978             assertEquals(EBADF, expected.errno);
1979         }
1980 
1981         // No pipe fd
1982         try (FileOutputStream streamOut = new FileOutputStream(out)) {
1983             try (FileInputStream streamIn = new FileInputStream(in)) {
1984                 FileDescriptor fdIn = streamIn.getFD();
1985                 FileDescriptor fdOut = streamOut.getFD();
1986                 Os.splice(fdIn, null  /* offIn */, fdOut, null /* offOut */, 10 /* len */,
1987                         0 /* flags */);
1988                 fail();
1989             } catch (ErrnoException expected) {
1990                 assertEquals(EINVAL, expected.errno);
1991             }
1992         }
1993 
1994         Os.close(pipe[0]);
1995         Os.close(pipe[1]);
1996     }
1997 
1998     @Test
1999     public void testCloseNullFileDescriptor() throws Exception {
2000         try {
2001             Os.close(null);
2002             fail();
2003         } catch (NullPointerException expected) {
2004         }
2005     }
2006 
2007     @Test
2008     public void testSocketpairNullFileDescriptor1() throws Exception {
2009         try {
2010             Os.socketpair(AF_UNIX, SOCK_STREAM, 0, null, new FileDescriptor());
2011             fail();
2012         } catch (NullPointerException expected) {
2013         }
2014     }
2015 
2016     @Test
2017     public void testSocketpairNullFileDescriptor2() throws Exception {
2018         try {
2019             Os.socketpair(AF_UNIX, SOCK_STREAM, 0, new FileDescriptor(), null);
2020             fail();
2021         } catch (NullPointerException expected) {
2022         }
2023     }
2024 
2025     @Test
2026     public void testSocketpairNullFileDescriptorBoth() throws Exception {
2027         try {
2028             Os.socketpair(AF_UNIX, SOCK_STREAM, 0, null, null);
2029             fail();
2030         } catch (NullPointerException expected) {
2031         }
2032     }
2033 
2034     @Test
2035     public void testInetPtonIpv4() {
2036         String srcAddress = "127.0.0.1";
2037         InetAddress inetAddress = Os.inet_pton(AF_INET, srcAddress);
2038         assertEquals(srcAddress, inetAddress.getHostAddress());
2039     }
2040 
2041     @Test
2042     public void testInetPtonIpv6() {
2043         String srcAddress = "1123:4567:89ab:cdef:fedc:ba98:7654:3210";
2044         InetAddress inetAddress = Os.inet_pton(AF_INET6, srcAddress);
2045         assertEquals(srcAddress, inetAddress.getHostAddress());
2046     }
2047 
2048     @Test
2049     public void testInetPtonInvalidFamily() {
2050         String srcAddress = "127.0.0.1";
2051         InetAddress inetAddress = Os.inet_pton(AF_UNIX, srcAddress);
2052         assertNull(inetAddress);
2053     }
2054 
2055     @Test
2056     public void testInetPtonWrongFamily() {
2057         String srcAddress = "127.0.0.1";
2058         InetAddress inetAddress = Os.inet_pton(AF_INET6, srcAddress);
2059         assertNull(inetAddress);
2060     }
2061 
2062     @Test
2063     public void testInetPtonInvalidData() {
2064         String srcAddress = "10.1";
2065         InetAddress inetAddress = Os.inet_pton(AF_INET, srcAddress);
2066         assertNull(inetAddress);
2067     }
2068 
2069     /**
2070      * Verifies the {@link OsConstants#MAP_ANONYMOUS}.
2071      */
2072     @Test
2073     public void testMapAnonymous() throws Exception {
2074         final long size = 4096;
2075         final long address = Os.mmap(0, size, PROT_READ,
2076                 MAP_PRIVATE | MAP_ANONYMOUS, new FileDescriptor(), 0);
2077         assertTrue(address > 0);
2078         Os.munmap(address, size);
2079     }
2080 
2081     @Test
2082     public void testMemfdCreate() throws Exception {
2083         FileDescriptor fd = null;
2084         try {
2085             fd = Os.memfd_create("test_memfd", 0);
2086             assertNotNull(fd);
2087             assertTrue(fd.valid());
2088 
2089             StructStat stat = Os.fstat(fd);
2090             assertEquals(0, stat.st_size);
2091 
2092             final byte[] expected = new byte[] {1, 2, 3, 4};
2093             Os.write(fd, expected, 0, expected.length);
2094             stat = Os.fstat(fd);
2095             assertEquals(expected.length, stat.st_size);
2096 
2097             byte[] actual = new byte[expected.length];
2098             // should be seekable
2099             Os.lseek(fd, 0, SEEK_SET);
2100             Os.read(fd, actual, 0, actual.length);
2101             assertArrayEquals(expected, actual);
2102         } finally {
2103             if (fd != null) {
2104                 Os.close(fd);
2105                 fd = null;
2106             }
2107         }
2108     }
2109 
2110     @Test
2111     public void testMemfdCreateFlags() throws Exception {
2112         FileDescriptor fd = null;
2113 
2114         // test that MFD_CLOEXEC is obeyed
2115         try {
2116             fd = Os.memfd_create("test_memfd", 0);
2117             assertNotNull(fd);
2118             assertTrue(fd.valid());
2119             int flags = Os.fcntlVoid(fd, F_GETFD);
2120             assertEquals("Expected flags to not include " + FD_CLOEXEC + ", actual value: " + flags,
2121                 0, (flags & FD_CLOEXEC));
2122         } finally {
2123             if (fd != null) {
2124                 Os.close(fd);
2125                 fd = null;
2126             }
2127         }
2128         try {
2129             fd = Os.memfd_create("test_memfd", MFD_CLOEXEC);
2130             assertNotNull(fd);
2131             assertTrue(fd.valid());
2132             int flags = Os.fcntlVoid(fd, F_GETFD);
2133             assertTrue("Expected flags to include " + FD_CLOEXEC + ", actual value: " + flags,
2134                     0 != (flags & FD_CLOEXEC));
2135         } finally {
2136             if (fd != null) {
2137                 Os.close(fd);
2138                 fd = null;
2139             }
2140         }
2141     }
2142 
2143     @Test
2144     public void testMemfdCreateErrno() {
2145         expectException(() -> Os.memfd_create(null, 0), NullPointerException.class, null,
2146                 "memfd_create(null, 0)");
2147 
2148         expectException(() -> Os.memfd_create("test_memfd", 0xffff), ErrnoException.class, EINVAL,
2149                 "memfd_create(\"test_memfd\", 0xffff)");
2150     }
2151 
2152     @Test
2153     public void environmentsInitiallyEqual() throws Exception {
2154         assertEnvironmentsEqual();
2155     }
2156 
2157     @Test
2158     public void getSetUnsetenvEnviron_Success() throws Exception {
2159         String variable1 = "OSTEST_VARIABLE1";
2160         String variable2 = "OSTEST_VARIABLE2";
2161         String value1 = "value1";
2162         String value2 = "value2";
2163 
2164         // Initial state, the test variables should not be set anywhere
2165         assertNull(System.getenv(variable1));
2166         assertNull(System.getenv(variable2));
2167         assertNull(Os.getenv(variable1));
2168         assertNull(Os.getenv(variable2));
2169 
2170         // Set and get
2171         Os.setenv(variable1, value1, false);
2172         Os.setenv(variable2, value2, false);
2173         assertEquals(value1, Os.getenv(variable1));
2174         assertEquals(value2, Os.getenv(variable2));
2175         assertEquals(value1, System.getenv(variable1));
2176         assertEquals(value2, System.getenv(variable2));
2177         // Comparing environments indirectly tests Os.environ()
2178         assertEnvironmentsEqual();
2179 
2180         // Update values with overwrite flag set to false - should be a no-op
2181         Os.setenv(variable1, value2, false);
2182         Os.setenv(variable2, value1, false);
2183         assertEquals(value1, Os.getenv(variable1));
2184         assertEquals(value2, Os.getenv(variable2));
2185         assertEquals(value1, System.getenv(variable1));
2186         assertEquals(value2, System.getenv(variable2));
2187         assertEnvironmentsEqual();
2188 
2189         // Update values (swap value1 and value2)
2190         Os.setenv(variable1, value2, true);
2191         Os.setenv(variable2, value1, true);
2192         assertEquals(value2, Os.getenv(variable1));
2193         assertEquals(value1, Os.getenv(variable2));
2194         assertEquals(value2, System.getenv(variable1));
2195         assertEquals(value1, System.getenv(variable2));
2196         assertEnvironmentsEqual();
2197 
2198         // Unset
2199         Os.unsetenv(variable1);
2200         Os.unsetenv(variable2);
2201         assertNull(System.getenv(variable1));
2202         assertNull(System.getenv(variable2));
2203         assertNull(Os.getenv(variable1));
2204         assertNull(Os.getenv(variable2));
2205         assertEnvironmentsEqual();
2206     }
2207 
2208     @Test
2209     public void setenv() {
2210         expectException(() -> Os.setenv(null, null, true), NullPointerException.class, null,
2211             "setenv(null, null, true)");
2212 
2213         expectException(() -> Os.setenv(null, "value", true), NullPointerException.class, null,
2214             "setenv(null, value, true)");
2215 
2216         expectException(() -> Os.setenv("a", null, true), NullPointerException.class, null,
2217             "setenv(\"a\", null, true)");
2218 
2219         expectException(() -> Os.setenv("", "value", true), ErrnoException.class, EINVAL,
2220             "setenv(\"\", value, true)");
2221 
2222         expectException(() -> Os.setenv("a=b", "value", true), ErrnoException.class, EINVAL,
2223             "setenv(\"a=b\", value, true)");
2224 
2225         expectException(() -> Os.setenv(null, null, false), NullPointerException.class, null,
2226             "setenv(null, null, false)");
2227 
2228         expectException(() -> Os.setenv(null, "value", false), NullPointerException.class, null,
2229             "setenv(null, value, false)");
2230 
2231         expectException(() -> Os.setenv("a", null, false), NullPointerException.class, null,
2232             "setenv(\"a\", null, false)");
2233 
2234         expectException(() -> Os.setenv("", "value", false), ErrnoException.class, EINVAL,
2235             "setenv(\"\", value, false)");
2236 
2237         expectException(() -> Os.setenv("a=b", "value", false), ErrnoException.class, EINVAL,
2238             "setenv(\"a=b\", value, false)");
2239     }
2240 
2241     @Test
2242     public void getenv() {
2243         assertNotNull(Os.getenv("PATH"));
2244         assertNull(Os.getenv("This can't possibly exist but is valid"));
2245         assertNull(Os.getenv("so=is=this"));
2246 
2247         expectException(() ->Os.getenv(null), NullPointerException.class, null,
2248             "getenv(null)");
2249     }
2250 
2251     @Test
2252     public void unsetenv() {
2253         expectException(() -> Os.unsetenv(null), NullPointerException.class, null,
2254             "unsetenv(null)");
2255 
2256         expectException(() -> Os.unsetenv(""), ErrnoException.class, EINVAL,
2257             "unsetenv(\"\")");
2258 
2259         expectException(() -> Os.unsetenv("a=b"), ErrnoException.class, EINVAL,
2260             "unsetenv(\"a=b\")");
2261     }
2262 
2263     @Test
2264     public void tcdrain_throwsWhenFdIsNotTty() throws Exception {
2265         File temp = Files.createTempFile("regular-file", "txt").toFile();
2266         FileDescriptor fd = Os.open(temp.getAbsolutePath(), O_RDWR, 0);
2267 
2268         try {
2269             assertThrows(ErrnoException.class, () -> Os.tcdrain(fd));
2270         } finally {
2271             if (fd != null) {
2272                 Os.close(fd);
2273             }
2274         }
2275     }
2276 
2277     @Test
2278     public void testMsync() throws Exception {
2279         File temp = Files.createTempFile("regular-file", "txt").toFile();
2280 
2281         try (FileOutputStream fos = new FileOutputStream(temp)) {
2282             fos.write("hello".getBytes(StandardCharsets.UTF_8));
2283             fos.flush();
2284         }
2285 
2286         final long size = 5;
2287         FileDescriptor fd = Os.open(temp.getAbsolutePath(), O_RDWR, 0);
2288         final long address = Os.mmap(0, size, PROT_WRITE,
2289                 MAP_SHARED, fd, 0);
2290         assertTrue(address > 0);
2291 
2292         // The easiest way to write at address from Java I came up with.
2293         var field = Unsafe.class.getDeclaredField("THE_ONE");
2294         field.setAccessible(true);
2295         Unsafe unsafe = (Unsafe) field.get(null);
2296         unsafe.setMemory(address, size, (byte) 'a');
2297 
2298         Os.msync(address, size, MS_SYNC);
2299 
2300         try (Stream<String> stream = Files.lines(temp.toPath())) {
2301             List<String> lines = stream.toList();
2302             assertEquals(1, lines.size());
2303             assertEquals("a".repeat((int) size), lines.get(0));
2304         }
2305 
2306         Os.munmap(address, size);
2307     }
2308 
2309     /*
2310      * Checks that all ways of accessing the environment are consistent by collecting:
2311      * osEnvironment      - The environment returned by Os.environ()
2312      * systemEnvironment  - The environment returned by System.getenv()
2313      * processEnvironment - The environment that will be passed to sub-processes via
2314      *                      ProcessBuilder
2315      * execedEnvironment  - The actual environment passed to an execed instance of env
2316      *
2317      * All are converted to a sorted list of strings of the form "NAME=VALUE" for comparison.
2318      */
2319     private void assertEnvironmentsEqual() throws IOException {
2320         List<String> osEnvironment = stringArrayToList(Os.environ());
2321         List<String> systemEnvironment = stringMapToList(System.getenv());
2322 
2323         ProcessBuilder pb = new ProcessBuilder("env");
2324         List<String> processEnvironment = stringMapToList(pb.environment());
2325 
2326         BufferedReader reader = new BufferedReader(
2327             new InputStreamReader(pb.start().getInputStream()));
2328 
2329         List<String> execedEnvironment = reader
2330             .lines()
2331             .sorted()
2332             .collect(Collectors.toList());
2333 
2334         assertEquals(osEnvironment, systemEnvironment);
2335         assertEquals(osEnvironment, processEnvironment);
2336         assertEquals(osEnvironment, execedEnvironment);
2337     }
2338 
2339     private static void assertStructStatsEqual(StructStat expected, StructStat actual) {
2340         assertEquals(expected.st_dev, actual.st_dev);
2341         assertEquals(expected.st_ino, actual.st_ino);
2342         assertEquals(expected.st_mode, actual.st_mode);
2343         assertEquals(expected.st_nlink, actual.st_nlink);
2344         assertEquals(expected.st_uid, actual.st_uid);
2345         assertEquals(expected.st_gid, actual.st_gid);
2346         assertEquals(expected.st_rdev, actual.st_rdev);
2347         assertEquals(expected.st_size, actual.st_size);
2348         assertEquals(expected.st_atime, actual.st_atime);
2349         assertEquals(expected.st_atim, actual.st_atim);
2350         assertEquals(expected.st_mtime, actual.st_mtime);
2351         assertEquals(expected.st_mtim, actual.st_mtim);
2352         assertEquals(expected.st_ctime, actual.st_ctime);
2353         assertEquals(expected.st_ctim, actual.st_ctim);
2354         assertEquals(expected.st_blksize, actual.st_blksize);
2355         assertEquals(expected.st_blocks, actual.st_blocks);
2356     }
2357 
2358     private List<String> stringMapToList(Map<String, String> stringMap) {
2359         return stringMap
2360             .entrySet()
2361             .stream()
2362             .map(e -> e.getKey() + "=" + e.getValue())
2363             .sorted()
2364             .collect(Collectors.toList());
2365     }
2366 
2367     private List<String> stringArrayToList(String[] stringArray) {
2368         List<String> result = Arrays.asList(stringArray);
2369         Collections.sort(result);
2370         return result;
2371     }
2372 }
2373