package org.webpieces.nio.impl.cm.basic.udp; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.PortUnreachableException; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.nio.channels.SelectableChannel; import java.util.Calendar; 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.UDPChannel; import org.webpieces.nio.api.exceptions.NioException; import org.webpieces.nio.api.exceptions.NioPortUnreachableException; import org.webpieces.nio.impl.cm.basic.BasChannelImpl; import org.webpieces.nio.impl.cm.basic.IdObject; import org.webpieces.nio.impl.cm.basic.SelectorManager2; public class UDPChannelImpl extends BasChannelImpl implements UDPChannel { private static final Logger log = LoggerFactory.getLogger(UDPChannel.class); private static final Logger apiLog = LoggerFactory.getLogger(UDPChannel.class); private DatagramChannel channel; private boolean isConnected = false; private Calendar expires; public UDPChannelImpl(IdObject id, SelectorManager2 selMgr, BufferPool pool) { super(id, selMgr, pool); try { channel = DatagramChannel.open(); channel.configureBlocking(false); channel.socket().setReuseAddress(true); } catch(IOException e) { throw new NioException(e); } } public void bindImpl2(SocketAddress addr) throws IOException { channel.socket().bind(addr); } protected synchronized CompletableFuture<Channel> connectImpl(SocketAddress addr) { CompletableFuture<Channel> promise = new CompletableFuture<>(); try { apiLog.trace(()->this+"Basic.connect called-addr="+addr); channel.connect(addr); isConnected = true; promise.complete(this); } catch(Exception e) { promise.completeExceptionally(e); } return promise; } public synchronized void disconnect() { apiLog.trace(()->this+"Basic.disconnect called"); try { isConnected = false; channel.disconnect(); } catch(IOException e) { throw new NioException(e); } } public void setReuseAddress(boolean b) { throw new UnsupportedOperationException("not implemented yet"); } public boolean isBlocking() { return channel.isBlocking(); } public void closeImpl() throws IOException { channel.close(); } public boolean isClosed() { return channel.socket().isClosed(); } public boolean isBound() { return channel.socket().isBound(); } public InetSocketAddress getLocalAddress() { InetAddress addr = channel.socket().getLocalAddress(); int port = channel.socket().getLocalPort(); return new InetSocketAddress(addr, port); } public InetSocketAddress getRemoteAddress() { return (InetSocketAddress)channel.socket().getRemoteSocketAddress(); } public boolean isConnected() { return channel.isConnected(); } @Override public SelectableChannel getRealChannel() { return channel; } @Override public int readImpl(ByteBuffer b) { if(b == null) throw new IllegalArgumentException("Cannot use a null ByteBuffer"); else if(!isConnected) throw new IllegalStateException("Currently not connected"); try { return channel.read(b); } catch(PortUnreachableException e) { if(expires != null) { //ignore the event if we are not at expires yet if(Calendar.getInstance().before(expires)) { return 0; } } expires = Calendar.getInstance(); expires.add(Calendar.SECOND, 10); log.error("PortUnreachable. NOTICE NOTICE: We will ignore this exc again on this channel for 10 seconds"); throw new NioPortUnreachableException(e); } catch (IOException e) { throw new NioException(e); } } @Override protected int writeImpl(ByteBuffer b) { try { return channel.write(b); } catch (IOException e) { throw new NioException(e); } } @Override public boolean isSslChannel() { return false; } }