/*
  $Id: ip_record.c,v 1.3 2003/03/10 01:39:37 slug Exp $

  (c) 2002 Nuno Sucena Almeida <slug_AT_aeminium_DOT_org>

*/

static const char cvsid[] = "$Id: ip_record.c,v 1.3 2003/03/10 01:39:37 slug Exp $";


#include <misc_includes.h>
// #include <stdlib.h>
// #include <string.h>
#include <ip_record.h>
#include <misc_util.h>

const char *direction_string[3] = {"N/A","In","Out"
};

const char ip_file_delimiters[] = DB_IP_FILE_DELIMITERS;

void show_ip_list (int fd,IP_RECORD *parent)
{
    IP_RECORD *current;
    char s[MAX_WRITE_STRING],source[MAX_STRING],destination[MAX_STRING];
    current = parent->next;
    while (current!=NULL)
    {
        strncpy(source,inet_ntoa(current->ip_src),MAX_STRING);
        strncpy(destination,inet_ntoa(current->ip_dst),MAX_STRING);
        snprintf (s,sizeof(s),"src:%s;dst:%s;bytes:%llu;dir:%s;time_t:%d\n" ,
                  source,destination,current->counter,
                  direction_string[current->direction],
                  current->last_seen);
        if (write_message(fd,s)==EXIT_FAILURE)
            return;
        current=current->next;
    }
}

int insert_into_ip_record(char *s, IP_RECORD *record)
{
    char *running, *initial;
    char *token;
    initial = running = strdup(s);
        /* 'src:' */
    token = strsep (&running, ip_file_delimiters);
    if (token==NULL)
        return(EXIT_FAILURE);    
        /* get source IP */
    token = strsep (&running, ip_file_delimiters);
    if (token==NULL)
        return(EXIT_FAILURE);
    if (inet_aton(token, & record->ip_src)==0)
        return(EXIT_FAILURE);
        /* 'dst:' */
    token = strsep (&running, ip_file_delimiters);
    if (token==NULL)
        return(EXIT_FAILURE);        
        /* get destination IP */
    token = strsep (&running, ip_file_delimiters);
    if (token==NULL)
        return(EXIT_FAILURE);
    if (inet_aton(token, & record->ip_dst)==0)
        return(EXIT_FAILURE);
        /* 'bytes:' */
    token = strsep (&running, ip_file_delimiters);
    if (token==NULL)
        return(EXIT_FAILURE);
         /* counter value: */
    token = strsep (&running, ip_file_delimiters);
    if (token==NULL)
        return(EXIT_FAILURE);
    if ((record->counter = strtoull(token,NULL,0))==0)
        return(EXIT_FAILURE);
        /* 'dir:' */
    token = strsep (&running, ip_file_delimiters);
    if (token==NULL)
        return(EXIT_FAILURE);
        /* direction string: */
    token = strsep (&running, ip_file_delimiters);
    if (token==NULL)
        return(EXIT_FAILURE);
        /* direction = N/A */
    if (strcmp(token,direction_string[0])==0)
        record->direction = NA;
    else
            /* direction =  In */
        if (strcmp(token,direction_string[1])==0)
            record->direction = INBOUND;
        else
                /* direction = Out */
            if (strcmp(token,direction_string[2])==0)
                record->direction = OUTBOUND;
            else
                return(EXIT_FAILURE);
    record->last_seen=0;
    free(initial);
    return(EXIT_SUCCESS);
}

int read_from_file_ip_record (char *filename, IP_RECORD *parent)
{
    FILE *fd;
    IP_RECORD *new_pair;
    char s[MAX_STRING];
    unsigned long long int total_traffic=0;
    int line;
    
    fd = fopen (filename, "r");
    if (fd==NULL)
    {
        print_debug("%s:fopen(%s):%s\n",__FUNCTION__,filename,
		    strerror(errno));
        return(EXIT_FAILURE);
    }
    rewind(fd);
    print_debug ("Reading IP Records from %s\n",filename);
    line=0;
    while (!feof(fd))
    {
        if (fgets(s,MAX_STRING,fd) != NULL )
        {
            line++;
            new_pair = (IP_RECORD *)malloc (sizeof(IP_RECORD));
            if ( insert_into_ip_record (s,new_pair) == EXIT_FAILURE )
            {
	      
                print_debug("%s: error at line %d: %s!\n",
			    filename ,line , s);
                fclose(fd);
                return(EXIT_FAILURE);
            }
            total_traffic += new_pair->counter;
            new_pair->next = parent->next;
            new_pair->prev = parent;
            if (parent->next!=NULL)
                    parent->next->prev = new_pair;
            parent->next = new_pair;
        }
    }
    fclose(fd);
    print_debug ("Read %d IP Records with %llu bytes of total traffic\n",
		 line,total_traffic);
    return(EXIT_SUCCESS);
}

