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 46 private IoBridge() { 47 } 48 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 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 */ 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 */ 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 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 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 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 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 */ 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 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 297 private static boolean booleanFromInt(int i) { 298 return (i != 0); 299 } 300 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 */ 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 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 */ 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 */ 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 */ 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 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 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 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 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 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 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 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 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 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 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