AbstractConnector.java

  1. /*
  2.  * Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others
  3.  *
  4.  * This program and the accompanying materials are made available under the
  5.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  6.  * https://www.eclipse.org/org/documents/edl-v10.php.
  7.  *
  8.  * SPDX-License-Identifier: BSD-3-Clause
  9.  */
  10. package org.eclipse.jgit.transport.sshd.agent;

  11. import java.io.IOException;
  12. import java.text.MessageFormat;
  13. import java.util.Objects;

  14. import org.apache.sshd.agent.SshAgentConstants;
  15. import org.apache.sshd.common.SshException;
  16. import org.apache.sshd.common.util.buffer.BufferUtils;
  17. import org.eclipse.jgit.internal.transport.sshd.SshdText;

  18. /**
  19.  * Provides some utility methods for implementing {@link Connector}s.
  20.  *
  21.  * @since 6.0
  22.  */
  23. public abstract class AbstractConnector implements Connector {

  24.     // A somewhat sane lower bound for the maximum reply length
  25.     private static final int MIN_REPLY_LENGTH = 8 * 1024;

  26.     /**
  27.      * Default maximum reply length. 256kB is the OpenSSH limit.
  28.      */
  29.     protected static final int DEFAULT_MAX_REPLY_LENGTH = 256 * 1024;

  30.     private final int maxReplyLength;

  31.     /**
  32.      * Creates a new instance using the {@link #DEFAULT_MAX_REPLY_LENGTH}.
  33.      */
  34.     protected AbstractConnector() {
  35.         this(DEFAULT_MAX_REPLY_LENGTH);
  36.     }

  37.     /**
  38.      * Creates a new instance.
  39.      *
  40.      * @param maxReplyLength
  41.      *            maximum number of payload bytes we're ready to accept
  42.      */
  43.     protected AbstractConnector(int maxReplyLength) {
  44.         if (maxReplyLength < MIN_REPLY_LENGTH) {
  45.             throw new IllegalArgumentException(
  46.                     "Maximum payload length too small"); //$NON-NLS-1$
  47.         }
  48.         this.maxReplyLength = maxReplyLength;
  49.     }

  50.     /**
  51.      * Retrieves the maximum message length this {@link AbstractConnector} is
  52.      * configured for.
  53.      *
  54.      * @return the maximum message length
  55.      */
  56.     protected int getMaximumMessageLength() {
  57.         return this.maxReplyLength;
  58.     }

  59.     /**
  60.      * Prepares a message for sending by inserting the command and message
  61.      * length.
  62.      *
  63.      * @param command
  64.      *            SSH agent command the request is for
  65.      * @param message
  66.      *            about to be sent, including the 5 spare bytes at the front
  67.      * @throws IllegalArgumentException
  68.      *             if {@code message} has less than 5 bytes
  69.      */
  70.     protected void prepareMessage(byte command, byte[] message)
  71.             throws IllegalArgumentException {
  72.         Objects.requireNonNull(message);
  73.         if (message.length < 5) {
  74.             // No translation; internal error
  75.             throw new IllegalArgumentException("Message buffer for " //$NON-NLS-1$
  76.                     + SshAgentConstants.getCommandMessageName(command)
  77.                     + " must have at least 5 bytes; have only " //$NON-NLS-1$
  78.                     + message.length);
  79.         }
  80.         BufferUtils.putUInt(message.length - 4, message);
  81.         message[4] = command;
  82.     }

  83.     /**
  84.      * Checks the received length of a reply.
  85.      *
  86.      * @param command
  87.      *            SSH agent command the reply is for
  88.      * @param length
  89.      *            length as received: number of payload bytes
  90.      * @return the length as an {@code int}
  91.      * @throws IOException
  92.      *             if the length is invalid
  93.      */
  94.     protected int toLength(byte command, byte[] length)
  95.             throws IOException {
  96.         long l = BufferUtils.getUInt(length);
  97.         if (l <= 0 || l > maxReplyLength - 4) {
  98.             throw new SshException(MessageFormat.format(
  99.                     SshdText.get().sshAgentReplyLengthError,
  100.                     Long.toString(l),
  101.                     SshAgentConstants.getCommandMessageName(command)));
  102.         }
  103.         return (int) l;
  104.     }
  105. }