/*
** SellaNMS
** $Id: icmp.h,v 1.15 2006/01/24 07:08:10 sella Exp $
** Copyright (c) 2001-2005 Digital Genesis Software, LLC. All Rights Reserved.
** Released under the GPL Version 2 License.
** http://www.digitalgenesis.com
*/

#ifndef __DGS_MONITOR_ICMP_H
#define __DGS_MONITOR_ICMP_H

#ifdef HAVE_CONFIG_H
	#include "config.h"
#endif

#include "defaults.h"
#include "common/util.h"
#include "common/netblock.h"
#include "storage/storagedata.h"
#include "state/state.h"
#include "policy_framework/policy_framework.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <stl/list>
#include <stl/queue>
#include <stl/list>
#include <stl/string>

#define MONITOR_TOS_DEF								0

#define MONITOR_ICMP_QUEUEDEPTH_DEF				4000
#define MONITOR_ICMP_QUEUEDEPTH_MIN				100
#define MONITOR_ICMP_QUEUEDEPTH_MAX				64000
#define MONITOR_ICMP_POLICYQUEUEDEPTH_MLT		4
#define MONITOR_ICMP_POLICYQUEUELIMIT_MIN		1
#define MONITOR_ICMP_POLICYQUEUELIMIT_MAX		MONITOR_ICMP_QUEUEDEPTH_MAX
#define MONITOR_ICMP_TRANSMIT_DEF				3
#define MONITOR_ICMP_TRANSMIT_MIN				1
#define MONITOR_ICMP_TRANSMIT_MAX				3600
#define MONITOR_ICMP_INTERVAL_DEF				60		// 60 sec
#define MONITOR_ICMP_INTERVAL_MIN				1		// 1 sec
#define MONITOR_ICMP_INTERVAL_MAX				21600	// 6 hours
#define MONITOR_ICMP_INTERVAL_ADJUST_DEF		5		// 5 sec
#define MONITOR_ICMP_INTERVAL_ADJUST_MIN		1		// 1 sec
#define MONITOR_ICMP_INTERVAL_ADJUST_MAX		(MONITOR_ICMP_INTERVAL_MAX / 2)
#define MONITOR_ICMP_CALCINTERVAL_DEF			(MONITOR_ICMP_INTERVAL_DEF / 2)
#define MONITOR_ICMP_CALCINTERVAL_MIN			MONITOR_ICMP_INTERVAL_MIN
#define MONITOR_ICMP_CALCINTERVAL_MAX			MONITOR_ICMP_INTERVAL_MAX
#define MONITOR_ICMP_CALCINTERVAL_ADJUST_DEF MONITOR_ICMP_INTERVAL_ADJUST_DEF
#define MONITOR_ICMP_CALCINTERVAL_ADJUST_MIN MONITOR_ICMP_INTERVAL_ADJUST_MIN
#define MONITOR_ICMP_CALCINTERVAL_ADJUST_MAX MONITOR_ICMP_INTERVAL_ADJUST_MAX
#define MONITOR_ICMP_QUEUELOWERTHRESHOLD_DEF 15
#define MONITOR_ICMP_QUEUELOWERTHRESHOLD_MIN 0
#define MONITOR_ICMP_QUEUELOWERTHRESHOLD_MAX 50
#define MONITOR_ICMP_QUEUEUPPERTHRESHOLD_DEF 75
#define MONITOR_ICMP_QUEUEUPPERTHRESHOLD_MIN 50
#define MONITOR_ICMP_QUEUEUPPERTHRESHOLD_MAX 100
#define MONITOR_ICMP_TIMEOUT_DEF					5000  // 5 sec
#define MONITOR_ICMP_TIMEOUT_MIN					100   // 100 ms
#define MONITOR_ICMP_TIMEOUT_MAX					60000	// 60 sec
#define MONITOR_ICMP_MAXNRM_DEF					10000000
#define MONITOR_ICMP_SEQUENCEMAXADJ_DEF		47
#define MONITOR_ICMP_PAYLOADMESSAGE_DEF		"SellaNMS - ICMP Monitor Module"
#define MONITOR_ICMP_SOURCE_DEF					""
#define MONITOR_ICMP_TOS_DEF						MONITOR_TOS_DEF
#define MONITOR_ICMP_TTL_DEF						IPDEFTTL
#define MONITOR_ICMP_TTL_MIN						1
#define MONITOR_ICMP_TTL_MAX						255

#define MONITOR_ICMP_LOSSSUPVAR_DEF				5
#define MONITOR_ICMP_RTTSUPVAR_DEF				30
#define MONITOR_ICMP_JTRSUPVAR_DEF				30
#define MONITOR_ICMP_NRMSUPVAR_DEF				30

#define FLAG_CALC_LOSS								(0x1 << 0)
#define FLAG_CALC_LTCY								(0x1 << 1)
#define FLAG_CALC_JTTR								(0x1 << 2)
#define FLAG_CALC_NORM								(0x1 << 3)
#define FLAG_CALC_TOSC								(0x1 << 4)

typedef struct icmp_payload {
	in_addr source;
	in_addr destination;
	u_int16_t sequence;
	timeval stamp;
	
	char message[36];
};

/* Calculation Thread's Queue (Used between recieve and calc thread) */
typedef struct _calc_queue_data_t {
	u_int32_t address;

	timeval timestamp;
	timeval rtt;

	int8_t type;
	int8_t code;

	u_int8_t tos;
} calc_queue_entry_t;
typedef queue<calc_queue_entry_t> calc_queue_t;

/* Policy Thread's Queue (Used between calc policy thread) */
typedef struct _policy_queue_entry_t {
	u_int32_t address;

	u_int32_t interval;

	char state[64];

	int8_t type;
	int8_t code;

	u_int8_t tos;

	int8_t loss; //Packet Loss percentage for interval.

	u_int16_t min_rtt; //Minimum RTT for interval.
	u_int16_t max_rtt; //Maximum RTT for interval.
	u_int16_t avg_rtt; //Average RTT for interval.

	u_int16_t min_jtr; //Minimum Jitter for interval.
	u_int16_t max_jtr; //Maximum Jitter for interval.
	u_int16_t avg_jtr; //Average Jitter for interval.

	u_int16_t nrm_rtt; //Normalized RTT (moving average)
	u_int16_t nrm_var_abs; //Normalized RTT variation from average abs(avg_rtt - nrm_rtt)
	u_int16_t nrm_var_inc; //Normalized RTT variation from average inc(avg_rtt - nrm_rtt)
	u_int16_t nrm_var_dec; //Normalized RTT variation from average dec(avg_rtt - nrm_rtt)
	u_int16_t nrm_per_abs; //Normalized RTT variation percentage abs(nrm_rtt/avg_rtt * 100)
	u_int16_t nrm_per_inc; //Normalized RTT variation percentage inc(nrm_rtt/avg_rtt * 100)
	u_int16_t nrm_per_dec; //Normalized RTT variation percentage dec(nrm_rtt/avg_rtt * 100)
} policy_queue_entry_t;
typedef queue<policy_queue_entry_t> policy_queue_t;

/* Calculation Thread's Internal Data Structure */
typedef struct _calc_data_entry_t {
	timeval timestamp;
	timeval rtt;

	int8_t type;
	int8_t code;

	u_int8_t tos;
} calc_data_entry_t;
typedef slist<calc_data_entry_t> calc_data_entry_list_t;
typedef hash_map<u_int32_t, pair<u_int32_t, u_int16_t> > nrm_rtt_hash_t;

typedef hash_map<u_int32_t, calc_data_entry_list_t> calc_data_t;
typedef hash_map<u_int32_t, hash_map<u_int32_t, policy_queue_entry_t> > calc_data_sup_t;

