PasvCommandHandler.java revision 4531116f8e675a208710e987bfe3b58faeb12db2
1/*
2 * Copyright 2007 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.mockftpserver.stub.command;
17
18import java.io.IOException;
19import java.net.InetAddress;
20
21
22import org.apache.log4j.Logger;
23import org.mockftpserver.core.command.Command;
24import org.mockftpserver.core.command.CommandHandler;
25import org.mockftpserver.core.command.InvocationRecord;
26import org.mockftpserver.core.command.ReplyCodes;
27import org.mockftpserver.core.session.Session;
28import org.mockftpserver.core.util.Assert;
29
30/**
31 * CommandHandler for the PASV (Passove Mode) command. Request the Session to switch to passive
32 * data connection mode. Return a reply code of 227, along with response text of the form:
33 * "<i>Entering Passive Mode. (h1,h2,h3,h4,p1,p2)</i>", where <i>h1..h4</i> are the 4
34 * bytes of the 32-bit internet host address of the server, and <i>p1..p2</i> are the 2
35 * bytes of the 16-bit TCP port address of the data connection on the server to which
36 * the client must connect. See RFC959 for more information.
37 * <p>
38 * Each invocation record stored by this CommandHandler contains no data elements.
39 *
40 * @version $Revision$ - $Date$
41 *
42 * @author Chris Mair
43 */
44public final class PasvCommandHandler extends AbstractStubCommandHandler implements CommandHandler {
45
46    private static final Logger LOG = Logger.getLogger(PasvCommandHandler.class);
47
48    /**
49     * Constructor. Initialize the replyCode.
50     */
51    public PasvCommandHandler() {
52        setReplyCode(ReplyCodes.PASV_OK);
53    }
54
55    /**
56     * @throws IOException
57     * @see org.mockftpserver.core.command.CommandHandler#handleCommand(Command, Session, InvocationRecord)
58     */
59    public void handleCommand(Command command, Session session, InvocationRecord invocationRecord)
60            throws IOException {
61
62        int port = session.switchToPassiveMode();
63        InetAddress server = session.getServerHost();
64
65        Assert.isTrue(port > -1, "The server-side port is invalid: " + port);
66        LOG.debug("server=" + server + " port=" + port);
67        String hostAndPort = "(" + convertHostAndPortToStringOfBytes(server, port) + ")";
68
69        sendReply(session, hostAndPort);
70    }
71
72    /**
73     * Convert the InetAddess and port number to a comma-delimited list of byte values,
74     * suitable for the response String from the PASV command.
75     * @param host - the InetAddress
76     * @param port - the port number
77     * @return the comma-delimited list of byte values, e.g., "196,168,44,55,23,77"
78     */
79    static String convertHostAndPortToStringOfBytes(InetAddress host, int port) {
80        StringBuffer buffer = new StringBuffer();
81        byte[] address = host.getAddress();
82        for (int i = 0; i < address.length; i++) {
83            int positiveValue = (address[i] >=0) ? address[i] : 256 + address[i];
84            buffer.append(positiveValue);
85            buffer.append(",");
86        }
87        int p1 = port >> 8;
88        int p2 = port % 256;
89        buffer.append(String.valueOf(p1));
90        buffer.append(",");
91        buffer.append(String.valueOf(p2));
92        return buffer.toString();
93    }
94
95}
96