/*
** SellaNMS
** $Id: monitor.cxx,v 2.50 2005/08/22 02:25:42 sella Exp $
** Copyright (c) 2001-2005 Digital Genesis Software, LLC. All Rights Reserved.
** Released under the GPL Version 2 License.
** http://www.digitalgenesis.com
*/

#include "monitor.h"
#include "debug.h"
#include "netblock.h"
#include "storagedata.h"
#include <stl/algorithm>

Monitor::Monitor():knownAddresses(0), tosDefault(MODULE_MONITOR_TOS_DEFAULT) {
	this->name.append(" monitor");

	has_scheduler = true;
	has_execute = false;
}

RESULT Monitor::handleTraceOptions() {
	/* Handle trace-options */
	if (trace.sql)
		storage.setDebug();

	if (trace.policy_sql) {
		inputPolicy.setDebug();
		outputPolicy.setDebug();
	}

	Module::handleTraceOptions();

	if (trace.policy_in && !inputPolicy.empty()) {
		if (trace.config) {
			inputPolicy.print();
		}
		inputPolicy.setTraceIn(true);
	}

	if (trace.policy_out && !outputPolicy.empty()) {
		if (trace.config) {
			outputPolicy.print();	
		}
		outputPolicy.setTraceOut(true);
	}

	return SUCCESS;
}

RESULT Monitor::readKnownAddress(bool ignore_edge = false) {
	ENTER(FLAG_TRACE_1, "RESULT Monitor::readKnownAddress()");

	RESULT result = FAILURE;
	string sql;
	vector<string>::iterator v_it;
	StorageData data;

	variable_binding_t	policy_input;
	variable_binding_t	policy_output;

	unsigned long id, tos_tmp;
	static unsigned long last_id = 0;

	/* Test for chagnes in IP dataset. */
	sql = "SELECT id FROM ip_data ORDER BY id DESC LIMIT 1";
	if (storage.queryf(data, sql.c_str()) != SUCCESS) {
		LMSG("WARNING: Select of largest IP id from database failed.");
	} else if (data.getNumRow() < 1) {
		result = SUCCESS;
		if (trace.debug) {
			LMSG("NOTICE: A discovery has not been complete. No prefixes available for '%s'", this->name.c_str());
			usleep(USLEEP_LONGLOOP_TIME);
		}
	} else {
		data.nextRow();
		data.getULong(id, "id");

		if (id == last_id) {
			result = SUCCESS;
		} else {
			last_id = id;

			if (trace.debug) {
				LMSG("Reading in new set of IP addresses for monitoring.");
			}

			/* Ignore edge interfaces */
			if (ignore_edge) {
				sql = "SELECT DISTINCT ip_data.value AS prefix FROM interface, interface_data, ip, ip_data, connection_point WHERE (interface.id = interface_data.interface AND interface.id = ip.interface AND ip.id = ip_data.ip AND ip.id = connection_point.point) AND interface_data.value = '1' AND interface_data.variable = '%s' AND ip_data.value NOT LIKE '0.%%' AND ip_data.variable = '%s' ORDER BY ip_data.value";
			} else {
				sql = "SELECT DISTINCT ip_data.value AS prefix FROM interface, interface_data, ip, ip_data WHERE (interface.id = interface_data.interface AND interface.id = ip.interface AND ip.id = ip_data.ip) AND interface_data.value = '1' AND interface_data.variable = '%s' AND ip_data.value NOT LIKE '0.%%' AND ip_data.variable = '%s' ORDER BY ip_data.value";
			}

			if (storage.queryf(data, sql.c_str(), ".1.3.6.1.2.1.2.2.1.7", ".1.3.6.1.2.1.4.20.1.1") != SUCCESS) {
				LMSG("WARNING: Select of prefix to monitor failed.");
			} else {
				/* Remove previous contents. */
				netblocks.clear();
				tosMap.clear();

				/* NOTE: This loop is slow when STLPort debugging is on. */
				while (data.nextRow()) {
					data.getString(policy_input["prefix"], "prefix");
					policy_input["prefix-except"] = policy_input["prefix"];

					if (this->inputPolicy.evaluate(policy_output, policy_input) != ACTION_REJECT) {
						netblocks.insert(netblocks.begin(), policy_output["prefix"]);

						/* Store all TOS values that are non-default. */
						if (policy_output.find("tos") != policy_output.end()) {
							tos_tmp = (u_int8_t) strtoul(policy_output["tos"].c_str(), NULL, 10);
							if (tos_tmp != tosDefault) {
								tosMap[policy_output["prefix"]] = tos_tmp;
								if (trace.debug) {
									LMSG("%s TOS value set to %lu (dscp: %lu, prec: %lu).", policy_output["prefix"].c_str(), tos_tmp, (u_int8_t) (tos_tmp >> 2), (u_int8_t) (tos_tmp >> 5));
								}
							}
						} else if (policy_output.find("dscp") != policy_output.end()) {
							tos_tmp = (u_int8_t) (strtoul(policy_output["dscp"].c_str(), NULL, 10) << 2);
							if (tos_tmp != tosDefault) {
								tosMap[policy_output["prefix"]] = tos_tmp;
								if (trace.debug) {
									LMSG("%s DSCP value set to %lu (%lu tos, prec: %lu).", policy_output["prefix"].c_str(), (u_int8_t) (tos_tmp >> 2), tos_tmp, (u_int8_t) (tos_tmp >> 5));
								}
							}
						} else if (policy_output.find("precedence") != policy_output.end()) {
						  	tos_tmp = (u_int8_t) (strtoul(policy_output["precedence"].c_str(), NULL, 10) << 5);
						  	if (tos_tmp != tosDefault) {
								tosMap[policy_output["prefix"]] = tos_tmp;
								if (trace.debug) {
									LMSG("%s precedence value set to %lu (tos: %lu, dscp: %lu).", policy_output["prefix"].c_str(), (u_int8_t) (tos_tmp >> 5), tos_tmp, (u_int8_t) (tos_tmp >> 2));
								}
							}
						}
					}
				}

				/* Remove duplicate IP addresses. */
				sort(netblocks.begin(), netblocks.end());
				v_it = unique(netblocks.begin(), netblocks.end());
				netblocks.erase(v_it, netblocks.end());

				/* Randomize to dispurse load across devices. */
				random_shuffle(netblocks.begin(), netblocks.end());

				this->knownAddresses = netblocks.size();

				if (this->trace.internal) {
					LMSG("netblocks.size() == %lu, tosMap.size() == %lu", this->knownAddresses, this->tosMap.size());
				}

				if ((this->knownAddresses < 1) && (this->trace.debug)) {
					LMSG("WARNING: No prefixes passed the policy. Verify your policy for '%s' is configured properly.", this->name.c_str());
				}


				result = SUCCESS;
			}
		}
	}

	RETURN(result);
}

/*
** Local Variables:
** c-basic-offset: 3
** tab-width: 3
** End:
** vim600: fdm=marker
** vim: noet ts=3 sw=3
*/