typedef struct _transmit_entry_t {
	u_int32_t address;

	u_int16_t sequence;
	timeval timestamp;
} transmit_entry_t;

typedef slist<transmit_entry_t> transmit_list_t;
typedef hash_map<pair<u_int32_t, int>, transmit_list_t::iterator, hash<pair<u_int32_t, int> > > transmit_hash_t;

class ICMP {
	public:
		ICMP();
		~ICMP();
		virtual RESULT execute();
		virtual RESULT readConfig();

	protected:
		RESULT transmitSleep(unsigned long t, unsigned long &accuracy);

		RESULT initPacket(char *packet, unsigned long size);
		RESULT transmitPacket(int s, char *packet, unsigned long size);
		RESULT watchNetwork(int s);
		RESULT calculateChecksum(char *packet, unsigned long size);

		RESULT pollTargets(int s, char *packet, timeval *interval);

		unsigned long	sleepIndex;
		unsigned long	sleepSample[8];	

	private:
		virtual void printConfig();

		static RESULT transmit_thread(void *args);
		static RESULT receive_thread(void *args);
		static RESULT timeout_thread(void *args);
		static RESULT policy_thread(void *args);
		static RESULT calc_queue_thread(void *args);
		static RESULT calculation_thread(void *args);
		static RESULT loadmon_thread(void* args);

		RESULT readKnownAddress(bool ignore_edge = false);

		RESULT calculate(slist<unsigned int> &interval_list);
		bool suppressDuplicate(const policy_queue_entry_t &policy_queue_entry);
		RESULT getPolicyIntervals(slist<unsigned int> &interval_list);
		RESULT setPolicyInputEventData(variable_binding_t *policy_input, char* event, unsigned long value);
		RESULT setPolicyInputTypeCode(variable_binding_t *policy_input, int8_t type, int8_t code);
		RESULT updateStatus();

		bool					ignoreEdge;
		bool					throttle;
		bool					suppression;

		uint32_t				source;
		string				payloadMessage;

		uint16_t				module_id;
		unsigned long		transmit;
		unsigned long		interval;
		unsigned long		intervalAdjust;
		struct timeval		timeout;

		calc_queue_t		calc_queue;
		policy_queue_t		policy_queue;
		pthread_mutex_t	calc_queue_mutex;
		pthread_mutex_t	policy_queue_mutex;

		calc_data_t			calc_data;
		calc_data_sup_t	calc_data_sup;
		pthread_mutex_t	calc_data_hash_mutex;
		pthread_mutex_t	calc_data_list_mutex;

		transmit_list_t	transmit_list;
		transmit_hash_t	transmit_hash;
		pthread_mutex_t	transmit_mutex;

		hash_map<u_int32_t, IPv4State *> state_hash;

		pthread_mutex_t	state_mutex;

		unsigned long calcQueueDepth;
		unsigned long policyQueueDepth;
		unsigned long calcInterval;
		unsigned long calcIntervalAdj;
		unsigned long calcFlags;
		unsigned long policyQueueLimit;
		unsigned long calcQueueLowerThreshold;
		unsigned long calcQueueUpperThreshold;
		unsigned long policyQueueLowerThreshold;
		unsigned long policyQueueUpperThreshold;
		unsigned long ttl;
		unsigned long lossSupVar;
		unsigned long rttSupVar;
		unsigned long jtrSupVar;
		unsigned long nrmSupVar;

		int				calc_flag[2];
		int				policy_flag[2];

		PolicyFramework inputPolicy;
		PolicyFramework outputPolicy;

		unsigned long tosDefault;	/* Stores default tos value. */
		hash_map<string, unsigned short int> tosMap; /* Stores non-default tos values. */

		vector<string> netblocks;
		unsigned long knownAddresses;
		unsigned long last_id;

		Storage storage;
};

#endif

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