package org.webpieces.nio.impl.cm.basic; import java.io.IOException; import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.channels.SelectableChannel; import java.util.concurrent.CompletableFuture; import org.webpieces.util.logging.Logger; import org.webpieces.util.logging.LoggerFactory; import org.webpieces.data.api.BufferPool; import org.webpieces.nio.api.channels.Channel; import org.webpieces.nio.api.channels.TCPChannel; import org.webpieces.nio.api.exceptions.NioException; import org.webpieces.nio.api.testutil.chanapi.ChannelsFactory; import org.webpieces.nio.api.testutil.chanapi.SocketChannel; /** * @author Dean Hiller */ class BasTCPChannel extends BasChannelImpl implements TCPChannel { private static final Logger apiLog = LoggerFactory.getLogger(TCPChannel.class); private static final Logger log = LoggerFactory.getLogger(BasTCPChannel.class); private org.webpieces.nio.api.testutil.chanapi.SocketChannel channel; public BasTCPChannel(IdObject id, ChannelsFactory factory, SelectorManager2 selMgr, BufferPool pool) { super(id, selMgr, pool); try { channel = factory.open(); channel.configureBlocking(false); } catch(IOException e) { throw new NioException(e); } } /** * Only used from TCPServerChannel.accept(). please keep it that way. thanks. * @param newChan * @param pool * @param executor */ public BasTCPChannel(IdObject id, SocketChannel newChan, SocketAddress remoteAddr, SelectorManager2 selMgr, BufferPool pool) { super(id, selMgr, pool); if(newChan.isBlocking()) throw new IllegalArgumentException(this+"TCPChannels can only be non-blocking socketChannels"); channel = newChan; setConnecting(remoteAddr); } protected void bindImpl2(SocketAddress address) throws IOException { channel.bind(address); } /* (non-Javadoc) * @see api.biz.xsoftware.nio.SocketChannel#isBound() */ public boolean isBound() { return channel.isBound(); } protected int writeImpl(ByteBuffer b) { try { return channel.write(b); } catch (IOException e) { throw new NioException(e); } } public int readImpl(ByteBuffer b) { if(b == null) throw new IllegalArgumentException(this+"Cannot use a null ByteBuffer"); //special code, read information in close() method if(isClosed()) return -1; try { return channel.read(b); } catch (IOException e) { throw new NioException(e); } } /** * @see org.webpieces.nio.impl.cm.basic.BasChannelImpl#closeImpl() */ @Override protected void closeImpl() throws IOException { channel.close(); } public boolean isClosed() { return channel.isClosed(); } public boolean isConnected() { return channel.isConnected(); } protected CompletableFuture<Channel> connectImpl(SocketAddress addr) { try { return connectImpl2(addr); } catch (IOException e) { throw new NioException(e); } catch (InterruptedException e) { throw new NioException(e); } } private CompletableFuture<Channel> connectImpl2(SocketAddress addr) throws IOException, InterruptedException { CompletableFuture<Channel> future = new CompletableFuture<>(); apiLog.trace(()->this+"Basic.connect-addr="+addr); try { boolean connected = channel.connect(addr); log.trace(()->this+"connected status="+connected); setConnecting(addr); if(connected) { try { future.complete(this); } catch(Throwable e) { log.error(this+"Exception occurred", e); } } else { return getSelectorManager().registerChannelForConnect(this); } } catch(Throwable t) { log.error("connecting failed"); future.completeExceptionally(t); } return future; } public boolean isBlocking() { return channel.isBlocking(); } /* (non-Javadoc) * @see biz.xsoftware.nio.RegisterableChannelImpl#getRealChannel() */ public SelectableChannel getRealChannel() { return channel.getSelectableChannel(); } /* (non-Javadoc) * @see api.biz.xsoftware.nio.NetSocketChannel#setReuseAddress(boolean) */ public void setReuseAddress(boolean b) { try { channel.setReuseAddress(b); } catch (SocketException e) { throw new NioException(e); } } /* (non-Javadoc) * @see api.biz.xsoftware.nio.ClientSocketChannel#getRemoteAddress() */ public InetSocketAddress getRemoteAddress() { InetAddress addr = channel.getInetAddress(); int port = channel.getPort(); return new InetSocketAddress(addr, port); } /** */ public InetSocketAddress getLocalAddress() { InetAddress addr = channel.getLocalAddress(); int port = channel.getLocalPort(); return new InetSocketAddress(addr, port); } public void finishConnect() throws IOException { try { channel.finishConnect(); } catch(ConnectException e) { ConnectException exc = new ConnectException("could not connect to="+isConnectingTo); exc.initCause(e); throw exc; } } public void setKeepAlive(boolean b) { try { channel.setKeepAlive(b); } catch (SocketException e) { throw new NioException(e); } } public boolean getKeepAlive() { try { return channel.getKeepAlive(); } catch (SocketException e) { throw new NioException(e); } } public int getSoTimeout() { try { return channel.getSoTimeout(); } catch (SocketException e) { throw new NioException(e); } } @Override public boolean isSslChannel() { return false; } }