Package com.davfx.ninio.telnet

Source Code of com.davfx.ninio.telnet.TelnetClient$TelnetResponseReader

package com.davfx.ninio.telnet;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;

import com.davfx.ninio.common.Address;
import com.davfx.ninio.common.ByteBufferAllocator;
import com.davfx.ninio.common.CloseableByteBufferHandler;
import com.davfx.ninio.common.FailableCloseableByteBufferHandler;
import com.davfx.ninio.common.OnceByteBufferAllocator;
import com.davfx.ninio.common.Queue;
import com.davfx.ninio.common.Ready;
import com.davfx.ninio.common.ReadyConnection;
import com.davfx.ninio.common.ReadyFactory;
import com.davfx.ninio.common.SocketReadyFactory;

public final class TelnetClient implements TelnetConnector {
  public static final int DEFAULT_PORT = 23;
  public static final String EOL = "\r\n";

  private Queue queue = null;
  private Address address = new Address("localhost", DEFAULT_PORT);
  private String host = null;
  private int port = -1;

  private ReadyFactory readyFactory = new SocketReadyFactory();

  public TelnetClient() {
  }
 
  @Override
  public String getEol() {
    return EOL;
  }
 
  @Override
  public TelnetClient withQueue(Queue queue) {
    this.queue = queue;
    return this;
  }
 
  @Override
  public TelnetClient withHost(String host) {
    this.host = host;
    return this;
  }
  @Override
  public TelnetClient withPort(int port) {
    this.port = port;
    return this;
  }
  @Override
  public TelnetClient withAddress(Address address) {
    this.address = address;
    return this;
  }
 
  @Override
  public TelnetClient override(ReadyFactory readyFactory) {
    this.readyFactory = readyFactory;
    return this;
  }
 
  @Override
  public void connect(final TelnetClientHandler clientHandler) {
    final Queue q;
    final boolean shouldCloseQueue;
    if (queue == null) {
      try {
        q = new Queue();
      } catch (IOException e) {
        clientHandler.failed(e);
        return;
      }
      shouldCloseQueue = true;
    } else {
      q = queue;
      shouldCloseQueue = false;
    }

    final Address a;
    if (host != null) {
      if (port < 0) {
        a = new Address(host, address.getPort());
      } else {
        a = new Address(host, port);
      }
    } else {
      a = address;
    }

    q.post(new Runnable() {
      @Override
      public void run() {
        ByteBufferAllocator allocator = new OnceByteBufferAllocator();
        Ready ready = readyFactory.create(q, allocator);
        ready.connect(a, new ReadyConnection() {
          private TelnetResponseReader reader = null;
          @Override
          public void handle(Address address, ByteBuffer buffer) {
            reader.handle(address, buffer);
          }
         
          @Override
          public void failed(IOException e) {
            if (shouldCloseQueue) {
              q.close();
            }
            clientHandler.failed(e);
          }
         
          @Override
          public void connected(FailableCloseableByteBufferHandler write) {
            reader = new TelnetResponseReader(clientHandler, write);
            clientHandler.launched(new TelnetClientHandler.Callback() {
              @Override
              public void close() {
                reader.close();
                if (shouldCloseQueue) {
                  q.close();
                }
              }
             
              @Override
              public void send(String line) {
                reader.send(line);
              }
            });
          }
         
          @Override
          public void close() {
            if (shouldCloseQueue) {
              q.close();
            }
            reader.close();
          }
        });
      }
    });
  }

  private static final class TelnetResponseReader implements CloseableByteBufferHandler, TelnetClientHandler.Callback {
    private static final Charset USASCII_CHARSET = Charset.forName("US-ASCII");

    private static enum State {
      NONE,
      IAC,
      COMMAND,
      SUBCOMMAND,
      SUBCOMMAND_IAC,
    }

    public static final byte DONT = (byte) 254;
    public static final byte DO = (byte) 253;
    public static final byte WONT = (byte) 252;
    public static final byte WILL = (byte) 251;
    public static final byte IAC = (byte) 255;
    public static final byte SB = (byte) 250;
    public static final byte SE = (byte) 240;
    public static final byte ECHO = (byte) 1;

    private boolean closed = false;
    private State readingCommand = State.NONE;
    private int lastRequest;
    private final StringBuilder subcommandLine = new StringBuilder();

    // private byte subCommandCode;

    private final CloseableByteBufferHandler write;

    private final TelnetClientHandler handler;

    public TelnetResponseReader(TelnetClientHandler handler, CloseableByteBufferHandler write) {
      this.handler = handler;
      this.write = write;
    }

    @Override
    public void close() {
      if (!closed) {
        closed = true;
        write.close();
        handler.close();
      }
    }
   
    @Override
    public void send(String line) {
      write.handle(null, ByteBuffer.wrap(line.getBytes(USASCII_CHARSET)));
    }

    private void write(byte response, byte command) {
      write.handle(null, ByteBuffer.wrap(new byte[] { IAC, response, command }));
    }

    @Override
    public void handle(Address address, ByteBuffer buffer) {
      if (closed) {
        return;
      }

      StringBuilder r = new StringBuilder();
      while (buffer.hasRemaining()) {
        byte b = buffer.get();
        switch (readingCommand) {
          case SUBCOMMAND:
            if (b == IAC) {
              readingCommand = State.SUBCOMMAND_IAC;
            } else {
              subcommandLine.append((char) b);
            }
            break;
          case SUBCOMMAND_IAC:
            if (b == IAC) {
              subcommandLine.append((char) b);
              readingCommand = State.SUBCOMMAND;
            } else if (b == SE) {
              subcommandLine.setLength(0);
              readingCommand = State.NONE;
            } else {
              closed = true;
              write.close();
              handler.failed(new IOException("Missing SE"));
            }
            break;
          case NONE:
            if (b == IAC) {
              readingCommand = State.IAC;
            } else {
              r.append((char) b);
            }
            break;
          case IAC:
            if (b == IAC) {
              r.append((char) b);
              readingCommand = State.NONE;
            } else {
              lastRequest = b;
              readingCommand = State.COMMAND;
            }
            break;
          case COMMAND:
            if (lastRequest == SB) {
              // subCommandCode = b;
              readingCommand = State.SUBCOMMAND;
            } else {
              if (lastRequest == DO) {
                write(WONT, b);
              } else if (lastRequest == WILL) {
                if (b == ECHO) {
                  write(DO, b);
                } else {
                  write(DONT, b);
                }
                /*
                } else if (lastRequest == DONT) {
                  write(WONT, b);
                } else if (lastRequest == WONT) {
                  write(DONT, b);
                */
              } else {
                // Ignored
              }
              readingCommand = State.NONE;
            }
            break;
        }
      }

      if (r.length() > 0) {
        handler.received(r.toString());
      }
    }

  }

}
TOP

Related Classes of com.davfx.ninio.telnet.TelnetClient$TelnetResponseReader

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.