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.StructRlimit; 26 import android.system.StructStat; 27 import android.system.StructTimeval; 28 import android.system.StructUcred; 29 import android.system.UnixSocketAddress; 30 31 import java.io.File; 32 import java.io.FileDescriptor; 33 import java.io.FileInputStream; 34 import java.io.FileOutputStream; 35 import java.io.FileWriter; 36 import java.io.IOException; 37 import java.net.DatagramPacket; 38 import java.net.DatagramSocket; 39 import java.net.Inet4Address; 40 import java.net.Inet6Address; 41 import java.net.InetAddress; 42 import java.net.InetSocketAddress; 43 import java.net.NetworkInterface; 44 import java.net.ServerSocket; 45 import java.net.SocketAddress; 46 import java.net.SocketException; 47 import java.nio.ByteBuffer; 48 import java.nio.charset.StandardCharsets; 49 import java.time.Duration; 50 import java.util.Arrays; 51 import java.util.Collections; 52 import java.util.List; 53 import java.util.Locale; 54 import java.util.concurrent.atomic.AtomicReference; 55 56 import junit.framework.TestCase; 57 58 import libcore.io.IoUtils; 59 import libcore.testing.io.TestIoUtils; 60 61 import static android.system.OsConstants.*; 62 63 public class OsTest extends TestCase { 64 testIsSocket()65 public void testIsSocket() throws Exception { 66 File f = new File("/dev/null"); 67 FileInputStream fis = new FileInputStream(f); 68 assertFalse(S_ISSOCK(Os.fstat(fis.getFD()).st_mode)); 69 fis.close(); 70 71 ServerSocket s = new ServerSocket(); 72 assertTrue(S_ISSOCK(Os.fstat(s.getImpl().getFD$()).st_mode)); 73 s.close(); 74 } 75 testFcntlInt()76 public void testFcntlInt() throws Exception { 77 File f = File.createTempFile("OsTest", "tst"); 78 FileInputStream fis = null; 79 try { 80 fis = new FileInputStream(f); 81 Os.fcntlInt(fis.getFD(), F_SETFD, FD_CLOEXEC); 82 int flags = Os.fcntlVoid(fis.getFD(), F_GETFD); 83 assertTrue((flags & FD_CLOEXEC) != 0); 84 } finally { 85 TestIoUtils.closeQuietly(fis); 86 f.delete(); 87 } 88 } 89 testFcntlInt_udpSocket()90 public void testFcntlInt_udpSocket() throws Exception { 91 final FileDescriptor fd = Os.socket(AF_INET, SOCK_DGRAM, 0); 92 try { 93 assertEquals(0, (Os.fcntlVoid(fd, F_GETFL) & O_NONBLOCK)); 94 95 // Verify that we can set file descriptor flags on sockets 96 Os.fcntlInt(fd, F_SETFL, SOCK_DGRAM | O_NONBLOCK); 97 assertTrue((Os.fcntlVoid(fd, F_GETFL) & O_NONBLOCK) != 0); 98 99 // Check that we can turn it off also. 100 Os.fcntlInt(fd, F_SETFL, SOCK_DGRAM); 101 assertEquals(0, (Os.fcntlVoid(fd, F_GETFL) & O_NONBLOCK)); 102 } finally { 103 Os.close(fd); 104 } 105 } 106 testFcntlInt_invalidCmd()107 public void testFcntlInt_invalidCmd() throws Exception { 108 final FileDescriptor fd = Os.socket(AF_INET, SOCK_DGRAM, 0); 109 try { 110 final int unknownCmd = -1; 111 Os.fcntlInt(fd, unknownCmd, 0); 112 fail("Expected failure due to invalid cmd"); 113 } catch (ErrnoException expected) { 114 assertEquals(EINVAL, expected.errno); 115 } finally { 116 Os.close(fd); 117 } 118 } 119 testFcntlInt_nullFd()120 public void testFcntlInt_nullFd() throws Exception { 121 try { 122 Os.fcntlInt(null, F_SETFL, O_NONBLOCK); 123 fail("Expected failure due to null file descriptor"); 124 } catch (ErrnoException expected) { 125 assertEquals(EBADF, expected.errno); 126 } 127 } 128 testUnixDomainSockets_in_file_system()129 public void testUnixDomainSockets_in_file_system() throws Exception { 130 String path = System.getProperty("java.io.tmpdir") + "/test_unix_socket"; 131 new File(path).delete(); 132 checkUnixDomainSocket(UnixSocketAddress.createFileSystem(path), false); 133 } 134 testUnixDomainSocket_abstract_name()135 public void testUnixDomainSocket_abstract_name() throws Exception { 136 // Linux treats a sun_path starting with a NUL byte as an abstract name. See unix(7). 137 checkUnixDomainSocket(UnixSocketAddress.createAbstract("/abstract_name_unix_socket"), true); 138 } 139 testUnixDomainSocket_unnamed()140 public void testUnixDomainSocket_unnamed() throws Exception { 141 final FileDescriptor fd = Os.socket(AF_UNIX, SOCK_STREAM, 0); 142 // unix(7) says an unbound socket is unnamed. 143 checkNoSockName(fd); 144 Os.close(fd); 145 } 146 checkUnixDomainSocket(final UnixSocketAddress address, final boolean isAbstract)147 private void checkUnixDomainSocket(final UnixSocketAddress address, final boolean isAbstract) 148 throws Exception { 149 final FileDescriptor serverFd = Os.socket(AF_UNIX, SOCK_STREAM, 0); 150 Os.bind(serverFd, address); 151 Os.listen(serverFd, 5); 152 153 checkSockName(serverFd, isAbstract, address); 154 155 Thread server = new Thread(new Runnable() { 156 public void run() { 157 try { 158 UnixSocketAddress peerAddress = UnixSocketAddress.createUnnamed(); 159 FileDescriptor clientFd = Os.accept(serverFd, peerAddress); 160 checkSockName(clientFd, isAbstract, address); 161 checkNoName(peerAddress); 162 163 checkNoPeerName(clientFd); 164 165 StructUcred credentials = Os.getsockoptUcred(clientFd, SOL_SOCKET, SO_PEERCRED); 166 assertEquals(Os.getpid(), credentials.pid); 167 assertEquals(Os.getuid(), credentials.uid); 168 assertEquals(Os.getgid(), credentials.gid); 169 170 byte[] request = new byte[256]; 171 Os.read(clientFd, request, 0, request.length); 172 173 String s = new String(request, "UTF-8"); 174 byte[] response = s.toUpperCase(Locale.ROOT).getBytes("UTF-8"); 175 Os.write(clientFd, response, 0, response.length); 176 177 Os.close(clientFd); 178 } catch (Exception ex) { 179 throw new RuntimeException(ex); 180 } 181 } 182 }); 183 server.start(); 184 185 FileDescriptor clientFd = Os.socket(AF_UNIX, SOCK_STREAM, 0); 186 187 Os.connect(clientFd, address); 188 checkNoSockName(clientFd); 189 190 String string = "hello, world!"; 191 192 byte[] request = string.getBytes("UTF-8"); 193 assertEquals(request.length, Os.write(clientFd, request, 0, request.length)); 194 195 byte[] response = new byte[request.length]; 196 assertEquals(response.length, Os.read(clientFd, response, 0, response.length)); 197 198 assertEquals(string.toUpperCase(Locale.ROOT), new String(response, "UTF-8")); 199 200 Os.close(clientFd); 201 } 202 checkSockName(FileDescriptor fd, boolean isAbstract, UnixSocketAddress address)203 private static void checkSockName(FileDescriptor fd, boolean isAbstract, 204 UnixSocketAddress address) throws Exception { 205 UnixSocketAddress isa = (UnixSocketAddress) Os.getsockname(fd); 206 assertEquals(address, isa); 207 if (isAbstract) { 208 assertEquals(0, isa.getSunPath()[0]); 209 } 210 } 211 checkNoName(UnixSocketAddress usa)212 private void checkNoName(UnixSocketAddress usa) { 213 assertEquals(0, usa.getSunPath().length); 214 } 215 checkNoPeerName(FileDescriptor fd)216 private void checkNoPeerName(FileDescriptor fd) throws Exception { 217 checkNoName((UnixSocketAddress) Os.getpeername(fd)); 218 } 219 checkNoSockName(FileDescriptor fd)220 private void checkNoSockName(FileDescriptor fd) throws Exception { 221 checkNoName((UnixSocketAddress) Os.getsockname(fd)); 222 } 223 test_strsignal()224 public void test_strsignal() throws Exception { 225 assertEquals("Killed", Os.strsignal(9)); 226 assertEquals("Unknown signal -1", Os.strsignal(-1)); 227 } 228 test_byteBufferPositions_write_pwrite()229 public void test_byteBufferPositions_write_pwrite() throws Exception { 230 FileOutputStream fos = new FileOutputStream(new File("/dev/null")); 231 FileDescriptor fd = fos.getFD(); 232 final byte[] contents = new String("goodbye, cruel world") 233 .getBytes(StandardCharsets.US_ASCII); 234 ByteBuffer byteBuffer = ByteBuffer.wrap(contents); 235 236 byteBuffer.position(0); 237 int written = Os.write(fd, byteBuffer); 238 assertTrue(written > 0); 239 assertEquals(written, byteBuffer.position()); 240 241 byteBuffer.position(4); 242 written = Os.write(fd, byteBuffer); 243 assertTrue(written > 0); 244 assertEquals(written + 4, byteBuffer.position()); 245 246 byteBuffer.position(0); 247 written = Os.pwrite(fd, byteBuffer, 64 /* offset */); 248 assertTrue(written > 0); 249 assertEquals(written, byteBuffer.position()); 250 251 byteBuffer.position(4); 252 written = Os.pwrite(fd, byteBuffer, 64 /* offset */); 253 assertTrue(written > 0); 254 assertEquals(written + 4, byteBuffer.position()); 255 256 fos.close(); 257 } 258 test_byteBufferPositions_read_pread()259 public void test_byteBufferPositions_read_pread() throws Exception { 260 FileInputStream fis = new FileInputStream(new File("/dev/zero")); 261 FileDescriptor fd = fis.getFD(); 262 ByteBuffer byteBuffer = ByteBuffer.allocate(64); 263 264 byteBuffer.position(0); 265 int read = Os.read(fd, byteBuffer); 266 assertTrue(read > 0); 267 assertEquals(read, byteBuffer.position()); 268 269 byteBuffer.position(4); 270 read = Os.read(fd, byteBuffer); 271 assertTrue(read > 0); 272 assertEquals(read + 4, byteBuffer.position()); 273 274 byteBuffer.position(0); 275 read = Os.pread(fd, byteBuffer, 64 /* offset */); 276 assertTrue(read > 0); 277 assertEquals(read, byteBuffer.position()); 278 279 byteBuffer.position(4); 280 read = Os.pread(fd, byteBuffer, 64 /* offset */); 281 assertTrue(read > 0); 282 assertEquals(read + 4, byteBuffer.position()); 283 284 fis.close(); 285 } 286 checkByteBufferPositions_sendto_recvfrom( int family, InetAddress loopback)287 static void checkByteBufferPositions_sendto_recvfrom( 288 int family, InetAddress loopback) throws Exception { 289 final FileDescriptor serverFd = Os.socket(family, SOCK_STREAM, 0); 290 Os.bind(serverFd, loopback, 0); 291 Os.listen(serverFd, 5); 292 293 InetSocketAddress address = (InetSocketAddress) Os.getsockname(serverFd); 294 295 final Thread server = new Thread(new Runnable() { 296 public void run() { 297 try { 298 InetSocketAddress peerAddress = new InetSocketAddress(); 299 FileDescriptor clientFd = Os.accept(serverFd, peerAddress); 300 301 // Attempt to receive a maximum of 24 bytes from the client, and then 302 // close the connection. 303 ByteBuffer buffer = ByteBuffer.allocate(16); 304 int received = Os.recvfrom(clientFd, buffer, 0, null); 305 assertTrue(received > 0); 306 assertEquals(received, buffer.position()); 307 308 ByteBuffer buffer2 = ByteBuffer.allocate(16); 309 buffer2.position(8); 310 received = Os.recvfrom(clientFd, buffer2, 0, null); 311 assertTrue(received > 0); 312 assertEquals(received + 8, buffer.position()); 313 314 Os.close(clientFd); 315 } catch (Exception ex) { 316 throw new RuntimeException(ex); 317 } 318 } 319 }); 320 321 server.start(); 322 323 FileDescriptor clientFd = Os.socket(family, SOCK_STREAM, 0); 324 Os.connect(clientFd, address.getAddress(), address.getPort()); 325 326 final byte[] bytes = "good bye, cruel black hole with fancy distortion" 327 .getBytes(StandardCharsets.US_ASCII); 328 assertTrue(bytes.length > 24); 329 330 ByteBuffer input = ByteBuffer.wrap(bytes); 331 input.position(0); 332 input.limit(16); 333 334 int sent = Os.sendto(clientFd, input, 0, address.getAddress(), address.getPort()); 335 assertTrue(sent > 0); 336 assertEquals(sent, input.position()); 337 338 input.position(16); 339 input.limit(24); 340 sent = Os.sendto(clientFd, input, 0, address.getAddress(), address.getPort()); 341 assertTrue(sent > 0); 342 assertEquals(sent + 16, input.position()); 343 344 Os.close(clientFd); 345 } 346 347 interface ExceptionalRunnable { 348 run()349 public void run() throws Exception; 350 } 351 352 /** 353 * Expects that the given Runnable will throw an exception of the specified class. If the class 354 * is ErrnoException, and expectedErrno is non-null, also checks that the errno is equal to 355 * expectedErrno. 356 */ expectException(ExceptionalRunnable r, Class<? extends Exception> exClass, Integer expectedErrno, String msg)357 private static void expectException(ExceptionalRunnable r, Class<? extends Exception> exClass, 358 Integer expectedErrno, String msg) { 359 try { 360 r.run(); 361 fail(msg + " did not throw exception"); 362 } catch (Exception e) { 363 assertEquals(msg + " threw unexpected exception", exClass, e.getClass()); 364 365 if (expectedErrno != null) { 366 if (e instanceof ErrnoException) { 367 assertEquals(msg + "threw ErrnoException with unexpected error number", 368 (int) expectedErrno, ((ErrnoException) e).errno); 369 } else { 370 fail("Can only pass expectedErrno when expecting ErrnoException"); 371 } 372 } 373 374 } 375 } 376 expectBindException(FileDescriptor socket, SocketAddress addr, Class exClass, Integer expectedErrno)377 private static void expectBindException(FileDescriptor socket, SocketAddress addr, 378 Class exClass, Integer expectedErrno) { 379 String msg = String.format("bind(%s, %s)", socket, addr); 380 expectException(() -> { 381 Os.bind(socket, addr); 382 }, exClass, expectedErrno, msg); 383 } 384 expectConnectException(FileDescriptor socket, SocketAddress addr, Class exClass, Integer expectedErrno)385 private static void expectConnectException(FileDescriptor socket, SocketAddress addr, 386 Class exClass, Integer expectedErrno) { 387 String msg = String.format("connect(%s, %s)", socket, addr); 388 expectException(() -> { 389 Os.connect(socket, addr); 390 }, exClass, expectedErrno, msg); 391 } 392 expectSendtoException(FileDescriptor socket, SocketAddress addr, Class exClass, Integer expectedErrno)393 private static void expectSendtoException(FileDescriptor socket, SocketAddress addr, 394 Class exClass, Integer expectedErrno) { 395 String msg = String.format("sendto(%s, %s)", socket, addr); 396 byte[] packet = new byte[42]; 397 expectException(() -> { 398 Os.sendto(socket, packet, 0, packet.length, 0, addr); 399 }, 400 exClass, expectedErrno, msg); 401 } 402 expectBindConnectSendtoSuccess(FileDescriptor socket, String socketDesc, SocketAddress addr)403 private static void expectBindConnectSendtoSuccess(FileDescriptor socket, String socketDesc, 404 SocketAddress addr) { 405 String msg = socketDesc + " socket to " + addr.toString(); 406 407 try { 408 try { 409 // Expect that bind throws when any of its arguments are null. 410 expectBindException(null, addr, ErrnoException.class, EBADF); 411 expectBindException(socket, null, NullPointerException.class, null); 412 expectBindException(null, null, NullPointerException.class, null); 413 414 // Expect bind to succeed. 415 Os.bind(socket, addr); 416 417 // Find out which port we're actually bound to, and use that in subsequent connect() 418 // and send() calls. We can't send to addr because that has a port of 0. 419 if (addr instanceof InetSocketAddress) { 420 InetSocketAddress addrISA = (InetSocketAddress) addr; 421 InetSocketAddress socknameISA = (InetSocketAddress) Os.getsockname(socket); 422 423 assertEquals(addrISA.getAddress(), socknameISA.getAddress()); 424 assertEquals(0, addrISA.getPort()); 425 assertFalse(0 == socknameISA.getPort()); 426 addr = socknameISA; 427 } 428 429 // Expect sendto with a null address to throw because the socket is not connected, 430 // but to succeed with a non-null address. 431 byte[] packet = new byte[42]; 432 Os.sendto(socket, packet, 0, packet.length, 0, addr); 433 // UNIX and IP sockets return different errors for this operation, so we can't check 434 // errno. 435 expectSendtoException(socket, null, ErrnoException.class, null); 436 expectSendtoException(null, null, ErrnoException.class, EBADF); 437 438 // Expect that connect throws when any of its arguments are null. 439 expectConnectException(null, addr, ErrnoException.class, EBADF); 440 expectConnectException(socket, null, NullPointerException.class, null); 441 expectConnectException(null, null, NullPointerException.class, null); 442 443 // Expect connect to succeed. 444 Os.connect(socket, addr); 445 assertEquals(Os.getsockname(socket), Os.getpeername(socket)); 446 447 // Expect sendto to succeed both when given an explicit address and a null address. 448 Os.sendto(socket, packet, 0, packet.length, 0, addr); 449 Os.sendto(socket, packet, 0, packet.length, 0, null); 450 } catch (SocketException | ErrnoException e) { 451 fail("Expected success for " + msg + ", but got: " + e); 452 } 453 454 } finally { 455 IoUtils.closeQuietly(socket); 456 } 457 } 458 expectBindConnectSendtoErrno(int bindErrno, int connectErrno, int sendtoErrno, FileDescriptor socket, String socketDesc, SocketAddress addr)459 private static void expectBindConnectSendtoErrno(int bindErrno, int connectErrno, 460 int sendtoErrno, FileDescriptor socket, String socketDesc, SocketAddress addr) { 461 try { 462 463 // Expect bind to fail with bindErrno. 464 String msg = "bind " + socketDesc + " socket to " + addr.toString(); 465 try { 466 Os.bind(socket, addr); 467 fail("Expected to fail " + msg); 468 } catch (ErrnoException e) { 469 assertEquals("Expected errno " + bindErrno + " " + msg, bindErrno, e.errno); 470 } catch (SocketException e) { 471 fail("Unexpected SocketException " + msg); 472 } 473 474 // Expect connect to fail with connectErrno. 475 msg = "connect " + socketDesc + " socket to " + addr.toString(); 476 try { 477 Os.connect(socket, addr); 478 fail("Expected to fail " + msg); 479 } catch (ErrnoException e) { 480 assertEquals("Expected errno " + connectErrno + " " + msg, connectErrno, e.errno); 481 } catch (SocketException e) { 482 fail("Unexpected SocketException " + msg); 483 } 484 485 // Expect sendto to fail with sendtoErrno. 486 byte[] packet = new byte[42]; 487 msg = "sendto " + socketDesc + " socket to " + addr.toString(); 488 try { 489 Os.sendto(socket, packet, 0, packet.length, 0, addr); 490 fail("Expected to fail " + msg); 491 } catch (ErrnoException e) { 492 assertEquals("Expected errno " + sendtoErrno + " " + msg, sendtoErrno, e.errno); 493 } catch (SocketException e) { 494 fail("Unexpected SocketException " + msg); 495 } 496 497 } finally { 498 // No matter what happened, close the socket. 499 IoUtils.closeQuietly(socket); 500 } 501 } 502 makeIpv4Socket()503 private FileDescriptor makeIpv4Socket() throws Exception { 504 return Os.socket(AF_INET, SOCK_DGRAM, 0); 505 } 506 makeIpv6Socket()507 private FileDescriptor makeIpv6Socket() throws Exception { 508 return Os.socket(AF_INET6, SOCK_DGRAM, 0); 509 } 510 makeUnixSocket()511 private FileDescriptor makeUnixSocket() throws Exception { 512 return Os.socket(AF_UNIX, SOCK_DGRAM, 0); 513 } 514 testCrossFamilyBindConnectSendto()515 public void testCrossFamilyBindConnectSendto() throws Exception { 516 SocketAddress addrIpv4 = new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0); 517 SocketAddress addrIpv6 = new InetSocketAddress(InetAddress.getByName("::1"), 0); 518 SocketAddress addrUnix = UnixSocketAddress.createAbstract("/abstract_name_unix_socket"); 519 520 expectBindConnectSendtoSuccess(makeIpv4Socket(), "ipv4", addrIpv4); 521 expectBindConnectSendtoErrno(EAFNOSUPPORT, EAFNOSUPPORT, EAFNOSUPPORT, 522 makeIpv4Socket(), "ipv4", addrIpv6); 523 expectBindConnectSendtoErrno(EAFNOSUPPORT, EAFNOSUPPORT, EAFNOSUPPORT, 524 makeIpv4Socket(), "ipv4", addrUnix); 525 526 // This succeeds because Java always uses dual-stack sockets and all InetAddress and 527 // InetSocketAddress objects represent IPv4 addresses using IPv4-mapped IPv6 addresses. 528 expectBindConnectSendtoSuccess(makeIpv6Socket(), "ipv6", addrIpv4); 529 expectBindConnectSendtoSuccess(makeIpv6Socket(), "ipv6", addrIpv6); 530 expectBindConnectSendtoErrno(EAFNOSUPPORT, EAFNOSUPPORT, EINVAL, 531 makeIpv6Socket(), "ipv6", addrUnix); 532 533 expectBindConnectSendtoErrno(EINVAL, EINVAL, EINVAL, 534 makeUnixSocket(), "unix", addrIpv4); 535 expectBindConnectSendtoErrno(EINVAL, EINVAL, EINVAL, 536 makeUnixSocket(), "unix", addrIpv6); 537 expectBindConnectSendtoSuccess(makeUnixSocket(), "unix", addrUnix); 538 } 539 testUnknownSocketAddressSubclass()540 public void testUnknownSocketAddressSubclass() throws Exception { 541 class MySocketAddress extends SocketAddress { 542 543 } 544 MySocketAddress myaddr = new MySocketAddress(); 545 546 for (int family : new int[] { AF_INET, AF_INET6, AF_NETLINK }) { 547 FileDescriptor s = Os.socket(family, SOCK_DGRAM, 0); 548 try { 549 550 try { 551 Os.bind(s, myaddr); 552 fail("bind socket family " + family 553 + " to unknown SocketAddress subclass succeeded"); 554 } catch (UnsupportedOperationException expected) { 555 } 556 557 try { 558 Os.connect(s, myaddr); 559 fail("connect socket family " + family 560 + " to unknown SocketAddress subclass succeeded"); 561 } catch (UnsupportedOperationException expected) { 562 } 563 564 byte[] msg = new byte[42]; 565 try { 566 Os.sendto(s, msg, 0, msg.length, 0, myaddr); 567 fail("sendto socket family " + family 568 + " to unknown SocketAddress subclass succeeded"); 569 } catch (UnsupportedOperationException expected) { 570 } 571 572 } finally { 573 Os.close(s); 574 } 575 } 576 } 577 test_NetlinkSocket()578 public void test_NetlinkSocket() throws Exception { 579 FileDescriptor nlSocket = Os.socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); 580 try { 581 Os.bind(nlSocket, new NetlinkSocketAddress()); 582 // Non-system processes should not be allowed to bind() to NETLINK_ROUTE sockets. 583 // http://b/141455849 584 fail("bind() on NETLINK_ROUTE socket succeeded"); 585 } catch (ErrnoException expectedException) { 586 assertEquals(expectedException.errno, EACCES); 587 } 588 589 NetlinkSocketAddress nlKernel = new NetlinkSocketAddress(); 590 Os.connect(nlSocket, nlKernel); 591 NetlinkSocketAddress nlPeer = (NetlinkSocketAddress) Os.getpeername(nlSocket); 592 assertEquals(0, nlPeer.getPortId()); 593 assertEquals(0, nlPeer.getGroupsMask()); 594 Os.close(nlSocket); 595 } 596 597 // This test is excluded from CTS via the knownfailures.txt because it requires extra 598 // permissions not available in CTS. To run it you have to use an -eng build and use a tool like 599 // vogar that runs the Android runtime as a privileged user. test_PacketSocketAddress()600 public void test_PacketSocketAddress() throws Exception { 601 NetworkInterface lo = NetworkInterface.getByName("lo"); 602 FileDescriptor fd = Os.socket(AF_PACKET, SOCK_DGRAM, ETH_P_IPV6); 603 PacketSocketAddress addr = 604 new PacketSocketAddress(ETH_P_IPV6, lo.getIndex(), null /* sll_addr */); 605 Os.bind(fd, addr); 606 607 PacketSocketAddress bound = (PacketSocketAddress) Os.getsockname(fd); 608 assertEquals(ETH_P_IPV6, bound.sll_protocol); 609 assertEquals(lo.getIndex(), bound.sll_ifindex); 610 assertEquals(ARPHRD_LOOPBACK, bound.sll_hatype); 611 assertEquals(0, bound.sll_pkttype); 612 613 // The loopback address is ETH_ALEN bytes long and is all zeros. 614 // http://lxr.free-electrons.com/source/drivers/net/loopback.c?v=3.10#L167 615 assertEquals(6, bound.sll_addr.length); 616 for (int i = 0; i < 6; i++) { 617 assertEquals(0, bound.sll_addr[i]); 618 } 619 620 // The following checks that the packet socket address was constructed correctly in a form 621 // that the kernel understands. If the address is correct, the bind should result in a 622 // socket that is listening only for IPv6 packets, and only on loopback. 623 624 // Send an IPv4 packet on loopback. 625 // We send ourselves an IPv4 packet first. If we don't receive it, that (with high 626 // probability) ensures that the packet socket does not see IPv4 packets. 627 try (DatagramSocket s = new DatagramSocket()) { 628 byte[] packet = new byte[64]; 629 s.send(new DatagramPacket(packet, 0, packet.length, Inet4Address.LOOPBACK, 630 53 /* arbitrary port */)); 631 } 632 633 // Send an IPv6 packet on loopback. 634 // Sending ourselves an IPv6 packet should cause the socket to receive a packet. 635 // The idea is that if the code gets sll_protocol wrong, then the packet socket will receive 636 // no packets and the test will fail. 637 try (DatagramSocket s = new DatagramSocket()) { 638 byte[] packet = new byte[64]; 639 s.send(new DatagramPacket(packet, 0, packet.length, Inet6Address.LOOPBACK, 640 53 /* arbitrary port */)); 641 } 642 643 // Check that the socket associated with fd has received an IPv6 packet, not necessarily the 644 // UDP one we sent above. IPv6 packets always begin with the nibble 6. If we get anything 645 // else it means we're catching non-IPv6 or non-loopback packets unexpectedly. Since the 646 // socket is not discriminating it may catch packets unrelated to this test from things 647 // happening on the device at the same time, so we can't assert too much about the received 648 // packet, i.e. no length / content check. 649 { 650 byte[] receivedPacket = new byte[4096]; 651 Os.read(fd, receivedPacket, 0, receivedPacket.length); 652 assertEquals(6, (receivedPacket[0] & 0xf0) >> 4); 653 654 byte[] sourceAddress = getIPv6AddressBytesAtOffset(receivedPacket, 8); 655 assertArrayEquals(Inet6Address.LOOPBACK.getAddress(), sourceAddress); 656 657 byte[] destAddress = getIPv6AddressBytesAtOffset(receivedPacket, 24); 658 assertArrayEquals(Inet6Address.LOOPBACK.getAddress(), destAddress); 659 } 660 661 Os.close(fd); 662 } 663 getIPv6AddressBytesAtOffset(byte[] packet, int offsetIndex)664 private static byte[] getIPv6AddressBytesAtOffset(byte[] packet, int offsetIndex) { 665 byte[] address = new byte[16]; 666 for (int i = 0; i < 16; i++) { 667 address[i] = packet[i + offsetIndex]; 668 } 669 return address; 670 } 671 test_byteBufferPositions_sendto_recvfrom_af_inet()672 public void test_byteBufferPositions_sendto_recvfrom_af_inet() throws Exception { 673 checkByteBufferPositions_sendto_recvfrom(AF_INET, InetAddress.getByName("127.0.0.1")); 674 } 675 test_byteBufferPositions_sendto_recvfrom_af_inet6()676 public void test_byteBufferPositions_sendto_recvfrom_af_inet6() throws Exception { 677 checkByteBufferPositions_sendto_recvfrom(AF_INET6, InetAddress.getByName("::1")); 678 } 679 checkSendToSocketAddress(int family, InetAddress loopback)680 private void checkSendToSocketAddress(int family, InetAddress loopback) throws Exception { 681 FileDescriptor recvFd = Os.socket(family, SOCK_DGRAM, 0); 682 Os.bind(recvFd, loopback, 0); 683 StructTimeval tv = StructTimeval.fromMillis(20); 684 Os.setsockoptTimeval(recvFd, SOL_SOCKET, SO_RCVTIMEO, tv); 685 686 InetSocketAddress to = ((InetSocketAddress) Os.getsockname(recvFd)); 687 FileDescriptor sendFd = Os.socket(family, SOCK_DGRAM, 0); 688 byte[] msg = ("Hello, I'm going to a socket address: " + to.toString()).getBytes("UTF-8"); 689 int len = msg.length; 690 691 assertEquals(len, Os.sendto(sendFd, msg, 0, len, 0, to)); 692 byte[] received = new byte[msg.length + 42]; 693 InetSocketAddress from = new InetSocketAddress(); 694 assertEquals(len, Os.recvfrom(recvFd, received, 0, received.length, 0, from)); 695 assertEquals(loopback, from.getAddress()); 696 } 697 test_sendtoSocketAddress_af_inet()698 public void test_sendtoSocketAddress_af_inet() throws Exception { 699 checkSendToSocketAddress(AF_INET, InetAddress.getByName("127.0.0.1")); 700 } 701 test_sendtoSocketAddress_af_inet6()702 public void test_sendtoSocketAddress_af_inet6() throws Exception { 703 checkSendToSocketAddress(AF_INET6, InetAddress.getByName("::1")); 704 } 705 test_socketFamilies()706 public void test_socketFamilies() throws Exception { 707 FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0); 708 Os.bind(fd, InetAddress.getByName("::"), 0); 709 InetSocketAddress localSocketAddress = (InetSocketAddress) Os.getsockname(fd); 710 assertEquals(Inet6Address.ANY, localSocketAddress.getAddress()); 711 712 fd = Os.socket(AF_INET6, SOCK_STREAM, 0); 713 Os.bind(fd, InetAddress.getByName("0.0.0.0"), 0); 714 localSocketAddress = (InetSocketAddress) Os.getsockname(fd); 715 assertEquals(Inet6Address.ANY, localSocketAddress.getAddress()); 716 717 fd = Os.socket(AF_INET, SOCK_STREAM, 0); 718 Os.bind(fd, InetAddress.getByName("0.0.0.0"), 0); 719 localSocketAddress = (InetSocketAddress) Os.getsockname(fd); 720 assertEquals(Inet4Address.ANY, localSocketAddress.getAddress()); 721 try { 722 Os.bind(fd, InetAddress.getByName("::"), 0); 723 fail("Expected ErrnoException binding IPv4 socket to ::"); 724 } catch (ErrnoException expected) { 725 assertEquals("Expected EAFNOSUPPORT binding IPv4 socket to ::", EAFNOSUPPORT, 726 expected.errno); 727 } 728 } 729 assertArrayEquals(byte[] expected, byte[] actual)730 private static void assertArrayEquals(byte[] expected, byte[] actual) { 731 assertTrue("Expected=" + Arrays.toString(expected) + ", actual=" + Arrays.toString(actual), 732 Arrays.equals(expected, actual)); 733 } 734 checkSocketPing(FileDescriptor fd, InetAddress to, byte[] packet, byte type, byte responseType, boolean useSendto)735 private static void checkSocketPing(FileDescriptor fd, InetAddress to, byte[] packet, 736 byte type, byte responseType, boolean useSendto) throws Exception { 737 int len = packet.length; 738 packet[0] = type; 739 if (useSendto) { 740 assertEquals(len, Os.sendto(fd, packet, 0, len, 0, to, 0)); 741 } else { 742 Os.connect(fd, to, 0); 743 assertEquals(len, Os.sendto(fd, packet, 0, len, 0, null, 0)); 744 } 745 746 int icmpId = ((InetSocketAddress) Os.getsockname(fd)).getPort(); 747 byte[] received = new byte[4096]; 748 InetSocketAddress srcAddress = new InetSocketAddress(); 749 assertEquals(len, Os.recvfrom(fd, received, 0, received.length, 0, srcAddress)); 750 assertEquals(to, srcAddress.getAddress()); 751 assertEquals(responseType, received[0]); 752 assertEquals(received[4], (byte) (icmpId >> 8)); 753 assertEquals(received[5], (byte) (icmpId & 0xff)); 754 755 received = Arrays.copyOf(received, len); 756 received[0] = (byte) type; 757 received[2] = received[3] = 0; // Checksum. 758 received[4] = received[5] = 0; // ICMP ID. 759 assertArrayEquals(packet, received); 760 } 761 test_socketPing()762 public void test_socketPing() throws Exception { 763 final byte ICMP_ECHO = 8, ICMP_ECHOREPLY = 0; 764 final byte ICMPV6_ECHO_REQUEST = (byte) 128, ICMPV6_ECHO_REPLY = (byte) 129; 765 final byte[] packet = ("\000\000\000\000" + // ICMP type, code. 766 "\000\000\000\003" + // ICMP ID (== port), sequence number. 767 "Hello myself").getBytes(StandardCharsets.US_ASCII); 768 769 FileDescriptor fd = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); 770 InetAddress ipv6Loopback = InetAddress.getByName("::1"); 771 checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, true); 772 checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, false); 773 774 fd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); 775 InetAddress ipv4Loopback = InetAddress.getByName("127.0.0.1"); 776 checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, true); 777 checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, false); 778 } 779 test_Ipv4Fallback()780 public void test_Ipv4Fallback() throws Exception { 781 // This number of iterations gives a ~60% chance of creating the conditions that caused 782 // http://b/23088314 without making test times too long. On a hammerhead running MRZ37C 783 // using vogar, this test takes about 4s. 784 final int ITERATIONS = 10000; 785 for (int i = 0; i < ITERATIONS; i++) { 786 FileDescriptor mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 787 try { 788 Os.bind(mUdpSock, Inet4Address.ANY, 0); 789 } catch (ErrnoException e) { 790 fail("ErrnoException after " + i + " iterations: " + e); 791 } finally { 792 Os.close(mUdpSock); 793 } 794 } 795 } 796 test_unlink()797 public void test_unlink() throws Exception { 798 File f = File.createTempFile("OsTest", "tst"); 799 assertTrue(f.exists()); 800 Os.unlink(f.getAbsolutePath()); 801 assertFalse(f.exists()); 802 803 try { 804 Os.unlink(f.getAbsolutePath()); 805 fail(); 806 } catch (ErrnoException e) { 807 assertEquals(OsConstants.ENOENT, e.errno); 808 } 809 } 810 811 // b/27294715 test_recvfrom_concurrentShutdown()812 public void test_recvfrom_concurrentShutdown() throws Exception { 813 final FileDescriptor serverFd = Os.socket(AF_INET, SOCK_DGRAM, 0); 814 Os.bind(serverFd, InetAddress.getByName("127.0.0.1"), 0); 815 // Set 4s timeout 816 StructTimeval tv = StructTimeval.fromMillis(4000); 817 Os.setsockoptTimeval(serverFd, SOL_SOCKET, SO_RCVTIMEO, tv); 818 819 final AtomicReference<Exception> killerThreadException = new AtomicReference<Exception>( 820 null); 821 final Thread killer = new Thread(new Runnable() { 822 public void run() { 823 try { 824 Thread.sleep(2000); 825 try { 826 Os.shutdown(serverFd, SHUT_RDWR); 827 } catch (ErrnoException expected) { 828 if (OsConstants.ENOTCONN != expected.errno) { 829 killerThreadException.set(expected); 830 } 831 } 832 } catch (Exception ex) { 833 killerThreadException.set(ex); 834 } 835 } 836 }); 837 killer.start(); 838 839 ByteBuffer buffer = ByteBuffer.allocate(16); 840 InetSocketAddress srcAddress = new InetSocketAddress(); 841 int received = Os.recvfrom(serverFd, buffer, 0, srcAddress); 842 assertTrue(received == 0); 843 Os.close(serverFd); 844 845 killer.join(); 846 assertNull(killerThreadException.get()); 847 } 848 test_xattr()849 public void test_xattr() throws Exception { 850 final String NAME_TEST = "user.meow"; 851 852 final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8); 853 final byte[] VALUE_PIE = "pie".getBytes(StandardCharsets.UTF_8); 854 855 File file = File.createTempFile("xattr", "test"); 856 String path = file.getAbsolutePath(); 857 858 try { 859 try { 860 Os.getxattr(path, NAME_TEST); 861 fail("Expected ENODATA"); 862 } catch (ErrnoException e) { 863 assertEquals(OsConstants.ENODATA, e.errno); 864 } 865 assertFalse(Arrays.asList(Os.listxattr(path)).contains(NAME_TEST)); 866 867 Os.setxattr(path, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE); 868 byte[] xattr_create = Os.getxattr(path, NAME_TEST); 869 assertTrue(Arrays.asList(Os.listxattr(path)).contains(NAME_TEST)); 870 assertEquals(VALUE_CAKE.length, xattr_create.length); 871 assertStartsWith(VALUE_CAKE, xattr_create); 872 873 try { 874 Os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_CREATE); 875 fail("Expected EEXIST"); 876 } catch (ErrnoException e) { 877 assertEquals(OsConstants.EEXIST, e.errno); 878 } 879 880 Os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_REPLACE); 881 byte[] xattr_replace = Os.getxattr(path, NAME_TEST); 882 assertTrue(Arrays.asList(Os.listxattr(path)).contains(NAME_TEST)); 883 assertEquals(VALUE_PIE.length, xattr_replace.length); 884 assertStartsWith(VALUE_PIE, xattr_replace); 885 886 Os.removexattr(path, NAME_TEST); 887 try { 888 Os.getxattr(path, NAME_TEST); 889 fail("Expected ENODATA"); 890 } catch (ErrnoException e) { 891 assertEquals(OsConstants.ENODATA, e.errno); 892 } 893 assertFalse(Arrays.asList(Os.listxattr(path)).contains(NAME_TEST)); 894 895 } finally { 896 file.delete(); 897 } 898 } 899 test_xattr_NPE()900 public void test_xattr_NPE() throws Exception { 901 File file = File.createTempFile("xattr", "test"); 902 final String path = file.getAbsolutePath(); 903 final String NAME_TEST = "user.meow"; 904 final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8); 905 906 // getxattr 907 try { 908 Os.getxattr(null, NAME_TEST); 909 fail(); 910 } catch (NullPointerException expected) { 911 } 912 try { 913 Os.getxattr(path, null); 914 fail(); 915 } catch (NullPointerException expected) { 916 } 917 918 // listxattr 919 try { 920 Os.listxattr(null); 921 fail(); 922 } catch (NullPointerException expected) { 923 } 924 925 // removexattr 926 try { 927 Os.removexattr(null, NAME_TEST); 928 fail(); 929 } catch (NullPointerException expected) { 930 } 931 try { 932 Os.removexattr(path, null); 933 fail(); 934 } catch (NullPointerException expected) { 935 } 936 937 // setxattr 938 try { 939 Os.setxattr(null, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE); 940 fail(); 941 } catch (NullPointerException expected) { 942 } 943 try { 944 Os.setxattr(path, null, VALUE_CAKE, OsConstants.XATTR_CREATE); 945 fail(); 946 } catch (NullPointerException expected) { 947 } 948 try { 949 Os.setxattr(path, NAME_TEST, null, OsConstants.XATTR_CREATE); 950 fail(); 951 } catch (NullPointerException expected) { 952 } 953 } 954 test_xattr_Errno()955 public void test_xattr_Errno() throws Exception { 956 final String NAME_TEST = "user.meow"; 957 final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8); 958 959 // ENOENT, No such file or directory. 960 try { 961 Os.getxattr("", NAME_TEST); 962 fail(); 963 } catch (ErrnoException e) { 964 assertEquals(ENOENT, e.errno); 965 } 966 try { 967 Os.listxattr(""); 968 fail(); 969 } catch (ErrnoException e) { 970 assertEquals(ENOENT, e.errno); 971 } 972 try { 973 Os.removexattr("", NAME_TEST); 974 fail(); 975 } catch (ErrnoException e) { 976 assertEquals(ENOENT, e.errno); 977 } 978 try { 979 Os.setxattr("", NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE); 980 fail(); 981 } catch (ErrnoException e) { 982 assertEquals(ENOENT, e.errno); 983 } 984 985 // ENOTSUP, Extended attributes are not supported by the filesystem, or are disabled. 986 // Since kernel version 4.9 (or some other version after 4.4), *xattr() methods 987 // may set errno to EACCES instead. This behavior change is likely related to 988 // https://patchwork.kernel.org/patch/9294421/ which reimplemented getxattr, setxattr, 989 // and removexattr on top of generic handlers. 990 final String path = "/proc/self/stat"; 991 try { 992 Os.setxattr(path, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE); 993 fail(); 994 } catch (ErrnoException e) { 995 assertTrue("Unexpected errno: " + e.errno, e.errno == ENOTSUP || e.errno == EACCES); 996 } 997 try { 998 Os.getxattr(path, NAME_TEST); 999 fail(); 1000 } catch (ErrnoException e) { 1001 assertEquals(ENOTSUP, e.errno); 1002 } 1003 try { 1004 // Linux listxattr does not set errno. 1005 Os.listxattr(path); 1006 } catch (ErrnoException e) { 1007 fail(); 1008 } 1009 try { 1010 Os.removexattr(path, NAME_TEST); 1011 fail(); 1012 } catch (ErrnoException e) { 1013 assertTrue("Unexpected errno: " + e.errno, e.errno == ENOTSUP || e.errno == EACCES); 1014 } 1015 } 1016 test_realpath()1017 public void test_realpath() throws Exception { 1018 File tmpDir = new File(System.getProperty("java.io.tmpdir")); 1019 // This is a chicken and egg problem. We have no way of knowing whether 1020 // the temporary directory or one of its path elements were symlinked, so 1021 // we'll need this call to realpath. 1022 String canonicalTmpDir = Os.realpath(tmpDir.getAbsolutePath()); 1023 1024 // Test that "." and ".." are resolved correctly. 1025 assertEquals(canonicalTmpDir, 1026 Os.realpath(canonicalTmpDir + "/./../" + tmpDir.getName())); 1027 1028 // Test that symlinks are resolved correctly. 1029 File target = new File(tmpDir, "target"); 1030 File link = new File(tmpDir, "link"); 1031 try { 1032 assertTrue(target.createNewFile()); 1033 Os.symlink(target.getAbsolutePath(), link.getAbsolutePath()); 1034 1035 assertEquals(canonicalTmpDir + "/target", 1036 Os.realpath(canonicalTmpDir + "/link")); 1037 } finally { 1038 boolean deletedTarget = target.delete(); 1039 boolean deletedLink = link.delete(); 1040 // Asserting this here to provide a definitive reason for 1041 // a subsequent failure on the same run. 1042 assertTrue("deletedTarget = " + deletedTarget + ", deletedLink =" + deletedLink, 1043 deletedTarget && deletedLink); 1044 } 1045 } 1046 1047 /** 1048 * Tests that TCP_USER_TIMEOUT can be set on a TCP socket, but doesn't test 1049 * that it behaves as expected. 1050 */ test_socket_tcpUserTimeout_setAndGet()1051 public void test_socket_tcpUserTimeout_setAndGet() throws Exception { 1052 final FileDescriptor fd = Os.socket(AF_INET, SOCK_STREAM, 0); 1053 try { 1054 int v = Os.getsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT); 1055 assertEquals(0, v); // system default value 1056 int newValue = 3000; 1057 Os.setsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT, 1058 newValue); 1059 int actualValue = Os.getsockoptInt(fd, OsConstants.IPPROTO_TCP, 1060 OsConstants.TCP_USER_TIMEOUT); 1061 // The kernel can round the requested value based on the HZ setting. We allow up to 10ms 1062 // difference. 1063 assertTrue("Returned incorrect timeout:" + actualValue, 1064 Math.abs(newValue - actualValue) <= 10); 1065 // No need to reset the value to 0, since we're throwing the socket away 1066 } finally { 1067 Os.close(fd); 1068 } 1069 } 1070 test_socket_tcpUserTimeout_doesNotWorkOnDatagramSocket()1071 public void test_socket_tcpUserTimeout_doesNotWorkOnDatagramSocket() throws Exception { 1072 final FileDescriptor fd = Os.socket(AF_INET, SOCK_DGRAM, 0); 1073 try { 1074 Os.setsockoptInt(fd, OsConstants.IPPROTO_TCP, OsConstants.TCP_USER_TIMEOUT, 1075 3000); 1076 fail("datagram (connectionless) sockets shouldn't support TCP_USER_TIMEOUT"); 1077 } catch (ErrnoException expected) { 1078 // expected 1079 } finally { 1080 Os.close(fd); 1081 } 1082 } 1083 test_socket_sockoptTimeval_readWrite()1084 public void test_socket_sockoptTimeval_readWrite() throws Exception { 1085 FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0); 1086 try { 1087 StructTimeval v = Os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO); 1088 assertEquals(0, v.toMillis()); // system default value 1089 1090 StructTimeval newValue = StructTimeval.fromMillis(3000); 1091 Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, newValue); 1092 1093 StructTimeval actualValue = Os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO); 1094 1095 // The kernel can round the requested value based on the HZ setting. We allow up to 10ms 1096 // difference. 1097 assertTrue("Returned incorrect timeout:" + actualValue, 1098 Math.abs(newValue.toMillis() - actualValue.toMillis()) <= 10); 1099 // No need to reset the value to 0, since we're throwing the socket away 1100 } finally { 1101 Os.close(fd); 1102 } 1103 } 1104 test_socket_setSockoptTimeval_effective()1105 public void test_socket_setSockoptTimeval_effective() throws Exception { 1106 int timeoutValueMillis = 50; 1107 int allowedTimeoutMillis = 500; 1108 1109 FileDescriptor fd = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 1110 try { 1111 StructTimeval tv = StructTimeval.fromMillis(timeoutValueMillis); 1112 Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, tv); 1113 Os.bind(fd, InetAddress.getByName("::1"), 0); 1114 1115 byte[] request = new byte[1]; 1116 long startTime = System.nanoTime(); 1117 expectException(() -> Os.read(fd, request, 0, request.length), 1118 ErrnoException.class, EAGAIN, "Expected timeout"); 1119 long endTime = System.nanoTime(); 1120 assertTrue(Duration.ofNanos(endTime - startTime).toMillis() < allowedTimeoutMillis); 1121 } finally { 1122 Os.close(fd); 1123 } 1124 } 1125 1126 public void test_socket_setSockoptTimeval_nullFd() throws Exception { 1127 StructTimeval tv = StructTimeval.fromMillis(500); 1128 expectException( 1129 () -> Os.setsockoptTimeval(null, SOL_SOCKET, SO_RCVTIMEO, tv), 1130 ErrnoException.class, EBADF, "setsockoptTimeval(null, ...)"); 1131 } 1132 test_socket_setSockoptTimeval_fileFd()1133 public void test_socket_setSockoptTimeval_fileFd() throws Exception { 1134 File testFile = createTempFile("test_socket_setSockoptTimeval_invalidFd", ""); 1135 try (FileInputStream fis = new FileInputStream(testFile)) { 1136 final FileDescriptor fd = fis.getFD(); 1137 1138 StructTimeval tv = StructTimeval.fromMillis(500); 1139 expectException( 1140 () -> Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, tv), 1141 ErrnoException.class, ENOTSOCK, "setsockoptTimeval(<file fd>, ...)"); 1142 } 1143 } 1144 test_socket_setSockoptTimeval_badFd()1145 public void test_socket_setSockoptTimeval_badFd() throws Exception { 1146 StructTimeval tv = StructTimeval.fromMillis(500); 1147 FileDescriptor invalidFd = Os.socket(AF_INET6, SOCK_STREAM, 0); 1148 Os.close(invalidFd); 1149 1150 expectException( 1151 () -> Os.setsockoptTimeval(invalidFd, SOL_SOCKET, SO_RCVTIMEO, tv), 1152 ErrnoException.class, EBADF, "setsockoptTimeval(<closed fd>, ...)"); 1153 } 1154 test_socket_setSockoptTimeval_invalidLevel()1155 public void test_socket_setSockoptTimeval_invalidLevel() throws Exception { 1156 StructTimeval tv = StructTimeval.fromMillis(500); 1157 FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0); 1158 try { 1159 expectException( 1160 () -> Os.setsockoptTimeval(fd, -1, SO_RCVTIMEO, tv), 1161 ErrnoException.class, ENOPROTOOPT, 1162 "setsockoptTimeval(fd, <invalid level>, ...)"); 1163 } finally { 1164 Os.close(fd); 1165 } 1166 } 1167 test_socket_setSockoptTimeval_invalidOpt()1168 public void test_socket_setSockoptTimeval_invalidOpt() throws Exception { 1169 StructTimeval tv = StructTimeval.fromMillis(500); 1170 FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0); 1171 try { 1172 expectException( 1173 () -> Os.setsockoptTimeval(fd, SOL_SOCKET, -1, tv), 1174 ErrnoException.class, ENOPROTOOPT, 1175 "setsockoptTimeval(fd, <invalid level>, ...)"); 1176 } finally { 1177 Os.close(fd); 1178 } 1179 } 1180 test_socket_setSockoptTimeval_nullTimeVal()1181 public void test_socket_setSockoptTimeval_nullTimeVal() throws Exception { 1182 FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0); 1183 try { 1184 expectException( 1185 () -> Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, null), 1186 NullPointerException.class, null, "setsockoptTimeval(..., null)"); 1187 } finally { 1188 Os.close(fd); 1189 } 1190 } 1191 test_socket_getSockoptTimeval_invalidOption()1192 public void test_socket_getSockoptTimeval_invalidOption() throws Exception { 1193 FileDescriptor fd = Os.socket(AF_INET6, SOCK_STREAM, 0); 1194 try { 1195 expectException( 1196 () -> Os.getsockoptTimeval(fd, SOL_SOCKET, SO_DEBUG), 1197 IllegalArgumentException.class, null, 1198 "getsockoptTimeval(..., <non-timeval option>)"); 1199 } finally { 1200 Os.close(fd); 1201 } 1202 } 1203 test_if_nametoindex_if_indextoname()1204 public void test_if_nametoindex_if_indextoname() throws Exception { 1205 List<NetworkInterface> nis = Collections.list(NetworkInterface.getNetworkInterfaces()); 1206 1207 assertTrue(nis.size() > 0); 1208 for (NetworkInterface ni : nis) { 1209 int index = ni.getIndex(); 1210 String name = ni.getName(); 1211 assertEquals(index, Os.if_nametoindex(name)); 1212 assertTrue(Os.if_indextoname(index).equals(name)); 1213 } 1214 1215 assertEquals(0, Os.if_nametoindex("this-interface-does-not-exist")); 1216 assertEquals(null, Os.if_indextoname(-1000)); 1217 1218 try { 1219 Os.if_nametoindex(null); 1220 fail(); 1221 } catch (NullPointerException expected) { 1222 } 1223 } 1224 assertStartsWith(byte[] expectedContents, byte[] container)1225 private static void assertStartsWith(byte[] expectedContents, byte[] container) { 1226 for (int i = 0; i < expectedContents.length; i++) { 1227 if (expectedContents[i] != container[i]) { 1228 fail("Expected " + Arrays.toString(expectedContents) + " but found " 1229 + Arrays.toString(expectedContents)); 1230 } 1231 } 1232 } 1233 test_readlink()1234 public void test_readlink() throws Exception { 1235 File path = new File(TestIoUtils.createTemporaryDirectory("test_readlink"), "symlink"); 1236 1237 // ext2 and ext4 have PAGE_SIZE limits on symlink targets. 1238 // If file encryption is enabled, there's extra overhead to store the 1239 // size of the encrypted symlink target. There's also an off-by-one 1240 // in current kernels (and marlin/sailfish where we're seeing this 1241 // failure are still on 3.18, far from current). Given that we don't 1242 // really care here, just use 2048 instead. http://b/33306057. 1243 int size = 2048; 1244 String xs = ""; 1245 for (int i = 0; i < size - 1; ++i) { 1246 xs += "x"; 1247 } 1248 1249 Os.symlink(xs, path.getPath()); 1250 1251 assertEquals(xs, Os.readlink(path.getPath())); 1252 } 1253 1254 // Address should be correctly set for empty packets. http://b/33481605 test_recvfrom_EmptyPacket()1255 public void test_recvfrom_EmptyPacket() throws Exception { 1256 try (DatagramSocket ds = new DatagramSocket(); 1257 DatagramSocket srcSock = new DatagramSocket()) { 1258 srcSock.send(new DatagramPacket(new byte[0], 0, ds.getLocalSocketAddress())); 1259 1260 byte[] recvBuf = new byte[16]; 1261 InetSocketAddress address = new InetSocketAddress(); 1262 int recvCount = 1263 android.system.Os.recvfrom(ds.getFileDescriptor$(), recvBuf, 0, 16, 0, address); 1264 assertEquals(0, recvCount); 1265 assertTrue(address.getAddress().isLoopbackAddress()); 1266 assertEquals(srcSock.getLocalPort(), address.getPort()); 1267 } 1268 } 1269 test_fstat_times()1270 public void test_fstat_times() throws Exception { 1271 File file = File.createTempFile("OsTest", "fstattest"); 1272 FileOutputStream fos = new FileOutputStream(file); 1273 StructStat structStat1 = Os.fstat(fos.getFD()); 1274 assertEquals(structStat1.st_mtim.tv_sec, structStat1.st_mtime); 1275 assertEquals(structStat1.st_ctim.tv_sec, structStat1.st_ctime); 1276 assertEquals(structStat1.st_atim.tv_sec, structStat1.st_atime); 1277 Thread.sleep(100); 1278 fos.write(new byte[] { 1, 2, 3 }); 1279 fos.flush(); 1280 StructStat structStat2 = Os.fstat(fos.getFD()); 1281 fos.close(); 1282 1283 assertEquals(-1, structStat1.st_mtim.compareTo(structStat2.st_mtim)); 1284 assertEquals(-1, structStat1.st_ctim.compareTo(structStat2.st_ctim)); 1285 assertEquals(0, structStat1.st_atim.compareTo(structStat2.st_atim)); 1286 } 1287 test_getrlimit()1288 public void test_getrlimit() throws Exception { 1289 StructRlimit rlimit = Os.getrlimit(OsConstants.RLIMIT_NOFILE); 1290 // We can't really make any assertions about these values since they might vary from 1291 // device to device and even process to process. We do know that they will be greater 1292 // than zero, though. 1293 assertTrue(rlimit.rlim_cur > 0); 1294 assertTrue(rlimit.rlim_max > 0); 1295 } 1296 1297 // http://b/65051835 test_pipe2_errno()1298 public void test_pipe2_errno() throws Exception { 1299 try { 1300 // flag=-1 is not a valid value for pip2, will EINVAL 1301 Os.pipe2(-1); 1302 fail(); 1303 } catch (ErrnoException expected) { 1304 } 1305 } 1306 1307 // http://b/65051835 test_sendfile_errno()1308 public void test_sendfile_errno() throws Exception { 1309 try { 1310 // FileDescriptor.out is not open for input, will cause EBADF 1311 Int64Ref offset = new Int64Ref(10); 1312 Os.sendfile(FileDescriptor.out, FileDescriptor.out, offset, 10); 1313 fail(); 1314 } catch (ErrnoException expected) { 1315 } 1316 } 1317 test_sendfile_null()1318 public void test_sendfile_null() throws Exception { 1319 File in = createTempFile("test_sendfile_null", "Hello, world!"); 1320 try { 1321 int len = "Hello".length(); 1322 assertEquals("Hello", checkSendfile(in, null, len, null)); 1323 } finally { 1324 in.delete(); 1325 } 1326 } 1327 test_sendfile_offset()1328 public void test_sendfile_offset() throws Exception { 1329 File in = createTempFile("test_sendfile_offset", "Hello, world!"); 1330 try { 1331 // checkSendfile(sendFileImplToUse, in, startOffset, maxBytes, expectedEndOffset) 1332 assertEquals("Hello", checkSendfile(in, 0L, 5, 5L)); 1333 assertEquals("ello,", checkSendfile(in, 1L, 5, 6L)); 1334 // At offset 9, only 4 bytes/chars available, even though we're asking for 5. 1335 assertEquals("rld!", checkSendfile(in, 9L, 5, 13L)); 1336 assertEquals("", checkSendfile(in, 1L, 0, 1L)); 1337 } finally { 1338 in.delete(); 1339 } 1340 } 1341 checkSendfile(File in, Long startOffset, int maxBytes, Long expectedEndOffset)1342 private static String checkSendfile(File in, Long startOffset, 1343 int maxBytes, Long expectedEndOffset) throws IOException, ErrnoException { 1344 File out = File.createTempFile(OsTest.class.getSimpleName() + "_checkSendFile", ".out"); 1345 try (FileInputStream inStream = new FileInputStream(in)) { 1346 FileDescriptor inFd = inStream.getFD(); 1347 try (FileOutputStream outStream = new FileOutputStream(out)) { 1348 FileDescriptor outFd = outStream.getFD(); 1349 Int64Ref offset = (startOffset == null) ? null : new Int64Ref(startOffset); 1350 android.system.Os.sendfile(outFd, inFd, offset, maxBytes); 1351 assertEquals(expectedEndOffset, offset == null ? null : offset.value); 1352 } 1353 return TestIoUtils.readFileAsString(out.getPath()); 1354 } finally { 1355 out.delete(); 1356 } 1357 } 1358 createTempFile(String namePart, String contents)1359 private static File createTempFile(String namePart, String contents) throws IOException { 1360 File f = File.createTempFile(OsTest.class.getSimpleName() + namePart, ".in"); 1361 try (FileWriter writer = new FileWriter(f)) { 1362 writer.write(contents); 1363 } 1364 return f; 1365 } 1366 test_odirect()1367 public void test_odirect() throws Exception { 1368 File testFile = createTempFile("test_odirect", ""); 1369 try { 1370 FileDescriptor fd = 1371 Os.open(testFile.toString(), O_WRONLY | O_DIRECT, S_IRUSR | S_IWUSR); 1372 assertNotNull(fd); 1373 assertTrue(fd.valid()); 1374 int flags = Os.fcntlVoid(fd, F_GETFL); 1375 assertTrue("Expected file flags to include " + O_DIRECT + ", actual value: " + flags, 1376 0 != (flags & O_DIRECT)); 1377 Os.close(fd); 1378 } finally { 1379 testFile.delete(); 1380 } 1381 } 1382 test_splice()1383 public void test_splice() throws Exception { 1384 FileDescriptor[] pipe = Os.pipe2(0); 1385 File in = createTempFile("splice1", "foobar"); 1386 File out = createTempFile("splice2", ""); 1387 1388 Int64Ref offIn = new Int64Ref(1); 1389 Int64Ref offOut = new Int64Ref(0); 1390 1391 // Splice into pipe 1392 try (FileInputStream streamIn = new FileInputStream(in)) { 1393 FileDescriptor fdIn = streamIn.getFD(); 1394 long result = Os 1395 .splice(fdIn, offIn, pipe[1], null /* offOut */, 10 /* len */, 0 /* flags */); 1396 assertEquals(5, result); 1397 assertEquals(6, offIn.value); 1398 } 1399 1400 // Splice from pipe 1401 try (FileOutputStream streamOut = new FileOutputStream(out)) { 1402 FileDescriptor fdOut = streamOut.getFD(); 1403 long result = Os 1404 .splice(pipe[0], null /* offIn */, fdOut, offOut, 10 /* len */, 0 /* flags */); 1405 assertEquals(5, result); 1406 assertEquals(5, offOut.value); 1407 } 1408 1409 assertEquals("oobar", TestIoUtils.readFileAsString(out.getPath())); 1410 1411 Os.close(pipe[0]); 1412 Os.close(pipe[1]); 1413 } 1414 test_splice_errors()1415 public void test_splice_errors() throws Exception { 1416 File in = createTempFile("splice3", ""); 1417 File out = createTempFile("splice4", ""); 1418 FileDescriptor[] pipe = Os.pipe2(0); 1419 1420 //.fdIn == null 1421 try { 1422 Os.splice(null /* fdIn */, null /* offIn */, pipe[1], 1423 null /*offOut*/, 10 /* len */, 0 /* flags */); 1424 fail(); 1425 } catch (ErrnoException expected) { 1426 assertEquals(EBADF, expected.errno); 1427 } 1428 1429 //.fdOut == null 1430 try { 1431 Os.splice(pipe[0] /* fdIn */, null /* offIn */, null /* fdOut */, 1432 null /*offOut*/, 10 /* len */, 0 /* flags */); 1433 fail(); 1434 } catch (ErrnoException expected) { 1435 assertEquals(EBADF, expected.errno); 1436 } 1437 1438 // No pipe fd 1439 try (FileOutputStream streamOut = new FileOutputStream(out)) { 1440 try (FileInputStream streamIn = new FileInputStream(in)) { 1441 FileDescriptor fdIn = streamIn.getFD(); 1442 FileDescriptor fdOut = streamOut.getFD(); 1443 Os.splice(fdIn, null /* offIn */, fdOut, null /* offOut */, 10 /* len */, 1444 0 /* flags */); 1445 fail(); 1446 } catch (ErrnoException expected) { 1447 assertEquals(EINVAL, expected.errno); 1448 } 1449 } 1450 1451 Os.close(pipe[0]); 1452 Os.close(pipe[1]); 1453 } 1454 testCloseNullFileDescriptor()1455 public void testCloseNullFileDescriptor() throws Exception { 1456 try { 1457 Os.close(null); 1458 fail(); 1459 } catch (NullPointerException expected) { 1460 } 1461 } 1462 testSocketpairNullFileDescriptor1()1463 public void testSocketpairNullFileDescriptor1() throws Exception { 1464 try { 1465 Os.socketpair(AF_UNIX, SOCK_STREAM, 0, null, new FileDescriptor()); 1466 fail(); 1467 } catch (NullPointerException expected) { 1468 } 1469 } 1470 testSocketpairNullFileDescriptor2()1471 public void testSocketpairNullFileDescriptor2() throws Exception { 1472 try { 1473 Os.socketpair(AF_UNIX, SOCK_STREAM, 0, new FileDescriptor(), null); 1474 fail(); 1475 } catch (NullPointerException expected) { 1476 } 1477 } 1478 testSocketpairNullFileDescriptorBoth()1479 public void testSocketpairNullFileDescriptorBoth() throws Exception { 1480 try { 1481 Os.socketpair(AF_UNIX, SOCK_STREAM, 0, null, null); 1482 fail(); 1483 } catch (NullPointerException expected) { 1484 } 1485 } 1486 testInetPtonIpv4()1487 public void testInetPtonIpv4() { 1488 String srcAddress = "127.0.0.1"; 1489 InetAddress inetAddress = Os.inet_pton(AF_INET, srcAddress); 1490 assertEquals(srcAddress, inetAddress.getHostAddress()); 1491 } 1492 testInetPtonIpv6()1493 public void testInetPtonIpv6() { 1494 String srcAddress = "1123:4567:89ab:cdef:fedc:ba98:7654:3210"; 1495 InetAddress inetAddress = Os.inet_pton(AF_INET6, srcAddress); 1496 assertEquals(srcAddress, inetAddress.getHostAddress()); 1497 } 1498 testInetPtonInvalidFamily()1499 public void testInetPtonInvalidFamily() { 1500 String srcAddress = "127.0.0.1"; 1501 InetAddress inetAddress = Os.inet_pton(AF_UNIX, srcAddress); 1502 assertNull(inetAddress); 1503 } 1504 testInetPtonWrongFamily()1505 public void testInetPtonWrongFamily() { 1506 String srcAddress = "127.0.0.1"; 1507 InetAddress inetAddress = Os.inet_pton(AF_INET6, srcAddress); 1508 assertNull(inetAddress); 1509 } 1510 testInetPtonInvalidData()1511 public void testInetPtonInvalidData() { 1512 String srcAddress = "10.1"; 1513 InetAddress inetAddress = Os.inet_pton(AF_INET, srcAddress); 1514 assertNull(inetAddress); 1515 } 1516 1517 /** 1518 * Verifies the {@link OsConstants#MAP_ANONYMOUS}. 1519 */ testMapAnonymous()1520 public void testMapAnonymous() throws Exception { 1521 final long size = 4096; 1522 final long address = Os.mmap(0, size, PROT_READ, 1523 MAP_PRIVATE | MAP_ANONYMOUS, new FileDescriptor(), 0); 1524 assertTrue(address > 0); 1525 Os.munmap(address, size); 1526 } 1527 testMemfdCreate()1528 public void testMemfdCreate() throws Exception { 1529 FileDescriptor fd = null; 1530 try { 1531 fd = Os.memfd_create("test_memfd", 0); 1532 assertNotNull(fd); 1533 assertTrue(fd.valid()); 1534 1535 StructStat stat = Os.fstat(fd); 1536 assertEquals(0, stat.st_size); 1537 1538 final byte[] expected = new byte[] {1, 2, 3, 4}; 1539 Os.write(fd, expected, 0, expected.length); 1540 stat = Os.fstat(fd); 1541 assertEquals(expected.length, stat.st_size); 1542 1543 byte[] actual = new byte[expected.length]; 1544 // should be seekable 1545 Os.lseek(fd, 0, SEEK_SET); 1546 Os.read(fd, actual, 0, actual.length); 1547 assertArrayEquals(expected, actual); 1548 } finally { 1549 if (fd != null) { 1550 Os.close(fd); 1551 fd = null; 1552 } 1553 } 1554 } 1555 testMemfdCreateFlags()1556 public void testMemfdCreateFlags() throws Exception { 1557 FileDescriptor fd = null; 1558 1559 // test that MFD_CLOEXEC is obeyed 1560 try { 1561 fd = Os.memfd_create("test_memfd", 0); 1562 assertNotNull(fd); 1563 assertTrue(fd.valid()); 1564 int flags = Os.fcntlVoid(fd, F_GETFD); 1565 assertTrue("Expected flags to not include " + FD_CLOEXEC + ", actual value: " + flags, 1566 0 == (flags & FD_CLOEXEC)); 1567 } finally { 1568 if (fd != null) { 1569 Os.close(fd); 1570 fd = null; 1571 } 1572 } 1573 try { 1574 fd = Os.memfd_create("test_memfd", MFD_CLOEXEC); 1575 assertNotNull(fd); 1576 assertTrue(fd.valid()); 1577 int flags = Os.fcntlVoid(fd, F_GETFD); 1578 assertTrue("Expected flags to include " + FD_CLOEXEC + ", actual value: " + flags, 1579 0 != (flags & FD_CLOEXEC)); 1580 } finally { 1581 if (fd != null) { 1582 Os.close(fd); 1583 fd = null; 1584 } 1585 } 1586 } 1587 testMemfdCreateErrno()1588 public void testMemfdCreateErrno() throws Exception { 1589 expectException(() -> Os.memfd_create(null, 0), NullPointerException.class, null, 1590 "memfd_create(null, 0)"); 1591 1592 expectException(() -> Os.memfd_create("test_memfd", 0xffff), ErrnoException.class, EINVAL, 1593 "memfd_create(\"test_memfd\", 0xffff)"); 1594 } 1595 } 1596