org.apache.sshd.common.session.Session Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.sshd.common.session;
import java.io.IOException;
import java.net.SocketAddress;
import java.time.Duration;
import java.time.Instant;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import org.apache.sshd.common.AttributeRepository;
import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.common.FactoryManagerHolder;
import org.apache.sshd.common.Service;
import org.apache.sshd.common.auth.MutableUserHolder;
import org.apache.sshd.common.channel.ChannelListenerManager;
import org.apache.sshd.common.channel.throttle.ChannelStreamWriterResolverManager;
import org.apache.sshd.common.forward.PortForwardingEventListenerManager;
import org.apache.sshd.common.forward.PortForwardingInformationProvider;
import org.apache.sshd.common.future.GlobalRequestFuture;
import org.apache.sshd.common.future.GlobalRequestFuture.ReplyHandler;
import org.apache.sshd.common.future.KeyExchangeFuture;
import org.apache.sshd.common.io.IoSession;
import org.apache.sshd.common.io.IoWriteFuture;
import org.apache.sshd.common.kex.KexFactoryManager;
import org.apache.sshd.common.kex.KeyExchange;
import org.apache.sshd.common.session.helpers.TimeoutIndicator;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
/**
* Represents an SSH session. Note: the associated username for the session may be {@code null}/empty if the
* session is not yet authenticated
*
* @author Apache MINA SSHD Project
*/
public interface Session
extends SessionContext,
MutableUserHolder,
KexFactoryManager,
SessionListenerManager,
ReservedSessionMessagesManager,
SessionDisconnectHandlerManager,
ChannelListenerManager,
ChannelStreamWriterResolverManager,
PortForwardingEventListenerManager,
UnknownChannelReferenceHandlerManager,
FactoryManagerHolder,
PortForwardingInformationProvider {
/**
* Create a new buffer for the specified SSH packet and reserve the needed space (5 bytes) for the packet header.
*
* @param cmd the SSH command
* @return a new buffer (of unknown size) ready for write
* @see #createBuffer(byte, int)
*/
default Buffer createBuffer(byte cmd) {
return createBuffer(cmd, 0);
}
/**
* Create a new buffer for the specified SSH packet and reserve the needed space (5 bytes) for the packet header.
*
* @param cmd The SSH command to initialize the buffer with
* @param estimatedSize Estimated number of bytes the buffer will hold, 0 if unknown.
* @return a new buffer ready for write
* @see #prepareBuffer(byte, Buffer)
*/
Buffer createBuffer(byte cmd, int estimatedSize);
/**
* Prepare a new "clean" buffer while reserving the needed space (5 bytes) for the packet header.
*
* @param cmd The SSH command to initialize the buffer with
* @param buffer The {@link Buffer} instance to initialize
* @return The initialized buffer
*/
Buffer prepareBuffer(byte cmd, Buffer buffer);
/**
* Sends an {@code SSH_MSG_DEBUG} to the peer session
*
* @param display {@code true} if OK to display the message at the peer as-is
* @param msg The message object whose {@code toString()} value to be used - if {@code null} then the
* "null" string is sent
* @param lang The language - {@code null}/empty if some pre-agreed default is used
* @return An {@code IoWriteFuture} that can be used to check when the packet has actually been sent
* @throws IOException if an error occurred when encoding or sending the packet
* @see RFC 4253 - section 11.3
*/
IoWriteFuture sendDebugMessage(boolean display, Object msg, String lang) throws IOException;
/**
* Sends an {@code SSH_MSG_IGNORE} to the peer session
*
* @param data The message data
* @return An {@code IoWriteFuture} that can be used to check when the packet has actually been sent
* @throws IOException if an error occurred when encoding or sending the packet
* @see RFC 4253 - section 11.2
*/
IoWriteFuture sendIgnoreMessage(byte... data) throws IOException;
/**
* Encode and send the given buffer. The buffer has to have 5 bytes free at the beginning to allow the encoding to
* take place. Also, the write position of the buffer has to be set to the position of the last byte to write.
*
* @param buffer the buffer to encode and send
* @return An {@code IoWriteFuture} that can be used to check when the packet has actually been sent
* @throws IOException if an error occurred when encoding sending the packet
*/
IoWriteFuture writePacket(Buffer buffer) throws IOException;
/**
* Encode and send the given buffer with the specified timeout. If the buffer could not be written before the
* timeout elapses, the returned {@link org.apache.sshd.common.io.IoWriteFuture} will be set with a
* {@link java.util.concurrent.TimeoutException} exception to indicate a timeout.
*
* @param buffer the buffer to encode and spend
* @param timeout the (never {@code null}) timeout value - its {@link Duration#toMillis() milliseconds} value
* will be used
* @return a future that can be used to check when the packet has actually been sent
* @throws IOException if an error occurred when encoding or sending the packet
* @see #writePacket(Buffer, long)
*/
default IoWriteFuture writePacket(Buffer buffer, Duration timeout) throws IOException {
Objects.requireNonNull(timeout, "No timeout was specified");
return writePacket(buffer, timeout.toMillis());
}
/**
* Encode and send the given buffer with the specified timeout. If the buffer could not be written before the
* timeout elapses, the returned {@link org.apache.sshd.common.io.IoWriteFuture} will be set with a
* {@link java.util.concurrent.TimeoutException} exception to indicate a timeout.
*
* @param buffer the buffer to encode and spend
* @param maxWaitMillis the timeout in milliseconds
* @return a future that can be used to check when the packet has actually been sent
* @throws IOException if an error occurred when encoding or sending the packet
*/
default IoWriteFuture writePacket(Buffer buffer, long maxWaitMillis) throws IOException {
return writePacket(buffer, maxWaitMillis, TimeUnit.MILLISECONDS);
}
/**
* Encode and send the given buffer with the specified timeout. If the buffer could not be written before the
* timeout elapses, the returned {@link org.apache.sshd.common.io.IoWriteFuture} will be set with a
* {@link java.util.concurrent.TimeoutException} exception to indicate a timeout.
*
* @param buffer the buffer to encode and spend
* @param timeout the timeout
* @param unit the time unit of the timeout parameter
* @return a future that can be used to check when the packet has actually been sent
* @throws IOException if an error occurred when encoding or sending the packet
*/
IoWriteFuture writePacket(Buffer buffer, long timeout, TimeUnit unit) throws IOException;
/**
* Send a global request and wait for the response, if the request is sent with {@code want-reply = true}.
*
* @param request the request name - used mainly for logging and debugging
* @param buffer the buffer containing the global request
* @param timeout The number of time units to wait - must be positive
* @param unit The {@link TimeUnit} to wait for the response
* @return the return buffer if the request was successful, {@code null} otherwise.
* @throws IOException if an error occurred when encoding or sending the packet
* @throws java.net.SocketTimeoutException If no response received within specified timeout
*/
default Buffer request(
String request, Buffer buffer, long timeout, TimeUnit unit)
throws IOException {
ValidateUtils.checkTrue(timeout > 0L, "Non-positive timeout requested: %d", timeout);
return request(request, buffer, TimeUnit.MILLISECONDS.convert(timeout, unit));
}
/**
*
* Send a global request and wait for the response, if the request is sent with {@code want-reply = true}.
*
* @param request the request name - used mainly for logging and debugging
* @param buffer the buffer containing the global request
* @param timeout The (never {@code null}) timeout to wait - its milliseconds value is used
* @return the return buffer if the request was successful, {@code null} otherwise.
* @throws IOException if an error occurred when encoding or sending the packet
* @throws java.net.SocketTimeoutException If no response received within specified timeout
*/
default Buffer request(String request, Buffer buffer, Duration timeout) throws IOException {
Objects.requireNonNull(timeout, "No timeout specified");
return request(request, buffer, timeout.toMillis());
}
/**
* Send a global request and wait for the response, if the request is sent with {@code want-reply = true}.
*
* @param request the request name - used mainly for logging and debugging
* @param buffer the buffer containing the global request
* @param maxWaitMillis maximum time in milliseconds to wait for the request to finish - must be
* positive
* @return the return buffer if the request was successful, {@code null} otherwise.
* @throws IOException if an error occurred when encoding or sending the packet
* @throws java.net.SocketTimeoutException If no response received within specified timeout
*/
Buffer request(String request, Buffer buffer, long maxWaitMillis) throws IOException;
/**
* Send a global request and handle the reply asynchronously. If {@code want-reply = true}, pass the received
* {@link Buffer} to the given {@link ReplyHandler}, which may execute in a different thread.
*
*
* - want-reply == true && replyHandler != null
* - The returned future is fulfilled with {@code null} when the request was sent, or with an exception if the
* request could not be sent. The {@code replyHandler} is invoked once the reply is received, with the SSH reply
* code and the data received.
* - want-reply == true && replyHandler == null
* - The returned future is fulfilled with an exception if the request could not be sent, or a failure reply was
* received. If a success reply was received, the future is fulfilled with the received data buffer.
* - want-reply == false
* - The returned future is fulfilled with an empty {@link Buffer} when the request was sent, or with an exception
* if the request could not be sent. If a reply handler is given, it is invoked with that empty buffer. The handler
* is not invoked if sending the request failed.
*
*
* @param buffer the {@link Buffer} containing the global request, with the {@code want-reply} flag set as
* appropriate
* @param request the request name
* @param replyHandler {@link ReplyHandler} for handling the reply; may be {@code null}
* @return Created {@link GlobalRequestFuture}
* @throws IOException if an error occurred while encoding or sending the packet
*/
GlobalRequestFuture request(Buffer buffer, String request, ReplyHandler replyHandler)
throws IOException;
/**
* Handle any exceptions that occurred on this session. The session will be closed and a disconnect packet will be
* sent before if the given exception is an {@link org.apache.sshd.common.SshException} with a positive error code
*
* @param t the exception to process
*/
void exceptionCaught(Throwable t);
/**
* Initiate a new key exchange.
*
* @return A {@link KeyExchangeFuture} for awaiting the completion of the exchange
* @throws IOException If failed to request keys re-negotiation
*/
KeyExchangeFuture reExchangeKeys() throws IOException;
/**
* Get the service of the specified type. If the service is not of the specified class, an IllegalStateException
* will be thrown.
*
* @param The generic {@link Service} type
* @param clazz The service class
* @return The service instance
* @throws IllegalStateException If failed to find a matching service
*/
T getService(Class clazz);
/**
* @return The {@link IoSession} associated to this session
*/
IoSession getIoSession();
@Override
default SocketAddress getLocalAddress() {
IoSession s = getIoSession();
return (s == null) ? null : s.getLocalAddress();
}
@Override
default SocketAddress getRemoteAddress() {
IoSession s = getIoSession();
return (s == null) ? null : s.getRemoteAddress();
}
/**
* Check if timeout has occurred.
*
* @return the timeout status - never {@code null}
*/
TimeoutIndicator getTimeoutStatus();
/**
* @return Timeout value in milliseconds for communication
*/
Duration getIdleTimeout();
/**
* @return The timestamp value (milliseconds since EPOCH) when timer was started
*/
Instant getIdleTimeoutStart();
/**
* Re-start idle timeout timer
*
* @return The timestamp value (milliseconds since EPOCH) when timer was started
* @see #getIdleTimeoutStart()
*/
Instant resetIdleTimeout();
/**
* @return Timeout value in milliseconds for authentication stage
*/
Duration getAuthTimeout();
/**
* @return The timestamp value (milliseconds since EPOCH) when timer was started
*/
Instant getAuthTimeoutStart();
/**
* Re-start the authentication timeout timer
*
* @return The timestamp value (milliseconds since EPOCH) when timer was started
* @see #getAuthTimeoutStart()
*/
Instant resetAuthTimeout();
void setAuthenticated() throws IOException;
/**
* @return The current {@link KeyExchange} in progress - {@code null} if KEX not started or successfully completed
*/
KeyExchange getKex();
/**
* Send a disconnect packet with the given reason and message. Once the packet has been sent, the session will be
* closed asynchronously.
*
* @param reason the reason code for this disconnect
* @param msg the text message
* @throws IOException if an error occurred sending the packet
*/
void disconnect(int reason, String msg) throws IOException;
/**
* @param name Service name
* @param buffer Extra information provided when the service start request was received
* @throws Exception If failed to start it
*/
void startService(String name, Buffer buffer) throws Exception;
@Override
default T resolveAttribute(AttributeRepository.AttributeKey key) {
return resolveAttribute(this, key);
}
/**
* Attempts to use the session's attribute, if not found then tries the factory manager
*
* @param The generic attribute type
* @param session The {@link Session} - ignored if {@code null}
* @param key The attribute key - never {@code null}
* @return Associated value - {@code null} if not found
* @see Session#getFactoryManager()
* @see FactoryManager#resolveAttribute(FactoryManager, AttributeRepository.AttributeKey)
*/
static T resolveAttribute(Session session, AttributeRepository.AttributeKey key) {
Objects.requireNonNull(key, "No key");
if (session == null) {
return null;
}
T value = session.getAttribute(key);
return (value != null) ? value : FactoryManager.resolveAttribute(session.getFactoryManager(), key);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy