int main(void)
{
    struct sockaddr_in si_other;
    int s, slen=sizeof(si_other);
	char file_name[30];
	char server[12];
	int read_ret;
	char prog_mode;
	char intentional_corruption;
	int file_length_left;
	int file_length;
	int bytes_written = 0;
	int packet_count;
	int r,c,i,j;
	int random;
	char **data_storage;
	int sequence;
	int prev_sequence;
	FILE* fp;
    WSADATA wsa;
			
	//packet sent preceding the data containing information to initiate the file transfer
	
	

	struct data_packet send_data;
	struct data_packet receive_data;
	struct data_packet ACK0;
	struct data_packet ACK1;
	struct header_packet header;

	//initalize ACK0

	memset(ACK0.data,'+',DATALEN);
	ACK0.sequence_number = 0;
	ACK0.packet_number = -1;
	ACK0.checksum = checksum((char*)&ACK0,sizeof(ACK0));

	//initalize ACK1

	memset(ACK0.data,'+',DATALEN);
	ACK1.sequence_number = 1;
	ACK1.packet_number = -1;
	ACK1.checksum = checksum((char*)&ACK1,sizeof(ACK1));


	//Initialise winsock
    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
    {
        printf("Failed. Error Code : %d",WSAGetLastError());
        exit(EXIT_FAILURE);
    }
    printf("Initialised.\n");
     
    //create socket
    if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == SOCKET_ERROR)
    {
        printf("socket() failed with error code : %d" , WSAGetLastError());
        exit(EXIT_FAILURE);
    }
     
	printf("For localhost enter: 127.0.0.1 \n");
	printf("Enter Server IP Address: ");
		scanf("%s", &server);
	


    //setup address structure
    memset((char *) &si_other, 0, sizeof(si_other));
    si_other.sin_family = AF_INET;
    si_other.sin_port = htons(PORT);
    si_other.sin_addr.S_un.S_addr = inet_addr(server);


    //start communication
    while(1)
    {
		bytes_written = 0;
		packet_count = 0;
		sequence = 0;
		prev_sequence = 1;


		printf("Do you want to send a file? <y/n>: ");
		scanf(" %c", &prog_mode);
		printf("Do you want intentional data corruption? <y/n>: ");
		scanf(" %c", &intentional_corruption);
		
		if (intentional_corruption == 'y'){

			printf("Options: \nACK packet bit-error = A\nData packet bit-error = B \n");
			printf("Please enter your selection <A/B>: ");
			scanf(" %c", &intentional_corruption);

		}



		//client will receive a file
			if(prog_mode == 'n'){

				printf("Enter file name to read on server : ");
				scanf("%s",header.file_name);
				printf("Enter file name to write on client : ");
				scanf("%s",file_name);
		

				fp = fopen(file_name,"wb");


				//make first packet (header_packet) requesting file to be sent

		

				header.file_size = 0;
				header.mode = 'n';
				header.packet_number = packet_count;
				header.intentional_corruption = intentional_corruption;
				header.checksum = checksum((char*)&header,sizeof(header));


				printf("\n HEADER INFORMATION \n");
				printf("packet number = %i \n",header.packet_number);
				//mode dictates whether the server should send or receive
				printf("mode = %c \n",header.mode);
				printf("File name = %s \n\n",header.file_name);

		
				//send header packet asking to send file

				send_packet((char*)&header,sizeof(struct header_packet),s,&si_other,slen);


				//wait for ACK for header
				printf("waiting for ACK from server \n");

				receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);
					
				
				//in case of corrupt header packet or corrupt ACK 
				while(corrupt(receive_data)||isACK(receive_data,prev_sequence)){
						
					//resend the header packet 
					send_packet((char*)&header,sizeof(struct header_packet),s,&si_other,slen);
						
					//look for new ACK from the server
						
					receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);
						
				}

				//notification for successful recepit of ACK
				if(isACK(receive_data,sequence) == 1){

					printf("received ACK for header packet from server \n");

				}else{

					printf("ERROR: UNKNOWN DATA RECEIVED \n");
				}



				//wait for return header packet from server indicating the file size

				printf("Waiting for header packet from client...\n");
	
				//get header packet from socket
				receive_packet((char*)&header,sizeof(struct header_packet),s,&si_other,slen);

				
				//if header packet is corrupt send the previous sequence number ACK
		
				while(corrupt_h(header) == 1){
					//resend the prev_sequence ACK packet
					send_packet((char*)&ACK1,sizeof(struct data_packet),s,&si_other,slen);

					//get a new header packet
					receive_packet((char*)&header,sizeof(struct header_packet),s,&si_other,slen);
				}
	
				//send ack
				printf("sending header acknowledgement \n");
				send_packet((char*)&ACK0,sizeof(struct data_packet),s,&si_other,slen);






				printf("\n HEADER INFORMATION \n");
				printf("packet number = %i \n",header.packet_number);
				printf("mode = %c \n",header.mode);
				printf("File size = %i \n",header.file_size);




				//Allocate array to hold data for packet reordering

				r = ((header.file_size-(header.file_size%(DATALEN)))/(DATALEN));
					
				if((header.file_size%DATALEN)!=0){
					r++;
				}
				
				c = DATALEN;

				data_storage = (char **)malloc(r * sizeof(char*));
				for (i=0; i<r; i++){
					data_storage[i] = (char *)malloc(c * sizeof(char));
				}
	
				//initalize array
				for (i = 0; i <  r; i++)
					for (j = 0; j < c; j++)
						data_storage[i][j] = '+';










				printf("Waiting for data...\n");
				fflush(stdout);
         
        
         
       
				//try to receive some data, stop when you recieve all the data which the file contains

				while(bytes_written < header.file_size){

					//clear out the buffer each time to eliminate extraneous data on the last packet
					memset(receive_data.data,0xFF, DATALEN);

		
					//listen for packet and store into data_packet struct

					receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);


					
					//intentionally corrupt data packet if user selected
					if(header.intentional_corruption == 'B'){

						random = rand() % 10;
						//randomly choose data packets and invalidate the sequence number

						if(random == 7){
							receive_data.sequence_number = 49;
						}

					}

					//if data is corrupt or has the wrong sequence number

					while(corrupt(receive_data)||receive_data.sequence_number == prev_sequence){
						//resend the prev_sequence ACK packet 
						if(prev_sequence == 0){
							send_packet((char*)&ACK0,sizeof(struct data_packet),s,&si_other,slen);

						}else{
							send_packet((char*)&ACK1,sizeof(struct data_packet),s,&si_other,slen);

						}


						//look for new data from client
						receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);

					}


					//If the correct sequence data packet was sucessfully received
					if(receive_data.sequence_number == sequence){

						printf("received data%i from client \n", sequence);

					}else{


						printf("ERROR: UNKNOWN DATA RECEIVED \n");
					}
					

					//send the ACK packet to the client
					if(sequence == 0){
						printf("Sending ACK0 to client \n");
						send_packet((char*)&ACK0,sizeof(struct data_packet),s,&si_other,slen);
						
					}else{
						printf("Sending ACK1 to client \n");
						send_packet((char*)&ACK1,sizeof(struct data_packet),s,&si_other,slen);

					}



					//copy data received into array to reorder packets

					memcpy(data_storage[receive_data.packet_number-1], receive_data.data, (DATALEN));

					printf("packet number = %i \n", receive_data.packet_number);
         
					//print the data received data and origin
		 
					printf("\n\n\nReceived packet from %s:%d \n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port));
					printf("Data: %s\n\n\n" , receive_data.data);
					bytes_written = bytes_written + DATALEN;



					prev_sequence=sequence;
					sequence++;

					//when sequence number 1 is done go back to sequence number 0
					if(sequence > 1){

						sequence = 0;
					}
	




				}
		

				bytes_written = 0;

				//copy data into file in the correct order until the file is the correct size

				while(bytes_written != header.file_size){

				//copy array

					

					for(i=0; i<r; i++){
						bytes_written = bytes_written + DATALEN;
						printf("Writing Packet#: %i \n", i+1);
						
						if(bytes_written < header.file_size){
							fwrite(data_storage[i],1,DATALEN,fp);
							printf("bytes_written: %i \n",bytes_written);
						
						//special case for the last packet which isen't DATALEN bytes long
						}else{
							bytes_written = bytes_written - (DATALEN);
							printf("bytes_written: %i \n",bytes_written);
							
							fwrite(data_storage[i],1,(header.file_size - bytes_written),fp);
							
							printf("PARTIAL PACKET WRITE \n");
							printf("Wrote: %i \n",(header.file_size - bytes_written));
							bytes_written += (header.file_size - bytes_written);
						}
					
					
					}

				}


				printf("Receive Done. \n");

		
				printf("header File size = %i \n",header.file_size);

				printf("End of Transmission \n");

				fclose(fp);

				//free data storage array
				for (i=0; i<r; i++){
					free(data_storage[i]);
				}
				free(data_storage);


			} 
		
		



			//client will send a file
			if(prog_mode == 'y'){



				// get file name to be sent from user



				printf("Enter file name to read on client : ");
				scanf("%s",file_name);
				printf("Enter file name to write on server : ");
				scanf("%s",header.file_name);


				fp = fopen(file_name,"rb");



				if (fp == NULL){
					printf("Invalid file name \n");
					exit(EXIT_FAILURE);
				}

				//find length of the file
				fseek(fp, 0L, SEEK_END);
				file_length = ftell(fp);
				file_length_left = file_length;
				rewind(fp);

		
				//make first packet (header_packet) containing file length

		

				header.file_size = file_length;
				header.mode = 'y';
				header.packet_number = packet_count;
				header.intentional_corruption = intentional_corruption;
				header.checksum = checksum((char*)&header, sizeof(header));

				printf("\n HEADER INFORMATION \n");
				printf("packet number = %i \n",header.packet_number);
				//mode dictates whether the server should send or receive
				printf("mode = %c \n",header.mode);
				printf("File size = %i \n\n",header.file_size);

		
				//send header packet

				send_packet((char*)&header,sizeof(struct header_packet),s,&si_other,slen);

				//wait for ACK for header
				printf("waiting for ACK from server \n");

				receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);
					
				
				//in case of corrupt header packet or corrupt ACK 
					while(corrupt(receive_data)||isACK(receive_data,prev_sequence)){
						
						//resend the header packet 
						send_packet((char*)&header,sizeof(struct header_packet),s,&si_other,slen);
						
						//look for new ACK from the server
						
						receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);
						
					}

					//notification for successful recepit of ACK
					if(isACK(receive_data,sequence) == 1){

						printf("received ACK for header packet from server \n");

					}else{

						printf("ERROR: UNKNOWN DATA RECEIVED \n");
					}








				//break up message into chunks for UDP packets

				while(file_length_left > 0){
		
					
				
					packet_count++;



					memset(send_data.data,'\0', DATALEN);
					send_data.packet_number = packet_count;

					read_ret=fread(send_data.data, 1, (DATALEN), fp);
			
					if(read_ret != DATALEN && file_length_left>DATALEN){
						printf("\n ERROR, did not read DATALEN \n");
						printf("read_ret = %i \n", read_ret);
					}
			
			

					//insert sequence number
					send_data.sequence_number = sequence;

					//compute and store checksum into packet
					send_data.checksum = checksum((char*)&send_data, sizeof(send_data));

					file_length_left = file_length_left - (DATALEN);
			
					printf("packet number = %i \n",send_data.packet_number);
			
					if(file_length_left > 0){
						printf("file length left: %i \n", file_length_left);
					}else{
						printf("file length left: 0 \n");
					}
			

				



					//send the data_packet struct to the server

					send_packet((char*)&send_data,sizeof(struct data_packet),s,&si_other,slen);
				

	
				
				
					//look for ACK from the server

					printf("waiting for ACK%i from server \n", sequence);

					receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);

					
					//intentionally corrupt the received ACK packet if user selected
					if(intentional_corruption == 'A'){

						random = rand() % 10;
						//randomly choose ACK packets and invalidate the sequence number

						if(random == 7){
						receive_data.sequence_number = 69;
						}

					}
					
					
					//if the ACK packet is corrupted or wrong sequence ACK is received
					while(corrupt(receive_data)||isACK(receive_data,prev_sequence)){
						
						printf("Resending Data packet \n");

						//resend the data packet 
						send_packet((char*)&send_data,sizeof(struct data_packet),s,&si_other,slen);
						

						//look for new ACK from the server

						printf("waiting for ACK%i from server \n", sequence);
						
						receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);
						

					}


					//If the correct ACK was sucessfully received
					if(isACK(receive_data,sequence) == 1){

						printf("received ACK%i from server \n", sequence);

					}else{


						printf("ERROR: UNKNOWN DATA RECEIVED \n");
					}




						prev_sequence=sequence;
						sequence++;

					//when sequence number 1 is done go back to sequence number 0
					if(sequence > 1){

						sequence = 0;
					}

				}

			fclose(fp);

			}


		



	}
 
    closesocket(s);
    WSACleanup();
 
    return 0;
}
int main()
{
    SOCKET s;
    struct sockaddr_in server, si_other;
    int slen;
    WSADATA wsa;
	int read_ret;
	int file_length_left;
	int file_length;
	int random;
	int bytes_written = 0;
	int packet_count = 0;
	int r,c,i,j;
	int sequence;
	int prev_sequence;
	char **data_storage;
	FILE* fp;
	
	



	struct data_packet receive_data;
	struct data_packet send_data;
	struct data_packet ACK0;
	struct data_packet ACK1;
	struct header_packet header;

	//initalize ACK0

	memset(ACK0.data,'+',DATALEN);
	ACK0.sequence_number = 0;
	ACK0.packet_number = -1;

	ACK0.checksum = data_CSI(ACK0);

	//initalize ACK1

	memset(ACK1.data,'+',DATALEN);
	ACK1.sequence_number = 1;
	ACK1.packet_number = -1;
	ACK1.checksum = data_CSI(ACK1);
//	ACK1.checksum = checksumAndInvert((char*)&ACK1,sizeof(ACK1));


    slen = sizeof(si_other) ;
     
    //Initialise winsock
    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
    {
        printf("Failed. Error Code : %d",WSAGetLastError());
        exit(EXIT_FAILURE);
    }
    printf("Initialised.\n");
     
    //Create a socket
    if((s = socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP)) == INVALID_SOCKET)
    {
        printf("Could not create socket : %d" , WSAGetLastError());
    }
    printf("Socket created.\n");
     
    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( PORT );
     
    //Bind
    if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
    {
        printf("Bind failed with error code : %d" , WSAGetLastError());
        exit(EXIT_FAILURE);
    }
    puts("Bind done \n");
 



    //keep listening for data
    while(1){
    
       bytes_written = 0;
	   packet_count = 0;
	   sequence = 0;
	   prev_sequence = 1;
	

		//look for header packet from client to determine send/receive
		

		printf("Waiting for header packet from client...\n");
		
		//wait for header packet
		receive_packet((char*)&header,sizeof(struct header_packet),s,&si_other,slen);
		printf("\n HEADER INFORMATION \n");
		printf("packet number = %i \n",header.packet_number);
		//mode dictates whether the server should send or receive
		printf("mode = %c \n",header.mode);
		printf("File name = %s \n\n",header.file_name);
		printf("Computed = %d Checksum = %u\n", header_CSI(header), header.checksum);
		//if header packet is corrupt send the previous sequence number ACK
		
		while(corrupt_h(header) == 1){
			//resend the prev_sequence ACK packet
				send_packet((char*)&ACK1,sizeof(struct data_packet),s,&si_other,slen);

				//get a new header packet
				receive_packet((char*)&header,sizeof(struct header_packet),s,&si_other,slen);
			}
	
		//send ack
		printf("sending header acknowledgement \n");
		send_packet((char*)&ACK0,sizeof(struct data_packet),s,&si_other,slen);


		printf("\n HEADER INFORMATION \n");
		printf("packet number = %i \n",header.packet_number);
		//mode dictates whether the server should send or receive
		printf("mode = %c \n",header.mode);
		printf("File size = %i \n",header.file_size);
				
	
	


		
				
				
				
		//Server will be sending a file		
				
		if(header.mode == 'n'){
		
				// get file name to be sent from header packet

         
			fp = fopen(header.file_name,"rb");



			if (fp == NULL) {
				printf("Invalid file name \n");
				exit(EXIT_FAILURE);
			}

			//find length of the file
			fseek(fp, 0L, SEEK_END);
			file_length = ftell(fp);
			file_length_left = file_length;
			rewind(fp);

		
			//make another packet in response to client's (header_packet) to transmit necessary data for file transfer

		

			header.file_size = file_length;
			header.mode = 'n';
			header.packet_number = packet_count;
			header.checksum = header_CSI(header);

			printf("\n HEADER INFORMATION \n");
			printf("packet number = %i \n",header.packet_number);
			//mode dictates whether the server should send or receive
			printf("mode = %c \n",header.mode);
			printf("File size = %i \n\n",header.file_size);


		
			//send header packet
			send_packet((char*)&header,sizeof(struct header_packet),s,&si_other,slen);

			//wait for ACK for header
			printf("waiting for ACK from client \n");


			receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);		
				
			//in case of corrupt header packet or corrupt/wrong ACK 
			while(corrupt(receive_data)||isACK(receive_data,prev_sequence)){
						
				//resend the header packet 
				send_packet((char*)&header,sizeof(struct header_packet),s,&si_other,slen);
						
				//look for new ACK from the server		
				receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);

			}

			//notification for successful recepit of ACK
			if(isACK(receive_data,sequence) == 1){

				printf("received ACK for header packet from client \n");

			}else{

				printf("ERROR: UNKNOWN DATA RECEIVED \n");
			}



			while(file_length_left > 0){
		
				memset(send_data.data,'\0', DATALEN);

				packet_count++;
				send_data.packet_number = packet_count;

				read_ret=fread(send_data.data, 1, DATALEN, fp);
				
				if(read_ret != DATALEN && file_length_left>DATALEN){
					printf("\n ERROR, did not write DATALEN \n");
				}
			
			

				file_length_left = file_length_left - (DATALEN);
			
				printf("packet number = %i \n",send_data.packet_number);
			
				if(file_length_left > 0){
					printf("file length left: %i \n", file_length_left);
				}else{
					printf("file length left: 0 \n");
				}
			

				//insert sequence number
				send_data.sequence_number = sequence;

				//compute and store checksum into packet
				send_data.checksum = data_CSI(send_data);
				

				//send the data packet
				send_packet((char*)&send_data,sizeof(struct data_packet),s,&si_other,slen);
				
				
		 
				//look for ACK from the server

					printf("waiting for ACK%i from server \n", sequence);

					receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);
					

					//intentionally corrupt the received ACK packet if user selected
					if(header.intentional_corruption == 'A'){

						random = rand() % 10;
						//randomly choose ACK packets and invalidate the sequence number

						if(random == 7){
						receive_data.sequence_number = 49;
						}

					}

					
					//if the packet is corrupted or wrong sequence ACK is received
					while(corrupt(receive_data)||isACK(receive_data,prev_sequence)){
						
						printf("CORRUPT OR WRONG SEQUENCE ACK PACKET RECEIVED \n");
						printf("Resending Data packet \n \n");
						
						//resend the data packet 
						send_packet((char*)&send_data,sizeof(struct data_packet),s,&si_other,slen);
						

						//look for new ACK from the server

						printf("waiting for ACK%i from server \n", sequence);
						
						receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);
						

					}


					//If the correct ACK was sucessfully received
					if(isACK(receive_data,sequence) == 1){

						printf("received ACK%i from client \n", sequence);

					}else{


						printf("ERROR: UNKNOWN DATA RECEIVED \n");
					}




						prev_sequence=sequence;
						sequence++;

					//when sequence number 1 is done go back to sequence number 0
					if(sequence > 1){

						sequence = 0;
					}

				}
		
		
	
		}
		
		




		//server will receive a file
		
		if(header.mode == 'y'){
		

			//Allocate array to hold data for packet reordering

			//calculate rows and columns of array
			r = ((header.file_size-(header.file_size%(DATALEN)))/(DATALEN));
			
			if((header.file_size%DATALEN)!=0){
				r++;
			}
				
			c = DATALEN;

			data_storage = (char **)malloc(r * sizeof(char*));
			
			for (i=0; i<r; i++){
				data_storage[i] = (char *)malloc(c * sizeof(char));
			}
	
			//initalize array
			for (i = 0; i <  r; i++)
				for (j = 0; j < c; j++)
					data_storage[i][j] = '+';
		
		
			fp = fopen(header.file_name,"wb");


			printf("Waiting for data...\n");
			fflush(stdout);
         
        
         
       
			//try to receive some data, stop when you recieve all the data which the file contains

			while(bytes_written < header.file_size){

				//clear out the buffer each time to eliminate extraneous data on the last packet
				memset(receive_data.data,0xFF, DATALEN);

				//look for data from client
				receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);


				//intentionally corrupt data packet if user selected
				if(header.intentional_corruption == 'B'){

					random = rand() % 10;
						//randomly choose data packets and invalidate the sequence number

						if(random == 7){
						receive_data.sequence_number = 49;
						}


				}

				//if data is corrupt or has the previous sequence number

				while(corrupt(receive_data)||receive_data.sequence_number == prev_sequence){
						//resend the prev_sequence ACK packet 
						printf("CORRUPT OR WRONG SEQUENCE DATA PACKET RECEIVED \n");
						printf("RESENDING PREVIOUS ACK \n\n");

					if(prev_sequence == 0){
						send_packet((char*)&ACK0,sizeof(struct data_packet),s,&si_other,slen);

					}else{
						send_packet((char*)&ACK1,sizeof(struct data_packet),s,&si_other,slen);

					}


					//look for new data from client
					receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);
					
				}


				//If the correct sequence data packet was sucessfully received
					if(receive_data.sequence_number == sequence){

						printf("received data%i from client \n", sequence);

					}else{


						printf("ERROR: UNKNOWN DATA RECEIVED \n");
					}


					


				//send the ACK packet to the client
				if(sequence == 0){
						printf("Sending ACK0 to client \n");
						send_packet((char*)&ACK0,sizeof(struct data_packet),s,&si_other,slen);
						
					}else{
						printf("Sending ACK1 to client \n");
						send_packet((char*)&ACK1,sizeof(struct data_packet),s,&si_other,slen);

					}




				//copy data received into array to reorder packets

				memcpy(data_storage[receive_data.packet_number-1], receive_data.data, (DATALEN));

				printf("packet_number = %i \n", receive_data.packet_number);
         
				//print the data received and origin
		 
				printf("\n\n\nReceived packet from %s:%d \n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port));
			    printf("Data: %s\n\n\n" , receive_data.data);
				bytes_written = bytes_written + DATALEN;




				prev_sequence=sequence;
						sequence++;

					//when sequence number 1 is done go back to sequence number 0
				if(sequence > 1){

					sequence = 0;
				}

				


			}
		

			bytes_written = 0;

			while(bytes_written != header.file_size){

				//copy array into file

					

				for(i=0; i<r; i++){
					bytes_written = bytes_written + DATALEN;
					printf("Writing Packet#: %i \n", i+1);
					if(bytes_written < header.file_size){
						fwrite(data_storage[i],1,DATALEN,fp);
						printf("bytes_written: %i \n",bytes_written);
					}else{
						bytes_written = bytes_written - (DATALEN);
						printf("bytes_written: %i \n",bytes_written);
							
						fwrite(data_storage[i],1,(header.file_size - bytes_written),fp);
							
						printf("PARTIAL PACKET WRITE \n");
						printf("Wrote: %i \n",(header.file_size - bytes_written));
						bytes_written += (header.file_size - bytes_written);
					}
				}
			}


			printf("Receive Done. \n");

		
			printf("header File size = %i \n",header.file_size);

			printf("End of Transmission \n");

			fclose(fp);

			//free data storage array
			for (i=0; i<r; i++){
				free(data_storage[i]);
			}
			free(data_storage);


		}

		if(header.mode != 'y' && header.mode != 'n'){

			printf("HEADER ERROR, invalid mode! \n");
			return 0;
		}

       
   }
 
    closesocket(s);
    WSACleanup();
     
    return 0;
}
示例#3
0
文件: TCPD.c 项目: dhineshd/my-tcp
int main (){

  int sock_main, sock_timer;
  struct sockaddr_in main, timer;
  char buf[TCP_SEGMENT_SIZE];
  char hostname[128];
  gethostname (hostname, sizeof(hostname));
  hp = gethostbyname(hostname); 
  
  sock_main = socket (AF_INET, SOCK_DGRAM, 0);
  
  if (sock_main < 0){
    perror("opening UDP socket for main use");
    exit(1);
  }

  bzero ((char*)&main, sizeof (main));
  main.sin_family = AF_INET;
  main.sin_port = TCPD_PORT;
  bcopy((void *)hp->h_addr_list[0], (void *)&main.sin_addr, hp->h_length);
    
  if (bind(sock_main, (struct sockaddr *)&main, sizeof(main)) < 0){
    perror("getting socket name of main TCPD port");
    exit(2);
  }

  printf("TCPD MAIN SOCKET : PORT = %d ADDR = %d\n",main.sin_port,main.sin_addr.s_addr);  
 
  bzero((char*)&timer, sizeof(timer));
  timer.sin_family = AF_INET;
  timer.sin_port = TIMER_PORT;
  bcopy((void *)hp->h_addr_list[0], (void *)&timer.sin_addr, hp->h_length);
  
  /* TODO : Initialize send and receive windows */
  sendWindow.low = 100;
  sendWindow.high = sendWindow.low + WINDOW_SIZE * TCP_MSS;
  recvWindow.low = 100;
  recvWindow.high = recvWindow.low + WINDOW_SIZE * TCP_MSS;

  while (1){
    
      int type = 0;
      void *ptr = NULL;
      int send_bytes = 0;
      int sock  = 0;
      int rlen = 0;
      int i = 0;
      TCP_segment ts;
      TCP_segment ts_recv;
      TCP_segment* tsp;
      struct sockaddr_in name;
      
      /*
      printf("Inside child process to receive data\n");
      */
      printf("\n\n");
      
      /* Initialize buffer to all zeroes */
      bzero(buf, TCP_MSS);
       
      /* Receive data from UDP port */
      rlen = recvSegment((TCP_segment *)&ts, sock_main, main);
       
      /* Get segment type (LOCAL, REMOTE or TIMER) */
      type = getSegmentType (ts);      

      /*
      printf("Segment Type = %d len = %d\n",type,rlen);
      */
    
      /* Segment received from local application process */
      if (type == LOCAL_SEGMENT) {
        
        printf("Received local segment len = %d\n",rlen);
        printf("sBufCount = %d\n",sBufCount);

        printf("Send window : (%d, %d)\n",sendWindow.low, sendWindow.high);        
        
        /* Receiving destination address when a CONNECT is called*/
        if (ts.hdr.seq == DEST_INFO) {
          memcpy ((void*)&dest, (void*)&(ts.data), sizeof(struct sockaddr_in));
          printf("Received destination info from app\n");
          continue;
        }
        /* Receiving source address when a BIND is called*/
        else if (ts.hdr.seq == SRC_INFO) {
          memcpy ((void*)&src, (void*)&(ts.data), sizeof(struct sockaddr_in));
          printf("Received source info from app port = %d\n",src.sin_port);
          continue;
        }

        /* 
        memcpy((void*)&buf[0], (void*)&ts.data, rlen-TCP_HEADER_SIZE);
        for (i = 0; i < rlen-TCP_HEADER_SIZE; ++i)
          printf("%d", buf[i]);
        printf("Recv bytes = %d\n",rlen-TCP_HEADER_SIZE);
        */
        if (sBufCount == BUFFER_SIZE) continue;
        /*
        sBufCount++;
        */
        /* Construct TCP segment with received data */
        ts = constructSegment((void*)&ts.data, rlen-TCP_HEADER_SIZE);
             
        /* Sequence number gets incremented by 
         * 1 for each byte sent */
        nextSeq = nextSeq + rlen-TCP_HEADER_SIZE;

        /* Add segment to send buffer */
        /* TODO: Revisit buffer overflow logic here */
        
        memcpy((void*)&buf, (void*) &ts.data, rlen);
        /*
        for (i = 0; i < rlen; ++i)
          printf("%c");
        printf("\n");
        */
        sBufPtr = addToBuffer (sBufPtr, &sBufCount, ts, rlen); 
          
        /* Send from send buffer */
        sendFromSendBuffer (sBufPtr, sock_main, dest, timer, SEND_ALL, NULL); 
            
      }
      /* Segment received from remote process */
      
      else if (type == REMOTE_SEGMENT) {
        printf("Received remote segment len = %d\n",rlen);
        
        printf("Recv window : (%d, %d)\n",recvWindow.low, recvWindow.high);        
        
        /* TODO : Checksum here */ 
        /*
        printf("seq = %d crc = %d len = %d\n",ts.hdr.seq,ts.hdr.sum, rlen);
        
        memcpy((void*)&buf[0], (void*)&ts, rlen);
        for (i = 0; i < TCP_HEADER_SIZE; ++i)
          printf("%d",buf[i]);
        printf("\n");
        */

        /* Check if segment has valid checksum */
        if (!isValidChecksum(&ts, rlen)){
          printf("Checksum FAILURE\n");
          continue;
        }
        printf("Checksum SUCCESS\n");

 
        /* Check if ACK flag is set */
        if (isACK(&ts)){
          /* TODO :Handle ACK for already ACKed segments here */
          
            printf("Received ACK no = %d\n", ts.hdr.ack);
          
            /* Remove ACKed segment from buffer */
            sBufPtr = removeFromSendBuffer(sBufPtr, sock_main, timer, ts.hdr.ack);        
          
            /* Maintain ACK Count and compute RTO  */
            ackCount += 1;

            computeRTO ();

            continue;
        }
         
        /* Check if segment has valid checksum */
        /*
        if (!isValidChecksum(&ts, rlen)){
          printf("Checksum FAILURE");
          continue;
        }
        printf("Checksum SUCCESS\n");
        */
       
        /* Process received segment and return ptr to data*/
        ptr = processSegment((TCP_segment *)&ts, rlen);

        setACKFlag(&ts);

        /* TODO : How ACK set?*/
        ts.hdr.ack = ts.hdr.seq + rlen-TCP_HEADER_SIZE;
        if (isWithinWindow(recvWindow, ts.hdr.seq+rlen-TCP_HEADER_SIZE)|| (ts.hdr.seq < recvWindow.low)){
          
          int seq = ts.hdr.seq;            
          printf("Sending ACK for seq = %d\n",ts.hdr.seq);
          ts.hdr.seq = nextSeq;
          ts.hdr.urp = 0;
          ts.hdr.sum = 0;
          memcpy((void*)&buf, (void*)&ts, TCP_HEADER_SIZE);
  
          ts.hdr.sum = computeChecksum(&buf[0], TCP_HEADER_SIZE, &(ts.hdr.sum));
        
          /*
          printf("Checksum for ACK seq : %d crc : %d len : %d\n",ts.hdr.seq, ts.hdr.sum, TCP_HEADER_SIZE);
          
          for (i = 0; i < TCP_HEADER_SIZE; ++i)
            printf("%d",buf[i]);
          printf("\n");
          */
          /*ts.hdr.urp = REMOTE_SEGMENT;*/
          /*
          for (i = 0; i < TCP_HEADER_SIZE; ++i)
            printf("%d",buf[i]);
          printf("\n");
          */
          /* Sending ACK to remote process */
          sendSegment(&ts, TCP_HEADER_SIZE, sock_main, replyaddr);
          
          nextSeq = nextSeq + TCP_HEADER_SIZE;      
          ts.hdr.seq = seq;
        }
         /*printf("Sent ACK for seq = %d to dest = %d\n",ts.hdr.seq, replyaddr.sin_addr.s_addr);
          */
        if (!isWithinWindow(recvWindow, ts.hdr.seq+rlen-TCP_HEADER_SIZE) 
            || nextExpectedSeq > ts.hdr.seq){
            
          printf("Not within recv window seq = %d\n",ts.hdr.seq);
          continue;
        }
          
        printf("rBufCount = %d\n",rBufCount);          
        /*
        if (rBufPtr != NULL)  printf("RB : headseq = %d nes = %d\n",rBufPtr->ts.hdr.seq, nextExpectedSeq);
        if (rBufPtr != NULL && rBufPtr->ts.hdr.seq < nextExpectedSeq){
          printf("EXITING.......... \n");
          exit(1);
        }
        */
        /*
        if (nextExpectedSeq < recvWindow.low){
          printf("EXITING..\n");
          exit(1);
        }
        */
        
        if (rBufCount == BUFFER_SIZE) continue;
        
        /*rBufCount++;
        */
        /* TODO: Temporary hack to avoid recv buffer */
        /*sendData(&ts, rlen, sock_main, src);  
        
        continue;
        */

        /* Add segment to receive buffer */
        rBufPtr = addToBuffer (rBufPtr, &rBufCount, ts, rlen); 
          
        if (rBufPtr == NULL){
          printf("rbufptr = NULL post adding\n");
          continue; 
        }
        /* Update receive window */          
        updateWindow(&recvWindow, ts.hdr.seq, rlen-TCP_HEADER_SIZE); 
          
        /* Send data to local process */
        rBufPtr = sendFromRecvBuffer(rBufPtr, sock_main, src);
      }
      else if (type == TIMER_SEGMENT){

          TCP_buffer* ptr = NULL;

          printf("Received timer segment len = %d\n",rlen);
       
          memcpy((void*)&ptr, (void*)&(ts.data), sizeof(ptr));
          
          /* Update RTO on timeout. Message from timer 
           * implies timeout. */
          computeRTO();
          
          /* Retransmit segment to remote process */    
          sendFromSendBuffer (sBufPtr, sock_main, dest, timer, SEND_ONE, ptr);   
      }
  }  
  return 0;
}
int main()
{
    SOCKET s;
    struct sockaddr_in server, si_other;
    int slen;
    WSADATA wsa;
	int read_ret;
	int file_length_left;
	int file_length;
	int random;
	int sequence;
	int bytes_written = 0;
	int packet_count = 0;
	int r,c,i,j;
	char **data_storage;
	int GBN_lower;
	int GBN_upper;
	struct data_packet* send_packets;
	FILE* fp;
	int* timers;
	int timeout_indicator;
	int corrupt_status;
	int no_ACK_indicator;
	int dropped_count;
	int start_time;
	



	struct data_packet receive_data;
	struct data_packet send_data;
	struct data_packet ACK;
	struct header_packet header;
	int recv_status;

	//initalize ACK

	memset(ACK.data,'+',DATALEN);
	ACK.packet_number = 0;
	ACK.checksum = data_CSI(ACK);

	

    slen = sizeof(si_other) ;
     
    //Initialise winsock
    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
    {
        printf("Failed. Error Code : %d",WSAGetLastError());
        exit(EXIT_FAILURE);
    }
    printf("Initialised.\n");
     
    //Create a socket
    if((s = socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP)) == INVALID_SOCKET)
    {
        printf("Could not create socket : %d" , WSAGetLastError());
    }
    printf("Socket created.\n");
     
    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( PORT );
     
    //Bind
    if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
    {
        printf("Bind failed with error code : %d" , WSAGetLastError());
        exit(EXIT_FAILURE);
    }
    puts("Bind done \n");
 



    //keep listening for data
    while(1){

		if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout_0, sizeof(timeout_0)) == SOCKET_ERROR)
	{
		printf("setsockopt() failed with error code : %d" , WSAGetLastError());
	}

		timeout_indicator = 0;
       bytes_written = 0;
	   packet_count = 0;
	   sequence = 0;
	   
	

		//look for header packet from client to determine send/receive
		

		printf("Waiting for header packet from client...\n");
		
		//wait for header packet
		receive_packet((char*)&header,sizeof(struct header_packet),s,&si_other,slen);
		printf("\n HEADER INFORMATION \n");
		printf("packet number = %i \n",header.packet_number);
		//mode dictates whether the server should send or receive
		printf("mode = %c \n",header.mode);
		printf("File name = %s \n\n",header.file_name);

		//if header packet is corrupt do nothing and wait for sender to resend
		
		while(corrupt_h(header) == 1){
			

				//get a new header packet
				receive_packet((char*)&header,sizeof(struct header_packet),s,&si_other,slen);
			}
	
		//send ack
		printf("sending header acknowledgement \n");
		ACK.packet_number = packet_count;
		ACK.checksum = data_CSI(ACK);
		send_packet((char*)&ACK,sizeof(struct data_packet),s,&si_other,slen);


		printf("\n HEADER INFORMATION \n");
		printf("packet number = %i \n",header.packet_number);
		//mode dictates whether the server should send or receive
		printf("mode = %c \n",header.mode);
		printf("File size = %i \n",header.file_size);
				
	
	

	
		
				
				
				
		//Server will be sending a file		
				
		if(header.mode == 'n'){

			start_time = clock();
		
			//set socket timeout

			if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout_1, sizeof(timeout_1)) == SOCKET_ERROR)
				{
					printf("setsockopt() failed with error code : %d" , WSAGetLastError());
				}
         
			// get file name to be sent from header packet

			fp = fopen(header.file_name,"rb");



			if (fp == NULL) {
				printf("Invalid file name \n");
				exit(EXIT_FAILURE);
			}

			//find length of the file
			fseek(fp, 0L, SEEK_END);
			file_length = ftell(fp);
			file_length_left = file_length;
			rewind(fp);

		
			//make another packet in response to client's (header_packet) to transmit necessary data for file transfer

		

			header.file_size = file_length;
			header.mode = 'n';
			header.packet_number = packet_count;
			header.checksum = header_CSI(header);

			printf("\n HEADER INFORMATION \n");
			printf("packet number = %i \n",header.packet_number);
			//mode dictates whether the server should send or receive
			printf("mode = %c \n",header.mode);
			printf("File size = %i \n\n",header.file_size);


			do {
				//send header packet
				send_packet((char*)&header,sizeof(struct header_packet),s,&si_other,slen);

				//wait for ACK for header
				printf("looking for ACK from client \n");

				//in case of corrupt header packet or corrupt/wrong ACK 
			} while(receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen) == -1 ||
				corrupt(receive_data) || !isACK(receive_data,packet_count));

			//notification for successful recepit of ACK
			if(isACK(receive_data,packet_count) == 1){

				printf("received ACK for header packet from client \n");

			}else{

				printf("ERROR: UNKNOWN DATA RECEIVED \n");
			}


			//calculate number of spaces in array needed to hold all the data packets

					r = ((header.file_size-(header.file_size%(DATALEN)))/(DATALEN));
			
					if((header.file_size%DATALEN)!=0){
					r++;
					}


					//make array to hold all the data packets

				send_packets = (struct data_packet*)malloc(r * sizeof(struct data_packet));
				timers = (int*)malloc(r * sizeof(int));

				GBN_lower = 0;
				



			while(file_length_left > 0){
		
				packet_count++;
				
				memset(send_data.data,'\0', DATALEN);
				send_data.packet_number = packet_count;

				read_ret=fread(send_data.data, 1, DATALEN, fp);
				
				if(read_ret != DATALEN && file_length_left>DATALEN){
					printf("\n ERROR, did not write DATALEN \n");
				}
			
				//compute and store checksum into packet
				send_data.checksum = data_CSI(send_data);

				file_length_left = file_length_left - (DATALEN);
			
				printf("packet number = %i \n",send_data.packet_number);
			
				if(file_length_left > 0){
					printf("file length left: %i \n", file_length_left);
				}else{
					printf("file length left: 0 \n");
				}
			

			

				
				

				send_packets[GBN_lower] = send_data;
				
					GBN_lower++;

				}

				packet_count = 1;

				//send all the data packets
				while( receive_data.packet_number != r ){

					if(packet_count == 1){
						
						GBN_lower = 1;
						GBN_upper = header.window;
						printf("Initalized...GBN_lower = %i and GBN_upper = %i \n", GBN_lower, GBN_upper);
					}


					while(packet_count <= GBN_upper){

						send_data = send_packets[packet_count - 1];
				
						printf("Sending Packet %i \n", packet_count);

						//send the data_packet struct to the server
						send_packet((char*)&send_data,sizeof(struct data_packet),s,&si_other,slen);

						
						timers[packet_count - 1] = (int)clock();

						
						packet_count++;
						

						}

					

					//check to see if any of the timers have expired
					for(i=GBN_lower; i<=GBN_upper; i++){
						if( (clock() - timers[i-1]) > header.timer*CLOCKS_PER_SEC ){
							printf("TIMEOUT DETECTED on packet %i, time = %f \n", i,(float)(clock() - timers[i-1])/(float)CLOCKS_PER_SEC);
							timeout_indicator = 1;
						}
					}


					//if the ACK packet is corrupted throw packet away and get new one from socket
					//if the timer for a certain ACK expires resend whole window


						if(timeout_indicator == 1){
							printf("TIMEOUT DETECTED: RESENDING WINDOW\n");

							packet_count = GBN_lower;


							while(packet_count <= GBN_upper){

								send_data = send_packets[packet_count - 1];


								printf("Timeout: Sending Packet %i \n", packet_count);
					
								
								
								
								//send the data_packet struct to the server
								send_packet((char*)&send_data,sizeof(struct data_packet),s,&si_other,slen);
								

								timers[packet_count - 1] = (int)clock();

								packet_count++;

								
							}



						}


						timeout_indicator = 0;


						recv_status=0;
						i=0;
						
						//pull as many ACKs off of the socket as possible and process
					while(recv_status != -1){
						
						

						


						//look for ACK from the server
						recv_status = receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);

					
					

						//intentionally corrupt the received ACK packet if user selected
						if(header.intentional_corruption == 'A'){

							random = rand() % 100;
							//randomly choose ACK packets and invalidate the sequence number

							if(random <= header.corruption && receive_data.packet_number != GBN_upper){
							receive_data.packet_number = 0;
							}

						}

						if(recv_status == -1 && i == 0 && corrupt_status < 2 && no_ACK_indicator < 1 ){
							printf("received no ACK from the server \n");
							no_ACK_indicator++;
						}
						
						if(recv_status > 0){
							printf("received ACK%i from server \n", receive_data.packet_number);
						}

						

						if(corrupt(receive_data)){
							
							
							if(corrupt_status == 0){
							printf("CORRUPT ACK PACKET RECEIVED \n");
							printf("corrupt = %i, sequence = %i \n", corrupt(receive_data), receive_data.packet_number);
							printf("Threw away, looking for new ACK packet \n");
							}
						
							

							corrupt_status++;

						}


							//ACK all packets equal to and less than the ACK# (cumulative ACK)
							//and don't slide the window longer than the bytes in the file
						if( receive_data.packet_number >= GBN_lower && GBN_upper < r){

							GBN_lower = receive_data.packet_number+1;
							GBN_upper = GBN_lower+(header.window-1);

							if(GBN_upper > r){
								GBN_upper = r;
							}
							printf(" GBN_lower = %i, GBN_upper = %i \n", GBN_lower, GBN_upper);
						
							corrupt_status = 0;
							no_ACK_indicator = 0;
							dropped_count = 0;
						}
						
						i++;

					}

					if(corrupt_status < 2 && no_ACK_indicator < 1)
						printf("\n\n\n\n");


				}
		
				free(timers);
				free(send_packets);
				printf("The transfer took %f seconds \n", (float)(clock()-start_time)/(float)CLOCKS_PER_SEC);

			}
		
	
		
		




		//server will receive a file
		
		if(header.mode == 'y'){

			//set socket timeout to zero

			if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout_0, sizeof(timeout_0)) == SOCKET_ERROR)
			{
			printf("setsockopt() failed with error code : %d" , WSAGetLastError());
			}
		

			//Allocate array to hold data for packet reordering

			//calculate rows and columns of array
			r = ((header.file_size-(header.file_size%(DATALEN)))/(DATALEN));
			
			if((header.file_size%DATALEN)!=0){
				r++;
			}
				
			c = DATALEN;

			data_storage = (char **)malloc(r * sizeof(char*));
			
			for (i=0; i<r; i++){
				data_storage[i] = (char *)malloc(c * sizeof(char));
			}
	
			//initalize array
			for (i = 0; i <  r; i++)
				for (j = 0; j < c; j++)
					data_storage[i][j] = '+';
		
		
			fp = fopen(header.file_name,"wb");


			printf("Waiting for data...\n");
			fflush(stdout);
         
        
		
			
       

			//try to receive some data, stop when you recieve all the data which the file contains

			while(bytes_written < header.file_size){

				sequence++;


				//clear out the buffer each time to eliminate extraneous data on the last packet
				memset(receive_data.data,0xFF, DATALEN);

				//look for data from client
				receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);


				//intentionally corrupt data packet if user selected
				if(header.intentional_corruption == 'B'){

					random = rand() % 100;
						//randomly choose data packets and invalidate the sequence number

					if(random <= header.corruption){
						receive_data.packet_number = 0;
						}


				}

				//if data is corrupt or has some sequence number other than expected resend previous ACK

				while(corrupt(receive_data)||receive_data.packet_number != sequence){
						
						printf("CORRUPT OR WRONG SEQUENCE DATA PACKET RECEIVED, packet = %i, sequence = %i \n",receive_data.packet_number,sequence);
						printf("RESENDING ACK FOR LAST PACKET \n\n");


						ACK.packet_number = sequence-1;
						ACK.checksum = data_CSI(ACK);
						printf("Sending ACK %i to client \n", sequence-1);
						send_packet((char*)&ACK,sizeof(struct data_packet),s,&si_other,slen);

					
					//look for new data from client
					receive_packet((char*)&receive_data,sizeof(struct data_packet),s,&si_other,slen);
					
				}


				//If the correct sequence data packet was sucessfully received
					if(receive_data.packet_number == sequence){

						printf("received data%i from client \n", sequence);

					}else{


						printf("ERROR: UNKNOWN DATA RECEIVED \n");
					}


					


				//send the ACK packet to the client
						ACK.packet_number = sequence;
						ACK.checksum = data_CSI(ACK);
						printf("Sending ACK %i to client \n", sequence);
						send_packet((char*)&ACK,sizeof(struct data_packet),s,&si_other,slen);
						
					




				//copy data received into array to reorder packets

				memcpy(data_storage[receive_data.packet_number-1], receive_data.data, (DATALEN));

				printf("packet_number = %i \n", receive_data.packet_number);
         
				//print the data received and origin
		 
				printf("\n\n\nReceived packet from %s:%d \n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port));
			    printf("Data: %s\n\n\n" , receive_data.data);
				bytes_written = bytes_written + DATALEN;






			}
		

			bytes_written = 0;

			while(bytes_written != header.file_size){

				//copy array into file

					

				for(i=0; i<r; i++){
					bytes_written = bytes_written + DATALEN;
					printf("Writing Packet#: %i \n", i+1);
					if(bytes_written < header.file_size){
						fwrite(data_storage[i],1,DATALEN,fp);
						printf("bytes_written: %i \n",bytes_written);
					}else{
						bytes_written = bytes_written - (DATALEN);
						printf("bytes_written: %i \n",bytes_written);
							
						fwrite(data_storage[i],1,(header.file_size - bytes_written),fp);
							
						printf("PARTIAL PACKET WRITE \n");
						printf("Wrote: %i \n",(header.file_size - bytes_written));
						bytes_written += (header.file_size - bytes_written);
					}
				}
			}


			printf("Receive Done. \n");

		
			printf("header File size = %i \n",header.file_size);

			printf("End of Transmission \n");

			fclose(fp);

			//free data storage array
			for (i=0; i<r; i++){
				free(data_storage[i]);
			}
			free(data_storage);


		}

		if(header.mode != 'y' && header.mode != 'n'){

			printf("HEADER ERROR, invalid mode! \n");
			return 0;
		}

       
   }
 
    closesocket(s);
    WSACleanup();
     
    return 0;
}