#include "stdafx.h"
#include <time.h>
#include <math.h>
#include <stdio.h>
#include <windows.h>

#define NTP_MSG_LEN 48

/* 
Decodes the timestamp
pointer: points to the first byte of the NTP time representation
returns: timestamp
*/
double decodeTimestamp(char* pointer)
{
	/* Exercise 3.2: Implement the algorithm here */

	/* ... */
}

/* 
Encode the timestamp
pointer: points to the first byte of the NTP time representation
timestamp: timestamp to be encoded
*/

void encodeTimestamp(char* pointer, double timestamp) 
{
	int i;
	double base;
	short byte;

	for (i = 0; i < 8; i++) {
		/* 2^24, 2^16, 2^8, 2^0, 2^-8, 2^-16, 2^-24, 2^-32 */
		base = pow((double)2, (double)(3 - i) * 8);
		*(i + pointer) = (char) (timestamp / base);
		/* short is a signed data type */
		byte = *(i + pointer);
		if (((*(i + pointer)) & 0x80) == 0x80) 
			 byte = (short) (128 + ((*(i + pointer)) & 0x7f)); 
		timestamp = timestamp - (double) (byte * base);
	}
}

int decodeTimestamp_test()
{
	double timestamp = time(NULL);
	double decoded_timestamp;
	char buff[NTP_MSG_LEN];
	encodeTimestamp(buff,timestamp);
	decoded_timestamp = decodeTimestamp(buff);
	if (timestamp == decoded_timestamp)
	{
		printf("Decoding correct!!!\n");
	}else
	{
		printf("Decoding error!!!\n");
		return -1;
	}
}


/*
Creates the NTP message, e.g. request from the client to the server
li: Leap Indicator [no warning = 0]
vn: Version Number [Version: IPv4 = 3]
mode: e.g. client [Mode: client mode = 3]
timestamp: transmit timestamp
pointer: pointer to the begin of the message [memery has to be allocated in the calling function]
*/

void createNTPMessage(char li, char vn, char mode, double timestamp, char* msg)
{

	msg[0] = (char) (li << 6 | vn << 3 | mode);
	encodeTimestamp((msg+40), timestamp);

}


void parseNTPMessage(double* referenceTimestamp, double* originateTimestamp, double* receiveTimestamp, double* transmitTimestamp, char* msg)
{
	*referenceTimestamp = decodeTimestamp(msg+16);
	*originateTimestamp = decodeTimestamp(msg+24);
	*receiveTimestamp = decodeTimestamp(msg+32);
	*transmitTimestamp = decodeTimestamp(msg+40);
}

int ntp_client()
{
	int sock;
	struct sockaddr_in server_address, local_address;
	char msg[NTP_MSG_LEN];
	time_t localTimestamp;
	double referenceTimestamp = 0;
	double originateTimestamp = 0;
	double receiveTimestamp = 0;
	double transmitTimestamp = 0;
	char *servername;
	struct hostent* he;
	WSADATA wsaData;
	struct in_addr addr;
	int i, addrlen;
	double roundTripDelay, localClockOffset;

	servername = "ntp.in.tum.de";

	memset(msg, 0, NTP_MSG_LEN);

	/* WSAStartup() initiates use of the Winsock DLL by a process */
	WSAStartup(2.2, &wsaData);

	/* Exercise 3.1: Create a UDP socket "sock" to send and to receive UDP datagrams here: sock() ... */
	/* For error detection: WSAGetLastError() returns the last error code */
	
	/* ... */

	if (sock == INVALID_SOCKET) {
		printf("Local Socket creation failed %i\n", WSAGetLastError());
		return (-1);
	}

	printf("Socket = %i\n", sock);

	/* The struct server_address is filled with the server address */

	he = gethostbyname(servername);

	if (he!=NULL){
		server_address.sin_addr.s_addr = *(u_long *) he->h_addr_list[0];
		addr.s_addr = *(u_long *) he->h_addr_list[0];
		printf("server address = %s\n", inet_ntoa(addr));
	} else {
		printf("Server address is incorrect!\n");
		return (-2);
	}

	/* Exercise 3.1: Fill out the remaining fields of the struct server_address */
	/* Note: The remaining necessary fields are: server_address.sin_family and server_address.sin_port */
	/* Note: By filling out the field server_address.sin_port, use the function htons() to translate the host byte order into network byte order */
	
	/* ... */

	localTimestamp = 0;

	/* Exercise 3.3: Store the local time in the variable localTimestamp, Note: time since January 1, 1970 */
	
	/* ... */

	/* Create NTP message */
	createNTPMessage(0, 3, 3, (double)localTimestamp, msg);

	/* Display the message */
	for (i=0; i<NTP_MSG_LEN; i++)
		printf("%i ",msg[i]);

	printf("\n");
	
	/* Send the message "msg" to the (S)NTP server, make use of sendto() */
	/* Note: the function returns back a value: number of bytes sent or SOCKET_ERROR if failed */
	
	if (sendto(sock, msg, NTP_MSG_LEN, 0, (struct sockaddr*)&server_address, sizeof(server_address)) == SOCKET_ERROR) {
		printf("Send operation is failed\n");
		return (-11);
	}

	printf("Send operation...\n");

	memset(msg, 0, NTP_MSG_LEN);
	
	/* Receive a datagram to the container "msg" from the socket "sock", make use of recvfrom() */
	/* Store the source address in struct local_address */
	/* Note: the function returns back a value: number of bytes received or SOCKET_ERROR if failed */

	addrlen = sizeof(struct sockaddr);
	
	if (recvfrom(sock, msg, NTP_MSG_LEN, 0, (struct sockaddr*)&local_address, &addrlen) == SOCKET_ERROR) {
		printf("receive operation is failed %i\n", WSAGetLastError());
		return (-1);
	}

	printf("receive operation...\n");

	/* Exercise 3.3: Store the local time in the variable localTimestamp, Note: time since January 1, 1970 */
	
	/* ... */

	/* Check if the source address in struct local_address is the same as the server address */
	/* Note: in C, you can not compare "structs" only simple data structures */

	if((local_address.sin_port == server_address.sin_port)&&(local_address.sin_addr.s_addr == server_address.sin_addr.s_addr))
		printf("The sender address is OK\n");

	/* Parse the (S)NTP Message */
	parseNTPMessage(&referenceTimestamp, &originateTimestamp, &receiveTimestamp, &transmitTimestamp, msg);

	/* Note: (S)NTP timestamps are the time since January 1, 1900 */

	printf("referenceTimestamp = %f\n", referenceTimestamp);
	printf("originateTimestamp = %f\n", originateTimestamp);
	printf("receiveTimestamp = %f\n", receiveTimestamp);
	printf("transmitTimestamp = %f\n", transmitTimestamp);


	/* Exercise 3.3: Calculate round trip time and local clock offset here */

	//Originate Timestamp: This is the time at which the request departed the client for the server, in 64-bit timestamp format. T1
	//Receive Timestamp: This is the time at which the request arrived at the server, in 64-bit timestamp format. T2
	//Transmit Timestamp: This is the time at which the reply departed the server for the client, in 64-bit timestamp format. T3
	//Destination Timestamp: This is the time at which the reply is received by client. T4

	//d = (T4 - T1) - (T3 - T2)     t = ((T2 - T1) + (T3 - T4)) / 2

	/* ... */

	closesocket(sock);
	
	return (1);
}

int _tmain(int argc, _TCHAR* argv[])
{
	ntp_client();

	
	return (1);
}
