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