/*
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          : routequery.c
Purpose           : Query the Test Traffic traceroute DB for a route
Author            : Manuel Valente <manuel@ripe.net>
Date              : 20000719
Revised           : 20020814 Rene Wilhelm: added AS path information
Revised		  : 20021210 Florian Frotzler: added code to query IPv6 data
Description       : 
Language Version  : gcc version 2.95.2
OSs Tested        : Solaris 2.6, Solaris 8 and Linux
Command Line      : routequery [-6] <source> <destination> <starttime> <endtime>
Note		  : The program will query EITHER ipv4 OR ipv6 data, not both
	            source & destination are fully qualified hostnames
		    starttime/endttime are UNIX time_t timestamps
Output 		  : information retrieved from TTM DB in ASCII format
External Programs : mysqld
To Do             :
Comments          : requires glib library (hash tables, sorting etc)
-------------------------------------------------------------------------------
*/

#include "querydb.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

static char const rcsid[] = "$Id: routequery.c,v 1.5 2002/12/11 11:48:03 ttraffic Exp $";


int bin2path (int hops, char *data, char **route)
{
        char addr[16];
        char ip6addr[MAX_IP6_SIZE];	
	int i,j,zero_count;

	*route = (char *) malloc ((MAX_IP6_SIZE+1) * hops);
	memset(*route,0,(MAX_IP6_SIZE+1) * hops);

        for (i=0;i<hops;i++) {
	        memcpy(addr,data+16*i,16);
                zero_count = 0;
                for (j=0;j<16;j++) {
			if ((addr[j]&0xFF) == 0x00) zero_count++;
		}
                if (zero_count == 16) {
			strcat(*route, "0::0"); 
		}
                else {
                	if(inet_ntop(AF_INET6, addr, ip6addr, MAX_IP6_SIZE) == NULL) {
                        	fprintf(stderr, "match_vector_by_time: Error in IPv6 database entry!");
                                exit(1);
                        }
                        strcat(*route, ip6addr);
                }
                if (i != (hops-1)) strcat(*route, " ");
        }

return(0);
}


