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