/*
* A CCNx command line utility for managing prefix registrations.
*
* Copyright (C) 2009-2012 Palo Alto Research Center, Inc.
*
* This work is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the
* Free Software Foundation.
* This work 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 org.ccnx.ccn.utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Vector;
import java.util.logging.Level;
import org.ccnx.ccn.CCNHandle;
import org.ccnx.ccn.config.ConfigurationException;
import org.ccnx.ccn.impl.CCNNetworkManager;
import org.ccnx.ccn.impl.CCNNetworkManager.NetworkProtocol;
import org.ccnx.ccn.impl.support.Log;
import org.ccnx.ccn.profiles.ccnd.CCNDaemonException;
import org.ccnx.ccn.profiles.ccnd.FaceManager;
import org.ccnx.ccn.profiles.ccnd.PrefixRegistrationManager;
/**
* Java utility to
*
*/
public class ccndcontrol {
public static String _extraUsage = "";
public enum Command {Add, Delete};
public static class RegEntry {
public Command command;
public String uri;
public NetworkProtocol protocol;
public String host;
public String hostName;
public Integer port;
public Integer flags;
public Integer multicastTTL;
public String multicastInterface;
public Integer faceID;
public RegEntry() {}
}
private static Vector<RegEntry> regList = new Vector<RegEntry>(5);
private static boolean verbose = false;
private static void parseString(String in) {
String [] tokens = in.split("\\s");
parseFromTokens(tokens, 0, tokens.length);
}
private static void parseFromTokens(String [] tokens, int start, int nTokens) {
RegEntry entry = new ccndcontrol.RegEntry();
if (nTokens < 1) {
usage(_extraUsage);
System.exit(1);
}
String tmp = tokens[start];
if (null == tmp || tmp.length() == 0) {
System.err.println("Command token either null or of 0 length.");
usage(_extraUsage);
System.exit(1);
}
/******** add command **********/
if (tmp.equalsIgnoreCase("add")) {
entry.command = Command.Add;
if (nTokens < 3) {
usage(_extraUsage);
System.exit(1);
}
tmp = tokens[start + 1];
if (null == tmp || tmp.length() == 0) {
System.err.println("URI token either null or of 0 length.");
usage(_extraUsage);
System.exit(1);
}
entry.uri = tokens[start + 1];
tmp = tokens[start + 2];
if (null == tmp || tmp.length() == 0) {
System.err.println("Protocol token either null or of 0 length.");
usage(_extraUsage);
System.exit(1);
}
entry.protocol = null;
for (NetworkProtocol p : NetworkProtocol.values()) {
String pAsString = p.toString();
if (tmp.equalsIgnoreCase(pAsString)) {
entry.protocol = p;
break;
}
}
if (null == entry.protocol) {
System.err.println("Protocol (" + tmp + ") not valid.");
usage(_extraUsage);
System.exit(1);
}
tmp = tokens[start + 3];
if (null == tmp || tmp.length() == 0) {
System.err.println("Host name either null or of 0 length.");
usage(_extraUsage);
System.exit(1);
}
String hostNameNumeric = null;
try {
InetAddress ipAddr = InetAddress.getByName(tmp);
hostNameNumeric = ipAddr.getHostAddress();
} catch (UnknownHostException e) {
String reason = e.getMessage();
System.err.println("Host name (" + tmp + ") not found. reason: " + reason);
usage(_extraUsage);
System.exit(1);
}
entry.hostName = tmp;
entry.host = hostNameNumeric;
if (start + 4 < nTokens && null != tokens[start + 4]) {
try {
entry.port = Integer.valueOf(tokens[start + 4]);
} catch (NumberFormatException e) {
System.err.println("Port (" + tokens[start + 4] + ") not valid.");
usage(_extraUsage);
System.exit(1);
}
} else {
entry.port = CCNNetworkManager.DEFAULT_AGENT_PORT;
}
if (start + 5 < nTokens && null != tokens[start + 5]) {
try {
entry.flags = Integer.valueOf(tokens[start + 5]);
} catch (NumberFormatException e) {
System.err.println("Flags (" + tokens[start + 5] + ") not valid.");
usage(_extraUsage);
System.exit(1);
}
}
if (start + 6 < nTokens && null != tokens[start + 6]) {
try {
entry.multicastTTL = Integer.valueOf(tokens[start + 6]);
} catch (NumberFormatException e) {
System.err.println("Multicast TTL (" + tokens[start + 6] + ") not valid.");
usage(_extraUsage);
System.exit(1);
}
}
if (7 < nTokens && null != tokens[start + 7]) {
entry.multicastInterface = tokens[start + 7];
}
} /* add */
/******** delete command **********/
else if ((tmp.equalsIgnoreCase("delete") || tmp.equalsIgnoreCase("del"))) {
entry.command = Command.Delete;
if (nTokens < 1) {
System.err.println("Exiting because nTokens < 1 and command is " + tmp + "nTokens: " + nTokens);
usage(_extraUsage);
System.exit(1);
}
tmp = tokens[start + 1];
if (null == tmp || tmp.length() == 0) {
System.err.println("FaceID token either null or of 0 length.");
usage(_extraUsage);
System.exit(1);
}
try {
entry.faceID = Integer.valueOf(tmp);
} catch (NumberFormatException e) {
System.err.println("Face ID (" + tokens[start + 1] + ") not valid.");
usage(_extraUsage);
System.exit(1);
}
} /* del */
else {
System.err.println("Command (" + tmp + ") not valid.");
usage(_extraUsage);
System.exit(1);
}
regList.add(entry);
}
private static void processConfigFile(String configFile) {
Log.info("Processing configuration file " + configFile + ".");
File file = new File(configFile);
FileReader reader = null;
try {
reader = new FileReader(file);
} catch (FileNotFoundException e) {
Log.severe("Unable to find " + configFile + ".");
System.err.println("Unable to find " + configFile + ".");
System.exit(1);
}
BufferedReader read = new BufferedReader(reader);
String line = null;
try {
while ((line = read.readLine()) != null) {
Log.info("processConfigFile: parsing " + line);
if (line.charAt(0) == '#') {
continue;
}
parseString(line);
}
} catch (IOException e) {
Log.severe("IO Error (" + e.getMessage() + ") reading " + configFile + ".");
System.err.println("IO Error (" + e.getMessage() + ") reading " + configFile + ".");
System.exit(1);
}
}
/**
* Function to print out the options for ccndcontrol
*
* @returns void
*/
public static void usage(String extraUsage) {
/*
* fprintf(stderr,
"%s [-d] (-f configfile | (add|del) uri proto host [port [flags [mcastttl [mcastif]]]])\n"
" -d enter dynamic mode and create FIB entries based on DNS SRV records\n"
" -f configfile add or delete FIB entries based on contents of configfile\n"
" add|del add or delete FIB entry based on parameters\n",
progname);
*/
System.out.println("usage: ccndcontrol " + extraUsage + "[-v|-vv] add uri protocol host [port [flags [multicastTTL [multicastInterface]]]]\n" +
" ccndcontrol " + extraUsage + "[-v|-vv] del face_id\n" +
" ccndcontrol " + extraUsage + "[-v|-vv] -f configfile");
}
/**
*Utility function for the ccndcontrol tool. Initializes the tool,
* reads the argument list and constructs face to be added.
*
* @param args Command line arguments:
*
* @return void
*/
@SuppressWarnings("unused")
public static int executeCommand(String[] args) {
boolean dynamic = false;
String configFile = null;
int startArg = 0;
Level logLevel = Level.SEVERE;
verbose = false;
for (int i = 0; i < args.length; i++) {
if (i == 0 && args[0].startsWith("[")) {
_extraUsage = args[0];
startArg++;
} else if (args[i].equals("-h")) {
usage(_extraUsage);
return(-1);
} else if (args[i].equals(("-v"))) {
if (startArg <= i)
startArg = i + 1;
verbose = true;
logLevel = Level.INFO;
} else if (args[i].equals(("-vv"))) {
if (startArg <= i)
startArg = i + 1;
logLevel = Level.ALL;
} else if (args[i].equals(("-d"))) {
if (startArg <= i)
startArg = i + 1;
dynamic = true; // never read
} else if (args[i].equals("-f")) {
if (args.length < (i + 2)) {
usage(_extraUsage);
return(-1);
}
configFile = args[++i];
if (startArg <= i) {
startArg = i + 1;
}
}
}
Log.setDefaultLevel(logLevel);
if (null == configFile && args.length < startArg + 2) {
usage(_extraUsage);
return(-1);
}
if (null != configFile) {
processConfigFile(configFile);
} else {
parseFromTokens(args, startArg, args.length);
}
int nReg = regList.size();
for (int i = 0; i < nReg; i++) {
RegEntry entry = regList.get(i);
CCNHandle ccnHandle = null;
FaceManager fHandle = null;
Integer faceID = null;
try {
ccnHandle = CCNHandle.open();
fHandle = new FaceManager(ccnHandle);
if (entry.command == Command.Add) {
faceID = fHandle.createFace(entry.protocol, entry.host, entry.port);
if (verbose) {
System.out.println("Created face " + faceID.toString());
}
PrefixRegistrationManager pre = new PrefixRegistrationManager(ccnHandle);
pre.registerPrefix(entry.uri, faceID, entry.flags);
if (verbose) {
System.out.println("Added registration for " + entry.uri);
}
} else if (entry.command == Command.Delete) {
fHandle.deleteFace(entry.faceID);
if (verbose) {
System.out.println("Deleted face " + entry.faceID.toString() + " in local ccnd");
}
} else {
/* This really can't happen unless the check above was wrong. */
System.err.println("Internal error. command (" + entry.command + ") not add or del");
return(-1);
}
} catch (ConfigurationException e) {
String m = e.getMessage();
System.err.println(m);
return(-1);
} catch (IOException e) {
String m = e.getMessage();
System.err.println(m);
return(-1);
}catch (CCNDaemonException e) {
String m = e.getMessage();
System.err.println(m);
return(-1);
} finally {
if (ccnHandle != null) {
ccnHandle.close();
}
}
}
return(0);
}
/**
* Main function for the ccndcontrol tool.
* Calls executeCommand() to pass args for processing the command.
*
* @param args Command line arguments:
*
* @return void
*/
public static void main(String[] args) {
if (executeCommand(args) < 0) {
System.err.println("Error processing command, unable to complete");
System.exit(1);
} else {
System.out.println("Success");
System.exit(0);
}
}
}