You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/07/16 15:48:38 UTC
[2/2] mina-sshd git commit: [SSHD-541] Re-use incoming request buffer
for outgoing response (where applicable)
[SSHD-541] Re-use incoming request buffer for outgoing response (where applicable)
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/0d86de53
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/0d86de53
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/0d86de53
Branch: refs/heads/master
Commit: 0d86de5384857e29b5a6f9e679fcdbf2e5b32f51
Parents: 1c80bb6
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Thu Jul 16 16:42:28 2015 +0300
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Thu Jul 16 16:44:54 2015 +0300
----------------------------------------------------------------------
.../sshd/agent/common/AbstractAgentClient.java | 98 ++++---
.../sshd/agent/local/AgentForwardedChannel.java | 6 +-
.../agent/local/ChannelAgentForwarding.java | 1 -
.../org/apache/sshd/client/SftpException.java | 44 ----
.../subsystem/sftp/AbstractSftpClient.java | 258 +++++++++++++------
.../subsystem/sftp/DefaultSftpClient.java | 45 ++--
.../client/subsystem/sftp/SftpException.java | 44 ++++
.../client/subsystem/sftp/SftpFileChannel.java | 1 -
.../subsystem/sftp/SftpFileSystemProvider.java | 5 +-
.../impl/AbstractSftpClientExtension.java | 8 +-
.../sshd/common/channel/AbstractChannel.java | 69 ++---
.../sshd/common/channel/RequestHandler.java | 49 +++-
.../common/forward/DefaultTcpipForwarder.java | 7 +-
.../session/AbstractConnectionService.java | 62 +++--
.../sshd/common/session/AbstractSession.java | 33 +--
.../openssh/AbstractOpenSSHExtensionParser.java | 2 +-
.../sshd/common/util/io/FileInfoExtractor.java | 85 ++++++
.../global/CancelTcpipForwardHandler.java | 11 +-
.../sshd/server/global/TcpipForwardHandler.java | 11 +-
.../server/subsystem/sftp/SftpSubsystem.java | 222 ++++++++++++----
.../sshd/server/x11/X11ForwardSupport.java | 7 +-
.../org/apache/sshd/client/scp/ScpTest.java | 44 +++-
.../subsystem/sftp/SftpFileSystemTest.java | 24 +-
.../sshd/client/subsystem/sftp/SftpTest.java | 9 +-
.../impl/AbstractCheckFileExtensionTest.java | 2 +-
.../impl/AbstractMD5HashExtensionTest.java | 2 +-
.../impl/CopyFileExtensionImplTest.java | 2 +-
27 files changed, 800 insertions(+), 351 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
index 6940bcd..0730cf6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
@@ -29,12 +29,14 @@ import static org.apache.sshd.agent.SshAgentConstants.SSH2_AGENT_SIGN_RESPONSE;
import static org.apache.sshd.agent.SshAgentConstants.SSH_AGENT_SUCCESS;
import java.io.IOException;
+import java.security.KeyPair;
import java.security.PublicKey;
import java.util.List;
import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.util.Pair;
+import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.BufferUtils;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
@@ -51,21 +53,43 @@ public abstract class AbstractAgentClient extends AbstractLoggingBean {
public synchronized void messageReceived(Buffer message) throws IOException {
buffer.putBuffer(message);
- if (buffer.available() < 4) {
+ int avail = buffer.available();
+ if (avail < 4) {
+ if (log.isTraceEnabled()) {
+ log.trace("Received message total length ({}) below minuimum ({})",
+ Integer.valueOf(avail), Integer.valueOf(4));
+ }
return;
}
+
int rpos = buffer.rpos();
int len = buffer.getInt();
buffer.rpos(rpos);
- if (buffer.available() < len + 4) {
+
+ avail = buffer.available();
+ if (avail < (len + 4)) {
+ if (log.isTraceEnabled()) {
+ log.trace("Received request length ({}) below minuimum ({})",
+ Integer.valueOf(avail), Integer.valueOf(len + 4));
+ }
return;
}
- Buffer rep = new ByteArrayBuffer();
+
+ // we can re-use the incoming message buffer since its data has been copied to the request buffer
+ Buffer rep = BufferUtils.clear(message);
rep.putInt(0);
rep.rpos(rep.wpos());
+
+ Buffer req = new ByteArrayBuffer(buffer.getBytes());
+ int cmd = (-1);
try {
- process(new ByteArrayBuffer(buffer.getBytes()), rep);
+ cmd = req.getUByte();
+ process(cmd, req, rep);
} catch (Exception e) {
+ if (log.isDebugEnabled()) {
+ log.debug("Failed ({}) to handle command={}: {}",
+ e.getClass().getSimpleName(), Integer.valueOf(cmd), e.getMessage());
+ }
rep.clear();
rep.putInt(0);
rep.rpos(rep.wpos());
@@ -75,45 +99,55 @@ public abstract class AbstractAgentClient extends AbstractLoggingBean {
reply(prepare(rep));
}
- protected void process(Buffer req, Buffer rep) throws Exception {
- int cmd = req.getUByte();
+ protected void process(int cmd, Buffer req, Buffer rep) throws Exception {
+ if (log.isDebugEnabled()) {
+ log.debug("process(cmd={})", Integer.valueOf(cmd));
+ }
switch (cmd) {
case SSH2_AGENTC_REQUEST_IDENTITIES: {
- List<Pair<PublicKey,String>> keys = agent.getIdentities();
- rep.putByte(SSH2_AGENT_IDENTITIES_ANSWER);
- rep.putInt(keys.size());
- for (Pair<PublicKey,String> key : keys) {
- rep.putPublicKey(key.getFirst());
- rep.putString(key.getSecond());
+ List<Pair<PublicKey,String>> keys = agent.getIdentities();
+ rep.putByte(SSH2_AGENT_IDENTITIES_ANSWER);
+ rep.putInt(keys.size());
+ for (Pair<PublicKey,String> key : keys) {
+ rep.putPublicKey(key.getFirst());
+ rep.putString(key.getSecond());
+ }
}
break;
- }
case SSH2_AGENTC_SIGN_REQUEST: {
- PublicKey key = req.getPublicKey();
- byte[] data = req.getBytes();
- int flags = req.getInt();
- if (log.isDebugEnabled()) {
- log.debug("SSH2_AGENTC_SIGN_REQUEST key={}, flags=0x{}, data={}",
- key.getAlgorithm(), Integer.toHexString(flags), BufferUtils.printHex(':', data));
+ PublicKey key = req.getPublicKey();
+ byte[] data = req.getBytes();
+ int flags = req.getInt();
+ if (log.isDebugEnabled()) {
+ log.debug("SSH2_AGENTC_SIGN_REQUEST key={}, flags=0x{}, data={}",
+ key.getAlgorithm(), Integer.toHexString(flags), BufferUtils.printHex(':', data));
+ }
+ String keyType = ValidateUtils.checkNotNullAndNotEmpty(
+ KeyUtils.getKeyType(key),
+ "Cannot resolve key type of %s",
+ key.getClass().getSimpleName());
+ Buffer sig = new ByteArrayBuffer();
+ sig.putString(keyType);
+ sig.putBytes(agent.sign(key, data));
+ rep.putByte(SSH2_AGENT_SIGN_RESPONSE);
+ rep.putBytes(sig.array(), sig.rpos(), sig.available());
}
- Buffer sig = new ByteArrayBuffer();
- sig.putString(KeyUtils.getKeyType(key));
- sig.putBytes(agent.sign(key, data));
- rep.putByte(SSH2_AGENT_SIGN_RESPONSE);
- rep.putBytes(sig.array(), sig.rpos(), sig.available());
break;
- }
case SSH2_AGENTC_ADD_IDENTITY: {
- agent.addIdentity(req.getKeyPair(), req.getString());
- rep.putByte(SSH_AGENT_SUCCESS);
+ KeyPair kp = req.getKeyPair();
+ String comment = req.getString();
+ log.debug("SSH2_AGENTC_ADD_IDENTITY comment={}", comment);
+ agent.addIdentity(kp, comment);
+ rep.putByte(SSH_AGENT_SUCCESS);
+ }
break;
- }
case SSH2_AGENTC_REMOVE_IDENTITY: {
- PublicKey key = req.getPublicKey();
- agent.removeIdentity(key);
- rep.putByte(SSH_AGENT_SUCCESS);
+ PublicKey key = req.getPublicKey();
+ log.debug("SSH2_AGENTC_REMOVE_IDENTITY {}", key.getClass().getSimpleName());
+ agent.removeIdentity(key);
+ rep.putByte(SSH_AGENT_SUCCESS);
+ }
break;
- }
case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
agent.removeAllIdentities();
rep.putByte(SSH_AGENT_SUCCESS);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java
index d0f8c39..d9e7521 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java
@@ -20,6 +20,7 @@ package org.apache.sshd.agent.local;
import java.io.IOException;
import java.io.InterruptedIOException;
+import java.io.OutputStream;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -68,8 +69,9 @@ public class AgentForwardedChannel extends AbstractClientChannel {
protected Buffer request(Buffer buffer) throws IOException {
synchronized (messages) {
try {
- getInvertedIn().write(buffer.array(), buffer.rpos(), buffer.available());
- getInvertedIn().flush();
+ OutputStream outputStream = getInvertedIn();
+ outputStream.write(buffer.array(), buffer.rpos(), buffer.available());
+ outputStream.flush();
localWindow.consumeAndCheck(buffer.available());
if (messages.isEmpty()) {
messages.wait();
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
index a8e0bd8..59eb2f8 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java
@@ -107,5 +107,4 @@ public class ChannelAgentForwarding extends AbstractServerChannel {
out.flush();
}
}
-
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/client/SftpException.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/SftpException.java b/sshd-core/src/main/java/org/apache/sshd/client/SftpException.java
deleted file mode 100644
index f06d406..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/SftpException.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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;
-
-import java.io.IOException;
-
-/**
- * @author <a href="http://mina.apache.org">Apache MINA Project</a>
- */
-public class SftpException extends IOException {
- private static final long serialVersionUID = 8096963562429466995L;
- private final int status;
-
- public SftpException(int status, String msg) {
- super(msg);
- this.status = status;
- }
-
- public int getStatus() {
- return status;
- }
-
- @Override
- public String toString() {
- String message = getLocalizedMessage();
- return "SFTP error (" + status + "): " + message;
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
index f896a8d..8f92951 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
@@ -100,7 +100,6 @@ import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
-import org.apache.sshd.client.SftpException;
import org.apache.sshd.client.subsystem.sftp.extensions.BuiltinSftpClientExtensions;
import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtension;
import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtensionFactory;
@@ -119,7 +118,7 @@ import org.apache.sshd.common.util.logging.AbstractLoggingBean;
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public abstract class AbstractSftpClient extends AbstractLoggingBean implements SftpClient, RawSftpClient {
- private final AtomicReference<Map<String,Object>> parsedExtensionsHolder = new AtomicReference<>(null);
+ private final AtomicReference<Map<String,Object>> parsedExtensionsHolder = new AtomicReference<Map<String,Object>>(null);
protected AbstractSftpClient() {
super();
@@ -248,7 +247,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
Map<String,Object> parsed = parsedExtensionsHolder.get();
if (parsed == null) {
if ((parsed=ParserUtils.parse(extensions)) == null) {
- parsed = Collections.emptyMap();
+ parsed = Collections.<String,Object>emptyMap();
}
parsedExtensionsHolder.set(parsed);
}
@@ -256,6 +255,29 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
return parsed;
}
+ /**
+ * Sends the specified command, waits for the response and then invokes {@link #checkStatus(Buffer)}
+ * @param cmd The command to send
+ * @param request The request {@link Buffer}
+ * @throws IOException If failed to send, receive or check the returned status
+ * @see #send(int, Buffer)
+ * @see #receive(int)
+ * @see #checkStatus(Buffer)
+ */
+ protected void checkStatus(int cmd, Buffer request) throws IOException {
+ int reqId = send(cmd, request);
+ Buffer response = receive(reqId);
+ checkStatus(response);
+ }
+
+ /**
+ * Checks if the incoming response is an {@code SSH_FXP_STATUS} one,
+ * and if so whether the substatus is {@code SSH_FX_OK}.
+ * @param buffer The received response {@link Buffer}
+ * @throws IOException If response does not carry a status or carries
+ * a bad status code
+ * @see #checkStatus(int, int, String, String)
+ */
protected void checkStatus(Buffer buffer) throws IOException {
int length = buffer.getInt();
int type = buffer.getUByte();
@@ -264,69 +286,126 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
int substatus = buffer.getInt();
String msg = buffer.getString();
String lang = buffer.getString();
- if (log.isTraceEnabled()) {
- log.trace("checkStatus(id={}) - status: {} [{}] {}", id, substatus, lang, msg);
- }
-
- if (substatus != SSH_FX_OK) {
- throw new SftpException(substatus, msg);
- }
+ checkStatus(id, substatus, msg, lang);
} else {
throw new SshException("Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length);
}
}
+ /**
+ * @param id The request id
+ * @param substatus The sub-status value
+ * @param msg The message
+ * @param lang The language
+ * @throws IOException if the sub-status is not {@code SSH_FX_OK}
+ * @see #throwStatusException(int, int, String, String)
+ */
+ protected void checkStatus(int id, int substatus, String msg, String lang) throws IOException {
+ if (log.isTraceEnabled()) {
+ log.trace("checkStatus(id=" + id + ") status: " + substatus + " [" + lang + "]" + msg );
+ }
+
+ if (substatus != SSH_FX_OK) {
+ throwStatusException(id, substatus, msg, lang);
+ }
+ }
+
+ protected void throwStatusException(int id, int substatus, String msg, String lang) throws IOException {
+ throw new SftpException(substatus, msg);
+ }
+
+ /**
+ * @param cmd Command to be sent
+ * @param request The {@link Buffer} containing the request
+ * @return The received handle identifier
+ * @throws IOException If failed to send/receive or process the response
+ * @see #send(int, Buffer)
+ * @see #receive(int)
+ * @see #checkHandle(Buffer)
+ */
+ protected byte[] checkHandle(int cmd, Buffer request) throws IOException {
+ int reqId = send(cmd, request);
+ Buffer response = receive(reqId);
+ return checkHandle(response);
+ }
+
protected byte[] checkHandle(Buffer buffer) throws IOException {
int length = buffer.getInt();
int type = buffer.getUByte();
int id = buffer.getInt();
+ if (type == SSH_FXP_HANDLE) {
+ return ValidateUtils.checkNotNullAndNotEmpty(buffer.getBytes(), "Null/empty handle in buffer", GenericUtils.EMPTY_OBJECT_ARRAY);
+ }
+
if (type == SSH_FXP_STATUS) {
int substatus = buffer.getInt();
String msg = buffer.getString();
String lang = buffer.getString();
if (log.isTraceEnabled()) {
- log.trace("checkHandle(id={}) - status: {} [{}] {}", id, substatus, lang, msg);
+ log.trace("checkHandle(id={}) - status: {} [{}] {}", Integer.valueOf(id), Integer.valueOf(substatus), lang, msg);
}
- throw new SftpException(substatus, msg);
- } else if (type == SSH_FXP_HANDLE) {
- return ValidateUtils.checkNotNullAndNotEmpty(buffer.getBytes(), "Null/empty handle in buffer");
- } else {
- throw new SshException("Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length);
+ throwStatusException(id, substatus, msg, lang);
}
+
+ throw new SshException("Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length);
+ }
+
+ /**
+ * @param cmd Command to be sent
+ * @param request Request {@link Buffer}
+ * @return The decoded response {@link Attributes}
+ * @throws IOException If failed to send/receive or process the response
+ * @see #send(int, Buffer)
+ * @see #receive(int)
+ * @see #checkAttributes(Buffer)
+ */
+ protected Attributes checkAttributes(int cmd, Buffer request) throws IOException {
+ int reqId = send(cmd, request);
+ Buffer response = receive(reqId);
+ return checkAttributes(response);
}
protected Attributes checkAttributes(Buffer buffer) throws IOException {
int length = buffer.getInt();
int type = buffer.getUByte();
int id = buffer.getInt();
+ if (type == SSH_FXP_ATTRS) {
+ return readAttributes(buffer);
+ }
+
if (type == SSH_FXP_STATUS) {
int substatus = buffer.getInt();
String msg = buffer.getString();
String lang = buffer.getString();
if (log.isTraceEnabled()) {
- log.trace("checkAttributes(id={}) - status: {} [{}] {}", id, substatus, lang, msg);
+ log.trace("checkAttributes(id={}) - status: {} [{}] {}", Integer.valueOf(id), Integer.valueOf(substatus), lang, msg);
}
- throw new SftpException(substatus, msg);
- } else if (type == SSH_FXP_ATTRS) {
- return readAttributes(buffer);
- } else {
- throw new SshException("Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length);
+ throwStatusException(id, substatus, msg, lang);
}
+
+ throw new SshException("Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length);
+ }
+
+ /**
+ * @param cmd Command to be sent
+ * @param request The request {@link Buffer}
+ * @return The retrieve name
+ * @throws IOException If failed to send/receive or process the response
+ * @see #send(int, Buffer)
+ * @see #receive(int)
+ * @see #checkOneName(Buffer)
+ */
+ protected String checkOneName(int cmd, Buffer request) throws IOException {
+ int reqId = send(cmd, request);
+ Buffer response = receive(reqId);
+ return checkOneName(response);
}
protected String checkOneName(Buffer buffer) throws IOException {
int length = buffer.getInt();
int type = buffer.getUByte();
int id = buffer.getInt();
- if (type == SSH_FXP_STATUS) {
- int substatus = buffer.getInt();
- String msg = buffer.getString();
- String lang = buffer.getString();
- if (log.isTraceEnabled()) {
- log.trace("checkOneName(id={}) - status: {} [{}] {}", id, substatus, lang, msg);
- }
- throw new SftpException(substatus, msg);
- } else if (type == SSH_FXP_NAME) {
+ if (type == SSH_FXP_NAME) {
int len = buffer.getInt();
if (len != 1) {
throw new SshException("SFTP error: received " + len + " names instead of 1");
@@ -338,12 +417,23 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
}
Attributes attrs = readAttributes(buffer);
if (log.isTraceEnabled()) {
- log.trace("checkOneName(id={}) ({})[{}]: {}", id, name, longName, attrs);
+ log.trace("checkOneName(id={}) ({})[{}]: {}", Integer.valueOf(id), name, longName, attrs);
}
return name;
- } else {
- throw new SshException("Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length);
}
+
+ if (type == SSH_FXP_STATUS) {
+ int substatus = buffer.getInt();
+ String msg = buffer.getString();
+ String lang = buffer.getString();
+ if (log.isTraceEnabled()) {
+ log.trace("checkOneName(id={}) - status: {} [{}] {}", Integer.valueOf(id), Integer.valueOf(substatus), lang, msg);
+ }
+
+ throwStatusException(id, substatus, msg, lang);
+ }
+
+ throw new SshException("Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length);
}
protected Attributes readAttributes(Buffer buffer) throws IOException {
@@ -605,7 +695,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
}
buffer.putInt(mode);
writeAttributes(buffer, new Attributes());
- return new DefaultCloseableHandle(this, checkHandle(receive(send(SSH_FXP_OPEN, buffer))));
+ return new DefaultCloseableHandle(this, checkHandle(SSH_FXP_OPEN, buffer));
}
@Override
@@ -617,7 +707,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
byte[] id = handle.getIdentifier();
Buffer buffer = new ByteArrayBuffer(id.length + Long.SIZE /* some extra fields */);
buffer.putBytes(id);
- checkStatus(receive(send(SSH_FXP_CLOSE, buffer)));
+ checkStatus(SSH_FXP_CLOSE, buffer);
}
@Override
@@ -628,7 +718,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */);
buffer.putString(path);
- checkStatus(receive(send(SSH_FXP_REMOVE, buffer)));
+ checkStatus(SSH_FXP_REMOVE, buffer);
}
@Override
@@ -663,7 +753,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
throw new UnsupportedOperationException("rename(" + oldPath + " => " + newPath + ")"
+ " - copy options can not be used with this SFTP version: " + options);
}
- checkStatus(receive(send(SSH_FXP_RENAME, buffer)));
+ checkStatus(SSH_FXP_RENAME, buffer);
}
@Override
@@ -677,33 +767,41 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
buffer.putBytes(id);
buffer.putLong(fileOffset);
buffer.putInt(len);
- return checkData(receive(send(SSH_FXP_READ, buffer)), dstOffset, dst);
+ return checkData(SSH_FXP_READ, buffer, dstOffset, dst);
+ }
+
+ protected int checkData(int cmd, Buffer request, int dstOffset, byte[] dst) throws IOException {
+ int reqId = send(cmd, request);
+ Buffer response = receive(reqId);
+ return checkData(response, dstOffset, dst);
}
protected int checkData(Buffer buffer, int dstoff, byte[] dst) throws IOException {
int length = buffer.getInt();
int type = buffer.getUByte();
int id = buffer.getInt();
+ if (type == SSH_FXP_DATA) {
+ int len = buffer.getInt();
+ buffer.getRawBytes(dst, dstoff, len);
+ return len;
+ }
+
if (type == SSH_FXP_STATUS) {
int substatus = buffer.getInt();
String msg = buffer.getString();
String lang = buffer.getString();
if (log.isTraceEnabled()) {
- log.trace("checkData(id={}) - status: {} [{}] {}", id, substatus, lang, msg);
+ log.trace("checkData(id={}) - status: {} [{}] {}", Integer.valueOf(id), Integer.valueOf(substatus), lang, msg);
}
if (substatus == SSH_FX_EOF) {
return -1;
}
- throw new SftpException(substatus, msg);
- } else if (type == SSH_FXP_DATA) {
- int len = buffer.getInt();
- buffer.getRawBytes(dst, dstoff, len);
- return len;
- } else {
- throw new SshException("Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length);
+ throwStatusException(id, substatus, msg, lang);
}
+
+ throw new SshException("Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length);
}
@Override
@@ -728,7 +826,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
buffer.putBytes(id);
buffer.putLong(fileOffset);
buffer.putBytes(src, srcOffset, len);
- checkStatus(receive(send(SSH_FXP_WRITE, buffer)));
+ checkStatus(SSH_FXP_WRITE, buffer);
}
@Override
@@ -746,7 +844,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
buffer.putByte((byte) 0);
}
- checkStatus(receive(send(SSH_FXP_MKDIR, buffer)));
+ checkStatus(SSH_FXP_MKDIR, buffer);
}
@Override
@@ -757,7 +855,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */);
buffer.putString(path);
- checkStatus(receive(send(SSH_FXP_RMDIR, buffer)));
+ checkStatus(SSH_FXP_RMDIR, buffer);
}
@Override
@@ -768,7 +866,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */);
buffer.putString(path);
- return new DefaultCloseableHandle(this, checkHandle(receive(send(SSH_FXP_OPENDIR, buffer))));
+ return new DefaultCloseableHandle(this, checkHandle(SSH_FXP_OPENDIR, buffer));
}
@Override
@@ -787,18 +885,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
int length = buffer.getInt();
int type = buffer.getUByte();
int id = buffer.getInt();
- if (type == SSH_FXP_STATUS) {
- int substatus = buffer.getInt();
- String msg = buffer.getString();
- String lang = buffer.getString();
- if (log.isTraceEnabled()) {
- log.trace("checkDir(id={}) - status: {} [{}] {}", id, substatus, lang, msg);
- }
- if (substatus == SSH_FX_EOF) {
- return null;
- }
- throw new SftpException(substatus, msg);
- } else if (type == SSH_FXP_NAME) {
+ if (type == SSH_FXP_NAME) {
int len = buffer.getInt();
List<DirEntry> entries = new ArrayList<DirEntry>(len);
for (int i = 0; i < len; i++) {
@@ -807,15 +894,30 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
String longName = (version == SFTP_V3) ? buffer.getString() : null;
Attributes attrs = readAttributes(buffer);
if (log.isTraceEnabled()) {
- log.trace("checkDir(id={})[{}] ({})[{}]: {}", id, i, name, longName, attrs);
+ log.trace("checkDir(id={})[{}] ({})[{}]: {}", Integer.valueOf(id), Integer.valueOf(i), name, longName, attrs);
}
-
+
entries.add(new DirEntry(name, longName, attrs));
}
return entries;
- } else {
- throw new SshException("Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length);
}
+
+ if (type == SSH_FXP_STATUS) {
+ int substatus = buffer.getInt();
+ String msg = buffer.getString();
+ String lang = buffer.getString();
+ if (log.isTraceEnabled()) {
+ log.trace("checkDir(id={}) - status: {} [{}] {}", Integer.valueOf(id), Integer.valueOf(substatus), lang, msg);
+ }
+
+ if (substatus == SSH_FX_EOF) {
+ return null;
+ }
+
+ throwStatusException(id, substatus, msg, lang);
+ }
+
+ throw new SshException("Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length);
}
@Override
@@ -826,7 +928,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
Buffer buffer = new ByteArrayBuffer();
buffer.putString(path);
- return checkOneName(receive(send(SSH_FXP_REALPATH, buffer)));
+ return checkOneName(SSH_FXP_REALPATH, buffer);
}
@Override
@@ -843,7 +945,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
buffer.putInt(SSH_FILEXFER_ATTR_ALL);
}
- return checkAttributes(receive(send(SSH_FXP_STAT, buffer)));
+ return checkAttributes(SSH_FXP_STAT, buffer);
}
@Override
@@ -860,7 +962,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
buffer.putInt(SSH_FILEXFER_ATTR_ALL);
}
- return checkAttributes(receive(send(SSH_FXP_LSTAT, buffer)));
+ return checkAttributes(SSH_FXP_LSTAT, buffer);
}
@Override
@@ -878,7 +980,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
buffer.putInt(SSH_FILEXFER_ATTR_ALL);
}
- return checkAttributes(receive(send(SSH_FXP_FSTAT, buffer)));
+ return checkAttributes(SSH_FXP_FSTAT, buffer);
}
@Override
@@ -890,7 +992,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
Buffer buffer = new ByteArrayBuffer();
buffer.putString(path);
writeAttributes(buffer, attributes);
- checkStatus(receive(send(SSH_FXP_SETSTAT, buffer)));
+ checkStatus(SSH_FXP_SETSTAT, buffer);
}
@Override
@@ -903,7 +1005,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
Buffer buffer = new ByteArrayBuffer(id.length + (2 * Long.SIZE) /* some extras */);
buffer.putBytes(id);
writeAttributes(buffer, attributes);
- checkStatus(receive(send(SSH_FXP_FSETSTAT, buffer)));
+ checkStatus(SSH_FXP_FSETSTAT, buffer);
}
@Override
@@ -914,7 +1016,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE /* some extra fields */);
buffer.putString(path);
- return checkOneName(receive(send(SSH_FXP_READLINK, buffer)));
+ return checkOneName(SSH_FXP_READLINK, buffer);
}
@Override
@@ -931,12 +1033,12 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
}
buffer.putString(targetPath);
buffer.putString(linkPath);
- checkStatus(receive(send(SSH_FXP_SYMLINK, buffer)));
+ checkStatus(SSH_FXP_SYMLINK, buffer);
} else {
buffer.putString(targetPath);
buffer.putString(linkPath);
buffer.putBoolean(symbolic);
- checkStatus(receive(send(SSH_FXP_LINK, buffer)));
+ checkStatus(SSH_FXP_LINK, buffer);
}
}
@@ -952,7 +1054,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
buffer.putLong(offset);
buffer.putLong(length);
buffer.putInt(mask);
- checkStatus(receive(send(SSH_FXP_BLOCK, buffer)));
+ checkStatus(SSH_FXP_BLOCK, buffer);
}
@Override
@@ -966,7 +1068,7 @@ public abstract class AbstractSftpClient extends AbstractLoggingBean implements
buffer.putBytes(id);
buffer.putLong(offset);
buffer.putLong(length);
- checkStatus(receive(send(SSH_FXP_UNBLOCK, buffer)));
+ checkStatus(SSH_FXP_UNBLOCK, buffer);
}
@Override
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultSftpClient.java
index 12830d5..dd313db 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultSftpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/DefaultSftpClient.java
@@ -39,7 +39,6 @@ import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.sshd.client.SftpException;
import org.apache.sshd.client.channel.ChannelSubsystem;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.FactoryManagerUtils;
@@ -48,6 +47,7 @@ import org.apache.sshd.common.subsystem.sftp.SftpConstants;
import org.apache.sshd.common.subsystem.sftp.extensions.ParserUtils;
import org.apache.sshd.common.subsystem.sftp.extensions.VersionsParser.Versions;
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.BufferUtils;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
@@ -58,19 +58,18 @@ import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
public class DefaultSftpClient extends AbstractSftpClient {
private final ClientSession clientSession;
private final ChannelSubsystem channel;
- private final Map<Integer, Buffer> messages;
+ private final Map<Integer, Buffer> messages = new HashMap<>();
private final AtomicInteger cmdId = new AtomicInteger(100);
private final Buffer receiveBuffer = new ByteArrayBuffer();
private final byte[] workBuf = new byte[Integer.SIZE / Byte.SIZE]; // TODO in JDK-8 use Integer.BYTES
private boolean closing;
private int version;
- private final Map<String,byte[]> extensions = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ private final Map<String,byte[]> extensions = new TreeMap<String,byte[]>(String.CASE_INSENSITIVE_ORDER);
private final Map<String,byte[]> exposedExtensions = Collections.unmodifiableMap(extensions);
public DefaultSftpClient(ClientSession clientSession) throws IOException {
- this.clientSession = clientSession;
+ this.clientSession = ValidateUtils.checkNotNull(clientSession, "No client session", GenericUtils.EMPTY_OBJECT_ARRAY);
this.channel = clientSession.createSubsystemChannel(SftpConstants.SFTP_SUBSYSTEM_NAME);
- this.messages = new HashMap<>();
this.channel.setOut(new OutputStream() {
@Override
public void write(int b) throws IOException {
@@ -190,38 +189,44 @@ public class DefaultSftpClient extends AbstractSftpClient {
int id = buffer.getInt();
buffer.rpos(0);
synchronized (messages) {
- messages.put(id, buffer);
+ messages.put(Integer.valueOf(id), buffer);
messages.notifyAll();
}
}
@Override
public int send(int cmd, Buffer buffer) throws IOException {
- int id = cmdId.incrementAndGet();
+ int id = cmdId.incrementAndGet(), len = buffer.available();
+ if (log.isTraceEnabled()) {
+ log.trace("send(cmd={}, len={}) id = {}",
+ Integer.valueOf(cmd), Integer.valueOf(len), Integer.valueOf(id));
+ }
+
OutputStream dos = channel.getInvertedIn();
BufferUtils.writeInt(dos, 1 /* cmd */ + (Integer.SIZE / Byte.SIZE) /* id */ + buffer.available(), workBuf);
dos.write(cmd & 0xFF);
BufferUtils.writeInt(dos, id, workBuf);
- dos.write(buffer.array(), buffer.rpos(), buffer.available());
+ dos.write(buffer.array(), buffer.rpos(), len);
dos.flush();
return id;
}
@Override
public Buffer receive(int id) throws IOException {
+ Integer reqId = Integer.valueOf(id);
synchronized (messages) {
- while (true) {
+ for (int count=1; ; count++) {
if (closing) {
throw new SshException("Channel has been closed");
}
- Buffer buffer = messages.remove(id);
+ Buffer buffer = messages.remove(reqId);
if (buffer != null) {
return buffer;
}
try {
messages.wait();
} catch (InterruptedException e) {
- throw (IOException) new InterruptedIOException("Interrupted while waiting for messages").initCause(e);
+ throw (IOException) new InterruptedIOException("Interrupted while waiting for messages at iteration #" + count).initCause(e);
}
}
}
@@ -292,10 +297,10 @@ public class DefaultSftpClient extends AbstractSftpClient {
String msg = buffer.getString();
String lang = buffer.getString();
if (log.isTraceEnabled()) {
- log.trace("init(id={}) - status: {} [{}] {}", id, substatus, lang, msg);
+ log.trace("init(id={}) - status: {} [{}] {}", Integer.valueOf(id), Integer.valueOf(substatus), lang, msg);
}
- throw new SftpException(substatus, msg);
+ throwStatusException(id, substatus, msg, lang);
} else {
throw new SshException("Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length);
}
@@ -308,22 +313,24 @@ public class DefaultSftpClient extends AbstractSftpClient {
*/
public int negotiateVersion(SftpVersionSelector selector) throws IOException {
int current = getVersion();
- Set<Integer> available = GenericUtils.asSortedSet(Collections.singleton(current));
+ Set<Integer> available = GenericUtils.asSortedSet(Collections.singleton(Integer.valueOf(current)));
Map<String,?> parsed = getParsedServerExtensions();
Collection<String> extensions = ParserUtils.supportedExtensions(parsed);
- if (!GenericUtils.isEmpty(extensions) && extensions.contains(SftpConstants.EXT_VERSELECT)) {
+ if ((GenericUtils.size(extensions) > 0) && extensions.contains(SftpConstants.EXT_VERSELECT)) {
Versions vers = GenericUtils.isEmpty(parsed) ? null : (Versions) parsed.get(SftpConstants.EXT_VERSIONS);
Collection<String> reported = (vers == null) ? null : vers.versions;
if (GenericUtils.size(reported) > 0) {
for (String v : reported) {
- available.add(Integer.valueOf(v));
+ if (!available.add(Integer.valueOf(v))) {
+ continue;
+ }
}
}
}
- int selected = selector.selectVersion(current, new ArrayList<>(available));
+ int selected = selector.selectVersion(current, new ArrayList<Integer>(available));
if (log.isDebugEnabled()) {
- log.debug("negotiateVersion({}) {} -> {}", current, available, selected);
+ log.debug("negotiateVersion({}) {} -> {}", Integer.valueOf(current), available, Integer.valueOf(selected));
}
if (selected == current) {
@@ -339,7 +346,7 @@ public class DefaultSftpClient extends AbstractSftpClient {
+ (Integer.SIZE / Byte.SIZE) + verVal.length());
buffer.putString(SftpConstants.EXT_VERSELECT);
buffer.putString(verVal);
- checkStatus(receive(send(SftpConstants.SSH_FXP_EXTENDED, buffer)));
+ checkStatus(SftpConstants.SSH_FXP_EXTENDED, buffer);
version = selected;
return selected;
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpException.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpException.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpException.java
new file mode 100644
index 0000000..3228269
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpException.java
@@ -0,0 +1,44 @@
+/*
+ * 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.subsystem.sftp;
+
+import java.io.IOException;
+
+/**
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class SftpException extends IOException {
+ private static final long serialVersionUID = 8096963562429466995L;
+ private final int status;
+
+ public SftpException(int status, String msg) {
+ super(msg);
+ this.status = status;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+
+ @Override
+ public String toString() {
+ String message = getMessage();
+ return "SFTP error (" + getStatus() + "): " + message;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java
index 53dd6ca..19ded8c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java
@@ -41,7 +41,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
-import org.apache.sshd.client.SftpException;
import org.apache.sshd.common.FactoryManagerUtils;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java
index 986f015..b0ecafc 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystemProvider.java
@@ -66,7 +66,6 @@ import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-import org.apache.sshd.client.SftpException;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.client.subsystem.sftp.SftpClient.Attributes;
@@ -319,7 +318,7 @@ public class SftpFileSystemProvider extends FileSystemProvider {
public Iterator<Path> iterator() {
return new Iterator<Path>() {
@SuppressWarnings("synthetic-access")
- private final Iterator<SftpClient.DirEntry> it = iter.iterator();
+ private final Iterator<SftpClient.DirEntry> it = (iter == null) ? null : iter.iterator();
private boolean dotIgnored, dotdotIgnored;
private SftpClient.DirEntry curEntry = nextEntry();
@@ -340,7 +339,7 @@ public class SftpFileSystemProvider extends FileSystemProvider {
}
private SftpClient.DirEntry nextEntry() {
- while(it.hasNext()) {
+ while((it != null) && it.hasNext()) {
SftpClient.DirEntry entry = it.next();
String name = entry.filename;
if (".".equals(name) && (!dotIgnored)) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractSftpClientExtension.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractSftpClientExtension.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractSftpClientExtension.java
index ccd55de..11b23f1 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractSftpClientExtension.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/extensions/impl/AbstractSftpClientExtension.java
@@ -24,9 +24,9 @@ import java.io.StreamCorruptedException;
import java.util.Collection;
import java.util.Map;
-import org.apache.sshd.client.SftpException;
import org.apache.sshd.client.subsystem.sftp.RawSftpClient;
import org.apache.sshd.client.subsystem.sftp.SftpClient;
+import org.apache.sshd.client.subsystem.sftp.SftpException;
import org.apache.sshd.client.subsystem.sftp.SftpClient.Handle;
import org.apache.sshd.client.subsystem.sftp.extensions.SftpClientExtension;
import org.apache.sshd.common.SshException;
@@ -188,7 +188,7 @@ public abstract class AbstractSftpClientExtension extends AbstractLoggingBean im
}
if (substatus != SftpConstants.SSH_FX_OK) {
- throw new SftpException(substatus, msg);
+ throwStatusException(id, substatus, msg, lang);
}
return null;
@@ -198,4 +198,8 @@ public abstract class AbstractSftpClientExtension extends AbstractLoggingBean im
throw new SshException("Unexpected SFTP packet received: type=" + type + ", id=" + id + ", length=" + length);
}
}
+
+ protected void throwStatusException(int id, int substatus, String msg, String lang) throws IOException {
+ throw new SftpException(substatus, msg);
+ }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
index 783cd17..2ec3f3f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
@@ -39,6 +39,7 @@ import org.apache.sshd.common.session.ConnectionService;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.util.CloseableUtils;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Int2IntFunction;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.BufferUtils;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
@@ -58,7 +59,7 @@ public abstract class AbstractChannel
public static final long DEFAULT_CHANNEL_CLOSE_TIMEOUT = 5000;
- protected enum GracefulState {
+ protected static enum GracefulState {
Opened, CloseSent, CloseReceived, Closed
}
@@ -71,9 +72,9 @@ public abstract class AbstractChannel
protected int id;
protected int recipient;
private final AtomicBoolean eof = new AtomicBoolean(false);
- protected AtomicReference<GracefulState> gracefulState = new AtomicReference<>(GracefulState.Opened);
+ protected AtomicReference<GracefulState> gracefulState = new AtomicReference<GracefulState>(GracefulState.Opened);
protected final DefaultCloseFuture gracefulFuture = new DefaultCloseFuture(lock);
- protected final List<RequestHandler<Channel>> handlers = new ArrayList<>();
+ protected final List<RequestHandler<Channel>> handlers = new ArrayList<RequestHandler<Channel>>();
protected AbstractChannel() {
super();
@@ -137,8 +138,10 @@ public abstract class AbstractChannel
String req = buffer.getString();
boolean wantReply = buffer.getBoolean();
if (log.isDebugEnabled()) {
- log.debug("Received SSH_MSG_CHANNEL_REQUEST {} on channel {} (wantReply {})", req, this, wantReply);
+ log.debug("Received SSH_MSG_CHANNEL_REQUEST {} on channel {} (wantReply {})",
+ req, this, Boolean.valueOf(wantReply));
}
+
for (RequestHandler<Channel> handler : handlers) {
RequestHandler.Result result;
try {
@@ -147,36 +150,44 @@ public abstract class AbstractChannel
log.warn("Error processing channel request " + req, e);
result = RequestHandler.Result.ReplyFailure;
}
- switch (result) {
- case Replied:
- return;
- case ReplySuccess:
- if (wantReply) {
- buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_SUCCESS);
- buffer.putInt(recipient);
- session.writePacket(buffer);
- }
- return;
- case ReplyFailure:
- if (wantReply) {
- buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_FAILURE);
- buffer.putInt(recipient);
- session.writePacket(buffer);
- }
- return;
- default:
- if (log.isTraceEnabled()) {
- log.trace("{}#process({}): {}", handler.getClass().getSimpleName(), req, result);
- }
+
+ // if Unsupported then check the next handler in line
+ if (RequestHandler.Result.Unsupported.equals(result)) {
+ if (log.isTraceEnabled()) {
+ log.trace("{}#process({}): {}", handler.getClass().getSimpleName(), req, result);
+ }
+ } else {
+ sendResponse(buffer, req, result, wantReply);
+ return;
}
}
+ // none of the handlers processed the request
log.warn("Unknown channel request: {}", req);
- if (wantReply) {
- buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_FAILURE);
- buffer.putInt(recipient);
- session.writePacket(buffer);
+ sendResponse(buffer, req, RequestHandler.Result.Unsupported, wantReply);
+ }
+
+ protected void sendResponse(Buffer buffer, String req, RequestHandler.Result result, boolean wantReply) throws IOException {
+ if (log.isDebugEnabled()) {
+ log.debug("sendResponse({}) result={}, want-reply={}", req, result, Boolean.valueOf(wantReply));
}
+
+ if (RequestHandler.Result.Replied.equals(result) || (!wantReply)) {
+ return;
+ }
+
+ byte cmd = RequestHandler.Result.ReplySuccess.equals(result)
+ ? SshConstants.SSH_MSG_CHANNEL_SUCCESS
+ : SshConstants.SSH_MSG_CHANNEL_FAILURE
+ ;
+ buffer.clear();
+ // leave room for the SSH header
+ buffer.ensureCapacity(5 + 1 + (Integer.SIZE / Byte.SIZE), Int2IntFunction.Utils.add(Byte.SIZE));
+ buffer.rpos(5);
+ buffer.wpos(5);
+ buffer.putByte(cmd);
+ buffer.putInt(recipient);
+ session.writePacket(buffer);
}
@Override
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/common/channel/RequestHandler.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/RequestHandler.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/RequestHandler.java
index 8c262ef..4f653f1 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/channel/RequestHandler.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/RequestHandler.java
@@ -18,6 +18,11 @@
*/
package org.apache.sshd.common.channel;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
/**
@@ -31,20 +36,42 @@ public interface RequestHandler<T> {
Unsupported,
Replied,
ReplySuccess,
- ReplyFailure
+ ReplyFailure;
+
+ public static final Set<Result> VALUES =
+ Collections.unmodifiableSet(EnumSet.allOf(Result.class));
+
+ /**
+ * @param name The result name - ignored if {@code null}/empty
+ * @return The matching {@link Result} value (case <U>insensitive</U>)
+ * or {@code null} if no match found
+ */
+ public static Result fromName(String name) {
+ if (GenericUtils.isEmpty(name)) {
+ return null;
+ }
+
+ for (Result r : VALUES) {
+ if (name.equalsIgnoreCase(r.name())) {
+ return r;
+ }
+ }
+
+ return null;
+ }
}
/**
- * Process the ssh-connection global request.
- * If an exception is thrown, the ConnectionService will send a failure message if needed
- * and the request will be considered handled.
- *
- * @param t
- * @param request
- * @param wantReply
- * @param buffer
- * @return
- * @throws Exception
+ * Process an SSH request. If an exception is thrown, the ConnectionService
+ * will send a failure message if needed and the request will be considered handled.
+ * @param t The input parameter
+ * @param request The request string
+ * @param wantReply Whether a reply is requested
+ * @param buffer The {@link Buffer} with request specific data
+ * @return The {@link Result}
+ * @throws Exception If failed to handle the request - <B>Note:</B> in
+ * order to signal an unsupported request the {@link Result#Unsupported}
+ * value should be returned
*/
Result process(T t, String request, boolean wantReply, Buffer buffer) throws Exception;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java
index 8af95ad..aad59eb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/forward/DefaultTcpipForwarder.java
@@ -19,6 +19,7 @@
package org.apache.sshd.common.forward;
import java.io.IOException;
+import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.HashMap;
@@ -412,8 +413,10 @@ public class DefaultTcpipForwarder extends CloseableUtils.AbstractInnerCloseable
Buffer buffer = new ByteArrayBuffer();
buffer.putBuffer(message);
channel.waitFor(ClientChannel.OPENED | ClientChannel.CLOSED, Long.MAX_VALUE);
- channel.getInvertedIn().write(buffer.array(), buffer.rpos(), buffer.available());
- channel.getInvertedIn().flush();
+
+ OutputStream outputStream = channel.getInvertedIn();
+ outputStream.write(buffer.array(), buffer.rpos(), buffer.available());
+ outputStream.flush();
}
@Override
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java
index 3d43fa2..47c6cc4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java
@@ -55,6 +55,7 @@ import org.apache.sshd.common.forward.TcpipForwarderFactory;
import org.apache.sshd.common.future.SshFutureListener;
import org.apache.sshd.common.util.CloseableUtils;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Int2IntFunction;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.server.channel.OpenChannelException;
@@ -419,9 +420,12 @@ public abstract class AbstractConnectionService extends CloseableUtils.AbstractI
protected void globalRequest(Buffer buffer) throws Exception {
String req = buffer.getString();
boolean wantReply = buffer.getBoolean();
- log.debug("Received SSH_MSG_GLOBAL_REQUEST {}", req);
+ if (log.isDebugEnabled()) {
+ log.debug("Received SSH_MSG_GLOBAL_REQUEST {} want-reply={}", req, Boolean.valueOf(wantReply));
+ }
+
List<RequestHandler<ConnectionService>> handlers = session.getFactoryManager().getGlobalRequestHandlers();
- if (handlers != null) {
+ if (GenericUtils.size(handlers) > 0) {
for (RequestHandler<ConnectionService> handler : handlers) {
RequestHandler.Result result;
try {
@@ -430,33 +434,43 @@ public abstract class AbstractConnectionService extends CloseableUtils.AbstractI
log.warn("Error processing global request " + req, e);
result = RequestHandler.Result.ReplyFailure;
}
- switch (result) {
- case Replied:
- return;
- case ReplySuccess:
- if (wantReply) {
- buffer = session.createBuffer(SshConstants.SSH_MSG_REQUEST_SUCCESS);
- session.writePacket(buffer);
- }
- return;
- case ReplyFailure:
- if (wantReply) {
- buffer = session.createBuffer(SshConstants.SSH_MSG_REQUEST_FAILURE);
- session.writePacket(buffer);
- }
- return;
- default:
- if (log.isTraceEnabled()) {
- log.trace("globalRequest({}) {}#process: {}", req, handler.getClass().getSimpleName(), result);
- }
+
+ // if Unsupported then check the next handler in line
+ if (RequestHandler.Result.Unsupported.equals(result)) {
+ if (log.isTraceEnabled()) {
+ log.trace("{}#process({}): {}", handler.getClass().getSimpleName(), req, result);
+ }
+ } else {
+ sendResponse(buffer, req, result, wantReply);
+ return;
}
}
}
+
log.warn("Unknown global request: {}", req);
- if (wantReply) {
- buffer = session.createBuffer(SshConstants.SSH_MSG_REQUEST_FAILURE);
- session.writePacket(buffer);
+ sendResponse(buffer, req, RequestHandler.Result.Unsupported, wantReply);
+ }
+
+ protected void sendResponse(Buffer buffer, String req, RequestHandler.Result result, boolean wantReply) throws IOException {
+ if (log.isDebugEnabled()) {
+ log.debug("sendResponse({}) result={}, want-reply={}", req, result, Boolean.valueOf(wantReply));
}
+
+ if (RequestHandler.Result.Replied.equals(result) || (!wantReply)) {
+ return;
+ }
+
+ byte cmd = RequestHandler.Result.ReplySuccess.equals(result)
+ ? SshConstants.SSH_MSG_CHANNEL_SUCCESS
+ : SshConstants.SSH_MSG_CHANNEL_FAILURE
+ ;
+ buffer.clear();
+ // leave room for the SSH header
+ buffer.ensureCapacity(5 + 1 + (Integer.SIZE / Byte.SIZE), Int2IntFunction.Utils.add(Byte.SIZE));
+ buffer.rpos(5);
+ buffer.wpos(5);
+ buffer.putByte(cmd);
+ session.writePacket(buffer);
}
protected void requestSuccess(Buffer buffer) throws Exception {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
index 535301c..aabc4cb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
@@ -37,6 +37,7 @@ import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -181,7 +182,7 @@ public abstract class AbstractSession extends CloseableUtils.AbstractInnerClosea
*/
public AbstractSession(boolean isServer, FactoryManager factoryManager, IoSession ioSession) {
this.isServer = isServer;
- this.factoryManager = factoryManager;
+ this.factoryManager = ValidateUtils.checkNotNull(factoryManager, "No factory manager provided", GenericUtils.EMPTY_OBJECT_ARRAY);
this.ioSession = ioSession;
sessionListenerProxy = EventListenerUtils.proxyWrapper(SessionListener.class, getClass().getClassLoader(), listeners);
random = factoryManager.getRandomFactory().create();
@@ -552,23 +553,25 @@ public abstract class AbstractSession extends CloseableUtils.AbstractInnerClosea
@SuppressWarnings("unchecked")
@Override
- public IoWriteFuture writePacket(Buffer buffer, long timeout, TimeUnit unit) throws IOException {
+ public IoWriteFuture writePacket(Buffer buffer, final long timeout, final TimeUnit unit) throws IOException {
final IoWriteFuture writeFuture = writePacket(buffer);
final DefaultSshFuture<IoWriteFuture> future = (DefaultSshFuture<IoWriteFuture>) writeFuture;
- final ScheduledFuture<?> sched = factoryManager.getScheduledExecutorService().schedule(new Runnable() {
- @SuppressWarnings("synthetic-access")
- @Override
- public void run() {
- log.info("Timeout writing packet.");
- future.setValue(new TimeoutException());
- }
- }, timeout, unit);
+ ScheduledExecutorService executor = factoryManager.getScheduledExecutorService();
+ final ScheduledFuture<?> sched = executor.schedule(new Runnable() {
+ @SuppressWarnings("synthetic-access")
+ @Override
+ public void run() {
+ Throwable t = new TimeoutException("Timeout writing packet: " + timeout + " " + unit);
+ log.info(t.getMessage());
+ future.setValue(t);
+ }
+ }, timeout, unit);
future.addListener(new SshFutureListener<IoWriteFuture>() {
- @Override
- public void operationComplete(IoWriteFuture future) {
- sched.cancel(false);
- }
- });
+ @Override
+ public void operationComplete(IoWriteFuture future) {
+ sched.cancel(false);
+ }
+ });
return writeFuture;
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/AbstractOpenSSHExtensionParser.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/AbstractOpenSSHExtensionParser.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/AbstractOpenSSHExtensionParser.java
index c6905f5..d408e3b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/AbstractOpenSSHExtensionParser.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/openssh/AbstractOpenSSHExtensionParser.java
@@ -90,7 +90,7 @@ public abstract class AbstractOpenSSHExtensionParser extends AbstractParser<Open
try {
return getClass().cast(super.clone());
} catch(CloneNotSupportedException e) {
- throw new RuntimeException("Unexpected clone exception: " + e.getLocalizedMessage());
+ throw new RuntimeException("Unexpected clone exception " + toString() + ": " + e.getMessage());
}
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/common/util/io/FileInfoExtractor.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/FileInfoExtractor.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/FileInfoExtractor.java
new file mode 100644
index 0000000..56be141
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/io/FileInfoExtractor.java
@@ -0,0 +1,85 @@
+/*
+ * 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.util.io;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface FileInfoExtractor<T> {
+ T infoOf(Path file, LinkOption ... options) throws IOException;
+
+ FileInfoExtractor<Boolean> EXISTS = new FileInfoExtractor<Boolean>() {
+ @Override
+ public Boolean infoOf(Path file, LinkOption... options) throws IOException {
+ return Boolean.valueOf(Files.exists(file, options));
+ }
+ };
+
+ FileInfoExtractor<Boolean> ISDIR = new FileInfoExtractor<Boolean>() {
+ @Override
+ public Boolean infoOf(Path file, LinkOption... options) throws IOException {
+ return Boolean.valueOf(Files.isDirectory(file, options));
+ }
+ };
+
+ FileInfoExtractor<Boolean> ISREG = new FileInfoExtractor<Boolean>() {
+ @Override
+ public Boolean infoOf(Path file, LinkOption... options) throws IOException {
+ return Boolean.valueOf(Files.isRegularFile(file, options));
+ }
+ };
+
+ FileInfoExtractor<Boolean> ISSYMLINK = new FileInfoExtractor<Boolean>() {
+ @Override
+ public Boolean infoOf(Path file, LinkOption... options) throws IOException {
+ return Boolean.valueOf(Files.isSymbolicLink(file));
+ }
+ };
+
+ FileInfoExtractor<Long> SIZE = new FileInfoExtractor<Long>() {
+ @Override
+ public Long infoOf(Path file, LinkOption... options) throws IOException {
+ return Long.valueOf(Files.size(file));
+ }
+ };
+
+ FileInfoExtractor<Set<PosixFilePermission>> PERMISSIONS = new FileInfoExtractor<Set<PosixFilePermission>>() {
+ @Override
+ public Set<PosixFilePermission> infoOf(Path file, LinkOption... options) throws IOException {
+ return IoUtils.getPermissions(file, options);
+ }
+ };
+
+ FileInfoExtractor<FileTime> LASTMODIFIED = new FileInfoExtractor<FileTime>() {
+ @Override
+ public FileTime infoOf(Path file, LinkOption... options) throws IOException {
+ return Files.getLastModifiedTime(file, options);
+ }
+
+ };
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
index ebc6914..557af0a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/global/CancelTcpipForwardHandler.java
@@ -24,6 +24,7 @@ import org.apache.sshd.common.forward.TcpipForwarder;
import org.apache.sshd.common.session.ConnectionService;
import org.apache.sshd.common.session.ConnectionServiceRequestHandler;
import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.util.Int2IntFunction;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.logging.AbstractLoggingBean;
@@ -54,9 +55,15 @@ public class CancelTcpipForwardHandler extends AbstractLoggingBean implements Co
forwarder.localPortForwardingCancelled(socketAddress);
if (wantReply) {
- Session session = connectionService.getSession();
- buffer = session.createBuffer(SshConstants.SSH_MSG_REQUEST_SUCCESS);
+ buffer.clear();
+ // leave room for the SSH header
+ buffer.ensureCapacity(5 + 1 + (Integer.SIZE / Byte.SIZE), Int2IntFunction.Utils.add(Byte.SIZE));
+ buffer.rpos(5);
+ buffer.wpos(5);
+ buffer.putByte(SshConstants.SSH_MSG_REQUEST_SUCCESS);
buffer.putInt(port);
+
+ Session session = connectionService.getSession();
session.writePacket(buffer);
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d86de53/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java b/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
index 33d64b0..3f5dc4d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/global/TcpipForwardHandler.java
@@ -24,6 +24,7 @@ import org.apache.sshd.common.forward.TcpipForwarder;
import org.apache.sshd.common.session.ConnectionService;
import org.apache.sshd.common.session.ConnectionServiceRequestHandler;
import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.util.Int2IntFunction;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.logging.AbstractLoggingBean;
@@ -54,9 +55,15 @@ public class TcpipForwardHandler extends AbstractLoggingBean implements Connecti
port = bound.getPort();
if (wantReply){
- Session session = connectionService.getSession();
- buffer = session.createBuffer(SshConstants.SSH_MSG_REQUEST_SUCCESS);
+ buffer.clear();
+ // leave room for the SSH header
+ buffer.ensureCapacity(5 + 1 + (Integer.SIZE / Byte.SIZE), Int2IntFunction.Utils.add(Byte.SIZE));
+ buffer.rpos(5);
+ buffer.wpos(5);
+ buffer.putByte(SshConstants.SSH_MSG_REQUEST_SUCCESS);
buffer.putInt(port);
+
+ Session session = connectionService.getSession();
session.writePacket(buffer);
}
return Result.Replied;