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