int save_to_file_ip_record (char *filename, IP_RECORD *parent)
{
    FILE *fd;
    IP_RECORD *current;
    char source[MAX_STRING],destination[MAX_STRING];
    int error,line;
    unsigned long long int total_traffic=0;
    fd = fopen (filename, "w");
    if (fd==NULL)
    {
        print_debug("%s:fopen(%s):%s\n",__FUNCTION__,filename,
		    strerror(errno));
        return(EXIT_FAILURE);
    }
    print_debug ("Saving IP Records to %s\n",filename);
    current = parent->next;
    line=0;
    while (current!=NULL)
    {
        strncpy(source,inet_ntoa(current->ip_src),MAX_STRING);
        strncpy(destination,inet_ntoa(current->ip_dst),MAX_STRING);
        error = fprintf (fd,"src:%s;dst:%s;bytes:%llu;dir:%s\n",
                         source,
                         destination,current->counter,
                         direction_string[current->direction]);
        if (error<0)
        {
            print_debug("%s,fprintf():%s\n",__FUNCTION__,filename);
            fclose(fd);
            return(EXIT_FAILURE);
        }
        total_traffic += current->counter;
        current=current->next;
        line++;
    }
    fclose(fd);
    print_debug("Saved %d IP Records with %llu bytes of total traffic\n",
		line,total_traffic);    
    return(EXIT_SUCCESS);
}

IP_RECORD * search_insert_increment (IP_RECORD *parent,
                                     struct ip *ip_packet,
                                     DIRECTION direction,
                                     time_t time_stamp)
{
    IP_RECORD *new_pair;
    IP_RECORD *current = parent->next;
        /* search for ip src/dst pair. increment and exit if found */
    while (current!=NULL)
    {
        if ((current->ip_src.s_addr==ip_packet->ip_src.s_addr)&&
            (current->ip_dst.s_addr==ip_packet->ip_dst.s_addr))
        {
            current->counter += ntohs(ip_packet->ip_len);
            current->last_seen = time_stamp;
            return(current);
        }
        current = current->next;
    }
        /* pair not found so insert it to the list */
    new_pair = (IP_RECORD *)malloc (sizeof(IP_RECORD));
    new_pair->ip_src = ip_packet->ip_src;
    new_pair->ip_dst = ip_packet->ip_dst;
    new_pair->counter = ntohs(ip_packet->ip_len);
    new_pair->direction = direction;
    new_pair->last_seen = time_stamp;
    new_pair->next = parent->next;
    new_pair->prev = parent;
    if (parent->next!=NULL)
        parent->next->prev = new_pair;
    parent->next = new_pair;
    return(NULL);
}

void clear_ip_records (IP_RECORD *parent)
{
    IP_RECORD *current,*temp;
    int records=0;    
    current = parent->next;
    print_debug("Clearing IP Records\n");
    while (current!=NULL)
    {
        temp=current->next;
        free(current);
        current=temp;
        records++;
    }
    parent->next=NULL;
    print_debug("Cleared %d IP Records\n",records);
}


/* this function will sort the ip_records based on their last_seen time,
   the oldest (lowest time stamp) will be at the end of the list.
*/

//int compare_function (IP_RECORD **a,IP_RECORD **b)
int compare_function (const void *va,const void *vb)
{
//    unsigned long long int da = (*a)->counter;
//    unsigned long long int db = (*b)->counter;
    IP_RECORD **a = (IP_RECORD**) va;
    IP_RECORD **b = (IP_RECORD**) vb;
    time_t da = (*a)->last_seen;
    time_t db = (*b)->last_seen;
    
//    printf ("da=[%d], db=[%d]\n",da,db);
    return (da < db) - (da > db);
}

void qsort_ip_record (IP_RECORD *parent)
{
    IP_RECORD *current,*new_one;
    IP_RECORD **array_of_p;
    int list_size=0,i;
        /* get size of ip_record list */
    current=parent->next;
    while(current!=NULL)
    {
        list_size++;
        current=current->next;
    }
        /* alloc space for an array of pointers to IP_RECORD structures */
    array_of_p = malloc(list_size*sizeof(IP_RECORD*));
        /* put ip_record addresses in the array:*/
    i=0;
    current=parent->next;
    while(current!=NULL)
    {
        array_of_p[i++]=current;
        current=current->next;
    }
  
    qsort(array_of_p,list_size,sizeof(IP_RECORD*),compare_function);
        /* recreate the list with the sorted elements: */
    current=parent;
    for (i=0;i<list_size;i++)
    {
        new_one = array_of_p[i];
        current->next = new_one;
        new_one->prev = current;
        current = new_one;
    }
    current->next=NULL;
    free(array_of_p);
}


void create_log_file_name (char *file_name, int length,
                           char *directory, char *partial_name)
/* this function creates the complete log path+filename, which includes
   the current year and month number */
{
    time_t current_time;
    struct tm *local_time;
    current_time = time(NULL);
    local_time = localtime (&current_time);
    snprintf(file_name,length,"%s/%s_%d_%d.log",
             directory,partial_name,
             1900+local_time->tm_year,1+local_time->tm_mon);
}
