• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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