/*
Copyright (c) 2000                      RIPE NCC


All Rights Reserved

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of the author not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.

THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

-------------------------------------------------------------------------------
Module Header
Filename          : common.c
Purpose           : Common functions used by all scripts of the application
Author            : Manuel Valente <manuel@ripe.net>
Date              : 20000510
Revised		  : 20021210 Florian Frotzler: added IPv6 compatibility 
Description       : 
Language Version  : gcc version 2.95.2
OSs Tested        : Solaris 2.6
Command Line      : 
Input Files       : 
Output Files      :
External Programs : mysqld
Problems          : 
To Do             :
Comments          :
-------------------------------------------------------------------------------
*/
static char const rcsid[] = "$Id: common.c,v 1.6 2004/03/10 18:04:33 wilhelm Exp $";
#include <math.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

#include "common.h"
#include "read_line.h"

/*
-------------------------------------------------------------------------------
Purpose           : Open MySQL connection
Params            : mysql handler
Returns           : 0
Comments          : Only works with the correct user ADMIN
*/
int open_admin_connection (MYSQL *mysql, char *mysql_host)
{
	/* Only the ADMIN login can use this function */
	if (getuid() != ADMIN_UID)
	{
		fprintf (stderr, "This program can only be run by ttraffic.\n");
		exit (1);
	};

	/* Initialize handler */
	mysql_init(mysql);

	/* Open connection */
	if (!mysql_real_connect(mysql,mysql_host,ADMIN_NAME_v4,ADMIN_PWD_v4,MYSQL_DB_v4,0,NULL,0))
	{
		fprintf(stderr, "Failed to connect to database: Error: %s\n",mysql_error(mysql));
		exit (1);
	};
	return (0); 
};

/*
-------------------------------------------------------------------------------
Purpose           : Open MySQL connection
Params            : mysql handler
Returns           : 0
Comments          : Only works with the correct user TTMV6ADM 
		    connects to IPv6 TTM database
*/
int open_admin_connection_ip6 (MYSQL *mysql, char *mysql_host)
{
        /* Only the ADMIN login can use this function */
        if (getuid() != ADMIN_UID)
        {
                fprintf (stderr, "This program can only be run by ttraffic.\n");
                exit (1);
        };

        /* Initialize handler */
        mysql_init(mysql);

        /* Open connection */
        if (!mysql_real_connect(mysql,mysql_host,ADMIN_NAME_v6,ADMIN_PWD_v6,MYSQL_DB_v6,0,NULL,0))
        {
                fprintf(stderr, "Failed to connect to database: Error: %s\n",mysql_error(mysql));
                exit (1);
        };
        return (0);
};


/*
-------------------------------------------------------------------------------
Purpose           : Open MySQL connection
Params            : mysql handler
Returns           : 0
Comments          :
*/
int open_user_connection (MYSQL *mysql, char *mysql_host)
{

	/* Initialize handler */
	mysql_init(mysql);

	/* Open connection */
	if (!mysql_real_connect(mysql,mysql_host,USER_NAME,USER_PWD,MYSQL_DB_v4,0,NULL,0))
	{
		fprintf(stderr, "Failed to connect to database: Error: %s\n",mysql_error(mysql));
		exit (1);
	};
	
	return (0); 
}


/*
-------------------------------------------------------------------------------
Purpose           : Open MySQL connection
Params            : mysql handler
Returns           : 0
Comments          : IPv6 counterpart to open_user_connection()
*/
int open_user_connection_ip6 (MYSQL *mysql, char *mysql_host)
{

        /* Initialize handler */
        mysql_init(mysql);

        /* Open connection */
        if (!mysql_real_connect(mysql,mysql_host,USER_NAME,USER_PWD,MYSQL_DB_v6,0,NULL,0))
        {
                fprintf(stderr, "Failed to connect to database: Error: %s\n",mysql_error(mysql));
                exit (1);
        };

        return (0);
}



/*
-------------------------------------------------------------------------------
Purpose           : Fill a hash with a Routes like table from the DB
Params            : mysql handle, routes hash, table name 
Returns           : 0
Comments          : Routes and ASpath table have similar layout
		    this routine can be used for both
*/
int get_table (MYSQL *mysql, GHashTable *hash, char* table)
{
	struct routestruct* rn;
	char query [1024];
	MYSQL_RES *result;
	MYSQL_ROW row;

	/* Select all routes from the DB */
	sprintf (query,"SELECT id,len,crc from %s",table);

	if (mysql_query(mysql,query))
	{
		fprintf(stderr, "Error: %s\n", mysql_error(mysql));
		exit (1);
	};   

	if (!(result = mysql_use_result(mysql)))
	{
		fprintf(stderr, "Error: %s\n", mysql_error(mysql));
		exit (1);
	};

	/* For each route */
	while ((row = mysql_fetch_row(result)))
	{
		/* Allocate memory to store the route */
		rn = malloc(sizeof(struct routestruct));

		/* Fill route with data from DB */
		rn->id  = atoi(row[0]);
		rn->len = atoi(row[1]);
		strcpy (rn->crc,row[2]);

		/* Store route in hash */
		g_hash_table_insert (hash,&rn->crc,rn);
	};

	mysql_free_result(result);

	return (0);
};

