com.jagornet.dhcpv6.client.TestClient.java Source code

Java tutorial

Introduction

Here is the source code for com.jagornet.dhcpv6.client.TestClient.java

Source

/*
 * Copyright 2009 Jagornet Technologies, LLC.  All Rights Reserved.
 *
 * This software is the proprietary information of Jagornet Technologies, LLC. 
 * Use is subject to license terms.
 *
 */

/*
 *   This file TestClient.java is part of DHCPv6.
 *
 *   DHCPv6 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 3 of the License, or
 *   (at your option) any later version.
 *
 *   DHCPv6 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 DHCPv6.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package com.jagornet.dhcpv6.client;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.future.IoFutureListener;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioDatagramConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jagornet.dhcpv6.message.DhcpMessage;
import com.jagornet.dhcpv6.message.DhcpMessageFactory;
import com.jagornet.dhcpv6.option.DhcpClientIdOption;
import com.jagornet.dhcpv6.option.DhcpElapsedTimeOption;
import com.jagornet.dhcpv6.option.DhcpUserClassOption;
import com.jagornet.dhcpv6.server.nio.DhcpDecoderAdapter;
import com.jagornet.dhcpv6.server.nio.DhcpEncoderAdapter;
import com.jagornet.dhcpv6.util.DhcpConstants;
import com.jagornet.dhcpv6.xml.ClientIdOption;
import com.jagornet.dhcpv6.xml.ElapsedTimeOption;
import com.jagornet.dhcpv6.xml.OpaqueData;
import com.jagornet.dhcpv6.xml.UserClassOption;

/**
 * A test client that just sends messages to a DHCPv6 server
 * via either unicast or multicast.
 * 
 * @author A. Gregory Rabil
 */
public class TestClient extends IoHandlerAdapter {
    /** The log. */
    private static Logger log = LoggerFactory.getLogger(TestClient.class);

    /** The options. */
    protected Options options = new Options();

    /** The parser. */
    protected CommandLineParser parser = new BasicParser();

    /** The formatter. */
    protected HelpFormatter formatter;

    /** The mcast net if. */
    protected NetworkInterface mcastNetIf = null;

    /** The server addr. */
    protected InetAddress serverAddr = DhcpConstants.LOCALHOST_V6;

    /** The server port. */
    protected int serverPort = DhcpConstants.SERVER_PORT;

    /** The client port. */
    protected int clientPort = DhcpConstants.CLIENT_PORT;

