#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include "trans.h"

#define BUFSIZE 255

/* proof-of-concept program */

/* 
 * This program 'thinks' it's communicating over IPv4, however instead
 * of 'sendto' it uses 'sendtov6', which transparently translates it to
 * IPv6.
 *
 * This program is used for testing the implementation of 'sendtov6'. In
 * the long run we're planning to use this function in a linux kernel module,
 * overloading 'sendto', allowing the kernel to transparently translate all
 * ipv4 traffic to ipv6.
 *
 * The advantage of this over ipv4-in-ipv6-tunneling is that no ipv4 address 
 * is needed for the client machines...
 *
 * It sends an IPv6 udp packet to the nameserver 131.174.60.21 asking for
 * the A record of www.bzzt.com. 
 * Then, it should try to recieve the response package :)
 */

int main ()
{
	int sock;
	int sent, got;
	int fromsize;

	struct sockaddr_in theiraddr;
	struct sockaddr_in ouraddr;

	uint8_t data [BUFSIZE];
	data[0] = 0xec;
	data[1] = 0x48;
	data[2] = 0x01;
	data[3] = 0x00;
	data[4] = 0x00;
	data[5] = 0x01;
	data[6] = 0;
	data[7] = 0;
	data[8] = 0;
	data[9] = 0;
	data[10] = 0;
	data[11] = 0;
	data[12] = 0x03;
	data[13] = 0x77;
	data[14] = 0x77;
	data[15] = 0x77;
	data[16] = 0x04;
	data[17] = 0x62;
	data[18] = 0x65;
	data[19] = 0x65;
	data[20] = 0x72;
	data[21] = 0x03;
	data[22] = 0x63;
	data[23] = 0x6f;
	data[24] = 0x6d;
	data[25] = 0;
	data[26] = 0;
	data[27] = 1;
	data[28] = 0;
	data[29] = 1;

	if (initsocketv6() == -1)
	{
		fprintf(stderr, "error initializing v6 socket code\n");
	}

	/* create the IPv4 UDP socket */
	if ((sock = socketv6 (AF_INET, SOCK_DGRAM, 0)) == -1)
	{
		perror("socket");
	}

	/* create IPv4 incoming UDP socket */
	bzero(&ouraddr, sizeof(struct sockaddr_in));
	ouraddr.sin_family = AF_INET;
	ouraddr.sin_port = 0;
	ouraddr.sin_addr.s_addr = INADDR_ANY;

	/* bind the IPv4 udp socket */
	if (bind (sock, (struct sockaddr *)&ouraddr, sizeof(struct sockaddr)) == -1)
	{
		perror("bind");
	}

	/* make the IPv4 sockaddr_in for the local side */
	bzero(&theiraddr, sizeof(struct sockaddr_in));
	theiraddr.sin_family = AF_INET;
	theiraddr.sin_port = htons(53);
	if ((theiraddr.sin_addr.s_addr = inet_addr("131.174.60.21")) == -1)
	{
		perror("Couldn't convert address to binary network byte order address");
		return 1;
	}

	/* send an UDP packet to an IPv4 host */
	if ((sent = sendtov6(sock, data, 30, 0, (struct sockaddr *)&theiraddr, sizeof(struct sockaddr))) == -1)
	{
		perror("sendto");
		return 1;
	}

	printf ("Source port: %d\n", ouraddr.sin_port);

	printf("Sent %d bytes\n", sent);

	/* recvfrom */
	fromsize = sizeof(struct sockaddr);
	if ((got = recvfromv6(sock, data, BUFSIZE, 0, (struct sockaddr *)&theiraddr, &fromsize)) == -1)
	{
		perror("recvfrom");
		return 1;
	}
	data[got] = '\0';
	fprintf(stderr, "Recieved from socked: %d bytes, %s", got, data);

	return 0;
}

