main() { FILE *file=fopen("sky.txt", "w"); short x, y; for ( x=0; x<21; ++x, fprintf(file, "\n") ) for ( y=0; y<21; ++y ) fprintf(file, random_prob(19) ? "." : " "); fclose(file); }
int main(int argc, char *argv[]) { //portNumber, CWND, Pr(loss), Pr(corruption) srand(time(0)); //Seed random number generator int server_sockfd, newsockfd, portno, window_size = 1, window_start_index = 0; //Default window Size double lossProbability = 0.0, corruptionProbability = 0.0; //Assume no loss/corruption by default socklen_t clilen; struct sockaddr_in serv_addr, cli_addr; char buffer[PACKET_SIZE]; bzero(buffer, PACKET_SIZE); //struct timeval timeout={2,0}; //set timeout for 2 seconds must be greater than TIMEOUT packet* Packet = (packet*)buffer; time_t timer; int timedOutCount = 0; //Keep track of the number of consecutive timeouts if(argc != 2 && argc != 5) { fprintf(stderr, "ERROR, Invalid number of arguments\n"); exit(1); } if(argc == 2) { //Only provided a port # assume no loss/corruption printf("NOTE: CWND is set to 1 packet of size 1024 bytes, assuming no loss/corruption\n"); } if(argc == 5) { //Use selected values for CWND, loss, & corruption //CWND will be passed in as bytes, so we need to convert it to packet counts. int count = atoi(argv[2])/(PACKET_SIZE+1); window_size = std::max(1,(int)(count+1)); printf("NOTE: CWND of %d bytes is converted to CWND of %d packet(s) each of size %d bytes\n", atoi(argv[2]), window_size, PACKET_SIZE); lossProbability = atof(argv[3]); corruptionProbability = atof(argv[4]); } //setsockopt(server_sockfd, SOL_SOCKET, SO_RCVTIMEO,(char*)&timeout,sizeof(struct timeval)); portno = atoi(argv[1]); printf("SERVER STARTED, AWAITING NEW REQUESTS ON PORT: %d\n", portno); server_sockfd = socket(AF_INET, SOCK_DGRAM, 0); //Create UDP socket if(server_sockfd < 0) fprintf(stderr, "ERROR creating UDP socket"); bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); if (bind(server_sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) printf("ERROR on binding"); clilen = sizeof(cli_addr); fcntl(server_sockfd, F_SETFL, O_NONBLOCK); LISTEN: while(1) { while (1) { while(1){ ssize_t n = recvfrom(server_sockfd, buffer, PACKET_SIZE, 0, (struct sockaddr *) &cli_addr, &clilen); if(n != -1) break; } //Print the packet we received printPacket(Packet); if(Packet->packetType == SYN) { printf("Received new connection\n"); createPacket(true, SYN_ACK, Packet->ACK_num, Packet->ACK_num+1, 0, (char *)"", Packet); int n = sendto(server_sockfd, buffer, PACKET_SIZE, 0, (const sockaddr*)&cli_addr, sizeof(cli_addr)); if(n < 0) { printf("ERROR sending SYN ACK\nRetrying...\n"); } else { printf("Sent SYN ACK: %d bytes\n", n); } } else { break; } } //We received file request //Print the packet we received printf("Received file request\n"); printPacket(Packet); //Initial packet has a filename in Data section //Search for file in file system printf("Searching for requested file...\n"); FILE* fp = fopen((const char*)Packet->data, "r"); if(fp == NULL) { fprintf(stderr, "Failed to open requested file\n"); //Ignore and go back to listen printf("AWAITING NEW REQUESTS ON PORT: %d\n", portno); goto LISTEN; //Go back to listening state } //File Found, determine how many bytes it is fseek(fp, 0, SEEK_END); long fileSize = ftell(fp); fseek(fp, 0, SEEK_SET); //printf("DEBUG: FileSize: %lu\n",fileSize); //Read file into memory (Not the best idea, but this is CS118) //Calculate number of packets needed unsigned long num_required_packets = std::max(1,(int)((fileSize/DATA_SIZE)+1)); printf("DEBUG: Num_Required_Packets: %lu\n", num_required_packets); socklen_t serv_addr_size = sizeof(serv_addr); packet* sendQueue[num_required_packets]; char* packetBuffers[num_required_packets]; char* datas[num_required_packets]; //Initialize every packet unsigned long tempSeqNum = Packet->seq_num; unsigned long tempACKNum = Packet->ACK_num; for(int index = 0; index < num_required_packets; index++) { packetBuffers[index] = (char *)calloc(PACKET_SIZE, sizeof(char)); //Dynamic allocated memory here-freed in fin section sendQueue[index] = (packet *)packetBuffers[index]; int read = pread(fileno(fp), sendQueue[index]->data, (size_t)DATA_SIZE, index*(DATA_SIZE)); sendQueue[index]->data[read+nullByte] = '\0'; //printf("DEBUG: Bytes read from file %d\n", read); if(index == num_required_packets-1) //Last packet, we want to set lastPacket flag to true initializePackets(1, DATA, tempACKNum, tempACKNum+1, read, sendQueue[index]); else initializePackets(0, DATA, tempACKNum, tempACKNum+1, read, sendQueue[index]); tempSeqNum+=2; tempACKNum+=2; } //At this point, we have the entire to-be-sent packets in queue. unsigned long receivedUpTo = 3; long sentUpTo = -1; //To track which packets in the window should be sent bool timedOut = false; //To track if we need to resend all packets in window while(window_start_index < num_required_packets) { //Send every packet in our window that has yet to be sent; jump here upon timeouts resend_window: for(int index = window_start_index; index < window_start_index + window_size; index++) { time(&timer); //Set/reset timer for this window //Send packets in window that haven't been sent, or if timeout, resend all packets in window if(index >= num_required_packets) //We have less packets than our window size, so we can breakout early break; if (index > sentUpTo || timedOut == true) { int n = sendto(server_sockfd, packetBuffers[index], PACKET_SIZE, 0, (const sockaddr*)&cli_addr, sizeof(cli_addr)); if(n < 0) printf("ERROR sending packet #: %d\n", index); else { printf("Sent: %d bytes\n", n); sentUpTo = index; } } } if (timedOut == true) //resent window, reset timeout flag timedOut = false; //Wait to receive an ACK, or a timeout while(1) { //TODO IF NO RESPONSE IN # TIME, BREAK //printf("Waiting to receive ACK"); //printf("time now: %ld, timer+timeout: %ld", time(NULL), timer+TIMEOUT); if (time(NULL) > timer + TIMEOUT && timedOut == false) { //std::cout << "timing out\n"; printf("Timing out..."); timedOut = true; if(timedOutCount >= TcpMaxDataRetransmissions) { bzero(buffer, PACKET_SIZE); window_start_index = 0; for (int i = 0; i < num_required_packets; i++) { //Free calloc'ed memory free(packetBuffers[i]); } fclose(fp); timedOutCount = 0; printf("\nMax retransmissions reached...\n"); printf("AWAITING NEW REQUESTS ON PORT: %d\n", portno); goto LISTEN; } timedOutCount++; printf("Resending window from packet num %d \n", window_start_index); goto resend_window; } if (recvfrom(server_sockfd, buffer, PACKET_SIZE, 0, (struct sockaddr *) &cli_addr, &clilen) > 0) { if(random_prob() < lossProbability) { printf("ACK lost\n"); continue; } if(random_prob() < corruptionProbability) { printf("ACK corrupted\n"); continue; } else break; } } //Print the packet we received printPacket(Packet); if(Packet->packetType == FIN) { printf("FIN received... Transfer complete! :)\n\n"); //TODO send FIN-ACK back? //go back to initial loop and listen for new requests printf("AWAITING REQUESTS ON PORT: %d\n", portno); bzero(buffer, PACKET_SIZE); window_start_index = 0; for (int i = 0; i < num_required_packets; i++) { //Free calloc'ed memory free(packetBuffers[i]); } fclose(fp); timedOutCount = 0; goto LISTEN; } //Check if we need to move window start if((Packet->seq_num > receivedUpTo)) { window_start_index += (Packet->seq_num - receivedUpTo)/2; receivedUpTo = Packet->seq_num; timedOutCount = 0; //TODO if we move window start, refresh timer //timer is refreshed at the sending of first packet in window in next loop //time(&timer); } else { //TODO, do nothing?... maybe timer related things will go here } } } }