All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.barchart.udt.nio.SocketChannelUDT Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2009-2013 Barchart, Inc. 
 *
 * All rights reserved. Licensed under the OSI BSD License.
 *
 * http://www.opensource.org/licenses/bsd-license.php
 */
package com.barchart.udt.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.ConnectionPendingException;
import java.nio.channels.IllegalBlockingModeException;
import java.nio.channels.SocketChannel;
import java.nio.channels.UnresolvedAddressException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.barchart.udt.ExceptionUDT;
import com.barchart.udt.SocketUDT;
import com.barchart.udt.TypeUDT;
import com.barchart.udt.anno.ThreadSafe;

/**
 * {@link SocketChannel}-like wrapper for {@link SocketUDT}, can be either
 * stream or message oriented, depending on {@link TypeUDT}
 * 

* The UDT socket that this SocketChannel wraps will be switched to blocking * mode since this is the default for all SocketChannels on construction. If you * require non-blocking functionality, you will need to call configureBlocking * on the constructed SocketChannel class. *

* you must use {@link SelectorProviderUDT#openSocketChannel()} to obtain * instance of this class; do not use JDK * {@link java.nio.channels.SocketChannel#open()}; *

* example: * *

 * SelectorProvider provider = SelectorProviderUDT.DATAGRAM;
 * SocketChannel clientChannel = provider.openSocketChannel();
 * clientChannel.configureBlocking(true);
 * Socket clientSocket = clientChannel.socket();
 * InetSocketAddress clientAddress = new InetSocketAddress("localhost", 10000);
 * clientSocket.bind(clientAddress);
 * assert clientSocket.isBound();
 * InetSocketAddress serverAddress = new InetSocketAddress("localhost", 12345);
 * clientChannel.connect(serverAddress);
 * assert clientSocket.isConnected();
 * 
*/ public class SocketChannelUDT extends SocketChannel implements ChannelUDT { protected static final Logger log = LoggerFactory .getLogger(SocketChannelUDT.class); protected final Object connectLock = new Object(); /** * local volatile variable, which mirrors super.blocking, to avoid the cost * of synchronized call inside isBlocking() */ protected volatile boolean isBlockingMode = isBlocking(); protected volatile boolean isConnectFinished; protected volatile boolean isConnectionPending; @ThreadSafe("this") protected NioSocketUDT socketAdapter; protected final SocketUDT socketUDT; protected SocketChannelUDT( // final SelectorProviderUDT provider, // final SocketUDT socketUDT // ) throws ExceptionUDT { super(provider); this.socketUDT = socketUDT; this.socketUDT.setBlocking(true); } protected SocketChannelUDT( // final SelectorProviderUDT provider, // final SocketUDT socketUDT, // final boolean isConnected // ) throws ExceptionUDT { this(provider, socketUDT); if (isConnected) { isConnectFinished = true; isConnectionPending = false; } else { isConnectFinished = false; isConnectionPending = true; } } @Override public boolean connect(final SocketAddress remote) throws IOException { if (!isOpen()) { throw new ClosedChannelException(); } if (isConnected()) { log.warn("already connected; ignoring remote={}", remote); return true; } if (remote == null) { close(); log.error("remote == null"); throw new NullPointerException(); } final InetSocketAddress remoteSocket = (InetSocketAddress) remote; if (remoteSocket.isUnresolved()) { log.error("can not use unresolved address: remote={}", remote); close(); throw new UnresolvedAddressException(); } if (isBlocking()) { synchronized (connectLock) { try { if (isConnectionPending) { close(); throw new ConnectionPendingException(); } isConnectionPending = true; begin(); socketUDT.connect(remoteSocket); } finally { end(true); isConnectionPending = false; connectLock.notifyAll(); } } return socketUDT.isConnected(); } else { /** non Blocking */ if (!isRegistered()) { /** this channel is independent of any selector */ log.error("UDT channel is in NON blocking mode; " + "must register with a selector " // + "before trying to connect(); " // + "socketId=" + socketUDT.id()); throw new IllegalBlockingModeException(); } /** this channel is registered with a selector */ synchronized (connectLock) { if (isConnectionPending) { close(); log.error("connection already in progress"); throw new ConnectionPendingException(); } isConnectFinished = false; isConnectionPending = true; socketUDT.connect(remoteSocket); } /** * connection operation must later be completed by invoking the * #finishConnect() method. */ return false; } } @Override public boolean finishConnect() throws IOException { if (!isOpen()) { throw new ClosedChannelException(); } if (isBlocking()) { synchronized (connectLock) { while (isConnectionPending) { try { connectLock.wait(); } catch (final InterruptedException e) { throw new IOException(e); } } } } if (isConnected()) { isConnectFinished = true; isConnectionPending = false; return true; } else { log.error("connect failure : {}", socketUDT); throw new IOException(); } } @Override protected void implCloseSelectableChannel() throws IOException { socketUDT.close(); } @Override protected void implConfigureBlocking(final boolean block) throws IOException { socketUDT.setBlocking(block); isBlockingMode = block; } @Override public boolean isConnected() { return socketUDT.isConnected(); } @Override public boolean isConnectFinished() { return isConnectFinished; } @Override public boolean isConnectionPending() { return isConnectionPending; } @Override public KindUDT kindUDT() { return KindUDT.CONNECTOR; } @Override public SelectorProviderUDT providerUDT() { return (SelectorProviderUDT) super.provider(); } // /** * See {@link java.nio.channels.SocketChannel#read(ByteBuffer)} contract; * note: this method does not return (-1) as EOS (end of stream flag) * * @return <0 should not happen
* =0 blocking mode: timeout occurred on receive
* =0 non-blocking mode: nothing is received by the * underlying UDT socket
* >0 actual bytes received count
* @see com.barchart.udt.SocketUDT#receive(ByteBuffer) * @see com.barchart.udt.SocketUDT#receive(byte[], int, int) */ @Override public int read(final ByteBuffer buffer) throws IOException { final int remaining = buffer.remaining(); if (remaining <= 0) { return 0; } final SocketUDT socket = socketUDT; final boolean isBlocking = isBlockingMode; final int sizeReceived; try { if (isBlocking) { begin(); // JDK contract for NIO blocking calls } if (buffer.isDirect()) { sizeReceived = socket.receive(buffer); } else { final byte[] array = buffer.array(); final int position = buffer.position(); final int limit = buffer.limit(); sizeReceived = socket.receive(array, position, limit); if (0 < sizeReceived && sizeReceived <= remaining) { buffer.position(position + sizeReceived); } } } finally { if (isBlocking) { end(true); // JDK contract for NIO blocking calls } } // see contract for receive() if (sizeReceived < 0) { // log.trace("nothing was received; socket={}", socket); return 0; } if (sizeReceived == 0) { // log.trace("receive timeout; socket={}", socket); return 0; } if (sizeReceived <= remaining) { return sizeReceived; } else { log.error("should not happen: socket={}", socket); return 0; } } @Override public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { throw new RuntimeException("feature not available"); } @Override public synchronized NioSocketUDT socket() { if (socketAdapter == null) { try { socketAdapter = new NioSocketUDT(this); } catch (final ExceptionUDT e) { log.error("failed to make socket", e); } } return socketAdapter; } @Override public SocketUDT socketUDT() { return socketUDT; } @Override public String toString() { return socketUDT.toString(); } /** * See {@link java.nio.channels.SocketChannel#write(ByteBuffer)} contract; * * @return <0 should not happen
* =0 blocking mode: timeout occurred on send
* =0 non-blocking mode: buffer is full in the * underlying UDT socket; nothing is sent
* >0 actual bytes sent count
* @see com.barchart.udt.SocketUDT#send(ByteBuffer) * @see com.barchart.udt.SocketUDT#send(byte[], int, int) */ @Override public int write(final ByteBuffer buffer) throws IOException { // writeCount.incrementAndGet(); if (buffer == null) { throw new NullPointerException("buffer == null"); } final int remaining = buffer.remaining(); if (remaining <= 0) { return 0; } final SocketUDT socket = socketUDT; final boolean isBlocking = isBlockingMode; int sizeSent = 0; int ret = 0; try { if (isBlocking) { begin(); // JDK contract for NIO blocking calls } if (buffer.isDirect()) { do { ret = socket.send(buffer); if (ret > 0) sizeSent += ret; } while (buffer.hasRemaining() && isBlocking); } else { final byte[] array = buffer.array(); int position = buffer.position(); final int limit = buffer.limit(); do { ret = socket.send(array, position, limit); if (0 < ret && ret <= remaining) { sizeSent += ret; position += ret; buffer.position(position); } } while (buffer.hasRemaining() && isBlocking); } } finally { if (isBlocking) { end(true); // JDK contract for NIO blocking calls } } // see contract for send() if (ret < 0) { // log.trace("no buffer space; socket={}", socket); return 0; } if (ret == 0) { // log.trace("send timeout; socket={}", socket); return 0; } if (sizeSent <= remaining) { return sizeSent; } else { log.error("should not happen; socket={}", socket); return 0; } } @Override public long write(final ByteBuffer[] bufferArray, final int offset, final int length) throws IOException { try { long total = 0; for (int index = offset; index < offset + length; index++) { final ByteBuffer buffer = bufferArray[index]; final int remaining = buffer.remaining(); final int processed = write(buffer); if (remaining == processed) { total += processed; } else { throw new IllegalStateException( "failed to write buffer in array"); } } return total; } catch (final Throwable e) { throw new IOException("failed to write buffer array", e); } } @Override public TypeUDT typeUDT() { return providerUDT().type(); } /** java 7 */ public SocketChannelUDT bind(final SocketAddress localAddress) throws IOException { socketUDT.bind((InetSocketAddress) localAddress); return this; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy