All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.sshd.client.channel.PtyCapableChannelSession Maven / Gradle / Ivy

There is a newer version: 2.12.1
Show newest version
/*
 * 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.client.channel;

import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

import org.apache.sshd.agent.SshAgentFactory;
import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.channel.PtyChannelConfiguration;
import org.apache.sshd.common.channel.PtyChannelConfigurationHolder;
import org.apache.sshd.common.channel.PtyChannelConfigurationMutator;
import org.apache.sshd.common.channel.PtyMode;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;

/**
 * 

Serves as the base channel session for executing remote commands - including * a full shell. Note: all the configuration changes via the various * {@code setXXX} methods must be made before the channel is actually * open. If they are invoked afterwards then they have no effect (silently * ignored).

*

A typical code snippet would be:

*

 * try (client = SshClient.setUpDefaultClient()) {
 *      client.start();
 *
 *      try (ClientSession s = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
 *          s.addPasswordIdentity(getCurrentTestName());
 *          s.auth().verify(5L, TimeUnit.SECONDS);
 *
 *          try (ChannelExec shell = s.createExecChannel("my super duper command")) {
 *              shell.setEnv("var1", "val1");
 *              shell.setEnv("var2", "val2");
 *              ...etc...
 *
 *              shell.setPtyType(...);
 *              shell.setPtyLines(...);
 *              ...etc...
 *
 *              shell.open().verify(5L, TimeUnit.SECONDS);
 *              shell.waitFor(ClientChannel.CLOSED, TimeUnit.SECONDS.toMillis(17L));    // can use zero for infinite wait
 *
 *              Integer status = shell.getExitStatus();
 *              if (status.intValue() != 0) {
 *                  ...error...
 *              }
 *          }
 *      } finally {
 *          client.stop();
 *      }
 * }
 * 
* * @author Apache MINA SSHD Project */ public class PtyCapableChannelSession extends ChannelSession implements PtyChannelConfigurationMutator { private boolean agentForwarding; private boolean usePty; private final Map env = new LinkedHashMap<>(); private final PtyChannelConfiguration config; public PtyCapableChannelSession(boolean usePty, PtyChannelConfigurationHolder configHolder, Map env) { this.usePty = usePty; this.config = PtyChannelConfigurationMutator.copyConfiguration( configHolder, new PtyChannelConfiguration()); this.config.setPtyType(resolvePtyType(this.config)); if (GenericUtils.isNotEmpty(env)) { for (Map.Entry ee : env.entrySet()) { setEnv(ee.getKey(), ee.getValue()); } } } protected String resolvePtyType(PtyChannelConfigurationHolder configHolder) { String ptyType = configHolder.getPtyType(); if (GenericUtils.isNotEmpty(ptyType)) { return ptyType; } ptyType = System.getenv("TERM"); if (GenericUtils.isNotEmpty(ptyType)) { return ptyType; } return DUMMY_PTY_TYPE; } public void setupSensibleDefaultPty() { try { PtyChannelConfigurationMutator.setupSensitiveDefaultPtyConfiguration(this); } catch (Throwable t) { if (log.isDebugEnabled()) { log.debug("setupSensibleDefaultPty({}) Failed ({}) to setup: {}", this, t.getClass().getSimpleName(), t.getMessage()); } if (log.isTraceEnabled()) { log.trace("setupSensibleDefaultPty(" + this + ") failure details", t); } } } public boolean isAgentForwarding() { return agentForwarding; } public void setAgentForwarding(boolean agentForwarding) { this.agentForwarding = agentForwarding; } public boolean isUsePty() { return usePty; } public void setUsePty(boolean usePty) { this.usePty = usePty; } @Override public String getPtyType() { return config.getPtyType(); } @Override public void setPtyType(String ptyType) { config.setPtyType(ptyType); } @Override public int getPtyColumns() { return config.getPtyColumns(); } @Override public void setPtyColumns(int ptyColumns) { config.setPtyColumns(ptyColumns); } @Override public int getPtyLines() { return config.getPtyLines(); } @Override public void setPtyLines(int ptyLines) { config.setPtyLines(ptyLines); } @Override public int getPtyWidth() { return config.getPtyWidth(); } @Override public void setPtyWidth(int ptyWidth) { config.setPtyWidth(ptyWidth); } @Override public int getPtyHeight() { return config.getPtyHeight(); } @Override public void setPtyHeight(int ptyHeight) { config.setPtyHeight(ptyHeight); } @Override public Map getPtyModes() { return config.getPtyModes(); } @Override public void setPtyModes(Map ptyModes) { config.setPtyModes((ptyModes == null) ? Collections.emptyMap() : ptyModes); } /** * @param key The (never {@code null}) key (Note: may be empty...) * @param value The value to set - if {@code null} then the pre-existing * value for the key (if any) is removed. * @return The replaced/removed previous value - {@code null} if no previous * value set for the key. */ public Object setEnv(String key, Object value) { ValidateUtils.checkNotNull(key, "No key provided"); if (value == null) { return env.remove(key); } else { return env.put(key, value); } } public void sendWindowChange(int columns, int lines) throws IOException { sendWindowChange(columns, lines, getPtyHeight(), getPtyWidth()); } public void sendWindowChange(int columns, int lines, int height, int width) throws IOException { if (log.isDebugEnabled()) { log.debug("sendWindowChange({}) cols={}, lines={}, height={}, width={}", this, columns, lines, height, width); } setPtyColumns(columns); setPtyLines(lines); setPtyHeight(height); setPtyWidth(width); Session session = getSession(); Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST, Long.SIZE); buffer.putInt(getRecipient()); buffer.putString("window-change"); buffer.putBoolean(false); // want-reply buffer.putInt(getPtyColumns()); buffer.putInt(getPtyLines()); buffer.putInt(getPtyHeight()); buffer.putInt(getPtyWidth()); writePacket(buffer); } protected void doOpenPty() throws IOException { Session session = getSession(); boolean debugEnabled = log.isDebugEnabled(); if (agentForwarding) { if (debugEnabled) { log.debug("doOpenPty({}) Send agent forwarding request", this); } String channelType = session.getStringProperty( SshAgentFactory.PROXY_AUTH_CHANNEL_TYPE, SshAgentFactory.DEFAULT_PROXY_AUTH_CHANNEL_TYPE); Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST, Long.SIZE); buffer.putInt(getRecipient()); buffer.putString(channelType); buffer.putBoolean(false); // want-reply writePacket(buffer); } if (usePty) { if (debugEnabled) { log.debug("doOpenPty({}) Send SSH_MSG_CHANNEL_REQUEST pty-req: {}", this, config); } Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST, Byte.MAX_VALUE); buffer.putInt(getRecipient()); buffer.putString("pty-req"); buffer.putBoolean(false); // want-reply buffer.putString(getPtyType()); buffer.putInt(getPtyColumns()); buffer.putInt(getPtyLines()); buffer.putInt(getPtyHeight()); buffer.putInt(getPtyWidth()); Map ptyModes = getPtyModes(); int numModes = GenericUtils.size(ptyModes); Buffer modes = new ByteArrayBuffer(numModes * (1 + Integer.BYTES) + Long.SIZE, false); if (numModes > 0) { ptyModes.forEach((mode, value) -> { modes.putByte((byte) mode.toInt()); modes.putInt(value.longValue()); }); } modes.putByte(PtyMode.TTY_OP_END); buffer.putBytes(modes.getCompactData()); writePacket(buffer); } if (GenericUtils.size(env) > 0) { if (debugEnabled) { log.debug("doOpenPty({}) Send SSH_MSG_CHANNEL_REQUEST env: {}", this, env); } // Cannot use forEach because of the IOException being thrown by writePacket for (Map.Entry entry : env.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); String str = Objects.toString(value); Buffer buffer = session.createBuffer( SshConstants.SSH_MSG_CHANNEL_REQUEST, key.length() + GenericUtils.length(str) + Integer.SIZE); buffer.putInt(getRecipient()); buffer.putString("env"); buffer.putBoolean(false); // want-reply buffer.putString(key); buffer.putString(str); writePacket(buffer); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy