📄 telnetio.java
字号:
//License/*** * Java TelnetD library (embeddable telnet daemon) * Copyright (c) 2000-2005 Dieter Wimberger * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. ***/package net.wimpi.telnetd.io;import net.wimpi.telnetd.net.Connection;import net.wimpi.telnetd.net.ConnectionData;import net.wimpi.telnetd.net.ConnectionEvent;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import java.io.BufferedOutputStream;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import java.net.InetAddress;/** * Class that represents the TelnetIO implementation. It contains * an inner IACHandler class to handle the telnet protocol level * communication. * <p/> * Although supposed to work full-duplex, we only process the telnet protocol * layer communication in case of reading requests from the higher levels. * This is the only way to meet the one thread per connection requirement. * </p> * <p/> * The output is done via byte-oriented streams, definately suitable for the * telnet protocol. The format of the output is UTF-8 (Unicode), which is a * standard and supported by any telnet client, including the ones included * in Microsoft OS's. * </p> * <em>Notes:</em> * <ul> * <li>The underlying output is buffered, to ensure that all bytes written * are send, the flush() method has to be called. * <li>This low-level routines ensure nice multithreading behaviour on I/O. * Neither large outputs, nor input sequences excuted by the connection thread * can hog the system. * </ul> * * @author Dieter Wimberger * @version 2.0 (16/07/2006) */public class TelnetIO { private static Log log = LogFactory.getLog(TelnetIO.class); private Connection m_Connection; //a reference to the connection this instance works for private ConnectionData m_ConnectionData; //holds all important information of the connection private DataOutputStream m_Out; //the byte oriented outputstream private DataInputStream m_In; //the byte oriented input stream //Aggregations private IACHandler m_IACHandler; //holds a reference to the aggregated IACHandler //Members private InetAddress m_LocalAddress; //address of the host the telnetd is running on private boolean m_NOIAC = false; //describes if IAC was found and if its just processed private boolean m_Initializing; private boolean m_CRFlag; /** * Creates a TelnetIO object for the given connection.<br> * Input- and OutputStreams are properly set and the primary telnet * protocol initialization is carried out by the inner IACHandler class.<BR> */ public TelnetIO() { }//constructor public void initIO() throws IOException { //we make an instance of our inner class m_IACHandler = new IACHandler(); //we setup underlying byte oriented streams m_In = new DataInputStream(m_ConnectionData.getSocket().getInputStream()); m_Out = new DataOutputStream(new BufferedOutputStream(m_ConnectionData.getSocket().getOutputStream())); //we save the local address (necessary?) m_LocalAddress = m_ConnectionData.getSocket().getLocalAddress(); m_CRFlag = false; //bootstrap telnet communication initTelnetCommunication(); }//initIO public void setConnection(Connection con) { m_Connection = con; m_ConnectionData = m_Connection.getConnectionData(); }//setConnection /**** Implementation of OutputStream ****************************************************/ /** * Method to output a byte. Ensures that CR(\r) is never send * alone,but CRLF(\r\n), which is a rule of the telnet protocol. * * @param b Byte to be written. */ public void write(byte b) throws IOException { //try { //ensure CRLF(\r\n) is written for LF(\n) to adhere //to the telnet protocol. if (!m_CRFlag && b == 10) { m_Out.write(13); } //ensure CRLF(\r\n) is written for CR(\r) to adhere //to the telnet protocol. if (m_CRFlag && b != 10) { m_Out.write(10); } m_Out.write(b); if (b == 13) { m_CRFlag = true; } else { m_CRFlag = false; } //} catch (IOException e) { // if (m_Connection.isActive()) { // m_ConnectionData.getManager().registerBrokenConnection(m_Connection); // } //} }//write(byte) /** * Method to output an int. * * @param i Integer to be written. */ public void write(int i) throws IOException { write((byte) i); }//write(int) /** * Method to write an array of bytes. * * @param sequence byte[] to be written. */ public void write(byte[] sequence) throws IOException { for (int z = 0; z < sequence.length; z++) { write(sequence[z]); } }//write(byte[]) /** * Method to output an array of int' s. * * @param sequence int [] to write */ public void write(int[] sequence) throws IOException { for (int j = 0; j < sequence.length; j++) { write((byte) sequence[j]); } }//write(int[]) /** * Method to write a char. * * @param ch char to be written. */ public void write(char ch) throws IOException { write((byte) ch); }//write(char) /** * Method to output a string. * * @param str String to be written. */ public void write(String str) throws IOException { write(str.getBytes()); }//write(String) /** * Method to flush all buffered output. */ public void flush() throws IOException { //try { m_Out.flush(); //} catch (IOException e) { // if (m_Connection.isActive()) { // m_ConnectionData.getManager().registerBrokenConnection(m_Connection); // } //} }//flush /** * Method to close the underlying output stream to free system resources.<br> * Most likely only to be called by the ConnectionManager upon clean up of * connections that ended or died. */ public void closeOutput() { try { //sends telnetprotocol logout acknowledgement write(IAC); write(DO); write(LOGOUT); //and now close underlying outputstream m_Out.close(); } catch (IOException ex) { log.error("closeOutput()", ex); //handle? } }//close private void rawWrite(int i) throws IOException { //try { m_Out.write(i); //} catch (IOException e) { // if (m_Connection.isActive()) { // m_ConnectionData.getManager().registerBrokenConnection(m_Connection); // } //} }//rawWrite /**** End implementation of OutputStream ***********************************************/ /**** Implementation of InputStream ****************************************************/ /** * Method to read a byte from the InputStream. * Invokes the IACHandler upon IAC (Byte=255). * * @return int read from stream. */ public int read() throws IOException { int c = rawread(); //if (c == 255) { m_NOIAC = false; while ((c == 255) && (!m_NOIAC)) { /** * Read next, and invoke * the IACHandler he is taking care of the rest. Or at least he should :) */ c = rawread(); if (c != 255) { m_IACHandler.handleC(c); c = rawread(); } else { m_NOIAC = true; } } return stripCRSeq(c); }//read /** * Method to close the underlying inputstream to free system resources.<br> * Most likely only to be called by the ConnectionManager upon clean up of * connections that ended or died. */ public void closeInput() { try { m_In.close(); } catch (IOException e) { //handle? } }//closeInput /** * This method reads an unsigned 16bit Integer from the stream, * its here for getting the NAWS Data Values for height and width. */ private int read16int() throws IOException { //try { int c = m_In.readUnsignedShort(); return c; /*} catch (EOFException e) { if (m_Connection.isActive()) { m_ConnectionData.getManager().registerBrokenConnection(m_Connection); } //for the sanity of the compiler we return something return -2; } catch (IOException e) { if (m_Connection.isActive()) { m_ConnectionData.getManager().registerBrokenConnection(m_Connection); } //for the sanity of the compiler we return something return -1; } */ }//read16int /** * Method to read a raw byte from the InputStream.<br> * Telnet protocol layer communication is filtered and processed here. * * @return int read from stream. */ private int rawread() throws IOException { int b = 0; //try { b = m_In.readUnsignedByte(); m_ConnectionData.activity(); return b; /* } catch (EOFException e) { //this means the stream came to an end we can let the //ConnectionManager do his job. if (m_Connection.isActive()) { //log.debug("Registering broken connection " + m_Connection.toString() + " active=" + m_Connection.isActive()); m_ConnectionData.getManager().registerBrokenConnection(m_Connection); } //for the sanity of the compiler we return something return -1; } catch (IOException e) { //this also means that the stream is buggy or something //going wrong. By definition we react the same as in above case if (!m_Initializing && m_Connection.isActive()) { //log.debug("Registering broken connection " + // m_Connection.toString() + " active=" + m_Connection.isActive() + // " initializing=" + m_Initializing); m_ConnectionData.getManager().registerBrokenConnection(m_Connection); } //for the sanity of the compiler we return something return -1; } */ }//rawread /** * Checks for the telnet protocol specified CR followed by NULL or LF<BR> * Subsequently reads for the next byte and forwards * only a ENTER represented by LF internally. */ private int stripCRSeq(int input) throws IOException { if (input == 13) { rawread(); return 10; } return input; }//stripCRSeq /**** Implementation of InputStream ****************************************************/ /**** * Following methods implement init/request/answer procedures for telnet * protocol level communication. */ /** * Method that initializes the telnet communication layer. */ private void initTelnetCommunication() { m_Initializing = true; try { //start out, some clients just wait if (m_ConnectionData.isLineMode()) { m_IACHandler.doLineModeInit(); log.debug("Line mode initialized."); } else { m_IACHandler.doCharacterModeInit(); log.debug("Character mode initialized."); } //open for a defined timeout so we read incoming negotiation m_ConnectionData.getSocket().setSoTimeout(1000); read(); } catch (Exception e) { //handle properly //log.error("initTelnetCommunication()",e); } finally { //this is important, dont ask me why :) try { m_ConnectionData.getSocket().setSoTimeout(0); } catch (Exception ex) { log.error("initTelnetCommunication()",ex);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -