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