Package ds.pjftp.main

Source Code of ds.pjftp.main.ServerDTP

/*
* pjftp FTP server.
* Copyright (C) 2012 Dmitriy Simbiriatin <dmitriy.simbiriatin@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package ds.pjftp.main;

import ds.pjftp.utils.NotNull;

import ds.pjftp.representation.Representations;
import ds.pjftp.transmission.TransmissionMode;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.InputStream;
import java.io.OutputStream;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

import java.nio.file.Path;
import java.nio.file.Files;
import java.nio.file.DirectoryStream;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.BasicFileAttributes;

import ds.pjftp.transmission.TransmissionModes;
import ds.pjftp.utils.IOUtils;
import ds.pjftp.utils.PassivePort;
import ds.pjftp.utils.DateUtils;
import ds.pjftp.representation.Representation;

import static ds.pjftp.utils.IOUtils.NEW_LINE;
import static java.nio.file.StandardOpenOption.READ;
import static java.nio.file.StandardOpenOption.WRITE;
import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;

/**
* This class handles file transfer.
*/
public class ServerDTP {

    /**
     * Connection timeout in passive mode (10 seconds).
     */
    public static final int PASV_TIMEOUT = 10000;

    /**
     * Default size for buffer, that holds info about the file.
     */
    public static final int FILE_INFO_BUF = 100;

    /**
     * Client data socket.
     */
    private Socket dataClient;

    /**
     * Server data socket.
     */
    private ServerSocket dataServer;

    /**
     * Address of data socket.
     */
    private InetSocketAddress addr;

    /**
     * DTP representation. By default Image representation is used.
     */
    private Representation representation = Representations.get('A');

    /**
     * Transmission mode used in DTP. By default Stream mode is used.
     */
    private TransmissionMode transmissionMode = TransmissionModes.get('S');

    /**
     * Client's session in which DTP works.
     */
    private final ClientSession session;

    /**
     * Constructs ServerDTP object.
     * @param session client session.
     */
    public ServerDTP(@NotNull final ClientSession session) {
        this.session = session;
    }

    /**
     * Changes address of data socket.
     * @param addr new address.
     */
    public void setInetAddr(final InetSocketAddress addr) {
        this.addr = addr;
    }

    /**
     * Returns an address of data socket.
     * @return an address of data socket.
     */
    public InetSocketAddress getInetAddr() {
        return addr;
    }

    /**
     * Changes current transmission mode of DTP server.
     * @param transmissionMode new transmission mode.
     */
    public void setTransmissionMode(final TransmissionMode transmissionMode) {
        this.transmissionMode = transmissionMode;
    }

    /**
     * Returns current representation.
     * @return current representation.
     */
    public Representation getRepresentation() {
        return representation;
    }

    /**
     * Changes current representation of DTP server.
     * @param representation new representation.
     */
    public void setRepresentation(final Representation representation) {
        this.representation = representation;
    }

    /**
     * Generates address for data socket. Used in passive mode.
     * Searches for available port, where data socket can be connected.
     * @return address, which can be used for connection.
     */
    public InetSocketAddress genInetAddr() {

        try {
            final int port = PassivePort.getAvailable();
            if (port == -1) {
                return null;
            }
            final InetAddress addr = InetAddress.getLocalHost();
            return new InetSocketAddress(addr, port);
        } catch (UnknownHostException ex) {
            return null;
        }
    }

    /**
     * Initiates data connection in active mode.
     */
    public void initActiveConnection() throws IOException {
        dataClient = new Socket(addr.getAddress(), addr.getPort());
    }

    /**
     * Initiates data connection in passive mode.
     */
    public void initPassiveConnection() throws IOException {

        dataServer = new ServerSocket(addr.getPort());
        dataServer.setSoTimeout(PASV_TIMEOUT);
    }

    /**
     * Opens data connection.
     */
    public void openConnection() throws IOException {

        session.replyWithSpace(150, "Opening connection in {} mode",
                representation);

        // We've initiated passive connection.
        if (dataClient == null) {
            dataClient = dataServer.accept();
        }
    }

    /**
     * Closes all opened data sockets.
     */
    public void closeConnection() {

        session.replyWithSpace(226, "Closing data connection");

        IOUtils.close(dataServer);
        IOUtils.close(dataClient);

        addr = null;
        dataServer = null;
        dataClient = null;
    }

    /**
     * Sends specified file to a client.
     * @param file file to be send.
     * @throws IOException if failed to send the file.
     */
    public void sendFile(@NotNull final Path file) throws IOException {

        try (InputStream input = Files.newInputStream(file, READ)) {
            transmissionMode.send(input, dataClient);
        }
    }

    /**
     * Receives file from client.
     * @param file place, where file should be saved.
     * @throws IOException if failed to receive the file.
     */
    public void receiveFile(@NotNull final Path file) throws IOException {

        try (OutputStream output = Files.newOutputStream(file, CREATE, WRITE)) {
            transmissionMode.receive(dataClient, output);
        }
    }

    /**
     * Lists files, available in specified directory. (prints only file names without additional information).
     * @param path directory to be listed.
     * @throws IOException if failed to list the files.
     */
    public void listFiles(@NotNull final Path path) throws IOException {

        final OutputStream output = representation.getOutputStream(dataClient);
        try (PrintWriter writer = IOUtils.getWriter(output)) {
            try (DirectoryStream<Path> dir = Files.newDirectoryStream(path)) {
                for (Path file : dir) {
                    final String name = file.getFileName().toString();
                    writer.print(name + NEW_LINE);
                    writer.flush();
                }
            }
        }
    }

    /**
     * Lists files, available in specified directory (prints detailed info for each file).
     * @param path directory to be listed.
     * @throws IOException if failed to list the files.
     */
    public void listFilesWithInfo(@NotNull final Path path) throws IOException {

        final OutputStream output = representation.getOutputStream(dataClient);
        try (PrintWriter writer = IOUtils.getWriter(output)) {
            // Specified parameter can be a directory or just a file.
            // We gonna check this.
            if (Files.isDirectory(path, NOFOLLOW_LINKS)) {
                // Listing files in the directory.
                try (DirectoryStream<Path> dir = Files.newDirectoryStream(path)) {
                    for (Path file : dir) {
                        listFile(file, writer);
                    }
                    writer.flush();
                }
            } else {
                // Listing info just for the specified file.
                listFile(path, writer);
                writer.flush();
            }
        }
    }

    /**
     * Prints detailed information for specified file.
     */
    private void listFile(@NotNull final Path path, @NotNull final PrintWriter writer) throws IOException {

        final BasicFileAttributeView view = Files.getFileAttributeView(
                path, BasicFileAttributeView.class);

        final BasicFileAttributes attrs = view.readAttributes();
        final String timeStr = DateUtils.format(attrs.lastModifiedTime());

        // As not all the file systems support POSIX file permissions,
        // we don't try to retrieve them + retrieving such information
        // for each file, can entail performance degradation.
        final StringBuilder infoStr = new StringBuilder(FILE_INFO_BUF);

        infoStr.append(attrs.isDirectory() ? 'd' : '-');
        infoStr.append("rwxrwxrwx 0 ftp ftp       ");
        infoStr.append(attrs.size());
        infoStr.append(' ');
        infoStr.append(timeStr);
        infoStr.append(' ');
        infoStr.append(path.getFileName());
        infoStr.append(NEW_LINE);
        writer.print(infoStr.toString());
    }
}
TOP

Related Classes of ds.pjftp.main.ServerDTP

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.