OsTest.java revision b4af0b52e1190846edde87f352ca722a7d9e0259
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 17package libcore.io; 18 19import android.system.ErrnoException; 20import android.system.NetlinkSocketAddress; 21import android.system.OsConstants; 22import android.system.PacketSocketAddress; 23import android.system.StructTimeval; 24import android.system.StructUcred; 25import android.system.UnixSocketAddress; 26 27import java.io.File; 28import java.io.FileDescriptor; 29import java.io.FileInputStream; 30import java.io.FileOutputStream; 31import java.net.Inet4Address; 32import java.net.Inet6Address; 33import java.net.InetAddress; 34import java.net.InetSocketAddress; 35import java.net.NetworkInterface; 36import java.net.ServerSocket; 37import java.nio.ByteBuffer; 38import java.nio.charset.StandardCharsets; 39import java.util.Arrays; 40import java.util.Locale; 41import junit.framework.TestCase; 42import static android.system.OsConstants.*; 43 44public class OsTest extends TestCase { 45 public void testIsSocket() throws Exception { 46 File f = new File("/dev/null"); 47 FileInputStream fis = new FileInputStream(f); 48 assertFalse(S_ISSOCK(Libcore.os.fstat(fis.getFD()).st_mode)); 49 fis.close(); 50 51 ServerSocket s = new ServerSocket(); 52 assertTrue(S_ISSOCK(Libcore.os.fstat(s.getImpl$().getFD$()).st_mode)); 53 s.close(); 54 } 55 56 public void testFcntlInt() throws Exception { 57 File f = File.createTempFile("OsTest", "tst"); 58 FileInputStream fis = null; 59 try { 60 fis = new FileInputStream(f); 61 Libcore.os.fcntlInt(fis.getFD(), F_SETFD, FD_CLOEXEC); 62 int flags = Libcore.os.fcntlVoid(fis.getFD(), F_GETFD); 63 assertTrue((flags & FD_CLOEXEC) != 0); 64 } finally { 65 IoUtils.closeQuietly(fis); 66 f.delete(); 67 } 68 } 69 70 public void testUnixDomainSockets_in_file_system() throws Exception { 71 String path = System.getProperty("java.io.tmpdir") + "/test_unix_socket"; 72 new File(path).delete(); 73 checkUnixDomainSocket(UnixSocketAddress.createFileSystem(path), false); 74 } 75 76 public void testUnixDomainSocket_abstract_name() throws Exception { 77 // Linux treats a sun_path starting with a NUL byte as an abstract name. See unix(7). 78 checkUnixDomainSocket(UnixSocketAddress.createAbstract("/abstract_name_unix_socket"), true); 79 } 80 81 public void testUnixDomainSocket_unnamed() throws Exception { 82 final FileDescriptor fd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0); 83 // unix(7) says an unbound socket is unnamed. 84 checkNoSockName(fd); 85 Libcore.os.close(fd); 86 } 87 88 private void checkUnixDomainSocket(final UnixSocketAddress address, final boolean isAbstract) 89 throws Exception { 90 final FileDescriptor serverFd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0); 91 Libcore.os.bind(serverFd, address); 92 Libcore.os.listen(serverFd, 5); 93 94 checkSockName(serverFd, isAbstract, address); 95 96 Thread server = new Thread(new Runnable() { 97 public void run() { 98 try { 99 UnixSocketAddress peerAddress = UnixSocketAddress.createUnnamed(); 100 FileDescriptor clientFd = Libcore.os.accept(serverFd, peerAddress); 101 checkSockName(clientFd, isAbstract, address); 102 checkNoName(peerAddress); 103 104 checkNoPeerName(clientFd); 105 106 StructUcred credentials = Libcore.os.getsockoptUcred(clientFd, SOL_SOCKET, SO_PEERCRED); 107 assertEquals(Libcore.os.getpid(), credentials.pid); 108 assertEquals(Libcore.os.getuid(), credentials.uid); 109 assertEquals(Libcore.os.getgid(), credentials.gid); 110 111 byte[] request = new byte[256]; 112 Libcore.os.read(clientFd, request, 0, request.length); 113 114 String s = new String(request, "UTF-8"); 115 byte[] response = s.toUpperCase(Locale.ROOT).getBytes("UTF-8"); 116 Libcore.os.write(clientFd, response, 0, response.length); 117 118 Libcore.os.close(clientFd); 119 } catch (Exception ex) { 120 throw new RuntimeException(ex); 121 } 122 } 123 }); 124 server.start(); 125 126 FileDescriptor clientFd = Libcore.os.socket(AF_UNIX, SOCK_STREAM, 0); 127 128 Libcore.os.connect(clientFd, address); 129 checkNoSockName(clientFd); 130 131 String string = "hello, world!"; 132 133 byte[] request = string.getBytes("UTF-8"); 134 assertEquals(request.length, Libcore.os.write(clientFd, request, 0, request.length)); 135 136 byte[] response = new byte[request.length]; 137 assertEquals(response.length, Libcore.os.read(clientFd, response, 0, response.length)); 138 139 assertEquals(string.toUpperCase(Locale.ROOT), new String(response, "UTF-8")); 140 141 Libcore.os.close(clientFd); 142 } 143 144 private static void checkSockName(FileDescriptor fd, boolean isAbstract, 145 UnixSocketAddress address) throws Exception { 146 UnixSocketAddress isa = (UnixSocketAddress) Libcore.os.getsockname(fd); 147 assertEquals(address, isa); 148 if (isAbstract) { 149 assertEquals(0, isa.getSunPath()[0]); 150 } 151 } 152 153 private void checkNoName(UnixSocketAddress usa) { 154 assertEquals(0, usa.getSunPath().length); 155 } 156 157 private void checkNoPeerName(FileDescriptor fd) throws Exception { 158 checkNoName((UnixSocketAddress) Libcore.os.getpeername(fd)); 159 } 160 161 private void checkNoSockName(FileDescriptor fd) throws Exception { 162 checkNoName((UnixSocketAddress) Libcore.os.getsockname(fd)); 163 } 164 165 public void test_strsignal() throws Exception { 166 assertEquals("Killed", Libcore.os.strsignal(9)); 167 assertEquals("Unknown signal -1", Libcore.os.strsignal(-1)); 168 } 169 170 public void test_byteBufferPositions_write_pwrite() throws Exception { 171 FileOutputStream fos = new FileOutputStream(new File("/dev/null")); 172 FileDescriptor fd = fos.getFD(); 173 final byte[] contents = new String("goodbye, cruel world").getBytes(StandardCharsets.US_ASCII); 174 ByteBuffer byteBuffer = ByteBuffer.wrap(contents); 175 176 byteBuffer.position(0); 177 int written = Libcore.os.write(fd, byteBuffer); 178 assertTrue(written > 0); 179 assertEquals(written, byteBuffer.position()); 180 181 byteBuffer.position(4); 182 written = Libcore.os.write(fd, byteBuffer); 183 assertTrue(written > 0); 184 assertEquals(written + 4, byteBuffer.position()); 185 186 byteBuffer.position(0); 187 written = Libcore.os.pwrite(fd, byteBuffer, 64 /* offset */); 188 assertTrue(written > 0); 189 assertEquals(written, byteBuffer.position()); 190 191 byteBuffer.position(4); 192 written = Libcore.os.pwrite(fd, byteBuffer, 64 /* offset */); 193 assertTrue(written > 0); 194 assertEquals(written + 4, byteBuffer.position()); 195 196 fos.close(); 197 } 198 199 public void test_byteBufferPositions_read_pread() throws Exception { 200 FileInputStream fis = new FileInputStream(new File("/dev/zero")); 201 FileDescriptor fd = fis.getFD(); 202 ByteBuffer byteBuffer = ByteBuffer.allocate(64); 203 204 byteBuffer.position(0); 205 int read = Libcore.os.read(fd, byteBuffer); 206 assertTrue(read > 0); 207 assertEquals(read, byteBuffer.position()); 208 209 byteBuffer.position(4); 210 read = Libcore.os.read(fd, byteBuffer); 211 assertTrue(read > 0); 212 assertEquals(read + 4, byteBuffer.position()); 213 214 byteBuffer.position(0); 215 read = Libcore.os.pread(fd, byteBuffer, 64 /* offset */); 216 assertTrue(read > 0); 217 assertEquals(read, byteBuffer.position()); 218 219 byteBuffer.position(4); 220 read = Libcore.os.pread(fd, byteBuffer, 64 /* offset */); 221 assertTrue(read > 0); 222 assertEquals(read + 4, byteBuffer.position()); 223 224 fis.close(); 225 } 226 227 static void checkByteBufferPositions_sendto_recvfrom( 228 int family, InetAddress loopback) throws Exception { 229 final FileDescriptor serverFd = Libcore.os.socket(family, SOCK_STREAM, 0); 230 Libcore.os.bind(serverFd, loopback, 0); 231 Libcore.os.listen(serverFd, 5); 232 233 InetSocketAddress address = (InetSocketAddress) Libcore.os.getsockname(serverFd); 234 235 final Thread server = new Thread(new Runnable() { 236 public void run() { 237 try { 238 InetSocketAddress peerAddress = new InetSocketAddress(); 239 FileDescriptor clientFd = Libcore.os.accept(serverFd, peerAddress); 240 241 // Attempt to receive a maximum of 24 bytes from the client, and then 242 // close the connection. 243 ByteBuffer buffer = ByteBuffer.allocate(16); 244 int received = Libcore.os.recvfrom(clientFd, buffer, 0, null); 245 assertTrue(received > 0); 246 assertEquals(received, buffer.position()); 247 248 ByteBuffer buffer2 = ByteBuffer.allocate(16); 249 buffer2.position(8); 250 received = Libcore.os.recvfrom(clientFd, buffer2, 0, null); 251 assertTrue(received > 0); 252 assertEquals(received + 8, buffer.position()); 253 254 Libcore.os.close(clientFd); 255 } catch (Exception ex) { 256 throw new RuntimeException(ex); 257 } 258 } 259 }); 260 261 server.start(); 262 263 FileDescriptor clientFd = Libcore.os.socket(family, SOCK_STREAM, 0); 264 Libcore.os.connect(clientFd, address.getAddress(), address.getPort()); 265 266 final byte[] bytes = "good bye, cruel black hole with fancy distortion" 267 .getBytes(StandardCharsets.US_ASCII); 268 assertTrue(bytes.length > 24); 269 270 ByteBuffer input = ByteBuffer.wrap(bytes); 271 input.position(0); 272 input.limit(16); 273 274 int sent = Libcore.os.sendto(clientFd, input, 0, address.getAddress(), address.getPort()); 275 assertTrue(sent > 0); 276 assertEquals(sent, input.position()); 277 278 input.position(16); 279 input.limit(24); 280 sent = Libcore.os.sendto(clientFd, input, 0, address.getAddress(), address.getPort()); 281 assertTrue(sent > 0); 282 assertEquals(sent + 16, input.position()); 283 284 Libcore.os.close(clientFd); 285 } 286 287 public void test_NetlinkSocket() throws Exception { 288 FileDescriptor nlSocket = Libcore.os.socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); 289 Libcore.os.bind(nlSocket, new NetlinkSocketAddress()); 290 NetlinkSocketAddress address = (NetlinkSocketAddress) Libcore.os.getsockname(nlSocket); 291 assertTrue(address.getPortId() > 0); 292 assertEquals(0, address.getGroupsMask()); 293 294 NetlinkSocketAddress nlKernel = new NetlinkSocketAddress(); 295 Libcore.os.connect(nlSocket, nlKernel); 296 NetlinkSocketAddress nlPeer = (NetlinkSocketAddress) Libcore.os.getpeername(nlSocket); 297 assertEquals(0, nlPeer.getPortId()); 298 assertEquals(0, nlPeer.getGroupsMask()); 299 Libcore.os.close(nlSocket); 300 } 301 302 public void test_PacketSocketAddress() throws Exception { 303 NetworkInterface lo = NetworkInterface.getByName("lo"); 304 FileDescriptor fd = Libcore.os.socket(AF_PACKET, SOCK_DGRAM, ETH_P_IPV6); 305 PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6, lo.getIndex()); 306 Libcore.os.bind(fd, addr); 307 308 PacketSocketAddress bound = (PacketSocketAddress) Libcore.os.getsockname(fd); 309 assertEquals((short) ETH_P_IPV6, bound.sll_protocol); // ETH_P_IPV6 is an int. 310 assertEquals(lo.getIndex(), bound.sll_ifindex); 311 assertEquals(ARPHRD_LOOPBACK, bound.sll_hatype); 312 assertEquals(0, bound.sll_pkttype); 313 314 // The loopback address is ETH_ALEN bytes long and is all zeros. 315 // http://lxr.free-electrons.com/source/drivers/net/loopback.c?v=3.10#L167 316 assertEquals(6, bound.sll_addr.length); 317 for (int i = 0; i < 6; i++) { 318 assertEquals(0, bound.sll_addr[i]); 319 } 320 } 321 322 public void test_byteBufferPositions_sendto_recvfrom_af_inet() throws Exception { 323 checkByteBufferPositions_sendto_recvfrom(AF_INET, InetAddress.getByName("127.0.0.1")); 324 } 325 326 public void test_byteBufferPositions_sendto_recvfrom_af_inet6() throws Exception { 327 checkByteBufferPositions_sendto_recvfrom(AF_INET6, InetAddress.getByName("::1")); 328 } 329 330 private void checkSendToSocketAddress(int family, InetAddress loopback) throws Exception { 331 FileDescriptor recvFd = Libcore.os.socket(family, SOCK_DGRAM, 0); 332 Libcore.os.bind(recvFd, loopback, 0); 333 StructTimeval tv = StructTimeval.fromMillis(20); 334 Libcore.os.setsockoptTimeval(recvFd, SOL_SOCKET, SO_RCVTIMEO, tv); 335 336 InetSocketAddress to = ((InetSocketAddress) Libcore.os.getsockname(recvFd)); 337 FileDescriptor sendFd = Libcore.os.socket(family, SOCK_DGRAM, 0); 338 byte[] msg = ("Hello, I'm going to a socket address: " + to.toString()).getBytes("UTF-8"); 339 int len = msg.length; 340 341 assertEquals(len, Libcore.os.sendto(sendFd, msg, 0, len, 0, to)); 342 byte[] received = new byte[msg.length + 42]; 343 InetSocketAddress from = new InetSocketAddress(); 344 assertEquals(len, Libcore.os.recvfrom(recvFd, received, 0, received.length, 0, from)); 345 assertEquals(loopback, from.getAddress()); 346 } 347 348 public void test_sendtoSocketAddress_af_inet() throws Exception { 349 checkSendToSocketAddress(AF_INET, InetAddress.getByName("127.0.0.1")); 350 } 351 352 public void test_sendtoSocketAddress_af_inet6() throws Exception { 353 checkSendToSocketAddress(AF_INET6, InetAddress.getByName("::1")); 354 } 355 356 public void test_socketFamilies() throws Exception { 357 FileDescriptor fd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0); 358 Libcore.os.bind(fd, InetAddress.getByName("::"), 0); 359 InetSocketAddress localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd); 360 assertEquals(Inet6Address.ANY, localSocketAddress.getAddress()); 361 362 fd = Libcore.os.socket(AF_INET6, SOCK_STREAM, 0); 363 Libcore.os.bind(fd, InetAddress.getByName("0.0.0.0"), 0); 364 localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd); 365 assertEquals(Inet6Address.ANY, localSocketAddress.getAddress()); 366 367 fd = Libcore.os.socket(AF_INET, SOCK_STREAM, 0); 368 Libcore.os.bind(fd, InetAddress.getByName("0.0.0.0"), 0); 369 localSocketAddress = (InetSocketAddress) Libcore.os.getsockname(fd); 370 assertEquals(Inet4Address.ANY, localSocketAddress.getAddress()); 371 try { 372 Libcore.os.bind(fd, InetAddress.getByName("::"), 0); 373 fail("Expected ErrnoException binding IPv4 socket to ::"); 374 } catch (ErrnoException expected) { 375 assertEquals("Expected EAFNOSUPPORT binding IPv4 socket to ::", EAFNOSUPPORT, expected.errno); 376 } 377 } 378 379 private static void assertArrayEquals(byte[] expected, byte[] actual) { 380 assertTrue("Expected=" + Arrays.toString(expected) + ", actual=" + Arrays.toString(actual), 381 Arrays.equals(expected, actual)); 382 } 383 384 private static void checkSocketPing(FileDescriptor fd, InetAddress to, byte[] packet, 385 byte type, byte responseType, boolean useSendto) throws Exception { 386 int len = packet.length; 387 packet[0] = type; 388 if (useSendto) { 389 assertEquals(len, Libcore.os.sendto(fd, packet, 0, len, 0, to, 0)); 390 } else { 391 Libcore.os.connect(fd, to, 0); 392 assertEquals(len, Libcore.os.sendto(fd, packet, 0, len, 0, null, 0)); 393 } 394 395 int icmpId = ((InetSocketAddress) Libcore.os.getsockname(fd)).getPort(); 396 byte[] received = new byte[4096]; 397 InetSocketAddress srcAddress = new InetSocketAddress(); 398 assertEquals(len, Libcore.os.recvfrom(fd, received, 0, received.length, 0, srcAddress)); 399 assertEquals(to, srcAddress.getAddress()); 400 assertEquals(responseType, received[0]); 401 assertEquals(received[4], (byte) (icmpId >> 8)); 402 assertEquals(received[5], (byte) (icmpId & 0xff)); 403 404 received = Arrays.copyOf(received, len); 405 received[0] = (byte) type; 406 received[2] = received[3] = 0; // Checksum. 407 received[4] = received[5] = 0; // ICMP ID. 408 assertArrayEquals(packet, received); 409 } 410 411 public void test_socketPing() throws Exception { 412 final byte ICMP_ECHO = 8, ICMP_ECHOREPLY = 0; 413 final byte ICMPV6_ECHO_REQUEST = (byte) 128, ICMPV6_ECHO_REPLY = (byte) 129; 414 final byte[] packet = ("\000\000\000\000" + // ICMP type, code. 415 "\000\000\000\003" + // ICMP ID (== port), sequence number. 416 "Hello myself").getBytes(StandardCharsets.US_ASCII); 417 418 FileDescriptor fd = Libcore.os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); 419 InetAddress ipv6Loopback = InetAddress.getByName("::1"); 420 checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, true); 421 checkSocketPing(fd, ipv6Loopback, packet, ICMPV6_ECHO_REQUEST, ICMPV6_ECHO_REPLY, false); 422 423 fd = Libcore.os.socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); 424 InetAddress ipv4Loopback = InetAddress.getByName("127.0.0.1"); 425 checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, true); 426 checkSocketPing(fd, ipv4Loopback, packet, ICMP_ECHO, ICMP_ECHOREPLY, false); 427 } 428 429 public void test_Ipv4Fallback() throws Exception { 430 // This number of iterations gives a ~60% chance of creating the conditions that caused 431 // http://b/23088314 without making test times too long. On a hammerhead running MRZ37C using 432 // vogar, this test takes about 4s. 433 final int ITERATIONS = 10000; 434 for (int i = 0; i < ITERATIONS; i++) { 435 FileDescriptor mUdpSock = Libcore.os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 436 try { 437 Libcore.os.bind(mUdpSock, Inet4Address.ANY, 0); 438 } catch(ErrnoException e) { 439 fail("ErrnoException after " + i + " iterations: " + e); 440 } finally { 441 Libcore.os.close(mUdpSock); 442 } 443 } 444 } 445 446 public void test_unlink() throws Exception { 447 File f = File.createTempFile("OsTest", "tst"); 448 assertTrue(f.exists()); 449 Libcore.os.unlink(f.getAbsolutePath()); 450 assertFalse(f.exists()); 451 452 try { 453 Libcore.os.unlink(f.getAbsolutePath()); 454 fail(); 455 } catch (ErrnoException e) { 456 assertEquals(OsConstants.ENOENT, e.errno); 457 } 458 } 459 460 public void test_xattr() throws Exception { 461 final String NAME_TEST = "user.meow"; 462 463 final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8); 464 final byte[] VALUE_PIE = "pie".getBytes(StandardCharsets.UTF_8); 465 466 File file = File.createTempFile("xattr", "test"); 467 String path = file.getAbsolutePath(); 468 469 byte[] tmp = new byte[1024]; 470 try { 471 try { 472 Libcore.os.getxattr(path, NAME_TEST, tmp); 473 fail("Expected ENODATA"); 474 } catch (ErrnoException e) { 475 assertEquals(OsConstants.ENODATA, e.errno); 476 } 477 478 Libcore.os.setxattr(path, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE); 479 assertEquals(VALUE_CAKE.length, Libcore.os.getxattr(path, NAME_TEST, tmp)); 480 assertStartsWith(VALUE_CAKE, tmp); 481 482 try { 483 Libcore.os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_CREATE); 484 fail("Expected EEXIST"); 485 } catch (ErrnoException e) { 486 assertEquals(OsConstants.EEXIST, e.errno); 487 } 488 489 Libcore.os.setxattr(path, NAME_TEST, VALUE_PIE, OsConstants.XATTR_REPLACE); 490 assertEquals(VALUE_PIE.length, Libcore.os.getxattr(path, NAME_TEST, tmp)); 491 assertStartsWith(VALUE_PIE, tmp); 492 493 Libcore.os.removexattr(path, NAME_TEST); 494 try { 495 Libcore.os.getxattr(path, NAME_TEST, tmp); 496 fail("Expected ENODATA"); 497 } catch (ErrnoException e) { 498 assertEquals(OsConstants.ENODATA, e.errno); 499 } 500 501 } finally { 502 file.delete(); 503 } 504 } 505 506 private static void assertStartsWith(byte[] expectedContents, byte[] container) { 507 for (int i = 0; i < expectedContents.length; i++) { 508 if (expectedContents[i] != container[i]) { 509 fail("Expected " + Arrays.toString(expectedContents) + " but found " 510 + Arrays.toString(expectedContents)); 511 } 512 } 513 } 514} 515