1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.harmony.nio.internal; 19 20 // BEGIN android-note 21 // In this class the address length was changed from long to int. 22 // END android-note 23 24 import java.io.FileDescriptor; 25 import java.io.IOException; 26 import java.io.InputStream; 27 import java.io.OutputStream; 28 import java.net.ConnectException; 29 import java.net.InetAddress; 30 import java.net.InetSocketAddress; 31 import java.net.Socket; 32 import java.net.SocketAddress; 33 import java.net.SocketException; 34 import java.net.SocketImpl; 35 import java.net.SocketOptions; 36 import java.net.UnknownHostException; 37 import java.nio.ByteBuffer; 38 import java.nio.channels.AlreadyConnectedException; 39 import java.nio.channels.ClosedChannelException; 40 import java.nio.channels.ConnectionPendingException; 41 import java.nio.channels.IllegalBlockingModeException; 42 import java.nio.channels.NoConnectionPendingException; 43 import java.nio.channels.NotYetConnectedException; 44 import java.nio.channels.SocketChannel; 45 import java.nio.channels.UnresolvedAddressException; 46 import java.nio.channels.UnsupportedAddressTypeException; 47 import java.nio.channels.spi.SelectorProvider; 48 49 import org.apache.harmony.luni.net.PlainSocketImpl; 50 import org.apache.harmony.luni.platform.FileDescriptorHandler; 51 import org.apache.harmony.luni.platform.INetworkSystem; 52 import org.apache.harmony.luni.platform.Platform; 53 //import org.apache.harmony.luni.util.ErrorCodeException; android-removed 54 import org.apache.harmony.luni.util.Msg; 55 import org.apache.harmony.nio.AddressUtil; 56 import org.apache.harmony.nio.internal.nls.Messages; 57 58 /* 59 * The default implementation class of java.nio.channels.SocketChannel. 60 */ 61 class SocketChannelImpl extends SocketChannel implements FileDescriptorHandler { 62 63 private static final int EOF = -1; 64 65 // android-removed: private static final int ERRCODE_SOCKET_NONBLOCKING_WOULD_BLOCK = -211; 66 67 // The singleton to do the native network operation. 68 static final INetworkSystem networkSystem = Platform.getNetworkSystem(); 69 70 // Status un-init, not initialized. 71 static final int SOCKET_STATUS_UNINIT = EOF; 72 73 // Status before connect. 74 static final int SOCKET_STATUS_UNCONNECTED = 0; 75 76 // Status connection pending. 77 static final int SOCKET_STATUS_PENDING = 1; 78 79 // Status after connection success. 80 static final int SOCKET_STATUS_CONNECTED = 2; 81 82 // Status closed. 83 static final int SOCKET_STATUS_CLOSED = 3; 84 85 // Timeout used for non-block mode. 86 private static final int TIMEOUT_NONBLOCK = 0; 87 88 // Timeout used for block mode. 89 private static final int TIMEOUT_BLOCK = EOF; 90 91 // Step used for connect. 92 private static final int HY_SOCK_STEP_START = 0; 93 94 // Step used for finishConnect. 95 private static final int HY_PORT_SOCKET_STEP_CHECK = 1; 96 97 // Connect success. 98 private static final int CONNECT_SUCCESS = 0; 99 100 // The descriptor to interact with native code. 101 FileDescriptor fd; 102 103 // Our internal Socket. 104 private Socket socket = null; 105 106 // The address to be connected. 107 InetSocketAddress connectAddress = null; 108 109 // Local address of the this socket (package private for adapter). 110 InetAddress localAddress = null; 111 112 // Local port number. 113 int localPort; 114 115 // At first, uninitialized. 116 int status = SOCKET_STATUS_UNINIT; 117 118 // Whether the socket is bound. 119 volatile boolean isBound = false; 120 121 private static class ReadLock {} 122 private final Object readLock = new ReadLock(); 123 124 private static class WriteLock {} 125 private final Object writeLock = new WriteLock(); 126 127 // BEGIN android-changed 128 // this content is a struct used in connect_withtimeout(). 129 // The structure its holding has a size of 392 bytes. 130 private byte[] connectContext = new byte[392]; 131 // END android-changed 132 133 // Used to store the trafficClass value which is simply returned 134 // as the value that was set. We also need it to pass it to methods 135 // that specify an address packets are going to be sent to. 136 private int trafficClass = 0; 137 138 /* 139 * Constructor for creating a connected socket channel. 140 */ 141 public SocketChannelImpl(SelectorProvider selectorProvider) 142 throws IOException { 143 this(selectorProvider, true); 144 } 145 146 /* 147 * Constructor for creating an optionally connected socket channel. 148 */ 149 public SocketChannelImpl(SelectorProvider selectorProvider, boolean connect) 150 throws IOException { 151 super(selectorProvider); 152 fd = new FileDescriptor(); 153 status = SOCKET_STATUS_UNCONNECTED; 154 if (connect) { 155 networkSystem.createStreamSocket(fd, true); 156 } 157 } 158 159 /* 160 * For native call. 161 */ 162 @SuppressWarnings("unused") 163 private SocketChannelImpl() { 164 super(SelectorProvider.provider()); 165 fd = new FileDescriptor(); 166 connectAddress = new InetSocketAddress(0); 167 status = SOCKET_STATUS_CONNECTED; 168 } 169 170 // Keep this to see if need next version 171 // SocketChannelImpl(SelectorProvider selectorProvider, FileDescriptor fd, 172 // SocketImpl si) { 173 // super(selectorProvider); 174 // fd = fd; 175 // networkSystem = OSNetworkSystem.getOSNetworkSystem(); 176 // status = SOCKET_STATUS_UNCONNECTED; 177 // networkSystem.createSocket(fd, true); 178 // } 179 180 /* 181 * Package private constructor. 182 */ 183 SocketChannelImpl(Socket aSocket, FileDescriptor aFd) { 184 super(SelectorProvider.provider()); 185 socket = aSocket; 186 fd = aFd; 187 status = SOCKET_STATUS_UNCONNECTED; 188 } 189 190 /* 191 * Getting the internal Socket If we have not the socket, we create a new 192 * one. 193 */ 194 @Override 195 synchronized public Socket socket() { 196 if (null == socket) { 197 try { 198 InetAddress addr = null; 199 int port = 0; 200 if (connectAddress != null) { 201 addr = connectAddress.getAddress(); 202 port = connectAddress.getPort(); 203 } 204 socket = new SocketAdapter( 205 new PlainSocketImpl(fd, localPort, addr, port), this); 206 } catch (SocketException e) { 207 return null; 208 } 209 } 210 return socket; 211 } 212 213 /** 214 * @see java.nio.channels.SocketChannel#isConnected() 215 */ 216 @Override 217 synchronized public boolean isConnected() { 218 return status == SOCKET_STATUS_CONNECTED; 219 } 220 221 /* 222 * Status setting used by other class. 223 */ 224 synchronized void setConnected() { 225 status = SOCKET_STATUS_CONNECTED; 226 } 227 228 void setBound(boolean flag) { 229 isBound = flag; 230 } 231 232 /** 233 * @see java.nio.channels.SocketChannel#isConnectionPending() 234 */ 235 @Override 236 synchronized public boolean isConnectionPending() { 237 return status == SOCKET_STATUS_PENDING; 238 } 239 240 /** 241 * @see java.nio.channels.SocketChannel#connect(java.net.SocketAddress) 242 */ 243 @Override 244 public boolean connect(SocketAddress socketAddress) throws IOException { 245 // status must be open and unconnected 246 checkUnconnected(); 247 248 // check the address 249 InetSocketAddress inetSocketAddress = validateAddress(socketAddress); 250 InetAddress normalAddr = inetSocketAddress.getAddress(); 251 252 // When connecting, map ANY address to Localhost 253 if (normalAddr.isAnyLocalAddress()) { 254 normalAddr = InetAddress.getLocalHost(); 255 } 256 257 int port = inetSocketAddress.getPort(); 258 String hostName = normalAddr.getHostName(); 259 // security check 260 SecurityManager sm = System.getSecurityManager(); 261 if (sm != null) { 262 sm.checkConnect(hostName, port); 263 } 264 265 // connect result 266 int result = EOF; 267 boolean finished = false; 268 269 try { 270 if (isBlocking()) { 271 begin(); 272 networkSystem.connect(fd, trafficClass, normalAddr, port); 273 result = CONNECT_SUCCESS; // Or we'd have thrown an exception. 274 } else { 275 result = networkSystem.connectWithTimeout(fd, 0, trafficClass, 276 normalAddr, port, HY_SOCK_STEP_START, connectContext); 277 // set back to nonblocking to work around with a bug in portlib 278 if (!this.isBlocking()) { 279 networkSystem.setNonBlocking(fd, true); 280 } 281 } 282 finished = (CONNECT_SUCCESS == result); 283 isBound = finished; 284 } catch (IOException e) { 285 if (e instanceof ConnectException && !isBlocking()) { 286 status = SOCKET_STATUS_PENDING; 287 } else { 288 if (isOpen()) { 289 close(); 290 finished = true; 291 } 292 throw e; 293 } 294 } finally { 295 if (isBlocking()) { 296 end(finished); 297 } 298 } 299 300 // set local port 301 localPort = networkSystem.getSocketLocalPort(fd); 302 localAddress = networkSystem.getSocketLocalAddress(fd); 303 304 // set the connected address. 305 connectAddress = inetSocketAddress; 306 synchronized (this) { 307 if (isBlocking()) { 308 status = (finished ? SOCKET_STATUS_CONNECTED 309 : SOCKET_STATUS_UNCONNECTED); 310 } else { 311 status = SOCKET_STATUS_PENDING; 312 } 313 } 314 return finished; 315 } 316 317 /** 318 * @see java.nio.channels.SocketChannel#finishConnect() 319 */ 320 @Override 321 public boolean finishConnect() throws IOException { 322 // status check 323 synchronized (this) { 324 if (!isOpen()) { 325 throw new ClosedChannelException(); 326 } 327 if (status == SOCKET_STATUS_CONNECTED) { 328 return true; 329 } 330 if (status != SOCKET_STATUS_PENDING) { 331 throw new NoConnectionPendingException(); 332 } 333 } 334 335 // finish result 336 int result = EOF; 337 boolean finished = false; 338 339 try { 340 begin(); 341 result = networkSystem.connectWithTimeout(fd, 342 isBlocking() ? -1 : 0, trafficClass, connectAddress 343 .getAddress(), connectAddress.getPort(), 344 HY_PORT_SOCKET_STEP_CHECK, connectContext); 345 finished = (result == CONNECT_SUCCESS); 346 isBound = finished; 347 localAddress = networkSystem.getSocketLocalAddress(fd); 348 } catch (ConnectException e) { 349 if (isOpen()) { 350 close(); 351 finished = true; 352 } 353 throw e; 354 } finally { 355 end(finished); 356 } 357 358 synchronized (this) { 359 status = (finished ? SOCKET_STATUS_CONNECTED : status); 360 isBound = finished; 361 // TPE: Workaround for bug that turns socket back to blocking 362 if (!isBlocking()) implConfigureBlocking(false); 363 } 364 return finished; 365 } 366 367 /** 368 * @see java.nio.channels.SocketChannel#read(java.nio.ByteBuffer) 369 */ 370 @Override 371 public int read(ByteBuffer target) throws IOException { 372 if (null == target) { 373 throw new NullPointerException(); 374 } 375 checkOpenConnected(); 376 if (!target.hasRemaining()) { 377 return 0; 378 } 379 380 int readCount; 381 if (target.isDirect() || target.hasArray()) { 382 readCount = readImpl(target); 383 if (readCount > 0) { 384 target.position(target.position() + readCount); 385 } 386 } else { 387 ByteBuffer readBuffer = null; 388 byte[] readArray = null; 389 readArray = new byte[target.remaining()]; 390 readBuffer = ByteBuffer.wrap(readArray); 391 readCount = readImpl(readBuffer); 392 if (readCount > 0) { 393 target.put(readArray, 0, readCount); 394 } 395 } 396 return readCount; 397 } 398 399 /** 400 * @see java.nio.channels.SocketChannel#read(java.nio.ByteBuffer[], int, 401 * int) 402 */ 403 @Override 404 public long read(ByteBuffer[] targets, int offset, int length) 405 throws IOException { 406 if (!isIndexValid(targets, offset, length)) { 407 throw new IndexOutOfBoundsException(); 408 } 409 410 checkOpenConnected(); 411 int totalCount = calculateByteBufferArray(targets, offset, length); 412 if (0 == totalCount) { 413 return 0; 414 } 415 byte[] readArray = new byte[totalCount]; 416 ByteBuffer readBuffer = ByteBuffer.wrap(readArray); 417 int readCount; 418 // read data to readBuffer, and then transfer data from readBuffer to 419 // targets. 420 readCount = readImpl(readBuffer); 421 if (readCount > 0) { 422 int left = readCount; 423 int index = offset; 424 // transfer data from readArray to targets 425 while (left > 0) { 426 int putLength = Math.min(targets[index].remaining(), left); 427 targets[index].put(readArray, readCount - left, putLength); 428 index++; 429 left -= putLength; 430 } 431 } 432 return readCount; 433 } 434 435 private boolean isIndexValid(ByteBuffer[] targets, int offset, int length) { 436 return (length >= 0) && (offset >= 0) 437 && ((long) length + (long) offset <= targets.length); 438 } 439 440 /** 441 * Read from channel, and store the result in the target. 442 * 443 * @param target 444 * output parameter 445 */ 446 private int readImpl(ByteBuffer target) throws IOException { 447 synchronized (readLock) { 448 int readCount = 0; 449 try { 450 if (isBlocking()) { 451 begin(); 452 } 453 int offset = target.position(); 454 int length = target.remaining(); 455 if (target.isDirect()) { 456 // BEGIN android-changed 457 // changed address from long to int 458 int address = AddressUtil.getDirectBufferAddress(target); 459 readCount = networkSystem.readDirect(fd, address + offset, 460 length, (isBlocking() ? TIMEOUT_BLOCK 461 : TIMEOUT_NONBLOCK)); 462 // END android-changed 463 } else { 464 // target is assured to have array. 465 byte[] array = target.array(); 466 offset += target.arrayOffset(); 467 readCount = networkSystem.read(fd, array, offset, length, 468 (isBlocking() ? TIMEOUT_BLOCK : TIMEOUT_NONBLOCK)); 469 } 470 return readCount; 471 } finally { 472 if (isBlocking()) { 473 end(readCount > 0); 474 } 475 } 476 } 477 } 478 479 /** 480 * @see java.nio.channels.SocketChannel#write(java.nio.ByteBuffer) 481 */ 482 @Override 483 public int write(ByteBuffer source) throws IOException { 484 if (null == source) { 485 throw new NullPointerException(); 486 } 487 checkOpenConnected(); 488 if (!source.hasRemaining()) { 489 return 0; 490 } 491 return writeImpl(source); 492 } 493 494 /** 495 * @see java.nio.channels.SocketChannel#write(java.nio.ByteBuffer[], int, 496 * int) 497 */ 498 @Override 499 public long write(ByteBuffer[] sources, int offset, int length) 500 throws IOException { 501 if (!isIndexValid(sources, offset, length)) { 502 throw new IndexOutOfBoundsException(); 503 } 504 505 checkOpenConnected(); 506 int count = calculateByteBufferArray(sources, offset, length); 507 if (0 == count) { 508 return 0; 509 } 510 ByteBuffer writeBuf = ByteBuffer.allocate(count); 511 for (int val = offset; val < length + offset; val++) { 512 ByteBuffer source = sources[val]; 513 int oldPosition = source.position(); 514 writeBuf.put(source); 515 source.position(oldPosition); 516 } 517 writeBuf.flip(); 518 int result = writeImpl(writeBuf); 519 int val = offset; 520 int written = result; 521 while (result > 0) { 522 ByteBuffer source = sources[val]; 523 int gap = Math.min(result, source.remaining()); 524 source.position(source.position() + gap); 525 val++; 526 result -= gap; 527 } 528 return written; 529 } 530 531 private int calculateByteBufferArray(ByteBuffer[] sources, int offset, 532 int length) { 533 int sum = 0; 534 for (int val = offset; val < offset + length; val++) { 535 sum = sum + sources[val].remaining(); 536 } 537 return sum; 538 } 539 540 /* 541 * Write the source. return the count of bytes written. 542 */ 543 private int writeImpl(ByteBuffer source) throws IOException { 544 synchronized (writeLock) { 545 if (!source.hasRemaining()) { 546 return 0; 547 } 548 int writeCount = 0; 549 try { 550 int pos = source.position(); 551 int length = source.remaining(); 552 if (isBlocking()) { 553 begin(); 554 } 555 if (source.isDirect()) { 556 // BEGIN android-changed 557 // changed address from long to int; split address and pos parameters 558 int address = AddressUtil.getDirectBufferAddress(source); 559 writeCount = networkSystem.writeDirect(fd, address, pos, 560 length); 561 // END android-changed 562 } else if (source.hasArray()) { 563 pos += source.arrayOffset(); 564 writeCount = networkSystem.write(fd, source.array(), pos, 565 length); 566 } else { 567 byte[] array = new byte[length]; 568 source.get(array); 569 writeCount = networkSystem.write(fd, array, 0, length); 570 } 571 source.position(pos + writeCount); 572 // android-removed: bogus catch (SocketException e) and use of ErrorCodeException. 573 } finally { 574 if (isBlocking()) { 575 end(writeCount >= 0); 576 } 577 } 578 return writeCount; 579 } 580 } 581 582 /* 583 * Status check, open and "connected", when read and write. 584 */ 585 synchronized private void checkOpenConnected() 586 throws ClosedChannelException { 587 if (!isOpen()) { 588 throw new ClosedChannelException(); 589 } 590 if (!isConnected()) { 591 throw new NotYetConnectedException(); 592 } 593 } 594 595 /* 596 * Status check, open and "unconnected", before connection. 597 */ 598 synchronized private void checkUnconnected() throws IOException { 599 if (!isOpen()) { 600 throw new ClosedChannelException(); 601 } 602 if (status == SOCKET_STATUS_CONNECTED) { 603 throw new AlreadyConnectedException(); 604 } 605 if (status == SOCKET_STATUS_PENDING) { 606 throw new ConnectionPendingException(); 607 } 608 } 609 610 /* 611 * Shared by this class and DatagramChannelImpl, to do the address transfer 612 * and check. 613 */ 614 static InetSocketAddress validateAddress(SocketAddress socketAddress) { 615 if (null == socketAddress) { 616 throw new IllegalArgumentException(); 617 } 618 if (!(socketAddress instanceof InetSocketAddress)) { 619 throw new UnsupportedAddressTypeException(); 620 } 621 InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress; 622 if (inetSocketAddress.isUnresolved()) { 623 throw new UnresolvedAddressException(); 624 } 625 return inetSocketAddress; 626 } 627 628 /* 629 * Get local address. 630 */ 631 public InetAddress getLocalAddress() throws UnknownHostException { 632 byte[] any_bytes = { 0, 0, 0, 0 }; 633 if (!isBound) { 634 return InetAddress.getByAddress(any_bytes); 635 } 636 return localAddress; 637 } 638 639 /* 640 * Do really closing action here. 641 */ 642 @Override 643 synchronized protected void implCloseSelectableChannel() throws IOException { 644 if (SOCKET_STATUS_CLOSED != status) { 645 status = SOCKET_STATUS_CLOSED; 646 if (null != socket && !socket.isClosed()) { 647 socket.close(); 648 } else { 649 networkSystem.socketClose(fd); 650 } 651 } 652 } 653 654 /** 655 * @see java.nio.channels.spi.AbstractSelectableChannel#implConfigureBlocking(boolean) 656 */ 657 @Override 658 protected void implConfigureBlocking(boolean blockMode) throws IOException { 659 synchronized (blockingLock()) { 660 networkSystem.setNonBlocking(fd, !blockMode); 661 } 662 } 663 664 /* 665 * Get the fd. 666 */ 667 public FileDescriptor getFD() { 668 return fd; 669 } 670 671 /* 672 * Adapter classes for internal socket. 673 */ 674 private static class SocketAdapter extends Socket { 675 676 SocketChannelImpl channel; 677 678 SocketImpl socketImpl; 679 680 SocketAdapter(SocketImpl socketimpl, SocketChannelImpl channel) 681 throws SocketException { 682 super(socketimpl); 683 socketImpl = socketimpl; 684 this.channel = channel; 685 } 686 687 /** 688 * @see java.net.Socket#getChannel() 689 */ 690 @Override 691 public SocketChannel getChannel() { 692 return channel; 693 } 694 695 /** 696 * @see java.net.Socket#isBound() 697 */ 698 @Override 699 public boolean isBound() { 700 return channel.isBound; 701 } 702 703 /** 704 * @see java.net.Socket#isConnected() 705 */ 706 @Override 707 public boolean isConnected() { 708 return channel.isConnected(); 709 } 710 711 /** 712 * @see java.net.Socket#getLocalAddress() 713 */ 714 @Override 715 public InetAddress getLocalAddress() { 716 try { 717 return channel.getLocalAddress(); 718 } catch (UnknownHostException e) { 719 return null; 720 } 721 } 722 723 /** 724 * @see java.net.Socket#connect(java.net.SocketAddress, int) 725 */ 726 @Override 727 public void connect(SocketAddress remoteAddr, int timeout) 728 throws IOException { 729 if (!channel.isBlocking()) { 730 throw new IllegalBlockingModeException(); 731 } 732 if (isConnected()) { 733 throw new AlreadyConnectedException(); 734 } 735 super.connect(remoteAddr, timeout); 736 channel.localAddress = networkSystem.getSocketLocalAddress(channel.fd); 737 if (super.isConnected()) { 738 channel.setConnected(); 739 channel.isBound = super.isBound(); 740 } 741 } 742 743 /** 744 * @see java.net.Socket#bind(java.net.SocketAddress) 745 */ 746 @Override 747 public void bind(SocketAddress localAddr) throws IOException { 748 if (channel.isConnected()) { 749 throw new AlreadyConnectedException(); 750 } 751 if (SocketChannelImpl.SOCKET_STATUS_PENDING == channel.status) { 752 throw new ConnectionPendingException(); 753 } 754 super.bind(localAddr); 755 // keep here to see if need next version 756 // channel.Address = getLocalSocketAddress(); 757 // channel.localport = getLocalPort(); 758 channel.isBound = true; 759 760 } 761 762 /** 763 * @see java.net.Socket#close() 764 */ 765 @Override 766 public void close() throws IOException { 767 synchronized (channel) { 768 if (channel.isOpen()) { 769 channel.close(); 770 } else { 771 super.close(); 772 } 773 channel.status = SocketChannelImpl.SOCKET_STATUS_CLOSED; 774 } 775 } 776 777 @Override 778 public boolean getReuseAddress() throws SocketException { 779 checkOpen(); 780 return ((Boolean) socketImpl.getOption(SocketOptions.SO_REUSEADDR)) 781 .booleanValue(); 782 } 783 784 @Override 785 public synchronized int getReceiveBufferSize() throws SocketException { 786 checkOpen(); 787 return ((Integer) socketImpl.getOption(SocketOptions.SO_RCVBUF)) 788 .intValue(); 789 } 790 791 @Override 792 public synchronized int getSendBufferSize() throws SocketException { 793 checkOpen(); 794 return ((Integer) socketImpl.getOption(SocketOptions.SO_SNDBUF)) 795 .intValue(); 796 } 797 798 @Override 799 public synchronized int getSoTimeout() throws SocketException { 800 checkOpen(); 801 return ((Integer) socketImpl.getOption(SocketOptions.SO_TIMEOUT)) 802 .intValue(); 803 } 804 805 @Override 806 public int getTrafficClass() throws SocketException { 807 checkOpen(); 808 return ((Number) socketImpl.getOption(SocketOptions.IP_TOS)) 809 .intValue(); 810 } 811 812 /** 813 * @see java.net.Socket#getKeepAlive() 814 */ 815 @Override 816 public boolean getKeepAlive() throws SocketException { 817 checkOpen(); 818 return ((Boolean) socketImpl.getOption(SocketOptions.SO_KEEPALIVE)) 819 .booleanValue(); 820 } 821 822 /** 823 * @see java.net.Socket#getOOBInline() 824 */ 825 @Override 826 public boolean getOOBInline() throws SocketException { 827 checkOpen(); 828 return ((Boolean) socketImpl.getOption(SocketOptions.SO_OOBINLINE)) 829 .booleanValue(); 830 } 831 832 /** 833 * @see java.net.Socket#getSoLinger() 834 */ 835 @Override 836 public int getSoLinger() throws SocketException { 837 checkOpen(); 838 return ((Integer) socketImpl.getOption(SocketOptions.SO_LINGER)) 839 .intValue(); 840 } 841 842 /** 843 * @see java.net.Socket#getTcpNoDelay() 844 */ 845 @Override 846 public boolean getTcpNoDelay() throws SocketException { 847 checkOpen(); 848 return ((Boolean) socketImpl.getOption(SocketOptions.TCP_NODELAY)) 849 .booleanValue(); 850 } 851 852 @Override 853 public void setKeepAlive(boolean value) throws SocketException { 854 checkOpen(); 855 socketImpl.setOption(SocketOptions.SO_KEEPALIVE, value ? Boolean.TRUE 856 : Boolean.FALSE); 857 } 858 859 @Override 860 public void setOOBInline(boolean oobinline) throws SocketException { 861 checkOpen(); 862 socketImpl.setOption(SocketOptions.SO_OOBINLINE, oobinline ? Boolean.TRUE 863 : Boolean.FALSE); 864 } 865 866 @Override 867 public synchronized void setReceiveBufferSize(int size) 868 throws SocketException { 869 checkOpen(); 870 if (size < 1) { 871 throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$ 872 } 873 socketImpl 874 .setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size)); 875 } 876 877 @Override 878 public void setReuseAddress(boolean reuse) throws SocketException { 879 checkOpen(); 880 socketImpl.setOption(SocketOptions.SO_REUSEADDR, reuse ? Boolean.TRUE 881 : Boolean.FALSE); 882 } 883 884 @Override 885 public synchronized void setSendBufferSize(int size) throws SocketException { 886 checkOpen(); 887 if (size < 1) { 888 throw new IllegalArgumentException(Msg.getString("K0035")); //$NON-NLS-1$ 889 } 890 socketImpl.setOption(SocketOptions.SO_SNDBUF, Integer.valueOf(size)); 891 } 892 893 @Override 894 public void setSoLinger(boolean on, int timeout) throws SocketException { 895 checkOpen(); 896 if (on && timeout < 0) { 897 throw new IllegalArgumentException(Msg.getString("K0045")); //$NON-NLS-1$ 898 } 899 int val = on ? (65535 < timeout ? 65535 : timeout) : -1; 900 socketImpl.setOption(SocketOptions.SO_LINGER, Integer.valueOf(val)); 901 } 902 903 @Override 904 public synchronized void setSoTimeout(int timeout) throws SocketException { 905 checkOpen(); 906 if (timeout < 0) { 907 throw new IllegalArgumentException(Msg.getString("K0036")); //$NON-NLS-1$ 908 } 909 socketImpl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(timeout)); 910 } 911 912 @Override 913 public void setTcpNoDelay(boolean on) throws SocketException { 914 checkOpen(); 915 socketImpl.setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on)); 916 } 917 918 @Override 919 public void setTrafficClass(int value) throws SocketException { 920 checkOpen(); 921 if (value < 0 || value > 255) { 922 throw new IllegalArgumentException(); 923 } 924 socketImpl.setOption(SocketOptions.IP_TOS, Integer.valueOf(value)); 925 } 926 927 /** 928 * @see java.net.Socket#getOutputStream() 929 */ 930 @Override 931 public OutputStream getOutputStream() throws IOException { 932 if (!channel.isOpen()) { 933 // nio.00=Socket is closed 934 throw new SocketException(Messages.getString("nio.00")); //$NON-NLS-1$ 935 } 936 if (!channel.isConnected()) { 937 // nio.01=Socket is not connected 938 throw new SocketException(Messages.getString("nio.01")); //$NON-NLS-1$ 939 } 940 if (isOutputShutdown()) { 941 // nio.02=Socket output is shutdown 942 throw new SocketException(Messages.getString("nio.02")); //$NON-NLS-1$ 943 } 944 return new SocketChannelOutputStream(channel); 945 } 946 947 /** 948 * @see java.net.Socket#getInputStream() 949 */ 950 @Override 951 public InputStream getInputStream() throws IOException { 952 if (!channel.isOpen()) { 953 // nio.00=Socket is closed 954 throw new SocketException(Messages.getString("nio.00")); //$NON-NLS-1$ 955 } 956 if (!channel.isConnected()) { 957 // nio.01=Socket is not connected 958 throw new SocketException(Messages.getString("nio.01")); //$NON-NLS-1$ 959 } 960 if (isInputShutdown()) { 961 // nio.03=Socket input is shutdown 962 throw new SocketException(Messages.getString("nio.03")); //$NON-NLS-1$ 963 } 964 return new SocketChannelInputStream(channel); 965 } 966 967 /* 968 * Checks whether the channel is open. 969 */ 970 private void checkOpen() throws SocketException { 971 if (isClosed()) { 972 // nio.00=Socket is closed 973 throw new SocketException(Messages.getString("nio.00")); //$NON-NLS-1$ 974 } 975 } 976 977 /* 978 * Used for net and nio exchange. 979 */ 980 public SocketImpl getImpl() { 981 return socketImpl; 982 } 983 } 984 985 /* 986 * This output stream delegates all operations to the associated channel. 987 * Throws an IllegalBlockingModeException if the channel is in non-blocking 988 * mode when performing write operations. 989 */ 990 private static class SocketChannelOutputStream extends OutputStream { 991 SocketChannel channel; 992 993 public SocketChannelOutputStream(SocketChannel channel) { 994 this.channel = channel; 995 } 996 997 /* 998 * Closes this stream and channel. 999 * 1000 * @exception IOException thrown if an error occurs during the close 1001 */ 1002 @Override 1003 public void close() throws IOException { 1004 channel.close(); 1005 } 1006 1007 /** 1008 * @see java.io.OutputStream#write(byte[], int, int) 1009 */ 1010 @Override 1011 public void write(byte[] buffer, int offset, int count) 1012 throws IOException { 1013 if (0 > offset || 0 > count || count + offset > buffer.length) { 1014 throw new IndexOutOfBoundsException(); 1015 } 1016 ByteBuffer buf = ByteBuffer.wrap(buffer, offset, count); 1017 if (!channel.isBlocking()) { 1018 throw new IllegalBlockingModeException(); 1019 } 1020 channel.write(buf); 1021 } 1022 1023 /** 1024 * @see java.io.OutputStream#write(int) 1025 */ 1026 @Override 1027 public void write(int oneByte) throws IOException { 1028 if (!channel.isBlocking()) { 1029 throw new IllegalBlockingModeException(); 1030 } 1031 ByteBuffer buffer = ByteBuffer.allocate(1); 1032 buffer.put(0, (byte) (oneByte & 0xFF)); 1033 channel.write(buffer); 1034 } 1035 } 1036 1037 /* 1038 * This input stream delegates all operations to the associated channel. 1039 * Throws an IllegalBlockingModeException if the channel is in non-blocking 1040 * mode when performing read operations. 1041 */ 1042 private static class SocketChannelInputStream extends InputStream { 1043 SocketChannel channel; 1044 1045 public SocketChannelInputStream(SocketChannel channel) { 1046 this.channel = channel; 1047 } 1048 1049 /* 1050 * Closes this stream and channel. 1051 */ 1052 @Override 1053 public void close() throws IOException { 1054 channel.close(); 1055 } 1056 1057 /** 1058 * @see java.io.InputStream#read() 1059 */ 1060 @Override 1061 public int read() throws IOException { 1062 if (!channel.isBlocking()) { 1063 throw new IllegalBlockingModeException(); 1064 } 1065 ByteBuffer buf = ByteBuffer.allocate(1); 1066 int result = channel.read(buf); 1067 // BEGIN android-changed: input was already consumed 1068 return (-1 == result) ? result : buf.get(0) & 0xFF; 1069 // END android-changed 1070 } 1071 1072 /** 1073 * @see java.io.InputStream#read(byte[], int, int) 1074 */ 1075 @Override 1076 public int read(byte[] buffer, int offset, int count) 1077 throws IOException { 1078 if (0 > offset || 0 > count || count + offset > buffer.length) { 1079 throw new IndexOutOfBoundsException(); 1080 } 1081 if (!channel.isBlocking()) { 1082 throw new IllegalBlockingModeException(); 1083 } 1084 ByteBuffer buf = ByteBuffer.wrap(buffer, offset, count); 1085 return channel.read(buf); 1086 } 1087 } 1088 } 1089