+ /**
+ * Reads up to len bytes of data from the input stream into an array of
+ * bytes.
+ *
+ * @param buf the buffer into which the data is read.
+ * @param off the start offset in array b at which the data is written.
+ * @param len the maximum number of bytes to read.
+ * @return the total number of bytes read into the buffer, or -1 if there
+ * is no more data because the end of the stream has been reached.
+ * @throws IOException if an I/O error occurs
+ */
+ private int readImpl(final byte[] buf, final int off,
+ final int len) throws IOException {
+
+ assert (len > 0);
+
+ // The current writing position in buf.
+ int bufN = 0;
+
+ // We will keep trying to read() until we have something to return.
+ do {
+
+ // Read up to len bytes
+ byte [] buffer = new byte[len];
+ int bufferN = 0;
+
+ // Read some data from the other end
+ int rc = input.read(buffer);
+
+ // Check for EOF or error
+ if (rc > 0) {
+ // More data came in
+ bufferN = rc;
+ } else {
+ // EOF, just return it.
+ return rc;
+ }
+
+ // Loop through the read bytes
+ for (int i = 0; i < bufferN; i++) {
+ byte b = buffer[i];
+
+ if (subnegEnd == true) {
+ // Looking for IAC SE to end this subnegotiation
+ if (b == (byte)TELNET_SE) {
+ if (iac == true) {
+ iac = false;
+ subnegEnd = false;
+ handleSubneg();
+ }
+ } else if (b == (byte)TELNET_IAC) {
+ if (iac == true) {
+ // An argument to the subnegotiation option
+ subnegBuffer.add((byte)TELNET_IAC);
+ } else {
+ iac = true;
+ }
+ } else {
+ // An argument to the subnegotiation option
+ subnegBuffer.add(b);
+ }
+ continue;
+ }
+
+ // Look for DO/DON'T/WILL/WON'T option
+ if (dowill == true) {
+
+ // Look for option/
+ switch (b) {
+
+ case 0:
+ // Binary Transmission
+ if (dowillType == (byte)TELNET_WILL) {
+ // Server will use binary transmission, yay.
+ master.binaryMode = true;
+ } else if (dowillType == (byte)TELNET_DO) {
+ // Server asks for binary transmission.
+ WILL(b);
+ master.binaryMode = true;
+ } else if (dowillType == (byte)TELNET_WONT) {
+ // We're screwed, server won't do binary
+ // transmission.
+ master.binaryMode = false;
+ } else {
+ // Server demands NVT ASCII mode.
+ master.binaryMode = false;
+ }
+ break;
+
+ case 1:
+ // Echo
+ if (dowillType == (byte)TELNET_WILL) {
+ // Server will use echo, yay.
+ master.echoMode = true;
+ } else if (dowillType == (byte)TELNET_DO) {
+ // Server asks for echo.
+ WILL(b);
+ master.echoMode = true;
+ } else if (dowillType == (byte)TELNET_WONT) {
+ // We're screwed, server won't do echo.
+ master.echoMode = false;
+ } else {
+ // Server demands no echo.
+ master.echoMode = false;
+ }
+ break;
+
+ case 3:
+ // Suppress Go Ahead
+ if (dowillType == (byte)TELNET_WILL) {
+ // Server will use suppress go-ahead, yay.
+ master.goAhead = false;
+ } else if (dowillType == (byte)TELNET_DO) {
+ // Server asks for suppress go-ahead.
+ WILL(b);
+ master.goAhead = false;
+ } else if (dowillType == (byte)TELNET_WONT) {
+ // We're screwed, server won't do suppress
+ // go-ahead.
+ master.goAhead = true;
+ } else {
+ // Server demands Go-Ahead mode.
+ master.goAhead = true;
+ }
+ break;
+
+ case 24:
+ // Terminal Type - send what's in TERM
+ if (dowillType == (byte)TELNET_WILL) {
+ // Server will use terminal type, yay.
+ if (master.isServer
+ && master.doTermType
+ ) {
+ requestTerminalType();
+ master.doTermType = false;
+ } else if (!master.isServer) {
+ master.doTermType = true;
+ }
+ } else if (dowillType == (byte)TELNET_DO) {
+ // Server asks for terminal type.
+ WILL(b);
+ master.doTermType = true;
+ } else if (dowillType == (byte)TELNET_WONT) {
+ // We're screwed, server won't do terminal type.
+ master.doTermType = false;
+ } else {
+ // Server will not listen to terminal type.
+ master.doTermType = false;
+ }
+ break;
+
+ case 31:
+ // NAWS
+ if (dowillType == (byte)TELNET_WILL) {
+ // Server will use NAWS, yay.
+ master.doNAWS = true;
+ // NAWS cannot be requested by the server, it is
+ // only sent by the client.
+ } else if (dowillType == (byte)TELNET_DO) {
+ // Server asks for NAWS.
+ WILL(b);
+ master.doNAWS = true;
+ } else if (dowillType == (byte)TELNET_WONT) {
+ // Server won't do NAWS.
+ master.doNAWS = false;
+ } else {
+ // Server will not listen to NAWS.
+ master.doNAWS = false;
+ }
+ break;
+
+ case 32:
+ // Terminal Speed
+ if (dowillType == (byte)TELNET_WILL) {
+ // Server will use terminal speed, yay.
+ if (master.isServer
+ && master.doTermSpeed
+ ) {
+ requestTerminalSpeed();
+ master.doTermSpeed = false;
+ } else if (!master.isServer) {
+ master.doTermSpeed = true;
+ }
+ } else if (dowillType == (byte)TELNET_DO) {
+ // Server asks for terminal speed.
+ WILL(b);
+ master.doTermSpeed = true;
+ } else if (dowillType == (byte)TELNET_WONT) {
+ // We're screwed, server won't do terminal speed.
+ master.doTermSpeed = false;
+ } else {
+ // Server will not listen to terminal speed.
+ master.doTermSpeed = false;
+ }
+ break;
+
+ case 39:
+ // New Environment
+ if (dowillType == (byte)TELNET_WILL) {
+ // Server will use NewEnvironment, yay.
+ if (master.isServer
+ && master.doEnvironment
+ ) {
+ requestEnvironment();
+ master.doEnvironment = false;
+ } else if (!master.isServer) {
+ master.doEnvironment = true;
+ }
+ } else if (dowillType == (byte)TELNET_DO) {
+ // Server asks for NewEnvironment.
+ WILL(b);
+ master.doEnvironment = true;
+ } else if (dowillType == (byte)TELNET_WONT) {
+ // Server won't do NewEnvironment.
+ master.doEnvironment = false;
+ } else {
+ // Server will not listen to New Environment.
+ master.doEnvironment = false;
+ }
+ break;
+
+
+ default:
+ // Other side asked for something we don't
+ // understand. Tell them we will not do this option.
+ refuse(dowillType, b);
+ break;
+ }
+
+ dowill = false;
+ continue;
+ } // if (dowill == true)
+
+ // Perform read processing
+ if (b == (byte)TELNET_IAC) {
+
+ // Telnet command
+ if (iac == true) {
+ // IAC IAC -> IAC
+ buf[bufN++] = (byte)TELNET_IAC;
+ iac = false;
+ } else {
+ iac = true;
+ }
+ continue;
+ } else {
+ if (iac == true) {
+
+ switch (b) {
+
+ case (byte)TELNET_SE:
+ // log.debug1(" END Sub-Negotiation");
+ break;
+ case (byte)TELNET_NOP:
+ // log.debug1(" NOP");
+ break;
+ case (byte)TELNET_DM:
+ // log.debug1(" Data Mark");
+ break;
+ case (byte)TELNET_BRK:
+ // log.debug1(" Break");
+ break;
+ case (byte)TELNET_IP:
+ // log.debug1(" Interrupt Process");
+ break;
+ case (byte)TELNET_AO:
+ // log.debug1(" Abort Output");
+ break;
+ case (byte)TELNET_AYT:
+ // log.debug1(" Are You There?");
+ break;
+ case (byte)TELNET_EC:
+ // log.debug1(" Erase Character");
+ break;
+ case (byte)TELNET_EL:
+ // log.debug1(" Erase Line");
+ break;
+ case (byte)TELNET_GA:
+ // log.debug1(" Go Ahead");
+ break;
+ case (byte)TELNET_SB:
+ // log.debug1(" START Sub-Negotiation");
+ // From here we wait for the IAC SE
+ subnegEnd = true;
+ subnegBuffer.clear();
+ break;
+ case (byte)TELNET_WILL:
+ // log.debug1(" WILL");
+ dowill = true;
+ dowillType = b;
+ break;
+ case (byte)TELNET_WONT:
+ // log.debug1(" WON'T");
+ dowill = true;
+ dowillType = b;
+ break;
+ case (byte)TELNET_DO:
+ // log.debug1(" DO");
+ dowill = true;
+ dowillType = b;
+
+ if (master.binaryMode == true) {
+ // log.debug1("Telnet DO in binary mode");
+ }
+
+ break;
+ case (byte)TELNET_DONT:
+ // log.debug1(" DON'T");
+ dowill = true;
+ dowillType = b;
+ break;
+ default:
+ // This should be equivalent to IAC NOP
+ // log.debug1("Will treat as IAC NOP");
+ break;
+ }
+ iac = false;
+ continue;
+
+ } // if (iac == true)
+
+ /*
+ * All of the regular IAC processing is completed at this
+ * point. Now we need to handle the CR and CR LF cases.
+ *
+ * According to RFC 854, in NVT ASCII mode:
+ * Bare CR -> CR NUL
+ * CR LF -> CR LF
+ *
+ */
+ if (master.binaryMode == false) {
+
+ if (b == C_LF) {
+ if (readCR == true) {
+ // This is CR LF. Send CR LF and turn the cr
+ // flag off.
+ buf[bufN++] = C_CR;
+ buf[bufN++] = C_LF;
+ readCR = false;
+ continue;
+ }
+ // This is bare LF. Send LF.
+ buf[bufN++] = C_LF;
+ continue;
+ }
+
+ if (b == C_NUL) {
+ if (readCR == true) {
+ // This is CR NUL. Send CR and turn the cr
+ // flag off.
+ buf[bufN++] = C_CR;
+ readCR = false;
+ continue;
+ }
+ // This is bare NUL. Send NUL.
+ buf[bufN++] = C_NUL;
+ continue;
+ }
+
+ if (b == C_CR) {
+ if (readCR == true) {
+ // This is CR CR. Send a CR NUL and leave
+ // the cr flag on.
+ buf[bufN++] = C_CR;
+ buf[bufN++] = C_NUL;
+ continue;
+ }
+ // This is the first CR. Set the cr flag.
+ readCR = true;
+ continue;
+ }
+
+ if (readCR == true) {
+ // This was a bare CR in the stream.
+ buf[bufN++] = C_CR;
+ readCR = false;
+ }
+
+ // This is a regular character. Pass it on.
+ buf[bufN++] = b;
+ continue;
+ }
+
+ /*
+ * This is the case for any of:
+ *
+ * 1) A NVT ASCII character that isn't CR, LF, or
+ * NUL.
+ *
+ * 2) A NVT binary character.
+ *
+ * For all of these cases, we just pass the character on.
+ */
+ buf[bufN++] = b;
+
+ } // if (b == TELNET_IAC)
+
+ } // for (int i = 0; i < bufferN; i++)
+
+ } while (bufN == 0);
+
+ // Return bytes read
+ return bufN;
+ }