#include "main.h"

#include <pcap/pcap.h>

#include <math.h>

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

#include <fcntl.h>

#define MINCOL 0.25
#define FACTOR 16.0
#define DEPTH (( 1024.0 / FACTOR) / 2)

struct packet_t inpacket;

enum {
	TCP 	= 6,
	UDP 	= 17
};

int pktpipe;
int resolvpipe;

u_int32_t resolvs[2];

void handle_tcp(const u_char *p) {
	unsigned short srcport;
	unsigned short dstport;
	memcpy(&srcport,p,2);
	memcpy(&dstport,(p + 2),2);
	srcport = ntohs(srcport);
	dstport = ntohs(dstport);
	inpacket.src.col.b = 1.0 * ((double)(65536.0 - srcport) / 65536.0);
	inpacket.dst.col.b = 1.0 * ((double)(65536.0 - dstport) / 65536.0);
	if(inpacket.src.col.b < MINCOL) {
		inpacket.src.col.b = MINCOL;
	}
	if(inpacket.dst.col.b < MINCOL) {
		inpacket.dst.col.b = MINCOL;
	}
	inpacket.life = 1;
}

void handle_udp(const u_char *p) {
	unsigned short srcport;
	unsigned short dstport;
	memcpy(&srcport,p,2);
	memcpy(&dstport,(p + 2),2);
	srcport = ntohs(srcport);
	dstport = ntohs(dstport);
	inpacket.src.col.g = 1.0 * ((double)(65536.0 - srcport) / 65536.0);
	inpacket.dst.col.g = 1.0 * ((double)(65536.0 - dstport) / 65536.0);
	if(inpacket.src.col.g < MINCOL) {
		inpacket.src.col.g = MINCOL;
	}
	if(inpacket.dst.col.g < MINCOL) {
		inpacket.dst.col.g = MINCOL;
	}
	inpacket.life = 1;
}

void handle_ip(unsigned short length) {
	double l = ((double)length / 1024.0);
	if(l > 1.0) {
		inpacket.src.col.r = 1.0;
		inpacket.dst.col.r = 1.0;
	} else if(l > MINCOL) {
		inpacket.src.col.r = l;
		inpacket.dst.col.r = l;
	} else {
		inpacket.src.col.r = MINCOL*2;
		inpacket.dst.col.r = MINCOL*2;
	}
	inpacket.life = 2;
}

void clean_pkt(void) {
	//memset(&inpacket,0,sizeof(struct packet_t));
	inpacket.src.col.r = 0.0;
	inpacket.dst.col.r = 0.0;
	inpacket.src.col.g = 0.0;
	inpacket.dst.col.g = 0.0;
	inpacket.src.col.b = 0.0;
	inpacket.dst.col.b = 0.0;
}

/* Network IP to Vert Structure */
void niptov(struct vert_t *v, u_int32_t ip) {
	unsigned short a,b,c;
	/* Lose 2 Bits */
	ip >>= 2;
	ip &= 0x3fffffffL;
	/* Split into 3x10Bits */
	a = ((ip & 0x3ff00000L) >> 20) & 0x000003ffL;
	b = ((ip & 0x000ffc00L) >> 10) & 0x000003ffL;
	c = ip & 0x000003ffL;
	v->x = DEPTH - ((double)a / FACTOR);
	v->y = DEPTH - ((double)b / FACTOR);
	v->z = DEPTH - ((double)c / FACTOR);
}

/* Ascii IP to Vert Structure */
void aiptov(struct vert_t *v, char *ip) {
	struct in_addr inet;
	inet_aton(ip,&inet);
	niptov(v,inet.s_addr);
}

void set_ip(unsigned long srcip, unsigned long dstip,
		unsigned short pktlength) {
	niptov(&(inpacket.src),srcip);
	niptov(&(inpacket.dst),dstip);
	
	resolvs[0] = srcip;
	resolvs[1] = dstip;
	
	/* Packet Life */
	if(pktlength >= 1500) {
		inpacket.life *= 1500 / 20;
	} else {
		pktlength /= 20;
		inpacket.life *= pktlength < 5 ? 5 : pktlength;
	}
	//fprintf(stderr,"Packet src,x:%f y:%f z:%f, srcip:%0lx\n",inpacket.src.x,inpacket.src.y,inpacket.src.z,srcip);
	//fprintf(stderr,"Packet dst,x:%f y:%f z:%f, dstip:%0lx\n",inpacket.dst.x,inpacket.dst.y,inpacket.dst.z,dstip);
}

void handle_packet(const u_char *p, unsigned long length) {
	/* Clean */
	unsigned char i = 0;
	unsigned long j = 0;
	unsigned long u = 0;
	unsigned char c = 0;
	unsigned int pktlength 	= 0;
	unsigned char pkttype 	= 0;
	unsigned long srcip 	= 0;
	unsigned long dstip 	= 0;
	/* Skip Mac and Ethernet Header */
	p += 14;
	/* Get Header Size */
	c = *(p++);
	c &= 0x0F;
	i = c;
	/* Packet Length */
	p++;
	c = *(p++);
	u = c << 8;
	c = *(p++);
	u |= c;
	pktlength = u;
	/* Header Length */
	j = (i * 4);
	/* Get Packet Type */
	p += 5;
	pkttype = *(p++);
	/* Past Checksum */
	p += 2;
	/* Copy Src */
	memcpy(&srcip,p,4);
	p += 4;
	/* Copy Dst */
	memcpy(&dstip,p,4);
	p += 4;
	/* Skip Past Any Remaining Header */
	p += (j - 20);
	
	clean_pkt();
	if(pkttype == TCP) {
		handle_tcp(p);
	} else if(pkttype == UDP) {
		handle_udp(p);
	} else {
		handle_ip(pktlength);
	}
	set_ip(srcip,dstip,pktlength);
}
	
void send_to_pipe(void) {
	write(pktpipe,&inpacket,sizeof(struct packet_t));
	write(resolvpipe,resolvs,sizeof(u_int32_t)*2);
}

void pcap_hler(u_char *a, const struct pcap_pkthdr *head, const u_char *p) {
	handle_packet(p,head->len);
	send_to_pipe();
}

void lsigpipe(int i) {
	fprintf(stderr,"packeth: SIGPIPE\n");
	exit(1);
}

int packet_handling_child(int pkp, int rp) {
	char buffer[1024];
	struct bpf_program *filter = xmalloc(sizeof(struct bpf_program));
	pcap_t *capsoc = NULL;
	
	signal(SIGPIPE,lsigpipe);
	
	pktpipe 	= pkp;
	resolvpipe 	= rp;
	fcntl(pktpipe, F_SETFL, O_NONBLOCK);
	fcntl(resolvpipe, F_SETFL, O_NONBLOCK);
	
	
	capsoc = pcap_open_live("eth0",96,1,0,buffer);
	if(capsoc == NULL) {
		fprintf(stderr,"Error %s\n",buffer);
		return 1;
	}
	pcap_compile(capsoc,filter,"ip",1,0);
	pcap_setfilter(capsoc,filter);
	pcap_loop(capsoc,0,(pcap_handler)&(pcap_hler),buffer);
	pcap_close(capsoc);
	exit(0);
}
