1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libcore.io; 18 19 import android.system.ErrnoException; 20 import android.system.Int32Ref; 21 import android.system.StructGroupReq; 22 import android.system.StructLinger; 23 import android.system.StructPollfd; 24 import android.system.StructTimeval; 25 26 import libcore.util.ArrayUtils; 27 28 import dalvik.annotation.compat.UnsupportedAppUsage; 29 import java.io.FileDescriptor; 30 import java.io.FileNotFoundException; 31 import java.io.IOException; 32 import java.net.BindException; 33 import java.net.ConnectException; 34 import java.net.DatagramPacket; 35 import java.net.Inet4Address; 36 import java.net.Inet6Address; 37 import java.net.InetAddress; 38 import java.net.InetSocketAddress; 39 import java.net.NetworkInterface; 40 import java.net.NoRouteToHostException; 41 import java.net.PortUnreachableException; 42 import java.net.SocketAddress; 43 import java.net.SocketException; 44 import java.net.SocketOptions; 45 import java.net.SocketTimeoutException; 46 import java.net.UnknownHostException; 47 import java.nio.ByteBuffer; 48 import java.util.concurrent.TimeUnit; 49 50 import static android.system.OsConstants.*; 51 52 /** 53 * Implements java.io/java.net/java.nio semantics in terms of the underlying POSIX system calls. 54 * 55 * @hide 56 */ 57 @libcore.api.CorePlatformApi 58 public final class IoBridge { 59 IoBridge()60 private IoBridge() { 61 } 62 available(FileDescriptor fd)63 public static int available(FileDescriptor fd) throws IOException { 64 try { 65 Int32Ref available = new Int32Ref(0); 66 Libcore.os.ioctlInt(fd, FIONREAD, available); 67 if (available.value < 0) { 68 // If the fd refers to a regular file, the result is the difference between 69 // the file size and the file position. This may be negative if the position 70 // is past the end of the file. If the fd refers to a special file masquerading 71 // as a regular file, the result may be negative because the special file 72 // may appear to have zero size and yet a previous read call may have 73 // read some amount of data and caused the file position to be advanced. 74 available.value = 0; 75 } 76 return available.value; 77 } catch (ErrnoException errnoException) { 78 if (errnoException.errno == ENOTTY) { 79 // The fd is unwilling to opine about its read buffer. 80 return 0; 81 } 82 throw errnoException.rethrowAsIOException(); 83 } 84 } 85 86 bind(FileDescriptor fd, InetAddress address, int port)87 public static void bind(FileDescriptor fd, InetAddress address, int port) throws SocketException { 88 if (address instanceof Inet6Address) { 89 Inet6Address inet6Address = (Inet6Address) address; 90 if (inet6Address.getScopeId() == 0 && inet6Address.isLinkLocalAddress()) { 91 // Linux won't let you bind a link-local address without a scope id. 92 // Find one. 93 NetworkInterface nif = NetworkInterface.getByInetAddress(address); 94 if (nif == null) { 95 throw new SocketException("Can't bind to a link-local address without a scope id: " + address); 96 } 97 try { 98 address = Inet6Address.getByAddress(address.getHostName(), address.getAddress(), nif.getIndex()); 99 } catch (UnknownHostException ex) { 100 throw new AssertionError(ex); // Can't happen. 101 } 102 } 103 } 104 try { 105 Libcore.os.bind(fd, address, port); 106 } catch (ErrnoException errnoException) { 107 if (errnoException.errno == EADDRINUSE || errnoException.errno == EADDRNOTAVAIL || 108 errnoException.errno == EPERM || errnoException.errno == EACCES) { 109 throw new BindException(errnoException.getMessage(), errnoException); 110 } else { 111 throw new SocketException(errnoException.getMessage(), errnoException); 112 } 113 } 114 } 115 116 117 /** 118 * Connects socket 'fd' to 'inetAddress' on 'port', with no timeout. The lack of a timeout 119 * means this method won't throw SocketTimeoutException. 120 */ connect(FileDescriptor fd, InetAddress inetAddress, int port)121 public static void connect(FileDescriptor fd, InetAddress inetAddress, int port) throws SocketException { 122 try { 123 IoBridge.connect(fd, inetAddress, port, 0); 124 } catch (SocketTimeoutException ex) { 125 throw new AssertionError(ex); // Can't happen for a connect without a timeout. 126 } 127 } 128 129 /** 130 * Connects socket 'fd' to 'inetAddress' on 'port', with a the given 'timeoutMs'. 131 * Use timeoutMs == 0 for a blocking connect with no timeout. 132 */ connect(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs)133 public static void connect(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws SocketException, SocketTimeoutException { 134 try { 135 connectErrno(fd, inetAddress, port, timeoutMs); 136 } catch (ErrnoException errnoException) { 137 if (errnoException.errno == EHOSTUNREACH) { 138 throw new NoRouteToHostException("Host unreachable"); 139 } 140 if (errnoException.errno == EADDRNOTAVAIL) { 141 throw new NoRouteToHostException("Address not available"); 142 } 143 throw new ConnectException(createMessageForException(fd, inetAddress, port, timeoutMs, 144 errnoException), errnoException); 145 } catch (SocketException ex) { 146 throw ex; // We don't want to doubly wrap these. 147 } catch (SocketTimeoutException ex) { 148 throw ex; // We don't want to doubly wrap these. 149 } catch (IOException ex) { 150 throw new SocketException(ex); 151 } 152 } 153 connectErrno(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs)154 private static void connectErrno(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs) throws ErrnoException, IOException { 155 // With no timeout, just call connect(2) directly. 156 if (timeoutMs <= 0) { 157 Libcore.os.connect(fd, inetAddress, port); 158 return; 159 } 160 161 // For connect with a timeout, we: 162 // 1. set the socket to non-blocking, 163 // 2. connect(2), 164 // 3. loop using poll(2) to decide whether we're connected, whether we should keep 165 // waiting, or whether we've seen a permanent failure and should give up, 166 // 4. set the socket back to blocking. 167 168 // 1. set the socket to non-blocking. 169 IoUtils.setBlocking(fd, false); 170 171 // 2. call connect(2) non-blocking. 172 long finishTimeNanos = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeoutMs); 173 try { 174 Libcore.os.connect(fd, inetAddress, port); 175 IoUtils.setBlocking(fd, true); // 4. set the socket back to blocking. 176 return; // We connected immediately. 177 } catch (ErrnoException errnoException) { 178 if (errnoException.errno != EINPROGRESS) { 179 throw errnoException; 180 } 181 // EINPROGRESS means we should keep trying... 182 } 183 184 // 3. loop using poll(2). 185 int remainingTimeoutMs; 186 do { 187 remainingTimeoutMs = 188 (int) TimeUnit.NANOSECONDS.toMillis(finishTimeNanos - System.nanoTime()); 189 if (remainingTimeoutMs <= 0) { 190 throw new SocketTimeoutException( 191 createMessageForException(fd, inetAddress, port, timeoutMs, null)); 192 } 193 } while (!IoBridge.isConnected(fd, inetAddress, port, timeoutMs, remainingTimeoutMs)); 194 IoUtils.setBlocking(fd, true); // 4. set the socket back to blocking. 195 } 196 197 /** 198 * Constructs the message for an exception that the caller is about to throw. 199 */ createMessageForException(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs, Exception causeOrNull)200 private static String createMessageForException(FileDescriptor fd, InetAddress inetAddress, 201 int port, int timeoutMs, Exception causeOrNull) { 202 // Figure out source address from fd. 203 InetSocketAddress localAddress = null; 204 try { 205 localAddress = getLocalInetSocketAddress(fd); 206 } catch (SocketException ignored) { 207 // The caller is about to throw an exception, so this one would only distract. 208 } 209 210 StringBuilder sb = new StringBuilder("failed to connect") 211 .append(" to ") 212 .append(inetAddress) 213 .append(" (port ") 214 .append(port) 215 .append(")"); 216 if (localAddress != null) { 217 sb.append(" from ") 218 .append(localAddress.getAddress()) 219 .append(" (port ") 220 .append(localAddress.getPort()) 221 .append(")"); 222 } 223 if (timeoutMs > 0) { 224 sb.append(" after ") 225 .append(timeoutMs) 226 .append("ms"); 227 } 228 if (causeOrNull != null) { 229 sb.append(": ") 230 .append(causeOrNull.getMessage()); 231 } 232 return sb.toString(); 233 } 234 235 /** 236 * Closes the Unix file descriptor associated with the supplied file descriptor, resets the 237 * internal int to -1, and sends a signal to any threads are currently blocking. In order for 238 * the signal to be sent the blocked threads must have registered with the 239 * AsynchronousCloseMonitor before they entered the blocking operation. {@code fd} will be 240 * invalid after this call. 241 * 242 * <p>This method is a no-op if passed a {@code null} or already-closed file descriptor. 243 */ 244 @libcore.api.CorePlatformApi closeAndSignalBlockedThreads(FileDescriptor fd)245 public static void closeAndSignalBlockedThreads(FileDescriptor fd) throws IOException { 246 if (fd == null || !fd.valid()) { 247 return; 248 } 249 // fd is invalid after we call release. 250 FileDescriptor oldFd = fd.release$(); 251 AsynchronousCloseMonitor.signalBlockedThreads(oldFd); 252 try { 253 Libcore.os.close(oldFd); 254 } catch (ErrnoException errnoException) { 255 throw errnoException.rethrowAsIOException(); 256 } 257 } 258 259 @UnsupportedAppUsage isConnected(FileDescriptor fd, InetAddress inetAddress, int port, int timeoutMs, int remainingTimeoutMs)260 public static boolean isConnected(FileDescriptor fd, InetAddress inetAddress, int port, 261 int timeoutMs, int remainingTimeoutMs) throws IOException { 262 ErrnoException cause; 263 try { 264 StructPollfd[] pollFds = new StructPollfd[] { new StructPollfd() }; 265 pollFds[0].fd = fd; 266 pollFds[0].events = (short) POLLOUT; 267 int rc = Libcore.os.poll(pollFds, remainingTimeoutMs); 268 if (rc == 0) { 269 return false; // Timeout. 270 } 271 int connectError = Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_ERROR); 272 if (connectError == 0) { 273 return true; // Success! 274 } 275 throw new ErrnoException("isConnected", connectError); // The connect(2) failed. 276 } catch (ErrnoException errnoException) { 277 if (!fd.valid()) { 278 throw new SocketException("Socket closed"); 279 } 280 cause = errnoException; 281 } 282 String detail = createMessageForException(fd, inetAddress, port, timeoutMs, cause); 283 if (cause.errno == ETIMEDOUT) { 284 SocketTimeoutException e = new SocketTimeoutException(detail); 285 e.initCause(cause); 286 throw e; 287 } 288 throw new ConnectException(detail, cause); 289 } 290 291 // Socket options used by java.net but not exposed in SocketOptions. 292 public static final int JAVA_MCAST_JOIN_GROUP = 19; 293 public static final int JAVA_MCAST_LEAVE_GROUP = 20; 294 public static final int JAVA_IP_MULTICAST_TTL = 17; 295 public static final int JAVA_IP_TTL = 25; 296 297 /** 298 * java.net has its own socket options similar to the underlying Unix ones. We paper over the 299 * differences here. 300 */ getSocketOption(FileDescriptor fd, int option)301 public static Object getSocketOption(FileDescriptor fd, int option) throws SocketException { 302 try { 303 return getSocketOptionErrno(fd, option); 304 } catch (ErrnoException errnoException) { 305 throw errnoException.rethrowAsSocketException(); 306 } 307 } 308 getSocketOptionErrno(FileDescriptor fd, int option)309 private static Object getSocketOptionErrno(FileDescriptor fd, int option) throws ErrnoException, SocketException { 310 switch (option) { 311 case SocketOptions.IP_MULTICAST_IF: 312 case SocketOptions.IP_MULTICAST_IF2: 313 return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF); 314 case SocketOptions.IP_MULTICAST_LOOP: 315 // Since setting this from java.net always sets IPv4 and IPv6 to the same value, 316 // it doesn't matter which we return. 317 // NOTE: getsockopt's return value means "isEnabled", while OpenJDK code java.net 318 // requires a value that means "isDisabled" so we NEGATE the system call value here. 319 return !booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP)); 320 case IoBridge.JAVA_IP_MULTICAST_TTL: 321 // Since setting this from java.net always sets IPv4 and IPv6 to the same value, 322 // it doesn't matter which we return. 323 return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); 324 case IoBridge.JAVA_IP_TTL: 325 // Since setting this from java.net always sets IPv4 and IPv6 to the same value, 326 // it doesn't matter which we return. 327 return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS); 328 case SocketOptions.IP_TOS: 329 // Since setting this from java.net always sets IPv4 and IPv6 to the same value, 330 // it doesn't matter which we return. 331 return Libcore.os.getsockoptInt(fd, IPPROTO_IPV6, IPV6_TCLASS); 332 case SocketOptions.SO_BROADCAST: 333 return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_BROADCAST)); 334 case SocketOptions.SO_KEEPALIVE: 335 return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_KEEPALIVE)); 336 case SocketOptions.SO_LINGER: 337 StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER); 338 if (!linger.isOn()) { 339 return false; 340 } 341 return linger.l_linger; 342 case SocketOptions.SO_OOBINLINE: 343 return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_OOBINLINE)); 344 case SocketOptions.SO_RCVBUF: 345 return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_RCVBUF); 346 case SocketOptions.SO_REUSEADDR: 347 return booleanFromInt(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR)); 348 case SocketOptions.SO_SNDBUF: 349 return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_SNDBUF); 350 case SocketOptions.SO_TIMEOUT: 351 return (int) Libcore.os.getsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO).toMillis(); 352 case SocketOptions.TCP_NODELAY: 353 return booleanFromInt(Libcore.os.getsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY)); 354 case SocketOptions.SO_BINDADDR: 355 return ((InetSocketAddress) Libcore.os.getsockname(fd)).getAddress(); 356 default: 357 throw new SocketException("Unknown socket option: " + option); 358 } 359 } 360 booleanFromInt(int i)361 private static boolean booleanFromInt(int i) { 362 return (i != 0); 363 } 364 booleanToInt(boolean b)365 private static int booleanToInt(boolean b) { 366 return b ? 1 : 0; 367 } 368 369 /** 370 * java.net has its own socket options similar to the underlying Unix ones. We paper over the 371 * differences here. 372 */ setSocketOption(FileDescriptor fd, int option, Object value)373 public static void setSocketOption(FileDescriptor fd, int option, Object value) throws SocketException { 374 try { 375 setSocketOptionErrno(fd, option, value); 376 } catch (ErrnoException errnoException) { 377 throw errnoException.rethrowAsSocketException(); 378 } 379 } 380 setSocketOptionErrno(FileDescriptor fd, int option, Object value)381 private static void setSocketOptionErrno(FileDescriptor fd, int option, Object value) throws ErrnoException, SocketException { 382 switch (option) { 383 case SocketOptions.IP_MULTICAST_IF: 384 NetworkInterface nif = NetworkInterface.getByInetAddress((InetAddress) value); 385 if (nif == null) { 386 throw new SocketException( 387 "bad argument for IP_MULTICAST_IF : address not bound to any interface"); 388 } 389 // Although IPv6 was cleaned up to use int, IPv4 uses an ip_mreqn containing an int. 390 Libcore.os.setsockoptIpMreqn(fd, IPPROTO_IP, IP_MULTICAST_IF, nif.getIndex()); 391 Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, nif.getIndex()); 392 return; 393 case SocketOptions.IP_MULTICAST_IF2: 394 // Although IPv6 was cleaned up to use int, IPv4 uses an ip_mreqn containing an int. 395 Libcore.os.setsockoptIpMreqn(fd, IPPROTO_IP, IP_MULTICAST_IF, (Integer) value); 396 Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (Integer) value); 397 return; 398 case SocketOptions.IP_MULTICAST_LOOP: 399 // Although IPv6 was cleaned up to use int, IPv4 multicast loopback uses a byte. 400 // NOTE: setsockopt's arguement value means "isEnabled", while OpenJDK code java.net 401 // uses a value that means "isDisabled" so we NEGATE the system call value here. 402 int enable = booleanToInt(!((Boolean) value)); 403 Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_LOOP, enable); 404 Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, enable); 405 return; 406 case IoBridge.JAVA_IP_MULTICAST_TTL: 407 // Although IPv6 was cleaned up to use int, and IPv4 non-multicast TTL uses int, 408 // IPv4 multicast TTL uses a byte. 409 Libcore.os.setsockoptByte(fd, IPPROTO_IP, IP_MULTICAST_TTL, (Integer) value); 410 Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (Integer) value); 411 return; 412 case IoBridge.JAVA_IP_TTL: 413 Libcore.os.setsockoptInt(fd, IPPROTO_IP, IP_TTL, (Integer) value); 414 Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (Integer) value); 415 return; 416 case SocketOptions.IP_TOS: 417 Libcore.os.setsockoptInt(fd, IPPROTO_IP, IP_TOS, (Integer) value); 418 Libcore.os.setsockoptInt(fd, IPPROTO_IPV6, IPV6_TCLASS, (Integer) value); 419 return; 420 case SocketOptions.SO_BROADCAST: 421 Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_BROADCAST, booleanToInt((Boolean) value)); 422 return; 423 case SocketOptions.SO_KEEPALIVE: 424 Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_KEEPALIVE, booleanToInt((Boolean) value)); 425 return; 426 case SocketOptions.SO_LINGER: 427 boolean on = false; 428 int seconds = 0; 429 if (value instanceof Integer) { 430 on = true; 431 seconds = Math.min((Integer) value, 65535); 432 } 433 StructLinger linger = new StructLinger(booleanToInt(on), seconds); 434 Libcore.os.setsockoptLinger(fd, SOL_SOCKET, SO_LINGER, linger); 435 return; 436 case SocketOptions.SO_OOBINLINE: 437 Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_OOBINLINE, booleanToInt((Boolean) value)); 438 return; 439 case SocketOptions.SO_RCVBUF: 440 Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, (Integer) value); 441 return; 442 case SocketOptions.SO_REUSEADDR: 443 Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_REUSEADDR, booleanToInt((Boolean) value)); 444 return; 445 case SocketOptions.SO_SNDBUF: 446 Libcore.os.setsockoptInt(fd, SOL_SOCKET, SO_SNDBUF, (Integer) value); 447 return; 448 case SocketOptions.SO_TIMEOUT: 449 int millis = (Integer) value; 450 StructTimeval tv = StructTimeval.fromMillis(millis); 451 Libcore.os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, tv); 452 return; 453 case SocketOptions.TCP_NODELAY: 454 Libcore.os.setsockoptInt(fd, IPPROTO_TCP, TCP_NODELAY, booleanToInt((Boolean) value)); 455 return; 456 case IoBridge.JAVA_MCAST_JOIN_GROUP: 457 case IoBridge.JAVA_MCAST_LEAVE_GROUP: 458 { 459 StructGroupReq groupReq = (StructGroupReq) value; 460 int level = (groupReq.gr_group instanceof Inet4Address) ? IPPROTO_IP : IPPROTO_IPV6; 461 int op = (option == JAVA_MCAST_JOIN_GROUP) ? MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP; 462 Libcore.os.setsockoptGroupReq(fd, level, op, groupReq); 463 return; 464 } 465 default: 466 throw new SocketException("Unknown socket option: " + option); 467 } 468 } 469 470 /** 471 * java.io only throws FileNotFoundException when opening files, regardless of what actually 472 * went wrong. Additionally, java.io is more restrictive than POSIX when it comes to opening 473 * directories: POSIX says read-only is okay, but java.io doesn't even allow that. We also 474 * have an Android-specific hack to alter the default permissions. 475 */ 476 @libcore.api.CorePlatformApi open(String path, int flags)477 public static FileDescriptor open(String path, int flags) throws FileNotFoundException { 478 FileDescriptor fd = null; 479 try { 480 // On Android, we don't want default permissions to allow global access. 481 int mode = ((flags & O_ACCMODE) == O_RDONLY) ? 0 : 0600; 482 fd = Libcore.os.open(path, flags, mode); 483 // Posix open(2) fails with EISDIR only if you ask for write permission. 484 // Java disallows reading directories too. 485 if (S_ISDIR(Libcore.os.fstat(fd).st_mode)) { 486 throw new ErrnoException("open", EISDIR); 487 } 488 return fd; 489 } catch (ErrnoException errnoException) { 490 try { 491 if (fd != null) { 492 closeAndSignalBlockedThreads(fd); 493 } 494 } catch (IOException ignored) { 495 } 496 FileNotFoundException ex = new FileNotFoundException(path + ": " + errnoException.getMessage()); 497 ex.initCause(errnoException); 498 throw ex; 499 } 500 } 501 502 /** 503 * java.io thinks that a read at EOF is an error and should return -1, contrary to traditional 504 * Unix practice where you'd read until you got 0 bytes (and any future read would return -1). 505 */ 506 @libcore.api.CorePlatformApi read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount)507 public static int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException { 508 ArrayUtils.throwsIfOutOfBounds(bytes.length, byteOffset, byteCount); 509 if (byteCount == 0) { 510 return 0; 511 } 512 try { 513 int readCount = Libcore.os.read(fd, bytes, byteOffset, byteCount); 514 if (readCount == 0) { 515 return -1; 516 } 517 return readCount; 518 } catch (ErrnoException errnoException) { 519 if (errnoException.errno == EAGAIN) { 520 // We return 0 rather than throw if we try to read from an empty non-blocking pipe. 521 return 0; 522 } 523 throw errnoException.rethrowAsIOException(); 524 } 525 } 526 527 /** 528 * java.io always writes every byte it's asked to, or fails with an error. (That is, unlike 529 * Unix it never just writes as many bytes as happens to be convenient.) 530 */ 531 @libcore.api.CorePlatformApi write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount)532 public static void write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws IOException { 533 ArrayUtils.throwsIfOutOfBounds(bytes.length, byteOffset, byteCount); 534 if (byteCount == 0) { 535 return; 536 } 537 try { 538 while (byteCount > 0) { 539 int bytesWritten = Libcore.os.write(fd, bytes, byteOffset, byteCount); 540 byteCount -= bytesWritten; 541 byteOffset += bytesWritten; 542 } 543 } catch (ErrnoException errnoException) { 544 throw errnoException.rethrowAsIOException(); 545 } 546 } 547 548 @libcore.api.CorePlatformApi sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port)549 public static int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws IOException { 550 boolean isDatagram = (inetAddress != null); 551 if (!isDatagram && byteCount <= 0) { 552 return 0; 553 } 554 int result; 555 try { 556 result = Libcore.os.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port); 557 } catch (ErrnoException errnoException) { 558 result = maybeThrowAfterSendto(isDatagram, errnoException); 559 } 560 return result; 561 } 562 sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port)563 public static int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws IOException { 564 boolean isDatagram = (inetAddress != null); 565 if (!isDatagram && buffer.remaining() == 0) { 566 return 0; 567 } 568 int result; 569 try { 570 result = Libcore.os.sendto(fd, buffer, flags, inetAddress, port); 571 } catch (ErrnoException errnoException) { 572 result = maybeThrowAfterSendto(isDatagram, errnoException); 573 } 574 return result; 575 } 576 maybeThrowAfterSendto(boolean isDatagram, ErrnoException errnoException)577 private static int maybeThrowAfterSendto(boolean isDatagram, ErrnoException errnoException) 578 throws IOException { 579 if (isDatagram) { 580 if (errnoException.errno == ECONNREFUSED) { 581 throw new PortUnreachableException("ICMP Port Unreachable"); 582 } 583 } else { 584 if (errnoException.errno == EAGAIN) { 585 // We were asked to write to a non-blocking socket, but were told 586 // it would block, so report "no bytes written". 587 return 0; 588 } 589 } 590 throw errnoException.rethrowAsIOException(); 591 } 592 593 @libcore.api.CorePlatformApi recvfrom(boolean isRead, FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, DatagramPacket packet, boolean isConnected)594 public static int recvfrom(boolean isRead, FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, DatagramPacket packet, boolean isConnected) throws IOException { 595 int result; 596 try { 597 InetSocketAddress srcAddress = packet != null ? new InetSocketAddress() : null; 598 result = Libcore.os.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress); 599 result = postRecvfrom(isRead, packet, srcAddress, result); 600 } catch (ErrnoException errnoException) { 601 result = maybeThrowAfterRecvfrom(isRead, isConnected, errnoException); 602 } 603 return result; 604 } 605 recvfrom(boolean isRead, FileDescriptor fd, ByteBuffer buffer, int flags, DatagramPacket packet, boolean isConnected)606 public static int recvfrom(boolean isRead, FileDescriptor fd, ByteBuffer buffer, int flags, DatagramPacket packet, boolean isConnected) throws IOException { 607 int result; 608 try { 609 InetSocketAddress srcAddress = packet != null ? new InetSocketAddress() : null; 610 result = Libcore.os.recvfrom(fd, buffer, flags, srcAddress); 611 result = postRecvfrom(isRead, packet, srcAddress, result); 612 } catch (ErrnoException errnoException) { 613 result = maybeThrowAfterRecvfrom(isRead, isConnected, errnoException); 614 } 615 return result; 616 } 617 postRecvfrom(boolean isRead, DatagramPacket packet, InetSocketAddress srcAddress, int byteCount)618 private static int postRecvfrom(boolean isRead, DatagramPacket packet, InetSocketAddress srcAddress, int byteCount) { 619 if (isRead && byteCount == 0) { 620 return -1; 621 } 622 if (packet != null) { 623 packet.setReceivedLength(byteCount); 624 packet.setPort(srcAddress.getPort()); 625 626 // packet.address should only be changed when it is different from srcAddress. 627 if (!srcAddress.getAddress().equals(packet.getAddress())) { 628 packet.setAddress(srcAddress.getAddress()); 629 } 630 } 631 return byteCount; 632 } 633 maybeThrowAfterRecvfrom(boolean isRead, boolean isConnected, ErrnoException errnoException)634 private static int maybeThrowAfterRecvfrom(boolean isRead, boolean isConnected, ErrnoException errnoException) throws SocketException, SocketTimeoutException { 635 if (isRead) { 636 if (errnoException.errno == EAGAIN) { 637 return 0; 638 } else { 639 throw errnoException.rethrowAsSocketException(); 640 } 641 } else { 642 if (isConnected && errnoException.errno == ECONNREFUSED) { 643 throw new PortUnreachableException("ICMP Port Unreachable", errnoException); 644 } else if (errnoException.errno == EAGAIN) { 645 SocketTimeoutException e = new SocketTimeoutException(); 646 e.initCause(errnoException); 647 throw e; 648 } else { 649 throw errnoException.rethrowAsSocketException(); 650 } 651 } 652 } 653 654 @libcore.api.CorePlatformApi socket(int domain, int type, int protocol)655 public static FileDescriptor socket(int domain, int type, int protocol) throws SocketException { 656 FileDescriptor fd; 657 try { 658 fd = Libcore.os.socket(domain, type, protocol); 659 660 return fd; 661 } catch (ErrnoException errnoException) { 662 throw errnoException.rethrowAsSocketException(); 663 } 664 } 665 666 /** 667 * Wait for some event on a file descriptor, blocks until the event happened or timeout period 668 * passed. See poll(2) and @link{android.system.Os.Poll}. 669 * 670 * @throws SocketException if poll(2) fails. 671 * @throws SocketTimeoutException if the event has not happened before timeout period has passed. 672 */ poll(FileDescriptor fd, int events, int timeout)673 public static void poll(FileDescriptor fd, int events, int timeout) 674 throws SocketException, SocketTimeoutException { 675 StructPollfd[] pollFds = new StructPollfd[]{ new StructPollfd() }; 676 pollFds[0].fd = fd; 677 pollFds[0].events = (short) events; 678 679 try { 680 int ret = android.system.Os.poll(pollFds, timeout); 681 if (ret == 0) { 682 throw new SocketTimeoutException("Poll timed out"); 683 } 684 } catch (ErrnoException e) { 685 e.rethrowAsSocketException(); 686 } 687 } 688 689 /** 690 * @throws SocketException if fd is not currently bound to an InetSocketAddress 691 */ 692 @libcore.api.CorePlatformApi getLocalInetSocketAddress(FileDescriptor fd)693 public static InetSocketAddress getLocalInetSocketAddress(FileDescriptor fd) 694 throws SocketException { 695 try { 696 SocketAddress socketAddress = Libcore.os.getsockname(fd); 697 // When a Socket is pending closure because socket.close() was called but other threads 698 // are still using it, the FileDescriptor can be dup2'ed to an AF_UNIX one; see the 699 // deferred close logic in PlainSocketImpl.socketClose0(true) for details. 700 // If socketAddress is not the expected type then we assume that the socket is being 701 // closed, so we throw a SocketException (just like in the case of an ErrnoException). 702 // http://b/64209834 703 if ((socketAddress != null) && !(socketAddress instanceof InetSocketAddress)) { 704 throw new SocketException("Socket assumed to be pending closure: Expected sockname " 705 + "to be an InetSocketAddress, got " + socketAddress.getClass()); 706 } 707 return (InetSocketAddress) socketAddress; 708 } catch (ErrnoException errnoException) { 709 throw errnoException.rethrowAsSocketException(); 710 } 711 } 712 } 713