package se.sics.gvod.ls.system; import java.beans.XMLDecoder; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.List; import org.apache.commons.cli.Option; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.sics.gvod.config.BaseCommandLineConfig; import se.sics.gvod.config.VodConfig; /** * * @author Niklas Wahlén <nwahlen@kth.se> */ public class LSConfig extends BaseCommandLineConfig { private static final Logger logger = LoggerFactory.getLogger(VodConfig.class); public static String STARTUP_CONFIG_FILE; // protected static StartupConfig startupConfig; private static List<String> argList; private static Option[] optArray; // Options protected Option seedOption; protected Option simulationOption; protected Option experimentIdOption; protected Option experimentIterationOption; protected Option sourceUrlOption; protected Option localHttpServerOption; protected Option inputFilenameOption; protected Option outputFilenameOption; protected Option monitorServerOption; protected Option sourceOption; // Option properties names (why public?) public static final String PROPERTY_SIMULATION_SET = "simulation.set"; public static final String PROPERTY_SOURCE = "source"; public static final String PROPERTY_SOURCE_URL_SET = "source.url.set"; public static final String PROPERTY_SOURCE_URL = "source.url"; public static final String PROPERTY_DEST_URL_SET = "local.http.server.set"; public static final String PROPERTY_DEST_IP = "local.http.server.ip"; public static final String PROPERTY_DEST_PORT = "local.http.server.port"; public static final String PROPERTY_INPUT_FILENAME_SET = "input.filename.set"; public static final String PROPERTY_INPUT_FILENAME = "input.filename"; public static final String PROPERTY_OUTPUT_FILENAME_SET = "output.filename.set"; public static final String PROPERTY_OUTPUT_FILENAME = "output.filename"; public static final String PROPERTY_MONITOR_SET = "monitor.set"; public static final String PROPERTY_MONITOR_SERVER_URL = "monitor.server.url"; public static final String PROPERTY_EXPERIMENT_ID = "experiment.id"; public static final String PROPERTY_EXPERIMENT_ITERATION = "experiment.iteration"; // Option properties default values // (if default set option is false default value doesn't matter) protected static final boolean DEFAULT_SIMULATION_SET = false; protected static final boolean DEFAULT_SOURCE = false; protected static final boolean DEFAULT_SOURCE_URL_SET = false; protected static final String DEFAULT_SOURCE_URL = "127.0.0.1:51120"; protected static final boolean DEFAULT_DEST_URL_SET = false; protected static final String DEFAULT_DEST_IP = "127.0.0.1"; protected static final int DEFAULT_DEST_PORT = 51121; protected static final boolean DEFAULT_INPUT_FILENAME_SET = false; protected static final String DEFAULT_INPUT_FILENAME = ""; protected static final boolean DEFAULT_OUTPUT_FILENAME_SET = false; protected static final String DEFAULT_OUTPUT_FILENAME = ""; protected static final boolean DEFAULT_MONITOR_SET = false; protected static final String DEFAULT_MONITOR_SERVER_URL = "127.0.0.1:8080/video"; protected static final int DEFAULT_EXPERIMENT_ID = 0; protected static final int DEFAULT_EXPERIMENT_ITERATION = 0; // Base public static final int BASE_CYCLE = 5 * 1000; // InterAS public static final int INTER_AS_SETS_EXCHANGE_PERIOD = BASE_CYCLE; public static final int INTER_AS_SETS_EXCHANGE_TIMEOUT = BASE_CYCLE; public static final int INTER_AS_MAX_NEIGHBOURS = 20; // Video public static final int VIDEO_WARMUP = 10; // to make sure source has connections public static final int VIDEO_CYCLE = BASE_CYCLE; // Video, neighbours public static final int VIDEO_MAX_OUT_CLOSE = 30;//10; public static final int VIDEO_MAX_OUT_RANDOM = 3; public static final int VIDEO_SOURCE_MAX_OUT_RANDOM = 5;//1; public static final int VIDEO_CLOSE_NEIGHBOUR_TIMEOUT = 10 * VIDEO_CYCLE; public static final int VIDEO_RANDOM_NEIGHBOUR_TIMEOUT = 10 * VIDEO_CYCLE; // Video, gossip public static final int VIDEO_PIECE_REQUEST_TIMEOUT = 3 * VIDEO_CYCLE; public static final int VIDEO_PIECE_REQUEST_TIMEOUT_MIN = 2 * VIDEO_CYCLE; public static final double VIDEO_PIECE_REQUEST_TIMEOUT_SCALE = 0.9; public static final int VIDEO_PIECE_REQUEST_RETRIES = 5; public static final int VIDEO_SOURCE_UPLOAD_CAPACITY = 5 * 5*14 * 1316; public static final int VIDEO_SOURCE_DEFAULT_FANOUT = 5; public static final int VIDEO_UPLOAD_CAPACITY = 5*2*14 * 1316; public static final int VIDEO_DEFAULT_FANOUT = 8; public static final int VIDEO_MAX_FANOUT = 20; public static final double VIDEO_MESSAGE_DROP_RATIO = 0.01; // Video, io, Forward Error Correction public static final int FEC_SUB_PIECES = 100; // sub-pieces per piece public static final int FEC_ENCODED_PIECES = 105; // sub-pieces plus extra pieces public static final int VIDEO_MAX_BUFFER_SIZE = VIDEO_PIECE_REQUEST_RETRIES * VIDEO_PIECE_REQUEST_TIMEOUT; // OVERLAY-ID RESERVATIONS public static final int SYSTEM_OVERLAY_ID = VodConfig.SYSTEM_OVERLAY_ID; // System-croupier public static final int STUN_OVERLAY_ID = 2; // stunClient, stunServer public static final int HP_OVERLAY_ID = 3; // hpClient, zServer, ParentMaker public static final int MONITOR_OVERLAY_ID = 4; // monitorClient, monitorServer // keep these high until resolved public static final int INTER_AS_OVERLAY_ID = 1005; public static final int VIDEO_OVERLAY_ID = 1006; protected LSConfig(String[] args) throws IOException { super(args); } public static final synchronized LSConfig init(String[] args) throws IOException { if (singleton != null) { return (LSConfig) singleton; } // XMLDecoder decoder = null; // try { // decoder = new XMLDecoder(new BufferedInputStream(new FileInputStream( // STARTUP_CONFIG_FILE)) // ) // ); // Object obj = decoder.readObject(); // if (obj == null) { // System.err.println("Configuration was null. Initializing new config."); // startupConfig = new StartupConfig(false, new VodAddressBean(), 0, 0); // } else { // startupConfig = (StartupConfig) obj; // } // } catch (FileNotFoundException e) { // logger.warn("No configuration found: " + STARTUP_CONFIG_FILE); // startupConfig = new StartupConfig(false, new VodAddressBean(), 0, 0); // } catch (Throwable e) { // logger.warn(e.toString()); // startupConfig = new StartupConfig(false, new VodAddressBean(), 0, 0); // } finally { // if (decoder != null) { // decoder.close(); // } // } singleton = new LSConfig(args); return (LSConfig) singleton; } @Override protected void parseAdditionalOptions(String[] args) throws IOException { // GENERAL seedOption = new Option("seed", true, "Random number seed"); seedOption.setArgName("number"); options.addOption(seedOption); // SIMULATION, EXPERIMENT simulationOption = new Option("sim", false, "Indicates simulation instance"); options.addOption(simulationOption); // video streaming source sourceOption = new Option("source", false, "This node is the streaming source for the video"); options.addOption(sourceOption); experimentIdOption = new Option("eid", true, "The unique identification number for this experiment"); experimentIdOption.setArgName("id"); options.addOption(experimentIdOption); experimentIterationOption = new Option("eit", true, "The iteration number of this experiment"); experimentIterationOption.setArgName("iteration"); options.addOption(experimentIterationOption); // HTTP Streaming sourceUrlOption = new Option("s", true, "URL to stream source"); sourceUrlOption.setArgName("ip[:port][path]"); options.addOption(sourceUrlOption); localHttpServerOption = new Option("d", true, "URL which to publish downloaded data to"); localHttpServerOption.setArgName("host[:port]"); options.addOption(localHttpServerOption); // File inputFilenameOption = new Option("i", true, "Path to the source file"); inputFilenameOption.setArgName("path"); options.addOption(inputFilenameOption); outputFilenameOption = new Option("o", true, "Path to output file destination"); outputFilenameOption.setArgName("path"); options.addOption(outputFilenameOption); // Monitoring monitorServerOption = new Option("m", true, "Turns on monitoring, data is sent to the specified location"); monitorServerOption.setArgName("host[:port][path]"); options.addOption(monitorServerOption); } @Override protected void processAdditionalOptions() throws IOException { /* * VALIDATION */ if (line.hasOption(sourceUrlOption.getOpt()) && line.hasOption(inputFilenameOption.getOpt())) { help(new String[]{""}, "It is not possible to use 2 data inputs" + " (" + sourceUrlOption.getOpt() + " " + line.getOptionValue(sourceUrlOption.getOpt()) + " " + inputFilenameOption.getOpt() + " " + line.getOptionValue(inputFilenameOption.getOpt()) + ")", options); } if (line.hasOption(simulationOption.getOpt())) { compositeConfig.setProperty(PROPERTY_SIMULATION_SET, true); } if (line.hasOption(sourceOption.getOpt())) { compositeConfig.setProperty(PROPERTY_SOURCE, true); } if (line.hasOption(experimentIdOption.getOpt())) { int id = Integer.parseInt(line.getOptionValue(experimentIdOption.getOpt())); compositeConfig.setProperty(PROPERTY_EXPERIMENT_ID, id); } if (line.hasOption(experimentIterationOption.getOpt())) { int iteration = Integer.parseInt(line.getOptionValue(experimentIterationOption.getOpt())); compositeConfig.setProperty(PROPERTY_EXPERIMENT_ITERATION, iteration); } /* * SOURCE HTTP SERVER */ if (line.hasOption(sourceUrlOption.getOpt())) { String url = line.getOptionValue(sourceUrlOption.getOpt()); String[] strs = url.split("[:/]"); // if (!validIPv4format(strs[0])) { // help(new String[]{""}, // sourceUrlOption.getOpt() + " " + strs[0] // + " is not a valid IPv4 address", options); // } if (url.contains(":") && strs.length > 1) { // if (!validSourcePort(strs[1])) { // help(new String[]{""}, sourceUrlOption.getOpt() // + " " + strs[1] // + " is not a valid port number", options); // } } // url = "http://" + url; compositeConfig.setProperty(PROPERTY_SOURCE_URL, url); compositeConfig.setProperty(PROPERTY_SOURCE_URL_SET, true); } /* * LOCAL HTTP SERVER */ if (line.hasOption(localHttpServerOption.getOpt())) { String url = line.getOptionValue(localHttpServerOption.getOpt()); String[] strs = url.split(":"); // if (!validIPv4format(strs[0])) { // help(new String[]{""}, localHttpServerOption.getOpt() // + " " + strs[0] // + " is not a valid IPv4 address", options); // } compositeConfig.setProperty(PROPERTY_DEST_IP, url); if (strs.length > 2) { // if (!validLocalPort(strs[1])) { // help(new String[]{""}, localHttpServerOption.getOpt() // + " " + strs[1] // + " is not a valid port number", options); // } compositeConfig.setProperty(PROPERTY_DEST_PORT, strs[2]); } compositeConfig.setProperty(PROPERTY_DEST_URL_SET, true); } /* * FILE */ if (line.hasOption(inputFilenameOption.getOpt())) { String path = line.getOptionValue(inputFilenameOption.getOpt()); if (!validLocalPath(path)) { help(new String[]{""}, inputFilenameOption.getOpt() + " " + path + " is not a valid local path", options); } compositeConfig.setProperty(PROPERTY_INPUT_FILENAME, path); compositeConfig.setProperty(PROPERTY_INPUT_FILENAME_SET, true); } if (line.hasOption(outputFilenameOption.getOpt())) { String path = line.getOptionValue(outputFilenameOption.getOpt()); if (!validLocalPath(path)) { help(new String[]{""}, outputFilenameOption.getOpt() + " " + path + " is not a valid local path", options); } compositeConfig.setProperty(PROPERTY_OUTPUT_FILENAME, path); compositeConfig.setProperty(PROPERTY_OUTPUT_FILENAME_SET, true); } /* * MONITORING */ if (line.hasOption(monitorServerOption.getOpt())) { String optValue = line.getOptionValue(monitorServerOption.getOpt()); compositeConfig.setProperty(PROPERTY_MONITOR_SERVER_URL, optValue); compositeConfig.setProperty(PROPERTY_MONITOR_SET, true); } argList = line.getArgList(); optArray = line.getOptions(); } public static boolean isSimulation() { baseInitialized(); return getCompositeConfiguration().getBoolean(PROPERTY_SIMULATION_SET, DEFAULT_SIMULATION_SET); } public static boolean isSource() { baseInitialized(); return getCompositeConfiguration().getBoolean(PROPERTY_SOURCE, DEFAULT_SOURCE); } public static int getExperimentId() { baseInitialized(); return getCompositeConfiguration().getInt(PROPERTY_EXPERIMENT_ID, DEFAULT_EXPERIMENT_ID); } public static int getExperimentIteration() { baseInitialized(); return getCompositeConfiguration().getInt(PROPERTY_EXPERIMENT_ITERATION, DEFAULT_EXPERIMENT_ITERATION); } public static boolean hasSourceUrlSet() { baseInitialized(); return getCompositeConfiguration().getBoolean(PROPERTY_SOURCE_URL_SET, DEFAULT_SOURCE_URL_SET); } public static String getSourceUrl() { baseInitialized(); return getCompositeConfiguration().getString(PROPERTY_SOURCE_URL, DEFAULT_SOURCE_URL); } public static boolean hasDestUrlSet() { baseInitialized(); return getCompositeConfiguration().getBoolean(PROPERTY_DEST_URL_SET, DEFAULT_DEST_URL_SET); } public static String getDestIp() { baseInitialized(); return getCompositeConfiguration().getString(PROPERTY_DEST_IP, DEFAULT_DEST_IP); } public static int getDestPort() { baseInitialized(); return getCompositeConfiguration().getInt(PROPERTY_DEST_PORT, DEFAULT_DEST_PORT); } public static boolean hasInputFileSet() { baseInitialized(); return getCompositeConfiguration().getBoolean(PROPERTY_INPUT_FILENAME_SET, DEFAULT_INPUT_FILENAME_SET); } public static String getInputFilename() { baseInitialized(); return getCompositeConfiguration().getString(PROPERTY_INPUT_FILENAME, DEFAULT_INPUT_FILENAME); } public static boolean hasOutputFileSet() { baseInitialized(); return getCompositeConfiguration().getBoolean(PROPERTY_OUTPUT_FILENAME_SET, DEFAULT_OUTPUT_FILENAME_SET); } public static String getOutputFilename() { baseInitialized(); return getCompositeConfiguration().getString(PROPERTY_OUTPUT_FILENAME, DEFAULT_OUTPUT_FILENAME); } public static boolean hasMonitorUrlSet() { baseInitialized(); return getCompositeConfiguration().getBoolean(PROPERTY_MONITOR_SET, DEFAULT_MONITOR_SET); } public static String getMonitorServerUrl() { baseInitialized(); return getCompositeConfiguration().getString(PROPERTY_MONITOR_SERVER_URL, DEFAULT_MONITOR_SERVER_URL); } /* * Misc help functions */ private boolean validLocalPath(String path) { if (path.contains(" ")) { return false; } return true; } private boolean validUrl(String url) { // TODO: check path String uri = url.split("/")[0]; return validUri(uri); } private boolean validUri(String uri) { String[] strs = uri.split(":"); if (strs.length > 1) { if (!validLocalPort(strs[1])) { return false; } } return validIPv4format(strs[0]); } private boolean validIPv4format(String ip) { // Validate IPv4 address format String[] strs = ip.split("\\."); if (strs.length != 4) { return false; } for (String str : strs) { int i = Integer.valueOf(str); if (i < 0 || i > 255) { return false; } } return true; } // Restrictions on the source port are lower than those on the local port, // as we are only responsible for initiating http service on the local private boolean validSourcePort(String port) { // does not currently check usage/availability Integer i = Integer.valueOf(port); if (i == 80 || (i > 1024 && i < 65535)) { return true; } return false; } private boolean validLocalPort(String port) { Integer i = Integer.valueOf(port); if (i > 1024 && i < 65535) { return true; } return false; } /* * Printing */ public static String getConfigString() { StringBuilder sb = new StringBuilder(); sb.append(" -- LSConfig --"); sb.append("\nvideo_home: ").append(GVOD_HOME); sb.append("\nseed: ").append(getSeed()); sb.append("\nisSimulation: ").append(isSimulation()); sb.append("\nisMonitoring: ").append(hasMonitorUrlSet()); if (hasMonitorUrlSet()) { sb.append("\n | monitorServerUrl: ").append(getMonitorServerUrl()); sb.append("\n | experimentId: ").append(getExperimentId()); sb.append("\n | experimentIteration: ").append(getExperimentIteration()); } sb.append("\nsourceUrlSet: ").append(hasSourceUrlSet()); if (hasSourceUrlSet()) { sb.append("\n | sourceUrl: ").append(getSourceUrl()); } sb.append("\nlocalHttpServerSet: ").append(hasDestUrlSet()); if (hasDestUrlSet()) { sb.append("\n | localHttpServerIp: ").append(getDestIp()); sb.append("\n | localHttpServerPort: ").append(getDestPort()); } sb.append("\ninputFileSet: ").append(hasInputFileSet()); if (hasInputFileSet()) { sb.append("\n | inputFilename: ").append(getInputFilename()); } sb.append("\noutputFileSet: ").append(hasOutputFileSet()); if (hasOutputFileSet()) { sb.append("\n | outputFilename: ").append(getOutputFilename()); } return sb.toString(); } public static String getCommandLineArgs() { baseInitialized(); StringBuilder sb = new StringBuilder(); for (Option o : optArray) { sb.append("-").append(o.getOpt()).append(" "); if (o.hasArg()) { sb.append(o.getValue()).append(" "); } } return sb.toString(); } }