• 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.io;
18 
19 import java.io.FileDescriptor;
20 import java.io.FileNotFoundException;
21 import java.io.IOException;
22 import java.net.BindException;
23 import java.net.ConnectException;
24 import java.net.DatagramPacket;
25 import java.net.Inet4Address;
26 import java.net.Inet6Address;
27 import java.net.InetAddress;
28 import java.net.InetSocketAddress;
29 import java.net.NetworkInterface;
30 import java.net.PortUnreachableException;
31 import java.net.SocketAddress;
32 import java.net.SocketException;
33 import java.net.SocketOptions;
34 import java.net.SocketTimeoutException;
35 import java.net.UnknownHostException;
36 import java.nio.ByteBuffer;
37 import java.util.Arrays;
38 import static libcore.io.OsConstants.*;
39 import libcore.util.MutableInt;
40 
41 /**
42  * Implements java.io/java.net/java.nio semantics in terms of the underlying POSIX system calls.
43  */
44 public final class IoBridge {
45 
IoBridge()46     private IoBridge() {
47     }
48 
available(FileDescriptor fd)49     public static int available(FileDescriptor fd) throws IOException {
50         try {
51             MutableInt available = new MutableInt(0);
52             Libcore.os.ioctlInt(fd, FIONREAD, available);
53             if (available.value < 0) {
54                 // If the fd refers to a regular file, the result is the difference between
55                 // the file size and the file position. This may be negative if the position
56                 // is past the end of the file. If the fd refers to a special file masquerading
57                 // as a regular file, the result may be negative because the special file
58                 // may appear to have zero size and yet a previous read call may have
59                 // read some amount of data and caused the file position to be advanced.
60                 available.value = 0;
61             }
62             return available.value;
63         } catch (ErrnoException errnoException) {
64             if (errnoException.errno == ENOTTY) {
65                 // The fd is unwilling to opine about its read buffer.
66                 return 0;
67             }
68             throw errnoException.rethrowAsIOException();
69         }
70     }
71 
72 
bind(FileDescriptor fd, InetAddress address, int port)73     public static void bind(FileDescriptor fd, InetAddress address, int port) throws SocketException {
74         if (address instanceof Inet6Address && ((Inet6Address) address).getScopeId() == 0) {
75             // Linux won't let you bind a link-local address without a scope id. Find one.
76             NetworkInterface nif = NetworkInterface.getByInetAddress(address);
77             if (nif == null) {
78                 throw new SocketException("Can't bind to a link-local address without a scope id: " + address);
79             }
80             try {
81                 address = Inet6Address.getByAddress(address.getHostName(), address.getAddress(), nif.getIndex());
82             } catch (UnknownHostException ex) {
83                 throw new AssertionError(ex); // Can't happen.
84             }
85         }
86         try {
87             Libcore.os.bind(fd, address, port);
88         } catch (ErrnoException errnoException) {
89             throw new BindException(errnoException.getMessage(), errnoException);
90         }
91     }
92 
93 
94     /**
95      * Connects socket 'fd' to 'inetAddress' on 'port', with no timeout. The lack of a timeout
96      * means this method won't throw SocketTimeoutException.
97      */
connect(FileDescriptor fd, InetAddress inetAddress, int port)98     public static boolean connect(FileDescriptor fd, InetAddress inetAddress, int port) throws SocketException {
99         try {
100             return IoBridge.connect(fd, inetAddress, port, 0);
101         } catch (SocketTimeoutException ex) {
102             throw new AssertionError(ex); // Can't happen for a connect without a timeout.
103         }
104     }
105 
106     /**
107      * Connects socket 'fd' to 'inetAddress' on 'port', with a the given 'timeoutMs'.
108      * Use timeoutMs == 0 for a blocking connect with no timeout.
109      */
connect(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs)110     public static boolean connect(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws SocketException, SocketTimeoutException {
111         try {
112             return connectErrno(fd, inetAddress, port, timeoutMs);
113         } catch (ErrnoException errnoException) {
114             throw new ConnectException(connectDetail(inetAddress, port, timeoutMs, errnoException), errnoException);
115         } catch (SocketException ex) {
116             throw ex; // We don't want to doubly wrap these.
117         } catch (SocketTimeoutException ex) {
118             throw ex; // We don't want to doubly wrap these.
119         } catch (IOException ex) {
120             throw new SocketException(ex);
121         }
122     }
123 
connectErrno(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs)124     private static boolean connectErrno(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws ErrnoException, IOException {
125         // With no timeout, just call connect(2) directly.
126         if (timeoutMs == 0) {
127             Libcore.os.connect(fd, inetAddress, port);
128             return true;
129         }
130 
131         // For connect with a timeout, we:
132         //   1. set the socket to non-blocking,
133         //   2. connect(2),
134         //   3. loop using poll(2) to decide whether we're connected, whether we should keep
135         //      waiting, or whether we've seen a permanent failure and should give up,
136         //   4. set the socket back to blocking.
137 
138         // 1. set the socket to non-blocking.
139         IoUtils.setBlocking(fd, false);
140 
141         // 2. call connect(2) non-blocking.
142         long finishTimeMs = System.currentTimeMillis() + timeoutMs;
143         try {
144             Libcore.os.connect(fd, inetAddress, port);
145             IoUtils.setBlocking(fd, true); // 4. set the socket back to blocking.
146             return true; // We connected immediately.
147         } catch (ErrnoException errnoException) {
148             if (errnoException.errno != EINPROGRESS) {
149                 throw errnoException;
150             }
151             // EINPROGRESS means we should keep trying...
152         }
153 
154         // 3. loop using poll(2).
155         int remainingTimeoutMs;
156         do {
157             remainingTimeoutMs = (int) (finishTimeMs - System.currentTimeMillis());
158             if (remainingTimeoutMs <= 0) {
159                 throw new SocketTimeoutException(connectDetail(inetAddress, port, timeoutMs, null));
160             }
161         } while (!IoBridge.isConnected(fd, inetAddress, port, timeoutMs, remainingTimeoutMs));
162         IoUtils.setBlocking(fd, true); // 4. set the socket back to blocking.
163         return true; // Or we'd have thrown.
164     }
165 
connectDetail(InetAddress inetAddress, int port, int timeoutMs, ErrnoException cause)166     private static String connectDetail(InetAddress inetAddress, int port, int timeoutMs, ErrnoException cause) {
167         String detail = "failed to connect to " + inetAddress + " (port " + port + ")";
168         if (timeoutMs > 0) {
169             detail += " after " + timeoutMs + "ms";
170         }
171         if (cause != null) {
172             detail += ": " + cause.getMessage();
173         }
174         return detail;
175     }
176 
closeSocket(FileDescriptor fd)177     public static void closeSocket(FileDescriptor fd) throws IOException {
178         if (!fd.valid()) {
179             // Socket.close doesn't throw if you try to close an already-closed socket.
180             return;
181         }
182         int intFd = fd.getInt$();
183         fd.setInt$(-1);
184         FileDescriptor oldFd = new FileDescriptor();
185         oldFd.setInt$(intFd);
186         AsynchronousCloseMonitor.signalBlockedThreads(oldFd);
187         try {
188             Libcore.os.close(oldFd);
189         } catch (ErrnoException errnoException) {
190             // TODO: are there any cases in which we should throw?
191         }
192     }
193 
isConnected(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs, int remainingTimeoutMs)194     public static boolean isConnected(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs, int remainingTimeoutMs) throws IOException {
195         ErrnoException cause;
196         try {
197             StructPollfd[] pollFds = new StructPollfd[] { new StructPollfd() };
198             pollFds[0].fd = fd;
199             pollFds[0].events = (short) POLLOUT;
200             int rc = Libcore.os.poll(pollFds, remainingTimeoutMs);
201             if (rc == 0) {
202                 return false; // Timeout.
203             }
204             int connectError = Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_ERROR);
205             if (connectError == 0) {
206                 return true; // Success!
207             }
208             throw new ErrnoException("isConnected", connectError); // The connect(2) failed.
209         } catch (ErrnoException errnoException) {
210             if (!fd.valid()) {
211                 throw new SocketException("Socket closed");
212             }
213             if (errnoException.errno == EINTR) {
214                 return false; // Punt and ask the caller to try again.
215             } else {
216                 cause = errnoException;
217             }
218         }
219         // TODO: is it really helpful/necessary to throw so many different exceptions?
220         String detail = connectDetail(inetAddress, port, timeoutMs, cause);
221         if (cause.errno == ECONNRESET || cause.errno == ECONNREFUSED ||
222                 cause.errno == EADDRNOTAVAIL || cause.errno == EADDRINUSE ||
223                 cause.errno == ENETUNREACH) {
224             throw new ConnectException(detail, cause);
225         } else if (cause.errno == EACCES) {
226             throw new SecurityException(detail, cause);
227         } else if (cause.errno == ETIMEDOUT) {
228             throw new SocketTimeoutException(detail, cause);
229         }
230         throw new SocketException(detail, cause);
231     }
232 
233     // Socket options used by java.net but not exposed in SocketOptions.
234     public static final int JAVA_MCAST_JOIN_GROUP = 19;
235     public static final int JAVA_MCAST_LEAVE_GROUP = 20;
236     public static final int JAVA_IP_MULTICAST_TTL = 17;
237 
238     /**
239      * java.net has its own socket options similar to the underlying Unix ones. We paper over the
240      * differences here.
241      */
getSocketOption(FileDescriptor fd, int option)242     public static Object getSocketOption(FileDescriptor fd, int option) throws SocketException {
243         try {
244             return getSocketOptionErrno(fd, option);
245         } catch (ErrnoException errnoException) {
246             throw errnoException.rethrowAsSocketException();
247         }
248     }
249 
getSocketOptionErrno(FileDescriptor fd, int option)250     private static Object getSocketOptionErrno(FileDescriptor fd, int option) throws ErrnoException, SocketException {
251         switch (option) {
252         case SocketOptions.IP_MULTICAST_IF:
253             // This is IPv4-only.
254             return Libcore.os.getsockoptInAddr(fd, IPPROTO_IP, IP_MULTICAST_IF);
255         case SocketOptions.IP_MULTICAST_IF2:
256             // This is IPv6-only.
257             return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF);
258         case SocketOptions.IP_MULTICAST_LOOP:
259             // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
260             // it doesn't matter which we return.
261             return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP));
262         case IoBridge.JAVA_IP_MULTICAST_TTL:
263             // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
264             // it doesn't matter which we return.
265             return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS);
266         case SocketOptions.IP_TOS:
267             // Since setting this from java.net always sets IPv4 and IPv6 to the same value,
268             // it doesn't matter which we return.
269             return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_TCLASS);
270         case SocketOptions.SO_BROADCAST:
271             return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_BROADCAST));
272         case SocketOptions.SO_KEEPALIVE:
273             return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_KEEPALIVE));
274         case SocketOptions.SO_LINGER:
275             StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER);
276             if (!linger.isOn()) {
277                 return false;
278             }
279             return linger.l_linger;
280         case SocketOptions.SO_OOBINLINE:
281             return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_OOBINLINE));
282         case SocketOptions.SO_RCVBUF:
283             return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_SNDBUF);
284         case SocketOptions.SO_REUSEADDR:
285             return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR));
286         case SocketOptions.SO_SNDBUF:
287             return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_SNDBUF);
288         case SocketOptions.SO_TIMEOUT:
289             return (int) Libcore.os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO).toMillis();
290         case SocketOptions.TCP_NODELAY:
291             return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY));
292         default:
293             throw new SocketException("Unknown socket option: " + option);
294         }
295     }
296 
booleanFromInt(int i)297     private static boolean booleanFromInt(int i) {
298         return (i != 0);
299     }
300 
booleanToInt(boolean b)301     private static int booleanToInt(boolean b) {
302         return b ? 1 : 0;
303     }
304 
305     /**
306      * java.net has its own socket options similar to the underlying Unix ones. We paper over the
307      * differences here.
308      */
setSocketOption(FileDescriptor fd, int option, Object value)309     public static void setSocketOption(FileDescriptor fd, int option, Object value) throws SocketException {
310         try {
311             setSocketOptionErrno(fd, option, value);
312         } catch (ErrnoException errnoException) {
313             throw errnoException.rethrowAsSocketException();
314         }
315     }
316 
setSocketOptionErrno(FileDescriptor fd, int option, Object value)317     private static void setSocketOptionErrno(FileDescriptor fd, int option, Object value) throws ErrnoException, SocketException {
318         switch (option) {
319         case SocketOptions.IP_MULTICAST_IF:
320             throw new UnsupportedOperationException("Use IP_MULTICAST_IF2 on Android");
321         case SocketOptions.IP_MULTICAST_IF2:
322             // Although IPv6 was cleaned up to use int, IPv4 uses an ip_mreqn containing an int.
323             Libcore.os.setsockoptIpMreqn(fd, IPPROTO_IP, IP_MULTICAST_IF, (Integer) value);
324             Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (Integer) value);
325             return;
326         case SocketOptions.IP_MULTICAST_LOOP:
327             // Although IPv6 was cleaned up to use int, IPv4 multicast loopback uses a byte.
328             Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_LOOP, booleanToInt((Boolean) value));
329             Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, booleanToInt((Boolean) value));
330             return;
331         case IoBridge.JAVA_IP_MULTICAST_TTL:
332             // Although IPv6 was cleaned up to use int, and IPv4 non-multicast TTL uses int,
333             // IPv4 multicast TTL uses a byte.
334             Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_TTL, (Integer) value);
335             Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (Integer) value);
336             return;
337         case SocketOptions.IP_TOS:
338             Libcore.os.setsockoptInt(fd, IPPROTO_IP, IP_TOS, (Integer) value);
339             Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_TCLASS, (Integer) value);
340             return;
341         case SocketOptions.SO_BROADCAST:
342             Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_BROADCAST, booleanToInt((Boolean) value));
343             return;
344         case SocketOptions.SO_KEEPALIVE:
345             Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_KEEPALIVE, booleanToInt((Boolean) value));
346             return;
347         case SocketOptions.SO_LINGER:
348             boolean on = false;
349             int seconds = 0;
350             if (value instanceof Integer) {
351                 on = true;
352                 seconds = Math.min((Integer) value, 65535);
353             }
354             StructLinger linger = new StructLinger(booleanToInt(on), seconds);
355             Libcore.os.setsockoptLinger(fd, SOL_SOCKET, SO_LINGER, linger);
356             return;
357         case SocketOptions.SO_OOBINLINE:
358             Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_OOBINLINE, booleanToInt((Boolean) value));
359             return;
360         case SocketOptions.SO_RCVBUF:
361             Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, (Integer) value);
362             return;
363         case SocketOptions.SO_REUSEADDR:
364             Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR, booleanToInt((Boolean) value));
365             return;
366         case SocketOptions.SO_SNDBUF:
367             Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_SNDBUF, (Integer) value);
368             return;
369         case SocketOptions.SO_TIMEOUT:
370             int millis = (Integer) value;
371             StructTimeval tv = StructTimeval.fromMillis(millis);
372             Libcore.os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, tv);
373             return;
374         case SocketOptions.TCP_NODELAY:
375             Libcore.os.setsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY, booleanToInt((Boolean) value));
376             return;
377         case IoBridge.JAVA_MCAST_JOIN_GROUP:
378         case IoBridge.JAVA_MCAST_LEAVE_GROUP:
379             StructGroupReq groupReq = (StructGroupReq) value;
380             int level = (groupReq.gr_group instanceof Inet4Address) ? IPPROTO_IP : IPPROTO_IPV6;
381             int op = (option == JAVA_MCAST_JOIN_GROUP) ? MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP;
382             Libcore.os.setsockoptGroupReq(fd, level, op, groupReq);
383             return;
384         default:
385             throw new SocketException("Unknown socket option: " + option);
386         }
387     }
388 
389     /**
390      * java.io only throws FileNotFoundException when opening files, regardless of what actually
391      * went wrong. Additionally, java.io is more restrictive than POSIX when it comes to opening
392      * directories: POSIX says read-only is okay, but java.io doesn't even allow that. We also
393      * have an Android-specific hack to alter the default permissions.
394      */
open(String path, int flags)395     public static FileDescriptor open(String path, int flags) throws FileNotFoundException {
396         FileDescriptor fd = null;
397         try {
398             // On Android, we don't want default permissions to allow global access.
399             int mode = ((flags & O_ACCMODE) == O_RDONLY) ? 0 : 0600;
400             fd = Libcore.os.open(path, flags, mode);
401             if (fd.valid()) {
402                 // Posix open(2) fails with EISDIR only if you ask for write permission.
403                 // Java disallows reading directories too.
404                 if (S_ISDIR(Libcore.os.fstat(fd).st_mode)) {
405                     throw new ErrnoException("open", EISDIR);
406                 }
407             }
408             return fd;
409         } catch (ErrnoException errnoException) {
410             try {
411                 if (fd != null) {
412                     IoUtils.close(fd);
413                 }
414             } catch (IOException ignored) {
415             }
416             FileNotFoundException ex = new FileNotFoundException(path + ": " + errnoException.getMessage());
417             ex.initCause(errnoException);
418             throw ex;
419         }
420     }
421 
422     /**
423      * java.io thinks that a read at EOF is an error and should return -1, contrary to traditional
424      * Unix practice where you'd read until you got 0 bytes (and any future read would return -1).
425      */
read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount)426     public static int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {
427         Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount);
428         if (byteCount == 0) {
429             return 0;
430         }
431         try {
432             int readCount = Libcore.os.read(fd, bytes, byteOffset, byteCount);
433             if (readCount == 0) {
434                 return -1;
435             }
436             return readCount;
437         } catch (ErrnoException errnoException) {
438             if (errnoException.errno == EAGAIN) {
439                 // We return 0 rather than throw if we try to read from an empty non-blocking pipe.
440                 return 0;
441             }
442             throw errnoException.rethrowAsIOException();
443         }
444     }
445 
446     /**
447      * java.io always writes every byte it's asked to, or fails with an error. (That is, unlike
448      * Unix it never just writes as many bytes as happens to be convenient.)
449      */
write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount)450     public static void write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException {
451         Arrays.checkOffsetAndCount(bytes.length, byteOffset, byteCount);
452         if (byteCount == 0) {
453             return;
454         }
455         try {
456             while (byteCount > 0) {
457                 int bytesWritten = Libcore.os.write(fd, bytes, byteOffset, byteCount);
458                 byteCount -= bytesWritten;
459                 byteOffset += bytesWritten;
460             }
461         } catch (ErrnoException errnoException) {
462             throw errnoException.rethrowAsIOException();
463         }
464     }
465 
sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port)466     public static int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws IOException {
467         boolean isDatagram = (inetAddress != null);
468         if (!isDatagram && byteCount <= 0) {
469             return 0;
470         }
471         int result;
472         try {
473             result = Libcore.os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port);
474         } catch (ErrnoException errnoException) {
475             result = maybeThrowAfterSendto(isDatagram, errnoException);
476         }
477         return result;
478     }
479 
sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port)480     public static int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws IOException {
481         boolean isDatagram = (inetAddress != null);
482         if (!isDatagram && buffer.remaining() == 0) {
483             return 0;
484         }
485         int result;
486         try {
487             result = Libcore.os.sendto(fd, buffer, flags, inetAddress, port);
488         } catch (ErrnoException errnoException) {
489             result = maybeThrowAfterSendto(isDatagram, errnoException);
490         }
491         return result;
492     }
493 
maybeThrowAfterSendto(boolean isDatagram, ErrnoException errnoException)494     private static int maybeThrowAfterSendto(boolean isDatagram, ErrnoException errnoException) throws SocketException {
495         if (isDatagram) {
496             if (errnoException.errno == ECONNRESET || errnoException.errno == ECONNREFUSED) {
497                 return 0;
498             }
499         } else {
500             if (errnoException.errno == EAGAIN || errnoException.errno == EWOULDBLOCK) {
501                 // We were asked to write to a non-blocking socket, but were told
502                 // it would block, so report "no bytes written".
503                 return 0;
504             }
505         }
506         throw errnoException.rethrowAsSocketException();
507     }
508 
recvfrom(boolean isRead, FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, DatagramPacket packet, boolean isConnected)509     public static int recvfrom(boolean isRead, FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, DatagramPacket packet, boolean isConnected) throws IOException {
510         int result;
511         try {
512             InetSocketAddress srcAddress = (packet != null && !isConnected) ? new InetSocketAddress() : null;
513             result = Libcore.os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress);
514             result = postRecvfrom(isRead, packet, isConnected, srcAddress, result);
515         } catch (ErrnoException errnoException) {
516             result = maybeThrowAfterRecvfrom(isRead, isConnected, errnoException);
517         }
518         return result;
519     }
520 
recvfrom(boolean isRead, FileDescriptor fd, ByteBuffer buffer, int flags, DatagramPacket packet, boolean isConnected)521     public static int recvfrom(boolean isRead, FileDescriptor fd, ByteBuffer buffer, int flags, DatagramPacket packet, boolean isConnected) throws IOException {
522         int result;
523         try {
524             InetSocketAddress srcAddress = (packet != null && !isConnected) ? new InetSocketAddress() : null;
525             result = Libcore.os.recvfrom(fd, buffer, flags, srcAddress);
526             result = postRecvfrom(isRead, packet, isConnected, srcAddress, result);
527         } catch (ErrnoException errnoException) {
528             result = maybeThrowAfterRecvfrom(isRead, isConnected, errnoException);
529         }
530         return result;
531     }
532 
postRecvfrom(boolean isRead, DatagramPacket packet, boolean isConnected, InetSocketAddress srcAddress, int byteCount)533     private static int postRecvfrom(boolean isRead, DatagramPacket packet, boolean isConnected, InetSocketAddress srcAddress, int byteCount) {
534         if (isRead && byteCount == 0) {
535             return -1;
536         }
537         if (packet != null) {
538             packet.setReceivedLength(byteCount);
539             if (!isConnected) {
540                 packet.setAddress(srcAddress.getAddress());
541                 packet.setPort(srcAddress.getPort());
542             }
543         }
544         return byteCount;
545     }
546 
maybeThrowAfterRecvfrom(boolean isRead, boolean isConnected, ErrnoException errnoException)547     private static int maybeThrowAfterRecvfrom(boolean isRead, boolean isConnected, ErrnoException errnoException) throws SocketException, SocketTimeoutException {
548         if (isRead) {
549             if (errnoException.errno == EAGAIN || errnoException.errno == EWOULDBLOCK) {
550                 return 0;
551             } else {
552                 throw errnoException.rethrowAsSocketException();
553             }
554         } else {
555             if (isConnected && errnoException.errno == ECONNREFUSED) {
556                 throw new PortUnreachableException("", errnoException);
557             } else if (errnoException.errno == EAGAIN || errnoException.errno == EWOULDBLOCK) {
558                 throw new SocketTimeoutException(errnoException);
559             } else {
560                 throw errnoException.rethrowAsSocketException();
561             }
562         }
563     }
564 
socket(boolean stream)565     public static FileDescriptor socket(boolean stream) throws SocketException {
566         FileDescriptor fd;
567         try {
568             fd = Libcore.os.socket(AF_INET6, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
569 
570             // The RFC (http://www.ietf.org/rfc/rfc3493.txt) says that IPV6_MULTICAST_HOPS defaults
571             // to 1. The Linux kernel (at least up to 2.6.38) accidentally defaults to 64 (which
572             // would be correct for the *unicast* hop limit).
573             // See http://www.spinics.net/lists/netdev/msg129022.html, though no patch appears to
574             // have been applied as a result of that discussion. If that bug is ever fixed, we can
575             // remove this code. Until then, we manually set the hop limit on IPv6 datagram sockets.
576             // (IPv4 is already correct.)
577             if (!stream) {
578                 Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 1);
579             }
580 
581             return fd;
582         } catch (ErrnoException errnoException) {
583             throw errnoException.rethrowAsSocketException();
584         }
585     }
586 
getSocketLocalAddress(FileDescriptor fd)587     public static InetAddress getSocketLocalAddress(FileDescriptor fd) {
588         try {
589             SocketAddress sa = Libcore.os.getsockname(fd);
590             InetSocketAddress isa = (InetSocketAddress) sa;
591             return isa.getAddress();
592         } catch (ErrnoException errnoException) {
593             throw new AssertionError(errnoException);
594         }
595     }
596 
getSocketLocalPort(FileDescriptor fd)597     public static int getSocketLocalPort(FileDescriptor fd) {
598         try {
599             SocketAddress sa = Libcore.os.getsockname(fd);
600             InetSocketAddress isa = (InetSocketAddress) sa;
601             return isa.getPort();
602         } catch (ErrnoException errnoException) {
603             throw new AssertionError(errnoException);
604         }
605     }
606 }
607