    /**
     * Instantiates a new test client.
     * 
     * @param args the args
     */
    public TestClient(String[] args) {
        setupOptions();

        if (!parseOptions(args)) {
            formatter = new HelpFormatter();
            String cliName = this.getClass().getName();
            formatter.printHelp(cliName, options);
            //            PrintWriter stderr = new PrintWriter(System.err, true);   // auto-flush=true
            //            formatter.printHelp(stderr, 80, cliName, null, options, 2, 2, null);
            System.exit(0);
        }

        try {
            if (mcastNetIf == null)
                start();
            else
                startMcast();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Setup options.
     */
    private void setupOptions() {
        Option addrOption = new Option("a", "address", true,
                "Address of DHCPv6 Server" + " [" + serverAddr.getHostAddress() + "]");
        options.addOption(addrOption);

        Option mcastOption = new Option("m", "multicast", true, "Multicast interface [none]");
        options.addOption(mcastOption);

        Option cpOption = new Option("cp", "clientport", true, "Client Port Number" + " [" + clientPort + "]");
        options.addOption(cpOption);

        Option spOption = new Option("sp", "serverport", true, "Server Port Number" + " [" + serverPort + "]");
        options.addOption(spOption);

        Option helpOption = new Option("?", "help", false, "Show this help page.");

        options.addOption(helpOption);
    }

    /**
     * Parses the options.
     * 
     * @param args the args
     * 
     * @return true, if successful
     */
    protected boolean parseOptions(String[] args) {
        try {
            CommandLine cmd = parser.parse(options, args);
            if (cmd.hasOption("?")) {
                return false;
            }
            if (cmd.hasOption("a")) {
                String a = cmd.getOptionValue("a");
                try {
                    serverAddr = InetAddress.getByName(a);
                } catch (UnknownHostException ex) {
                    serverAddr = DhcpConstants.LOCALHOST_V6;
                    System.err.println("Invalid address: '" + a + "' using default: " + serverAddr);
                }
            }
            if (cmd.hasOption("m")) {
                String m = cmd.getOptionValue("m");
                try {
                    mcastNetIf = NetworkInterface.getByName(m);
                } catch (SocketException ex) {
                    System.err.println("Invalid interface: " + m + " - " + ex);
                }
            }
            if (cmd.hasOption("cp")) {
                String p = cmd.getOptionValue("cp");
                try {
                    clientPort = Integer.parseInt(p);
                } catch (NumberFormatException ex) {
                    clientPort = DhcpConstants.CLIENT_PORT;
                    System.err.println("Invalid client port number: '" + p + "' using default: " + clientPort);
                }
            }
            if (cmd.hasOption("sp")) {
                String p = cmd.getOptionValue("sp");
                try {
                    serverPort = Integer.parseInt(p);
                } catch (NumberFormatException ex) {
                    serverPort = DhcpConstants.SERVER_PORT;
                    System.err.println("Invalid server port number: '" + p + "' using default: " + serverPort);
                }
            }
        } catch (ParseException pe) {
            System.err.println("Command line option parsing failure: " + pe);
            return false;
        }
        return true;
    }

    /**
     * Start.
     */
    public void start() {
        // pre-configure the message factory instance
        DhcpMessageFactory.setType(DhcpMessageFactory.Type.STATELESS_CLIENT);

        log.debug("Creating a datagram connector");
        IoConnector connector = new NioDatagramConnector();

        log.debug("Setting the handler");
        connector.setHandler(this);

        DefaultIoFilterChainBuilder chain = connector.getFilterChain();
        chain.addLast("logger", new LoggingFilter());

        ProtocolEncoder encoder = new DhcpEncoderAdapter();
        ProtocolDecoder decoder = new DhcpDecoderAdapter();
        chain.addLast("codec", new ProtocolCodecFilter(encoder, decoder));

        log.debug("About to connect to the server...");
        ConnectFuture connFuture = connector.connect(new InetSocketAddress(serverAddr, serverPort));

        log.debug("About to wait.");
        connFuture.awaitUninterruptibly();

        log.debug("Adding a future listener.");
        connFuture.addListener(new IoFutureListener<ConnectFuture>() {
            public void operationComplete(ConnectFuture future) {
                if (future.isConnected()) {
                    log.debug("...connected");
                    IoSession session = future.getSession();
                    List<DhcpMessage> msgs = buildRequestMessages();
                    for (DhcpMessage msg : msgs) {
                        // write the message, the codec will convert it
                        // to wire format... well, hopefully it will!
                        session.write(msg);
                    }
                    System.exit(0);
                } else {
                    log.error("Not connected...exiting");
                }
            }
        });
    }

    /**
     * Start mcast.
     * 
     * @throws IOException Signals that an I/O exception has occurred.
     * @throws SocketException the socket exception
     */
    public void startMcast() throws IOException, SocketException {
        MulticastSocket msock = new MulticastSocket(new InetSocketAddress(clientPort));
        msock.setNetworkInterface(mcastNetIf);

        // override any serverAddr to be the All_Servers_and_Relays multicast address
        serverAddr = InetAddress.getByName("FF02::1:2");

        List<DhcpMessage> msgs = buildRequestMessages();
        for (DhcpMessage msg : msgs) {
            byte[] buf = msg.encode().array();
            DatagramPacket packet = new DatagramPacket(buf, buf.length);
            packet.setAddress(msg.getRemoteAddress().getAddress());
            packet.setPort(msg.getRemoteAddress().getPort());
            msock.send(packet);
        }
        System.exit(0);
    }

    /**
     * Builds the request messages.
     * 
     * @return the list< dhcp message>
     */
    private List<DhcpMessage> buildRequestMessages() {
        List<DhcpMessage> msgs = new ArrayList<DhcpMessage>();
        for (int id = 0; id < 100; id++) {
            DhcpMessage msg = new DhcpMessage(null, new InetSocketAddress(serverAddr, serverPort));

            msg.setMessageType(DhcpConstants.INFO_REQUEST);
            msg.setTransactionId(id);
            byte[] clientIdBytes = { (byte) 0xde, (byte) 0xbd, (byte) 0xeb, (byte) 0xde, (byte) 0xb0, (byte) id };
            OpaqueData opaque = OpaqueData.Factory.newInstance();
            opaque.setHexValue(clientIdBytes);

            ClientIdOption clientIdOption = ClientIdOption.Factory.newInstance();
            clientIdOption.setOpaqueData(opaque);

            msg.setOption(new DhcpClientIdOption(clientIdOption));

            ElapsedTimeOption elapsedTimeOption = ElapsedTimeOption.Factory.newInstance();
            elapsedTimeOption.setUnsignedShort(id + 1000);
            msg.setOption(new DhcpElapsedTimeOption(elapsedTimeOption));

            UserClassOption userClassOption = UserClassOption.Factory.newInstance();
            // wrap it with the DhcpOption subclass to get at
            // utility method for adding userclass string
            DhcpUserClassOption dhcpUserClassOption = new DhcpUserClassOption(userClassOption);
            dhcpUserClassOption.addOpaqueData("FilterUserClass");
            msg.setOption(dhcpUserClassOption);

            msgs.add(msg);
        }
        return msgs;
    }

    /* (non-Javadoc)
     * @see org.apache.mina.core.service.IoHandlerAdapter#exceptionCaught(org.apache.mina.core.session.IoSession, java.lang.Throwable)
     */
    @Override
    public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
        cause.printStackTrace();
    }

    /* (non-Javadoc)
     * @see org.apache.mina.core.service.IoHandlerAdapter#messageReceived(org.apache.mina.core.session.IoSession, java.lang.Object)
     */
    @Override
    public void messageReceived(IoSession session, Object message) throws Exception {
        log.debug("Session recv...");
    }

    /* (non-Javadoc)
     * @see org.apache.mina.core.service.IoHandlerAdapter#messageSent(org.apache.mina.core.session.IoSession, java.lang.Object)
     */
    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        log.debug("Message sent...");
    }

    /* (non-Javadoc)
     * @see org.apache.mina.core.service.IoHandlerAdapter#sessionClosed(org.apache.mina.core.session.IoSession)
     */
    @Override
    public void sessionClosed(IoSession session) throws Exception {
        log.debug("Session closed...");
    }

    /* (non-Javadoc)
     * @see org.apache.mina.core.service.IoHandlerAdapter#sessionCreated(org.apache.mina.core.session.IoSession)
     */
    @Override
    public void sessionCreated(IoSession session) throws Exception {
        log.debug("Session created...");
    }

    /* (non-Javadoc)
     * @see org.apache.mina.core.service.IoHandlerAdapter#sessionIdle(org.apache.mina.core.session.IoSession, org.apache.mina.core.session.IdleStatus)
     */
    @Override
    public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
        log.debug("Session idle...");
    }

    /* (non-Javadoc)
     * @see org.apache.mina.core.service.IoHandlerAdapter#sessionOpened(org.apache.mina.core.session.IoSession)
     */
    @Override
    public void sessionOpened(IoSession session) throws Exception {
        log.debug("Session opened...");
    }

    /**
     * The main method.
     * 
     * @param args the arguments
     */
    public static void main(String[] args) {
        new TestClient(args);
    }

}