int match_vector_by_time(MYSQL *mysql, char *srcbox, char *dstbox, time_t t_start, time_t t_end, struct querystruct *data, int ip6flag)
{
	char query [1024];
	MYSQL_RES *result;
	MYSQL_ROW row;
	
	struct querystruct* current;
	struct querystruct* index;
	struct querystruct* limit_record;

	unsigned int src;
	unsigned int dst;
	unsigned int counter;
	
        GHashTable *ranges;
	unsigned int *pz;
	
	unsigned int flag;

	char *buffer;
	
	data = NULL;
	counter = 0;
	flag = 0;

	ranges  = g_hash_table_new (g_str_hash,g_str_equal);

	limit_record = malloc(sizeof(struct querystruct));
	memset(limit_record,0,sizeof(struct querystruct));
	limit_record->tend = 0;
	
        get_ranges_by_boxname (ranges, PATHBOXES);

	pz = g_hash_table_lookup (ranges,srcbox);
	
	if (pz == NULL)
	{
		fprintf (stderr,"Box %s does not exist.\n",srcbox);
		return (0);
	};
	
	src = *(int *)pz;
	
	pz = g_hash_table_lookup (ranges,dstbox);
		
	if (pz == NULL)
	{
		fprintf (stderr,"Box %s does not exist.\n",dstbox);
		return (0);
	};	
	
	dst = *(int *)pz;
	
	/*Query the DB*/
	sprintf (query,"SELECT Routes.len, Records.routeid, Records.aspathid, Records.tstart, Records.tend, Records.numrec, Routes.route, ASpaths.len, ASpaths.path FROM Routes, Records, ASpaths WHERE Records.src=%u AND Records.dst=%u AND  Records.routeid=Routes.id AND Records.aspathid=ASpaths.id AND ((Records.tstart BETWEEN %u AND %u) OR (%u BETWEEN Records.tstart AND Records.tend+%u)) ORDER BY Records.tstart",
	src,dst,(unsigned int)(t_start),(unsigned int)(t_end),(unsigned int)(t_start),TIME_LIMIT);
	
	// printf ("%s\n",query);
	// tt01.ripe.net tt47.ripe.net 960900000 961000000

	if (mysql_query(mysql,query))
	{
		fprintf(stderr, "MySQL query error: %s\n", mysql_error(mysql));
		return (0);
	};   

	if (!(result = mysql_use_result(mysql)))
	{
		fprintf(stderr, "MySQL Result error: %s\n", mysql_error(mysql));
		mysql_free_result(result);	
		return (0);
	};

	/* Set return params - add new element to Buffers */
	while ((row = mysql_fetch_row(result)))
	{
		if ((atoi(row[3]) < (unsigned int)(t_start)) &&
		((atoi(row[4]) + TIME_LIMIT) > (unsigned int)(t_start)) &&
		(atoi(row[4]) > (unsigned int)(limit_record->tend)))
		{			

			if (limit_record->tend != 0) memset(limit_record,0,sizeof(struct querystruct));

			limit_record->nhops   = atoi(row[0]);
			limit_record->routeid = atoi(row[1]);
			limit_record->aspathid = atoi(row[2]);
			limit_record->tstart  = atoi(row[3]);
			limit_record->tend    = atoi(row[4]);
			limit_record->numrec  = atoi(row[5]);
			limit_record->next    = NULL;
	
			if (!ip6flag)		
				strcpy (limit_record->route,route_int_to_ip (row[6]));
			else {
				bin2path (limit_record->nhops, row[6], &buffer);
				strcpy (limit_record->route, buffer);
				free (buffer);	
			}

			limit_record->ashops = atoi(row[7]);
			strcpy (limit_record->aspath,row[8]);
			
			continue;
		};
		
		if ((atoi(row[3]) < (unsigned int)(t_start)) ||
		(atoi(row[3]) > (unsigned int)(t_end))) { continue; };
		
		current = malloc(sizeof(struct querystruct));
		memset(current,0,sizeof(struct querystruct));
		current->nhops   = atoi(row[0]);
		current->routeid = atoi(row[1]);
		current->aspathid = atoi(row[2]);
		current->tstart  = atoi(row[3]);
		current->tend    = atoi(row[4]);
		current->numrec  = atoi(row[5]);
		current->next    = NULL;
	

		if (!ip6flag)			
			strcpy (current->route,route_int_to_ip (row[6]));
                else {
               		bin2path (current->nhops, row[6], &buffer);
                        strcpy (current->route, buffer);
                        free (buffer); 
		}

		current->ashops = atoi(row[7]);
		strcpy (current->aspath,row[8]);
		
		if (data == NULL)
		{
			data = current;
		}
		else
		{
			index = data;
			
			while (index->next != NULL)
			{
				index = index->next;
			};
			
			index->next = current;
		};
		
		if (++counter > MAX_QUERY_LINES)
		{
			flag = 1;
			break;
		};
	};
	
	/* limit_record was not used ? */
	if (limit_record->tend == 0)
	{
		free(limit_record);
	}
	else
	{
		/* Append limit_record at the beginning of data */
		limit_record->next = data;
		data = limit_record;
	};
	
	index = data;
	while (index != NULL)
	{
		printf ("%s %s %d %d %d %d %d %s %d %d %s\n",srcbox,dstbox,index->tstart,index->tend,index->routeid,index->nhops,index->numrec,index->route,index->aspathid,index->ashops,index->aspath);	
		index = index->next;
	};		
	
	if (flag)
	{
		printf (".%u\n",MAX_QUERY_LINES);
	}
	else
	{
		printf (".\n");
	};
	
	mysql_free_result(result);

	return (1);

};

int main (int argc, char *argv[])
{
	MYSQL mysql;
	struct querystruct *data;
	char *src, *dst, *host;
	unsigned int tstart, tend;
	int ip6flag;


	char source[40], dest[40], timestart[40], timeend[40];

	data = NULL;

	ip6flag = 0;

	/* Parse arguments */

	if (argc == 1) {
		/* backwards compatible, take data from stdin */
		scanf("%s %s %s %s",source,dest,timestart,timeend);
		src = source;
		dst = dest;
		tstart = atoi(timestart);
		tend = atoi(timeend);
		host = MYSQL_HOST;
	}
	else if (argc < 5 || argc > 7) 
        { 
                fprintf (stderr,"Usage: %s [-6] <source> <destination> <starttime> <endtime>\n",argv[0]); 
                exit (1); 
        }
	else {
		if (strcmp(argv[1],"-6") == 0) {
			ip6flag = 1;
			src = argv[2];
			dst = argv[3];
			tstart = atoi(argv[4]);
			tend = atoi(argv[5]);

			if (argc == 7) {
				/* should check if argument makes sense as hostname */
				/* future version ...  */
				host = argv[6];
			}
			else {
				host = MYSQL_HOST;
			}
		} else {
                        src = argv[1];
                        dst = argv[2];
                        tstart = atoi(argv[3]);
                        tend = atoi(argv[4]);

                        if (argc == 6) {
                                /* should check if argument makes sense as hostname */
                                /* future version ...  */
                                host = argv[5];
                        }
                        else {
                                host = MYSQL_HOST;
                        }
		}	
	}

	/* process request */

	if (!ip6flag) {
		open_user_connection (&mysql, host);
	}
	else {
        	open_user_connection_ip6 (&mysql, host);
	}

	if (!match_vector_by_time(&mysql, src, dst, tstart, tend, data, ip6flag))
       	{
      		fprintf (stderr,"match_vector_by_time: Cannot send query.\n");
               	exit (1);
       	};

	mysql_close(&mysql);

	return (0);
};
