Package com.davfx.ninio.common

Source Code of com.davfx.ninio.common.DatagramReady

package com.davfx.ninio.common;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.LinkedList;

public final class DatagramReady implements Ready {
  private static final class AddressedByteBuffer {
    Address address;
    ByteBuffer buffer;
  }

  private final Selector selector;
  private final ByteBufferAllocator byteBufferAllocator;

  public DatagramReady(Selector selector, ByteBufferAllocator byteBufferAllocator) {
    this.selector = selector;
    this.byteBufferAllocator = byteBufferAllocator;
  }
 
  @Override
  public void connect(Address address, final ReadyConnection connection) {
    try {
      final DatagramChannel channel = DatagramChannel.open();
      try {
        channel.configureBlocking(false);
        final SelectionKey selectionKey = channel.register(selector, 0);
       
        final LinkedList<AddressedByteBuffer> toWriteQueue = new LinkedList<AddressedByteBuffer>();
 
        selectionKey.attach(new SelectionKeyVisitor() {
          @Override
          public void visit(final SelectionKey key) {
            if (!channel.isOpen()) {
              return;
            }
            if (key.isReadable()) {
              ByteBuffer readBuffer = byteBufferAllocator.allocate();
              try {
                InetSocketAddress from = (InetSocketAddress) channel.receive(readBuffer);
                if (from == null) {
                  try {
                    channel.close();
                  } catch (IOException ee) {
                  }
                  connection.close();
                } else {
                  readBuffer.flip();
                  connection.handle(new Address(from.getHostName(), from.getPort()), readBuffer);
                }
              } catch (IOException e) {
                try {
                  channel.close();
                } catch (IOException ee) {
                }
                connection.close();
              }
            } else if (key.isWritable()) {
              while (!toWriteQueue.isEmpty()) {
                AddressedByteBuffer b = toWriteQueue.getFirst();
                if (b == null) {
                  try {
                    channel.close();
                  } catch (IOException ee) {
                  }
                  return;
                } else {
                  try {
                    if (b.address == null) {
                      channel.write(b.buffer);
                    } else {
                      channel.send(b.buffer, AddressUtils.toConnectableInetSocketAddress(b.address));
                    }
                  } catch (IOException e) {
                    try {
                      channel.close();
                    } catch (IOException ee) {
                    }
                    connection.close();
                    break;
                  }
                 
                  if (b.buffer.hasRemaining()) {
                    return;
                  }
                 
                  toWriteQueue.removeFirst();
                }
              }
              if (!selector.isOpen()) {
                return;
              }
              if (!channel.isOpen()) {
                return;
              }
              if (!selectionKey.isValid()) {
                return;
              }
              selectionKey.interestOps(selectionKey.interestOps() & ~SelectionKey.OP_WRITE);
            }
          }
        });
 
        selectionKey.interestOps(selectionKey.interestOps() | SelectionKey.OP_READ);
       
        try {
          boolean bind = false;
          InetSocketAddress a = AddressUtils.toConnectableInetSocketAddress(address);
          if (a == null) {
            a = AddressUtils.toBindableInetSocketAddress(address);
            bind = true;
          }
          if (a == null) {
            throw new IOException("Invalid address");
          }
          if (bind) {
            channel.socket().bind(a);
          } else {
            channel.connect(a);
          }
        } catch (IOException e) {
          selectionKey.cancel();
          throw e;
        }
 
        connection.connected(new FailableCloseableByteBufferHandler() {
          @Override
          public void handle(Address address, ByteBuffer buffer) {
            if (!selector.isOpen()) {
              return;
            }
            if (!channel.isOpen()) {
              return;
            }
            if (!selectionKey.isValid()) {
              return;
            }
            AddressedByteBuffer b = new AddressedByteBuffer();
            b.address = address;
            b.buffer = buffer;
            toWriteQueue.addLast(b);
            selectionKey.interestOps(selectionKey.interestOps() | SelectionKey.OP_WRITE);
          }
          @Override
          public void close() {
            if (!selector.isOpen()) {
              return;
            }
            if (!channel.isOpen()) {
              return;
            }
            if (!selectionKey.isValid()) {
              return;
            }
            toWriteQueue.addLast(null);
            selectionKey.interestOps(selectionKey.interestOps() | SelectionKey.OP_WRITE);
          }
          @Override
          public void failed(IOException e) {
            close();
          }
        });
      } catch (IOException e) {
        try {
          channel.close();
        } catch (IOException ee) {
        }
        throw e;
      }
    } catch (IOException e) {
      connection.failed(e);
    }
  }
}
TOP

Related Classes of com.davfx.ninio.common.DatagramReady

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.