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