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