/*
-------------------------------------------------------------------------------
Purpose           : Fill a hash with the "Ranges" from TTM config
		    this hash will match IP addresses with Testbox IDs
Params            : ranges hash, path to LIST_OF_BOXES file, IP specific flag
Returns           : 0
Comments          : key = ip / value = id
                    ip6flag = 0: make hash with IPv4 testbox addresses
                    ip6flag = 1: make hash with IPv6 testbox addresses
*/
int get_ranges (GHashTable *ranges, char *path_boxes, int ip6flag)
{
	char *p;
	int id;
	char boxname [50];
	char cip [50];
	unsigned int ip;

	FILE *fd;

	int *key;
	int *val;
	char *ip6key;

	char buf [1024];
 
 	/* Open LIST_OF_BOXES file */
	if((fd = fopen(path_boxes,"rb")) == NULL)
	{
		fprintf(stderr, "Cannot open %s: %s\n", path_boxes, strerror(errno));
		exit (1);
	};

	/* Read file */
	while (!feof(fd))
	{
		if(fgets(buf, sizeof(buf), fd) == NULL) continue;
		buf[strlen(buf)-1] = '\0';

		/* Split the line in 3 tokens:
		id	boxname		ip */
		
		p = strtok (buf,"\t");
		id = atoi (p);

		p = strtok (NULL,"\t");
		strcpy (boxname,p);

		p = strtok (NULL,"\t");

                val = malloc (sizeof(int));
		*val = id;

		if ((strstr(p,":") != NULL) && (ip6flag)) {
			struct in6_addr v6addr;

			ip6key = (char * ) malloc (MAX_IP6_SIZE);

			/* shake forth and back, to arrive at standard ascii
			   representation, protect against mismatches due to
			   human vs. inet_ntop presentation */

			inet_pton(AF_INET6, p, &v6addr);
			inet_ntop(AF_INET6, &v6addr, ip6key, MAX_IP6_SIZE);

			g_hash_table_insert (ranges,ip6key,val);

		} else if ((strstr(p,":") == NULL) && (!ip6flag)) {

			strcpy (cip,p);
                	ip = rv_iptoint(cip);

			key = malloc (sizeof(int));

			/* Store the data in a hash */

			*key = ip;
			g_hash_table_insert (ranges,key,val);
		}

	};

	fclose (fd);

	return (0);
};

/*
-------------------------------------------------------------------------------
Purpose           : Fill a hash with the "Ranges" from TTM config
		    this hash will match Testbox names with Testbox IDs
Params            : ranges hash, path to LIST_OF_BOXES file
Returns           : 0
Comments          : key = boxname / value = id
*/
int get_ranges_by_boxname (GHashTable *ranges,char *path_boxes)
{
	char *p;
	int id;
	char boxname [256];	/* some domain names are looooong */

	FILE *fd;

	char* key;
	int *val;

	char buf [1024];
	
  	/* Open LIST_OF_BOXES file */
	if((fd = fopen(path_boxes,"rb")) == NULL)
	{
		fprintf(stderr, "Cannot open %s: %s\n", path_boxes, strerror(errno));
		exit (1);
	};

	/* Read file */
	while (!feof(fd))
	{
		if(fgets(buf, sizeof(buf), fd) == NULL) continue;
		buf[strlen(buf)-1] = '\0';
		
		/* Split the line in 3 tokens:
		id	boxname		ip */
		
		p = strtok (buf,"\t");
		id = atoi (p);

		p = strtok (NULL,"\t");
		strcpy (boxname,p);

		p = strtok (NULL,"\t");

		/* Store the data in a hash */

		val = malloc (sizeof(int));
	
		key = strdup(boxname);
		*val = id;

		g_hash_table_insert (ranges,key,val);

	};

	fclose (fd);

	return (0);
};


