1e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair/* 2e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * Copyright 2007 the original author or authors. 3e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * 4e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * Licensed under the Apache License, Version 2.0 (the "License"); 5e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * you may not use this file except in compliance with the License. 6e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * You may obtain a copy of the License at 7e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * 8e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * http://www.apache.org/licenses/LICENSE-2.0 9e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * 10e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * Unless required by applicable law or agreed to in writing, software 11e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * distributed under the License is distributed on an "AS IS" BASIS, 12e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * See the License for the specific language governing permissions and 14e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * limitations under the License. 15e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair */ 16e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismairpackage org.mockftpserver.stub.command; 17e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 18e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismairimport java.net.InetAddress; 19e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismairimport java.net.UnknownHostException; 20e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismairimport java.util.Arrays; 21e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 22e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismairimport org.apache.log4j.Logger; 23e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismairimport org.mockftpserver.core.command.Command; 24e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismairimport org.mockftpserver.core.command.CommandHandler; 25e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismairimport org.mockftpserver.core.command.InvocationRecord; 26e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismairimport org.mockftpserver.core.command.ReplyCodes; 27e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismairimport org.mockftpserver.core.session.Session; 28e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismairimport org.mockftpserver.core.util.Assert; 29e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismairimport org.mockftpserver.core.util.AssertFailedException; 30e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 31e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair/** 32e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * CommandHandler for the PORT command. Send back a reply code of 200. 33e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * <p> 34e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * Each invocation record stored by this CommandHandler includes the following data element key/values: 35e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * <ul> 36e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * <li>{@link #HOST_KEY} ("host") - the client data host (InetAddress) submitted on the invocation (from parameters 1-4) 37e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * <li>{@link #PORT_KEY} ("port") - the port number (Integer) submitted on the invocation (from parameter 5-6) 38e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * </ul> 39e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * 40e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @version $Revision$ - $Date$ 41e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * 42e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @author Chris Mair 43e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair */ 44e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismairpublic final class PortCommandHandler extends AbstractStubCommandHandler implements CommandHandler { 45e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 46e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair public static final String HOST_KEY = "host"; 47e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair public static final String PORT_KEY = "port"; 48e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair private static final Logger LOG = Logger.getLogger(PortCommandHandler.class); 49e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 50e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair /** 51e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * Constructor. Initialize the replyCode. 52e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair */ 53e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair public PortCommandHandler() { 54e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair setReplyCode(ReplyCodes.PORT_OK); 55e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair } 56e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 57e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair /** 58e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @throws UnknownHostException 59e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @throws UnknownHostException 60e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @see org.mockftpserver.core.command.CommandHandler#handleCommand(Command, Session, InvocationRecord) 61e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair */ 62e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair public void handleCommand(Command command, Session session, InvocationRecord invocationRecord) throws UnknownHostException { 63e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair InetAddress host = parseHost(command.getParameters()); 64e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair int port = parsePortNumber(command.getParameters()); 65e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair LOG.debug("host=" + host + " port=" + port); 66e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair session.setClientDataHost(host); 67e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair session.setClientDataPort(port); 68e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair invocationRecord.set(HOST_KEY, host); 69e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair invocationRecord.set(PORT_KEY, new Integer(port)); 70e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair sendReply(session); 71e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair } 72e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 73e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair /** 74e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * Parse a 32-bit IP address from the String[] of FTP command parameters. 75e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * 76e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @param parameters - the String[] of command parameters. It is the concatenation 77e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * of a 32-bit internet host address and a 16-bit TCP port address. This address 78e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * information is broken into 8-bit fields and the value of each field is encoded 79e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * as a separate parameter whose value is a decimal number (in character string 80e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * representation). Thus, the six parameters for the port command would be: 81e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * h1,h2,h3,h4,p1,p2 82e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * where h1 is the high order 8 bits of the internet host address, and p1 is the 83e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * high order 8 bits of the port number. 84e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * 85e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @return the InetAddres representing the host parsed from the parameters 86e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * 87e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @throws AssertFailedException - if parameters is null or contains an insufficient number of elements 88e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @throws NumberFormatException - if one of the parameters does not contain a parsable integer 89e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @throws UnknownHostException 90e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair */ 91e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair static InetAddress parseHost(String[] parameters) throws UnknownHostException { 92e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair verifySufficientParameters(parameters); 93e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 94e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair byte host1 = Byte.parseByte(parameters[0]); 95e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair byte host2 = Byte.parseByte(parameters[1]); 96e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair byte host3 = Byte.parseByte(parameters[2]); 97e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair byte host4 = Byte.parseByte(parameters[3]); 98e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 99e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair byte[] address = { host1, host2, host3, host4 }; 100e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair InetAddress inetAddress = InetAddress.getByAddress(address); 101e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 102e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair return inetAddress; 103e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair } 104e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 105e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair /** 106e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * Parse a 16-bit port number from the String[] of FTP command parameters. 107e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * 108e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @param parameters - the String[] of command parameters. It is the concatenation 109e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * of a 32-bit internet host address and a 16-bit TCP port address. This address 110e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * information is broken into 8-bit fields and the value of each field is encoded 111e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * as a separate parameter whose value is a decimal number (in character string 112e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * representation). Thus, the six parameters for the port command would be: 113e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * h1,h2,h3,h4,p1,p2 114e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * where h1 is the high order 8 bits of the internet host address, and p1 is the 115e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * high order 8 bits of the port number. 116e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * 117e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @return the port number parsed from the parameters 118e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * 119e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @throws AssertFailedException - if parameters is null or contains an insufficient number of elements 120e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @throws NumberFormatException - if one of the parameters does not contain a parsable integer 121e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair */ 122e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair static int parsePortNumber(String[] parameters) { 123e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair verifySufficientParameters(parameters); 124e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 125e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair int port1 = Integer.parseInt(parameters[4]); 126e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair int port2 = Integer.parseInt(parameters[5]); 127e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair int port = (port1 << 8) + port2; 128e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 129e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair return port; 130e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair } 131e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 132e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair /** 133e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * Verify that the parameters is not null and contains the required number of elements 134e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @param parameters - the String[] of command parameters 135e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair * @throws AssertFailedException - if parameters is null or contains an insufficient number of elements 136e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair */ 137e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair private static void verifySufficientParameters(String[] parameters) { 138e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair Assert.notNull(parameters, "parameters"); 139e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair Assert.isTrue(parameters.length >= 6, "The PORT command must contain least be 6 parameters: " + Arrays.asList(parameters)); 140e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair } 141e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair 142e47352fb2508e2b25f003b8df12fa79c3215b4b1chrismair} 143