package udpserversocketchannel.channel; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; import io.netty.buffer.ByteBuf; import io.netty.channel.AbstractChannel; import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelOutboundBuffer; import io.netty.channel.ChannelPromise; import io.netty.channel.DefaultChannelConfig; import io.netty.channel.EventLoop; import io.netty.util.ReferenceCountUtil; import io.netty.util.internal.RecyclableArrayList; public class UdpChannel extends AbstractChannel { protected final ChannelMetadata metadata = new ChannelMetadata(false); protected final DefaultChannelConfig config = new DefaultChannelConfig(this); protected final UdpServerChannel serverChannel; protected final InetSocketAddress remote; protected UdpChannel(UdpServerChannel serverchannel, InetSocketAddress remote) { super(serverchannel); this.serverChannel = serverchannel; this.remote = remote; } protected AtomicBoolean isNew = new AtomicBoolean(true); protected boolean getIsNew() { return isNew.compareAndSet(true, false); } @Override public ChannelMetadata metadata() { return metadata; } @Override public ChannelConfig config() { return config; } protected volatile boolean open = true; @Override public boolean isActive() { return open; } @Override public boolean isOpen() { return isActive(); } @Override protected void doClose() throws Exception { open = false; serverChannel.doUserChannelRemove(this); } @Override protected void doDisconnect() throws Exception { doClose(); } protected final ConcurrentLinkedQueue<ByteBuf> buffers = new ConcurrentLinkedQueue<>(); protected void addBuffer(ByteBuf buffer) { this.buffers.add(buffer); } protected boolean reading = false; @Override protected void doBeginRead() throws Exception { if (reading) { return; } reading = true; try { ByteBuf buffer = null; while ((buffer = buffers.poll()) != null) { pipeline().fireChannelRead(buffer); } pipeline().fireChannelReadComplete(); } finally { reading = false; } } @Override protected void doWrite(ChannelOutboundBuffer buffer) throws Exception { final RecyclableArrayList list = RecyclableArrayList.newInstance(); boolean freeList = true; try { ByteBuf buf = null; while ((buf = (ByteBuf) buffer.current()) != null) { list.add(buf.retain()); buffer.remove(); } freeList = false; } finally { if (freeList) { for (Object obj : list) { ReferenceCountUtil.safeRelease(obj); } list.recycle(); } } serverChannel.doWrite(list, remote); } @Override protected boolean isCompatible(EventLoop eventloop) { return true; } @Override protected AbstractUnsafe newUnsafe() { return new AbstractUnsafe() { @Override public void connect(SocketAddress addr1, SocketAddress addr2, ChannelPromise pr) { throw new UnsupportedOperationException(); } }; } @Override protected SocketAddress localAddress0() { return serverChannel.localAddress0(); } @Override protected SocketAddress remoteAddress0() { return remote; } @Override protected void doBind(SocketAddress addr) throws Exception { throw new UnsupportedOperationException(); } }