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