/*
-------------------------------------------------------------------------------
Purpose           : Return all the files that need to be processed
Params            : Path to read, files array
Returns           : Number of files
Comments          : Works on a list of directories
*/
int get_filenames_recursive (char *path, char **files)
{
	unsigned int i;
	char inpath[256];
	char filename[256];
	char buf[256];

	DIR *dir;
	struct dirent *dirhdl;

	DIR *indir;
	struct dirent *indirhdl;

	i = 0;

	/* Open directory */
	if (!(dir = opendir (path)))
	{
		printf ("Cannot open %s : %s\n",path,strerror(errno));
		exit(1);
	};

	/* Read Dir contents */
	while ((dirhdl = readdir (dir)))
	{
		/* Skip '.' and '..' */
		if ((strcmp (".",dirhdl->d_name)==0)||(strcmp("..",dirhdl->d_name)==0)) { continue; };
		sprintf (inpath,"%s%s/",path,dirhdl->d_name);

		/* Open subdir */
		if (!(indir = opendir (inpath)))
		{
			printf ("Cannot open %s : %s\n",inpath,strerror(errno));
			exit(1);
		}

		/* Read subdir contents */
		while ((indirhdl = readdir (indir)))
		{
			/* Skip '.' and '..' */
			if ((strcmp (".",indirhdl->d_name)==0)||(strcmp("..",indirhdl->d_name)==0)) {continue; };

			/* Skip if file does not start with RVEC */
			strncpy (buf,indirhdl->d_name,4);
			buf[4]='\0';
	
			if (!(strcmp ("RVEC",buf)==0)) { continue; };

			/* Store filename in files[] */
			sprintf (filename,"%s%s",inpath,indirhdl->d_name);

			files[i++] = strdup (filename);
	
		};
		closedir (indir);
	};
	closedir (dir);
	return (i);
};

/*
-------------------------------------------------------------------------------
Purpose           : Return all the files that need to be processed
Params            : Filename to read, files array
Returns           : Number of files
Comments          : gets either RVEC or RVEC6 files, depends on ip6flag  
*/
int get_filenames (char *path, char **files, int ip6flag)
{
	FILE *fd;
	char buf[512];
	int i;

	i = 0;

	/* Open file */
	if((fd = fopen(path,"rb")) == NULL)
	{
		fprintf(stderr, "Cannot open %s: %s\n", path, strerror(errno));
		exit (1);
	};

	while (!feof(fd))
	{
		if(fgets(buf, sizeof(buf), fd) == NULL) continue;

		buf[strlen(buf)-1] = '\0';

		/* Push filename in files[] */
		if ( (!ip6flag && (strstr(buf,"RVEC.") != NULL)) || 
		     (ip6flag && (strstr(buf,"RVEC6") != NULL)) ) {
			files[i++] = strdup (buf);
		}
	};

	fclose (fd);

	return (i);
};

/*
-------------------------------------------------------------------------------
Purpose           : Transform an IP quads route into integer route
Params            : IP quads route
Returns           : Integer route
Comments          : Returns " " if route is NULL
*/
char* route_ip_to_int (const char *route)
{
	char route_buffer [1024];
	char buffer [1024];
	unsigned int b;
	char *p;
	char str [30];
	char *lasts;
		
	if (strlen(route)==0) { return (" "); };
			
	strcpy (route_buffer,route);

	p = strtok_r (route_buffer," ",&lasts);

	strcpy (str,p);
			
	b = rv_iptoint(str);
	
	sprintf(buffer,"%u ",b);
		
	while ((p = strtok_r (NULL," ",&lasts)))
	{
		strcpy(str,p);
		b = rv_iptoint(str);
				
		sprintf (str,"%u ",b);
		
		strcat (buffer,str);
	};
		
	buffer[strlen(buffer)-1] = '\0';
	
	return strdup(buffer);
	
};
	
/*
-------------------------------------------------------------------------------
Purpose           : Transform an IP integer route into quads route
Params            : Integer route
Returns           : IP quads route
Comments          : Returns " " if route is NULL
*/
char* route_int_to_ip (const char *route)
{
	char route_buffer [1024];
	char buffer [1024];
	char *p;
	char str [30];
	char ip [30];
	char *lasts;
		
	if (strlen(route)==0) { return (" "); };
			
	strcpy (route_buffer,route);

	p = strtok_r (route_buffer," ",&lasts);

	strcpy (str,p);
			
	rv_inttoip((unsigned int) ATOUI(str),ip);
	
	sprintf(buffer,"%s ",ip);
		
	while ((p = strtok_r (NULL," ",&lasts)))
	{
		strcpy(str,p);
		rv_inttoip(ATOUI(str),ip);
				
		sprintf (str,"%s ",ip);
		
		strcat (buffer,str);
	};
		
	buffer[strlen(buffer)-1] = '\0';
	
	return strdup(buffer);
	
};
