0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package org.apache.harmony.nio.internal;
0019:
0020: import java.io.FileDescriptor;
0021: import java.io.IOException;
0022: import java.io.InputStream;
0023: import java.io.OutputStream;
0024: import java.net.ConnectException;
0025: import java.net.InetAddress;
0026: import java.net.InetSocketAddress;
0027: import java.net.Socket;
0028: import java.net.SocketAddress;
0029: import java.net.SocketException;
0030: import java.net.SocketImpl;
0031: import java.net.SocketOptions;
0032: import java.net.UnknownHostException;
0033: import java.nio.ByteBuffer;
0034: import java.nio.channels.AlreadyConnectedException;
0035: import java.nio.channels.ClosedChannelException;
0036: import java.nio.channels.ConnectionPendingException;
0037: import java.nio.channels.IllegalBlockingModeException;
0038: import java.nio.channels.NoConnectionPendingException;
0039: import java.nio.channels.NotYetConnectedException;
0040: import java.nio.channels.SocketChannel;
0041: import java.nio.channels.UnresolvedAddressException;
0042: import java.nio.channels.UnsupportedAddressTypeException;
0043: import java.nio.channels.spi.SelectorProvider;
0044:
0045: import org.apache.harmony.luni.net.SocketImplProvider;
0046: import org.apache.harmony.luni.platform.FileDescriptorHandler;
0047: import org.apache.harmony.luni.platform.INetworkSystem;
0048: import org.apache.harmony.luni.platform.Platform;
0049: import org.apache.harmony.luni.util.ErrorCodeException;
0050: import org.apache.harmony.nio.AddressUtil;
0051: import org.apache.harmony.nio.internal.nls.Messages;
0052:
0053: /*
0054: * The default implementation class of java.nio.channels.SocketChannel.
0055: */
0056: class SocketChannelImpl extends SocketChannel implements
0057: FileDescriptorHandler {
0058:
0059: private static final int EOF = -1;
0060:
0061: private static final int ERRCODE_SOCKET_NONBLOCKING_WOULD_BLOCK = -211;
0062:
0063: // The singleton to do the native network operation.
0064: static final INetworkSystem networkSystem = Platform
0065: .getNetworkSystem();
0066:
0067: // Status un-init, not initialized.
0068: static final int SOCKET_STATUS_UNINIT = EOF;
0069:
0070: // Status before connect.
0071: static final int SOCKET_STATUS_UNCONNECTED = 0;
0072:
0073: // Status connection pending.
0074: static final int SOCKET_STATUS_PENDING = 1;
0075:
0076: // Status after connection success.
0077: static final int SOCKET_STATUS_CONNECTED = 2;
0078:
0079: // Status closed.
0080: static final int SOCKET_STATUS_CLOSED = 3;
0081:
0082: // Timeout used for non-block mode.
0083: private static final int TIMEOUT_NONBLOCK = 0;
0084:
0085: // Timeout used for block mode.
0086: private static final int TIMEOUT_BLOCK = EOF;
0087:
0088: // Step used for connect.
0089: private static final int HY_SOCK_STEP_START = 0;
0090:
0091: // Step used for finishConnect.
0092: private static final int HY_PORT_SOCKET_STEP_CHECK = 1;
0093:
0094: // Connect success.
0095: private static final int CONNECT_SUCCESS = 0;
0096:
0097: // The descriptor to interact with native code.
0098: FileDescriptor fd;
0099:
0100: // Our internal Socket.
0101: private Socket socket = null;
0102:
0103: // The address to be connected.
0104: InetSocketAddress connectAddress = null;
0105:
0106: // Local address of the this socket (package private for adapter).
0107: InetAddress localAddress = null;
0108:
0109: // Local port number.
0110: int localPort;
0111:
0112: // At first, uninitialized.
0113: int status = SOCKET_STATUS_UNINIT;
0114:
0115: // Whether the socket is bound.
0116: volatile boolean isBound = false;
0117:
0118: private static class ReadLock {
0119: }
0120:
0121: private final Object readLock = new ReadLock();
0122:
0123: private static class WriteLock {
0124: }
0125:
0126: private final Object writeLock = new WriteLock();
0127:
0128: // This content is a point used to set in connect_withtimeout() in pending
0129: // mode.
0130: private Long connectContext = Long.valueOf(0L);
0131:
0132: // Used to store the trafficClass value which is simply returned
0133: // as the value that was set. We also need it to pass it to methods
0134: // that specify an address packets are going to be sent to.
0135: private int trafficClass = 0;
0136:
0137: /*
0138: * Constructor for creating a connected socket channel.
0139: */
0140: public SocketChannelImpl(SelectorProvider selectorProvider)
0141: throws IOException {
0142: this (selectorProvider, true);
0143: }
0144:
0145: /*
0146: * Constructor for creating an optionally connected socket channel.
0147: */
0148: public SocketChannelImpl(SelectorProvider selectorProvider,
0149: boolean connect) throws IOException {
0150: super (selectorProvider);
0151: fd = new FileDescriptor();
0152: status = SOCKET_STATUS_UNCONNECTED;
0153: if (connect) {
0154: networkSystem.createSocket(fd, true);
0155: }
0156: }
0157:
0158: /*
0159: * For native call.
0160: */
0161: @SuppressWarnings("unused")
0162: private SocketChannelImpl() {
0163: super (SelectorProvider.provider());
0164: fd = new FileDescriptor();
0165: connectAddress = new InetSocketAddress(0);
0166: status = SOCKET_STATUS_CONNECTED;
0167: }
0168:
0169: // Keep this to see if need next version
0170: // SocketChannelImpl(SelectorProvider selectorProvider, FileDescriptor fd,
0171: // SocketImpl si) {
0172: // super(selectorProvider);
0173: // fd = fd;
0174: // networkSystem = OSNetworkSystem.getOSNetworkSystem();
0175: // status = SOCKET_STATUS_UNCONNECTED;
0176: // networkSystem.createSocket(fd, true);
0177: // }
0178:
0179: /*
0180: * Package private constructor.
0181: */
0182: SocketChannelImpl(Socket aSocket, FileDescriptor aFd) {
0183: super (SelectorProvider.provider());
0184: socket = aSocket;
0185: fd = aFd;
0186: status = SOCKET_STATUS_UNCONNECTED;
0187: }
0188:
0189: /*
0190: * Getting the internal Socket If we have not the socket, we create a new
0191: * one.
0192: */
0193: @Override
0194: synchronized public Socket socket() {
0195: if (null == socket) {
0196: try {
0197: InetAddress addr = null;
0198: int port = 0;
0199: if (connectAddress != null) {
0200: addr = connectAddress.getAddress();
0201: port = connectAddress.getPort();
0202: }
0203: socket = new SocketAdapter(SocketImplProvider
0204: .getSocketImpl(fd, localPort, addr, port), this );
0205: } catch (SocketException e) {
0206: return null;
0207: }
0208: }
0209: return socket;
0210: }
0211:
0212: /**
0213: * @see java.nio.channels.SocketChannel#isConnected()
0214: */
0215: @Override
0216: synchronized public boolean isConnected() {
0217: return status == SOCKET_STATUS_CONNECTED;
0218: }
0219:
0220: /*
0221: * Status setting used by other class.
0222: */
0223: synchronized void setConnected() {
0224: status = SOCKET_STATUS_CONNECTED;
0225: }
0226:
0227: void setBound(boolean flag) {
0228: isBound = flag;
0229: }
0230:
0231: /**
0232: * @see java.nio.channels.SocketChannel#isConnectionPending()
0233: */
0234: @Override
0235: synchronized public boolean isConnectionPending() {
0236: return status == SOCKET_STATUS_PENDING;
0237: }
0238:
0239: /**
0240: * @see java.nio.channels.SocketChannel#connect(java.net.SocketAddress)
0241: */
0242: @Override
0243: public boolean connect(SocketAddress socketAddress)
0244: throws IOException {
0245: // status must be open and unconnected
0246: checkUnconnected();
0247:
0248: // check the address
0249: InetSocketAddress inetSocketAddress = validateAddress(socketAddress);
0250:
0251: int port = inetSocketAddress.getPort();
0252: String hostName = inetSocketAddress.getAddress().getHostName();
0253: // security check
0254: SecurityManager sm = System.getSecurityManager();
0255: if (sm != null) {
0256: sm.checkConnect(hostName, port);
0257: }
0258:
0259: // connect result
0260: int result = EOF;
0261: boolean finished = false;
0262:
0263: try {
0264: if (!isBound) {
0265: // bind
0266: networkSystem.bind2(fd, 0, true, InetAddress
0267: .getByAddress(new byte[] { 0, 0, 0, 0 }));
0268: isBound = true;
0269: }
0270:
0271: if (isBlocking()) {
0272: begin();
0273: result = networkSystem.connect(fd, trafficClass,
0274: inetSocketAddress.getAddress(),
0275: inetSocketAddress.getPort());
0276:
0277: } else {
0278: result = networkSystem.connectWithTimeout(fd, 0,
0279: trafficClass, inetSocketAddress.getAddress(),
0280: inetSocketAddress.getPort(),
0281: HY_SOCK_STEP_START, connectContext);
0282: // set back to nonblocking to work around with a bug in portlib
0283: if (!this .isBlocking()) {
0284: networkSystem.setNonBlocking(fd, true);
0285: }
0286: }
0287: finished = (CONNECT_SUCCESS == result);
0288: isBound = finished;
0289: } catch (IOException e) {
0290: if (e instanceof ConnectException && !isBlocking()) {
0291: status = SOCKET_STATUS_PENDING;
0292: } else {
0293: if (isOpen()) {
0294: close();
0295: finished = true;
0296: }
0297: throw e;
0298: }
0299: } finally {
0300: if (isBlocking()) {
0301: end(finished);
0302: }
0303: }
0304:
0305: // set local port
0306: localPort = networkSystem.getSocketLocalPort(fd, false);
0307: localAddress = networkSystem.getSocketLocalAddress(fd, false);
0308:
0309: // set the connected address.
0310: connectAddress = inetSocketAddress;
0311: synchronized (this ) {
0312: if (isBlocking()) {
0313: status = (finished ? SOCKET_STATUS_CONNECTED
0314: : SOCKET_STATUS_UNCONNECTED);
0315: } else {
0316: status = SOCKET_STATUS_PENDING;
0317: }
0318: }
0319: return finished;
0320: }
0321:
0322: /**
0323: * @see java.nio.channels.SocketChannel#finishConnect()
0324: */
0325: @Override
0326: public boolean finishConnect() throws IOException {
0327: // status check
0328: synchronized (this ) {
0329: if (!isOpen()) {
0330: throw new ClosedChannelException();
0331: }
0332: if (status == SOCKET_STATUS_CONNECTED) {
0333: return true;
0334: }
0335: if (status != SOCKET_STATUS_PENDING) {
0336: throw new NoConnectionPendingException();
0337: }
0338: }
0339:
0340: // finish result
0341: int result = EOF;
0342: boolean finished = false;
0343:
0344: try {
0345: begin();
0346: result = networkSystem.connectWithTimeout(fd,
0347: isBlocking() ? -1 : 0, trafficClass, connectAddress
0348: .getAddress(), connectAddress.getPort(),
0349: HY_PORT_SOCKET_STEP_CHECK, connectContext);
0350: finished = (result == CONNECT_SUCCESS);
0351: isBound = finished;
0352: localAddress = networkSystem.getSocketLocalAddress(fd,
0353: false);
0354: } catch (ConnectException e) {
0355: if (isOpen()) {
0356: close();
0357: finished = true;
0358: }
0359: throw e;
0360: } finally {
0361: end(finished);
0362: }
0363:
0364: synchronized (this ) {
0365: status = (finished ? SOCKET_STATUS_CONNECTED : status);
0366: isBound = finished;
0367: }
0368: return finished;
0369: }
0370:
0371: /**
0372: * @see java.nio.channels.SocketChannel#read(java.nio.ByteBuffer)
0373: */
0374: @Override
0375: public int read(ByteBuffer target) throws IOException {
0376: if (null == target) {
0377: throw new NullPointerException();
0378: }
0379: checkOpenConnected();
0380: if (!target.hasRemaining()) {
0381: return 0;
0382: }
0383:
0384: int readCount;
0385: if (target.isDirect() || target.hasArray()) {
0386: readCount = readImpl(target);
0387: if (readCount > 0) {
0388: target.position(target.position() + readCount);
0389: }
0390: } else {
0391: ByteBuffer readBuffer = null;
0392: byte[] readArray = null;
0393: readArray = new byte[target.remaining()];
0394: readBuffer = ByteBuffer.wrap(readArray);
0395: readCount = readImpl(readBuffer);
0396: if (readCount > 0) {
0397: target.put(readArray, 0, readCount);
0398: }
0399: }
0400: return readCount;
0401: }
0402:
0403: /**
0404: * @see java.nio.channels.SocketChannel#read(java.nio.ByteBuffer[], int,
0405: * int)
0406: */
0407: @Override
0408: public long read(ByteBuffer[] targets, int offset, int length)
0409: throws IOException {
0410: if (!isIndexValid(targets, offset, length)) {
0411: throw new IndexOutOfBoundsException();
0412: }
0413:
0414: checkOpenConnected();
0415: int totalCount = calculateByteBufferArray(targets, offset,
0416: length);
0417: if (0 == totalCount) {
0418: return 0;
0419: }
0420: byte[] readArray = new byte[totalCount];
0421: ByteBuffer readBuffer = ByteBuffer.wrap(readArray);
0422: int readCount;
0423: // read data to readBuffer, and then transfer data from readBuffer to
0424: // targets.
0425: readCount = readImpl(readBuffer);
0426: if (readCount > 0) {
0427: int left = readCount;
0428: int index = offset;
0429: // transfer data from readArray to targets
0430: while (left > 0) {
0431: int putLength = Math.min(targets[index].remaining(),
0432: left);
0433: targets[index].put(readArray, readCount - left,
0434: putLength);
0435: index++;
0436: left -= putLength;
0437: }
0438: }
0439: return readCount;
0440: }
0441:
0442: private boolean isIndexValid(ByteBuffer[] targets, int offset,
0443: int length) {
0444: return (length >= 0) && (offset >= 0)
0445: && ((long) length + (long) offset <= targets.length);
0446: }
0447:
0448: /**
0449: * Read from channel, and store the result in the target.
0450: *
0451: * @param target
0452: * output parameter
0453: */
0454: private int readImpl(ByteBuffer target) throws IOException {
0455: synchronized (readLock) {
0456: int readCount = 0;
0457: try {
0458: if (isBlocking()) {
0459: begin();
0460: }
0461: int offset = target.position();
0462: int length = target.remaining();
0463: if (target.isDirect()) {
0464: long address = AddressUtil
0465: .getDirectBufferAddress(target);
0466: readCount = networkSystem.readDirect(fd, address
0467: + offset, length,
0468: (isBlocking() ? TIMEOUT_BLOCK
0469: : TIMEOUT_NONBLOCK));
0470: } else {
0471: // target is assured to have array.
0472: byte[] array = target.array();
0473: offset += target.arrayOffset();
0474: readCount = networkSystem.read(fd, array, offset,
0475: length, (isBlocking() ? TIMEOUT_BLOCK
0476: : TIMEOUT_NONBLOCK));
0477: }
0478: return readCount;
0479: } finally {
0480: if (isBlocking()) {
0481: end(readCount > 0);
0482: }
0483: }
0484: }
0485: }
0486:
0487: /**
0488: * @see java.nio.channels.SocketChannel#write(java.nio.ByteBuffer)
0489: */
0490: @Override
0491: public int write(ByteBuffer source) throws IOException {
0492: if (null == source) {
0493: throw new NullPointerException();
0494: }
0495: checkOpenConnected();
0496: if (!source.hasRemaining()) {
0497: return 0;
0498: }
0499: return writeImpl(source);
0500: }
0501:
0502: /**
0503: * @see java.nio.channels.SocketChannel#write(java.nio.ByteBuffer[], int,
0504: * int)
0505: */
0506: @Override
0507: public long write(ByteBuffer[] sources, int offset, int length)
0508: throws IOException {
0509: if (!isIndexValid(sources, offset, length)) {
0510: throw new IndexOutOfBoundsException();
0511: }
0512:
0513: checkOpenConnected();
0514: int count = calculateByteBufferArray(sources, offset, length);
0515: if (0 == count) {
0516: return 0;
0517: }
0518: ByteBuffer writeBuf = ByteBuffer.allocate(count);
0519: for (int val = offset; val < length + offset; val++) {
0520: ByteBuffer source = sources[val];
0521: int oldPosition = source.position();
0522: writeBuf.put(source);
0523: source.position(oldPosition);
0524: }
0525: writeBuf.flip();
0526: int result = writeImpl(writeBuf);
0527: int val = offset;
0528: int written = result;
0529: while (result > 0) {
0530: ByteBuffer source = sources[val];
0531: int gap = Math.min(result, source.remaining());
0532: source.position(source.position() + gap);
0533: val++;
0534: result -= gap;
0535: }
0536: return written;
0537: }
0538:
0539: private int calculateByteBufferArray(ByteBuffer[] sources,
0540: int offset, int length) {
0541: int sum = 0;
0542: for (int val = offset; val < offset + length; val++) {
0543: sum = sum + sources[val].remaining();
0544: }
0545: return sum;
0546: }
0547:
0548: /*
0549: * Write the source. return the count of bytes written.
0550: */
0551: private int writeImpl(ByteBuffer source) throws IOException {
0552: synchronized (writeLock) {
0553: if (!source.hasRemaining()) {
0554: return 0;
0555: }
0556: int writeCount = 0;
0557: try {
0558: int pos = source.position();
0559: int length = source.remaining();
0560: if (isBlocking()) {
0561: begin();
0562: }
0563: if (source.isDirect()) {
0564: long address = AddressUtil
0565: .getDirectBufferAddress(source);
0566: writeCount = networkSystem.writeDirect(fd, address
0567: + pos, length);
0568: } else if (source.hasArray()) {
0569: pos += source.arrayOffset();
0570: writeCount = networkSystem.write(fd,
0571: source.array(), pos, length);
0572: } else {
0573: byte[] array = new byte[length];
0574: source.get(array);
0575: writeCount = networkSystem.write(fd, array, 0,
0576: length);
0577: }
0578: source.position(pos + writeCount);
0579: } catch (SocketException e) {
0580: if (e.getCause() instanceof ErrorCodeException) {
0581: if (ERRCODE_SOCKET_NONBLOCKING_WOULD_BLOCK == ((ErrorCodeException) e
0582: .getCause()).getErrorCode()) {
0583: return writeCount;
0584: }
0585: }
0586: throw e;
0587: } finally {
0588: if (isBlocking()) {
0589: end(writeCount >= 0);
0590: }
0591: }
0592: return writeCount;
0593: }
0594: }
0595:
0596: /*
0597: * Status check, open and "connected", when read and write.
0598: */
0599: synchronized private void checkOpenConnected()
0600: throws ClosedChannelException {
0601: if (!isOpen()) {
0602: throw new ClosedChannelException();
0603: }
0604: if (!isConnected()) {
0605: throw new NotYetConnectedException();
0606: }
0607: }
0608:
0609: /*
0610: * Status check, open and "unconnected", before connection.
0611: */
0612: synchronized private void checkUnconnected() throws IOException {
0613: if (!isOpen()) {
0614: throw new ClosedChannelException();
0615: }
0616: if (status == SOCKET_STATUS_CONNECTED) {
0617: throw new AlreadyConnectedException();
0618: }
0619: if (status == SOCKET_STATUS_PENDING) {
0620: throw new ConnectionPendingException();
0621: }
0622: }
0623:
0624: /*
0625: * Shared by this class and DatagramChannelImpl, to do the address transfer
0626: * and check.
0627: */
0628: static InetSocketAddress validateAddress(SocketAddress socketAddress) {
0629: if (null == socketAddress) {
0630: throw new IllegalArgumentException();
0631: }
0632: if (!(socketAddress instanceof InetSocketAddress)) {
0633: throw new UnsupportedAddressTypeException();
0634: }
0635: InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
0636: if (inetSocketAddress.isUnresolved()) {
0637: throw new UnresolvedAddressException();
0638: }
0639: return inetSocketAddress;
0640: }
0641:
0642: /*
0643: * Get local address.
0644: */
0645: public InetAddress getLocalAddress() throws UnknownHostException {
0646: byte[] any_bytes = { 0, 0, 0, 0 };
0647: if (!isBound) {
0648: return InetAddress.getByAddress(any_bytes);
0649: }
0650: return localAddress;
0651: }
0652:
0653: /*
0654: * Do really closing action here.
0655: */
0656: @Override
0657: synchronized protected void implCloseSelectableChannel()
0658: throws IOException {
0659: if (SOCKET_STATUS_CLOSED != status) {
0660: status = SOCKET_STATUS_CLOSED;
0661: if (null != socket && !socket.isClosed()) {
0662: socket.close();
0663: } else {
0664: networkSystem.socketClose(fd);
0665: }
0666: }
0667: }
0668:
0669: /**
0670: * @see java.nio.channels.spi.AbstractSelectableChannel#implConfigureBlocking(boolean)
0671: */
0672: @Override
0673: protected void implConfigureBlocking(boolean blockMode)
0674: throws IOException {
0675: synchronized (blockingLock()) {
0676: networkSystem.setNonBlocking(fd, !blockMode);
0677: }
0678: }
0679:
0680: /*
0681: * Get the fd.
0682: */
0683: public FileDescriptor getFD() {
0684: return fd;
0685: }
0686:
0687: /*
0688: * Adapter classes for internal socket.
0689: */
0690: private static class SocketAdapter extends Socket {
0691:
0692: SocketChannelImpl channel;
0693:
0694: SocketImpl socketImpl;
0695:
0696: SocketAdapter(SocketImpl socketimpl, SocketChannelImpl channel)
0697: throws SocketException {
0698: super (socketimpl);
0699: socketImpl = socketimpl;
0700: this .channel = channel;
0701: }
0702:
0703: /**
0704: * @see java.net.Socket#getChannel()
0705: */
0706: @Override
0707: public SocketChannel getChannel() {
0708: return channel;
0709: }
0710:
0711: /**
0712: * @see java.net.Socket#isBound()
0713: */
0714: @Override
0715: public boolean isBound() {
0716: return channel.isBound;
0717: }
0718:
0719: /**
0720: * @see java.net.Socket#isConnected()
0721: */
0722: @Override
0723: public boolean isConnected() {
0724: return channel.isConnected();
0725: }
0726:
0727: /**
0728: * @see java.net.Socket#getLocalAddress()
0729: */
0730: @Override
0731: public InetAddress getLocalAddress() {
0732: try {
0733: return channel.getLocalAddress();
0734: } catch (UnknownHostException e) {
0735: return null;
0736: }
0737: }
0738:
0739: /**
0740: * @see java.net.Socket#connect(java.net.SocketAddress, int)
0741: */
0742: @Override
0743: public void connect(SocketAddress remoteAddr, int timeout)
0744: throws IOException {
0745: if (!channel.isBlocking()) {
0746: throw new IllegalBlockingModeException();
0747: }
0748: if (isConnected()) {
0749: throw new AlreadyConnectedException();
0750: }
0751: super .connect(remoteAddr, timeout);
0752: channel.localAddress = networkSystem.getSocketLocalAddress(
0753: channel.fd, false);
0754: if (super .isConnected()) {
0755: channel.setConnected();
0756: channel.isBound = super .isBound();
0757: }
0758: }
0759:
0760: /**
0761: * @see java.net.Socket#bind(java.net.SocketAddress)
0762: */
0763: @Override
0764: public void bind(SocketAddress localAddr) throws IOException {
0765: if (channel.isConnected()) {
0766: throw new AlreadyConnectedException();
0767: }
0768: if (SocketChannelImpl.SOCKET_STATUS_PENDING == channel.status) {
0769: throw new ConnectionPendingException();
0770: }
0771: super .bind(localAddr);
0772: // keep here to see if need next version
0773: // channel.Address = getLocalSocketAddress();
0774: // channel.localport = getLocalPort();
0775: channel.isBound = true;
0776:
0777: }
0778:
0779: /**
0780: * @see java.net.Socket#close()
0781: */
0782: @Override
0783: public void close() throws IOException {
0784: synchronized (channel) {
0785: if (channel.isOpen()) {
0786: channel.close();
0787: } else {
0788: super .close();
0789: }
0790: channel.status = SocketChannelImpl.SOCKET_STATUS_CLOSED;
0791: }
0792: }
0793:
0794: @Override
0795: public boolean getReuseAddress() throws SocketException {
0796: checkOpen();
0797: return ((Boolean) socketImpl
0798: .getOption(SocketOptions.SO_REUSEADDR))
0799: .booleanValue();
0800: }
0801:
0802: @Override
0803: public synchronized int getReceiveBufferSize()
0804: throws SocketException {
0805: checkOpen();
0806: return ((Integer) socketImpl
0807: .getOption(SocketOptions.SO_RCVBUF)).intValue();
0808: }
0809:
0810: @Override
0811: public synchronized int getSendBufferSize()
0812: throws SocketException {
0813: checkOpen();
0814: return ((Integer) socketImpl
0815: .getOption(SocketOptions.SO_SNDBUF)).intValue();
0816: }
0817:
0818: @Override
0819: public synchronized int getSoTimeout() throws SocketException {
0820: checkOpen();
0821: return ((Integer) socketImpl
0822: .getOption(SocketOptions.SO_TIMEOUT)).intValue();
0823: }
0824:
0825: @Override
0826: public int getTrafficClass() throws SocketException {
0827: checkOpen();
0828: return ((Number) socketImpl.getOption(SocketOptions.IP_TOS))
0829: .intValue();
0830: }
0831:
0832: /**
0833: * @see java.net.Socket#getKeepAlive()
0834: */
0835: @Override
0836: public boolean getKeepAlive() throws SocketException {
0837: checkOpen();
0838: return ((Boolean) socketImpl
0839: .getOption(SocketOptions.SO_KEEPALIVE))
0840: .booleanValue();
0841: }
0842:
0843: /**
0844: * @see java.net.Socket#getOOBInline()
0845: */
0846: @Override
0847: public boolean getOOBInline() throws SocketException {
0848: checkOpen();
0849: return ((Boolean) socketImpl
0850: .getOption(SocketOptions.SO_OOBINLINE))
0851: .booleanValue();
0852: }
0853:
0854: /**
0855: * @see java.net.Socket#getSoLinger()
0856: */
0857: @Override
0858: public int getSoLinger() throws SocketException {
0859: checkOpen();
0860: return ((Integer) socketImpl
0861: .getOption(SocketOptions.SO_LINGER)).intValue();
0862: }
0863:
0864: /**
0865: * @see java.net.Socket#getTcpNoDelay()
0866: */
0867: @Override
0868: public boolean getTcpNoDelay() throws SocketException {
0869: checkOpen();
0870: return ((Boolean) socketImpl
0871: .getOption(SocketOptions.TCP_NODELAY))
0872: .booleanValue();
0873: }
0874:
0875: /**
0876: * @see java.net.Socket#getOutputStream()
0877: */
0878: @Override
0879: public OutputStream getOutputStream() throws IOException {
0880: if (!channel.isOpen()) {
0881: // nio.00=Socket is closed
0882: throw new SocketException(Messages.getString("nio.00")); //$NON-NLS-1$
0883: }
0884: if (!channel.isConnected()) {
0885: // nio.01=Socket is not connected
0886: throw new SocketException(Messages.getString("nio.01")); //$NON-NLS-1$
0887: }
0888: if (isOutputShutdown()) {
0889: // nio.02=Socket output is shutdown
0890: throw new SocketException(Messages.getString("nio.02")); //$NON-NLS-1$
0891: }
0892: return new SocketChannelOutputStream(channel);
0893: }
0894:
0895: /**
0896: * @see java.net.Socket#getInputStream()
0897: */
0898: @Override
0899: public InputStream getInputStream() throws IOException {
0900: if (!channel.isOpen()) {
0901: // nio.00=Socket is closed
0902: throw new SocketException(Messages.getString("nio.00")); //$NON-NLS-1$
0903: }
0904: if (!channel.isConnected()) {
0905: // nio.01=Socket is not connected
0906: throw new SocketException(Messages.getString("nio.01")); //$NON-NLS-1$
0907: }
0908: if (isInputShutdown()) {
0909: // nio.03=Socket input is shutdown
0910: throw new SocketException(Messages.getString("nio.03")); //$NON-NLS-1$
0911: }
0912: return new SocketChannelInputStream(channel);
0913: }
0914:
0915: /*
0916: * Checks whether the channel is open.
0917: */
0918: private void checkOpen() throws SocketException {
0919: if (isClosed()) {
0920: // nio.00=Socket is closed
0921: throw new SocketException(Messages.getString("nio.00")); //$NON-NLS-1$
0922: }
0923: }
0924:
0925: /*
0926: * Used for net and nio exchange.
0927: */
0928: public SocketImpl getImpl() {
0929: return socketImpl;
0930: }
0931: }
0932:
0933: /*
0934: * This output stream delegates all operations to the associated channel.
0935: * Throws an IllegalBlockingModeException if the channel is in non-blocking
0936: * mode when performing write operations.
0937: */
0938: private static class SocketChannelOutputStream extends OutputStream {
0939: SocketChannel channel;
0940:
0941: public SocketChannelOutputStream(SocketChannel channel) {
0942: this .channel = channel;
0943: }
0944:
0945: /*
0946: * Closes this stream and channel.
0947: *
0948: * @exception IOException thrown if an error occurs during the close
0949: */
0950: @Override
0951: public void close() throws IOException {
0952: channel.close();
0953: }
0954:
0955: /**
0956: * @see java.io.OutputStream#write(byte[], int, int)
0957: */
0958: @Override
0959: public void write(byte[] buffer, int offset, int count)
0960: throws IOException {
0961: if (0 > offset || 0 > count
0962: || count + offset > buffer.length) {
0963: throw new IndexOutOfBoundsException();
0964: }
0965: ByteBuffer buf = ByteBuffer.wrap(buffer, offset, count);
0966: if (!channel.isBlocking()) {
0967: throw new IllegalBlockingModeException();
0968: }
0969: channel.write(buf);
0970: }
0971:
0972: /**
0973: * @see java.io.OutputStream#write(int)
0974: */
0975: @Override
0976: public void write(int oneByte) throws IOException {
0977: if (!channel.isBlocking()) {
0978: throw new IllegalBlockingModeException();
0979: }
0980: ByteBuffer buffer = ByteBuffer.allocate(1);
0981: buffer.put(0, (byte) (oneByte & 0xFF));
0982: channel.write(buffer);
0983: }
0984: }
0985:
0986: /*
0987: * This input stream delegates all operations to the associated channel.
0988: * Throws an IllegalBlockingModeException if the channel is in non-blocking
0989: * mode when performing read operations.
0990: */
0991: private static class SocketChannelInputStream extends InputStream {
0992: SocketChannel channel;
0993:
0994: public SocketChannelInputStream(SocketChannel channel) {
0995: this .channel = channel;
0996: }
0997:
0998: /*
0999: * Closes this stream and channel.
1000: */
1001: @Override
1002: public void close() throws IOException {
1003: channel.close();
1004: }
1005:
1006: /**
1007: * @see java.io.InputStream#read()
1008: */
1009: @Override
1010: public int read() throws IOException {
1011: if (!channel.isBlocking()) {
1012: throw new IllegalBlockingModeException();
1013: }
1014: ByteBuffer buf = ByteBuffer.allocate(1);
1015: int result = channel.read(buf);
1016: return (-1 == result) ? result : buf.get() & 0xFF;
1017: }
1018:
1019: /**
1020: * @see java.io.InputStream#read(byte[], int, int)
1021: */
1022: @Override
1023: public int read(byte[] buffer, int offset, int count)
1024: throws IOException {
1025: if (0 > offset || 0 > count
1026: || count + offset > buffer.length) {
1027: throw new IndexOutOfBoundsException();
1028: }
1029: if (!channel.isBlocking()) {
1030: throw new IllegalBlockingModeException();
1031: }
1032: ByteBuffer buf = ByteBuffer.wrap(buffer, offset, count);
1033: return channel.read(buf);
1034: }
1035: }
1036: }
|