protected Buffer encode()

in sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractSession.java [1440:1540]


    protected Buffer encode(Buffer buffer) throws IOException {
        try {
            // Check that the packet has some free space for the header
            int curPos = buffer.rpos();
            int cmd = buffer.rawByte(curPos) & 0xFF; // usually the 1st byte is an SSH opcode
            Buffer nb = preProcessEncodeBuffer(cmd, buffer);
            if (nb != buffer) {
                buffer = nb;
                curPos = buffer.rpos();

                int newCmd = buffer.rawByte(curPos) & 0xFF;
                if (cmd != newCmd) {
                    log.warn("encode({}) - command changed from {}[{}] to {}[{}] by pre-processor",
                            this, cmd, SshConstants.getCommandMessageName(cmd),
                            newCmd, SshConstants.getCommandMessageName(newCmd));
                    cmd = newCmd;
                }
            }

            // Grab the length of the packet (excluding the 5 header bytes)
            int len = buffer.available();
            if (log.isDebugEnabled()) {
                log.debug("encode({}) packet #{} sending command={}[{}] len={}",
                        this, seqo, cmd, SshConstants.getCommandMessageName(cmd), len);
            }

            int off = curPos - SshConstants.SSH_PACKET_HEADER_LEN;
            // Debug log the packet
            boolean traceEnabled = log.isTraceEnabled();
            if (traceEnabled) {
                buffer.dumpHex(getSimplifiedLogger(), Level.FINEST,
                        "encode(" + this + ") packet #" + seqo, this);
            }

            // Compress the packet if needed
            if ((outCompression != null)
                    && outCompression.isCompressionExecuted()
                    && (isAuthenticated() || (!outCompression.isDelayed()))) {
                int oldLen = len;
                outCompression.compress(buffer);
                len = buffer.available();
                if (traceEnabled) {
                    log.trace("encode({}) packet #{} command={}[{}] compressed {} -> {}",
                            this, seqo, cmd, SshConstants.getCommandMessageName(cmd), oldLen, len);
                }
            }

            // Compute padding length
            boolean etmMode = outMac != null && outMac.isEncryptThenMac();
            int authSize = outCipher != null ? outCipher.getAuthenticationTagSize() : 0;
            boolean authMode = authSize > 0;
            int oldLen = len;

            int pad = calculatePadLength(len, outCipherSize, etmMode || authMode);

            len += Byte.BYTES + pad;

            if (traceEnabled) {
                log.trace("encode({}) packet #{} command={}[{}] len={}, pad={}, mac={}",
                        this, seqo, cmd, SshConstants.getCommandMessageName(cmd), len, pad, outMac);
            }

            // Write 5 header bytes
            buffer.wpos(off);
            buffer.putUInt(len);
            buffer.putByte((byte) pad);
            // Make sure enough room for padding and then fill it
            buffer.wpos(off + oldLen + SshConstants.SSH_PACKET_HEADER_LEN + pad);
            synchronized (random) {
                random.fill(buffer.array(), buffer.wpos() - pad, pad);
            }

            if (authMode) {
                int wpos = buffer.wpos();
                buffer.wpos(wpos + authSize);
                aeadOutgoingBuffer(buffer, off, len);
            } else if (etmMode) {
                // Do not encrypt the length field
                encryptOutgoingBuffer(buffer, off + Integer.BYTES, len);
                appendOutgoingMac(buffer, off, len);
            } else {
                appendOutgoingMac(buffer, off, len);
                encryptOutgoingBuffer(buffer, off, len + Integer.BYTES);
            }

            // Increment packet id
            seqo = (seqo + 1L) & 0x0ffffffffL;

            // Update counters used to track re-keying
            outPacketsCount.incrementAndGet();
            outBytesCount.addAndGet(len);

            // Make buffer ready to be read
            buffer.rpos(off);
            return buffer;
        } catch (IOException e) {
            throw e;
        } catch (Exception e) {
            throw new SshException(e);
        }
    }