Package net.schmizz.sshj.xfer.scp

Source Code of net.schmizz.sshj.xfer.scp.SCPEngine

/*
* Copyright 2010, 2011 sshj contributors
*
* Licensed 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 net.schmizz.sshj.xfer.scp;

import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.common.SSHException;
import net.schmizz.sshj.common.StreamCopier;
import net.schmizz.sshj.connection.channel.direct.Session.Command;
import net.schmizz.sshj.connection.channel.direct.SessionFactory;
import net.schmizz.sshj.xfer.TransferListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

/** @see <a href="http://blogs.sun.com/janp/entry/how_the_scp_protocol_works">SCP Protocol</a> */
class SCPEngine {

    static enum Arg {
        SOURCE('f'),
        SINK('t'),
        RECURSIVE('r'),
        VERBOSE('v'),
        PRESERVE_TIMES('p'),
        QUIET('q');

        private final char a;

        private Arg(char a) {
            this.a = a;
        }

        @Override
        public String toString() {
            return "-" + a;
        }
    }

    private static final String SCP_COMMAND = "scp";
    private static final char LF = '\n';

    private final Logger log = LoggerFactory.getLogger(getClass());

    private final SessionFactory host;
    private final TransferListener listener;

    private Command scp;
    private int exitStatus;

    SCPEngine(SessionFactory host, TransferListener listener) {
        this.host = host;
        this.listener = listener;
    }

    public int getExitStatus() {
        return exitStatus;
    }

    void check(String what)
            throws IOException {
        int code = scp.getInputStream().read();
        switch (code) {
            case -1:
                String stderr = IOUtils.readFully(scp.getErrorStream()).toString();
                if (!stderr.isEmpty())
                    stderr = ". Additional info: `" + stderr + "`";
                throw new SCPException("EOF while expecting response to protocol message" + stderr);
            case 0: // OK
                log.debug(what);
                return;
            case 1: // Warning? not
            case 2:
                throw new SCPException("Remote SCP command had error: " + readMessage());
            default:
                throw new SCPException("Received unknown response code");
        }
    }

    void cleanSlate() {
        exitStatus = -1;
    }

    void execSCPWith(List<Arg> args, String path)
            throws SSHException {
        final StringBuilder cmd = new StringBuilder(SCP_COMMAND);
        for (Arg arg : args)
            cmd.append(" ").append(arg);
        cmd.append(" ");
        if (path == null || path.isEmpty())
            cmd.append(".");
        else
            cmd.append("'").append(path.replaceAll("'", "\\'")).append("'");
        scp = host.startSession().exec(cmd.toString());
    }

    void exit() {
        if (scp != null) {

            IOUtils.closeQuietly(scp);

            if (scp.getExitStatus() != null) {
                exitStatus = scp.getExitStatus();
                if (scp.getExitStatus() != 0)
                    log.warn("SCP exit status: {}", scp.getExitStatus());
            } else
                exitStatus = -1;

            if (scp.getExitSignal() != null)
                log.warn("SCP exit signal: {}", scp.getExitSignal());
        }

        scp = null;
    }

    String readMessage()
            throws IOException {
        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int x;
        while ((x = scp.getInputStream().read()) != LF)
            if (x == -1) {
                if (baos.size() == 0)
                    return "";
                else
                    throw new IOException("EOF while reading message");
            } else
                baos.write(x);
        final String msg = baos.toString(IOUtils.UTF8.displayName());
        log.debug("Read message: `{}`", msg);
        return msg;
    }

    void sendMessage(String msg)
            throws IOException {
        log.debug("Sending message: {}", msg);
        scp.getOutputStream().write((msg + LF).getBytes(IOUtils.UTF8));
        scp.getOutputStream().flush();
        check("Message ACK received");
    }

    void signal(String what)
            throws IOException {
        log.debug("Signalling: {}", what);
        scp.getOutputStream().write(0);
        scp.getOutputStream().flush();
    }

    long transferToRemote(InputStream src, long length)
            throws IOException {
        return transfer(src, scp.getOutputStream(), scp.getRemoteMaxPacketSize(), length);
    }

    long transferFromRemote(OutputStream dest, long length)
            throws IOException {
        return transfer(scp.getInputStream(), dest, scp.getLocalMaxPacketSize(), length);
    }

    private long transfer(InputStream in, OutputStream out, int bufSize, long len)
            throws IOException {
        return new StreamCopier(in, out)
                .bufSize(bufSize).length(len)
                .keepFlushing(false)
                .listener(listener)
                .copy();
    }

    void startedDir(String dirname) {
        listener.startedDir(dirname);
    }

    void finishedDir() {
        listener.finishedDir();
    }

    void startedFile(String filename, long length) {
        listener.startedFile(filename, length);
    }

    void finishedFile() {
        listener.finishedFile();
    }

}
TOP

Related Classes of net.schmizz.sshj.xfer.scp.SCPEngine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.