// Sends a termination message to the server // @param sockfd the socket file descriptor // @param server the server being sent to // @param seq the sequence number of the message // @param p a pointer to the filename // @param client a pointer to the client variable static void send_termination(int sockfd, host *server, int *seq, csv_record *p, client_info *client) { hftp_control_message *control = (hftp_control_message*)create_control_message(TERMINATE, *seq, p, client->token, 0); syslog(LOG_DEBUG, "Type: Termination, Sequence: %d", control->sequence); transmit(sockfd, (message**)&control, server, seq); } //end send_termination
// Sends an intialize message to the server // @param sockfd the socket file descriptor // @param server the server being sent to // @param seq the sequence number of the message // @param file a pointer to the file variable // @param client a pointer to the client variable // @param hftpd a pointer to the server information // @param p a pointer to the filename // @param count the position in the list of files static void send_initialize(int sockfd, host *server, int *seq, file_info *file, client_info *client, server_info *hftpd, csv_record *p, int count) { hftp_control_message *control = (hftp_control_message*)create_control_message(INITIALIZE, *seq, p, client->token, file->file_length); syslog(LOG_INFO, "Transferring '%s' (%d of %d)", p->filename, count, get_list_length(client->response_list)); syslog(LOG_DEBUG, "Type: Initialization, Sequence: %d, Filename length: %d", control->sequence, ntohs(control->filename_length)); // Transmit a control request if (transmit(sockfd, (message**)&control, server, seq) == -1) { syslog(LOG_INFO, "Authentication with Hooli file transfer server failed"); free_file_info(file); close(sockfd); free_server_info(hftpd); free_client_info(client); exit(EXIT_FAILURE); } //end if } //end send_control
int main (int argc, char** argv) { int c, i, sockfd; // For switch and optind int seqNum = 0; // Keep track of what's expected int timeout = 50; // Default timeout char* hostname; // Set by command line argument char* filename; // Set by command line argument char* convert; // To convert c-line timeout value to int char* port = "5000"; // Default static int verbose_flag = 0; // Set from command line host_t server; // Address of the server control_message_t* ctrlMsg = NULL; // Control messages received message_t* msg = NULL; // Messages to send data_message_t* dataMsg = NULL; // Data messages received while (1) { static struct option long_options[] = { {"verbose", no_argument, &verbose_flag, 1}, {"timeout", required_argument, 0, 't'}, {"port", required_argument, 0, 'p'}, {0,0,0,0} }; int option_index = 0; c = getopt_long(argc, argv, "vt:p:", long_options, &option_index); // If we've reached the end of the options, stop iterating if (c == -1) break; switch (c) { case 'v': verbose_flag = 1; break; case 't': convert = optarg; // Save as char* sscanf(convert, "%d", &timeout); // Convert to int for timeout break; case 'p': port = optarg; break; case '?': exit(EXIT_FAILURE); break; } } // Grab command line arguments i = optind; hostname = argv[i++]; filename = argv[i]; // Check that hostname and filename have been given if (hostname == NULL || filename == NULL) { printf("ERROR: Hostname and filename required\n"); exit(EXIT_FAILURE); } // Get file size uint32_t fileSize = fsize(filename); // Print info printf("Transferring file: %s\nTotal size: %d bytes\n--------------------------------\n", filename, fileSize); // Filename length uint32_t fNameLength = sizeof(filename); // Create a socket and listen sockfd = create_client_socket(hostname, port, &server); // Encode the message msg = create_control_message(INITIATE, SEND, seqNum, fileSize, fNameLength, filename); // If timeout is reached or seqNum of ACK is wrong then retransmit while (ctrlMsg == NULL || ctrlMsg->seqNum != 0) { // Send initial request send_message(sockfd, msg, &server); if (verbose_flag) send_verbose(msg); ctrlMsg = (control_message_t*)receive_message_with_timeout(sockfd, timeout, &server); } free(msg); // Network order conversion and verbose check ctrlMsg->seqNum = ntohs(ctrlMsg->seqNum); if (verbose_flag == 1) ack_verbose((message_t*)ctrlMsg); free(ctrlMsg); // Type 1 ACK received FILE* fp = fopen(filename, "r"); // File to copy from int eof_flag = 1; // For when eof is reached int bytes_transferred = 0; // keep track of amount of data transferred // Until end of file is reached while (eof_flag != 0) { // Initialize array to zero char buffer[1464] = {}; // Send data until fread returns 0 eof_flag = fread(buffer, 1464, 1, fp); // Set length of data to send uint32_t dataLength = strlen(buffer); // Encode data message and set length seqNum = nextSeqNum(seqNum); msg = create_data_message(SEND, seqNum, dataLength, buffer); // Read response // If timeout is reached then retransmit while (dataMsg == NULL || dataMsg->seqNum != seqNum) { // Send and free its memory send_message(sockfd, msg, &server); if (verbose_flag) send_verbose(msg); dataMsg = (data_message_t*)receive_message_with_timeout(sockfd, timeout, &server); dataMsg->seqNum = ntohs(dataMsg->seqNum); if (verbose_flag) ack_verbose((message_t*)dataMsg); } free(msg); // Network order conversion and verbose check free(dataMsg); // Keep track of how much data transferred bytes_transferred += dataLength; int percent = (double)bytes_transferred/(double)fileSize*100; // Print info if percentge is multiple of 10 if (percent % 10 == 0) { printf("--------------------------------\n"); printf("Bytes transferred: %d\n", dataLength); printf("Total bytes transferred: %d\n", bytes_transferred); printf("Percentage complete: %d%%\n--------------------------------\n", percent); } } fclose(fp); seqNum = nextSeqNum(seqNum); msg = create_control_message(TERMINATE, SEND, seqNum, fileSize, fNameLength, filename); // Read final acknowledgment response // If timeout is reached then retransmit while (ctrlMsg == NULL || ctrlMsg->seqNum != seqNum) { // Send type 2 control message to signal eof has been reached send_message(sockfd, msg, &server); if (verbose_flag) send_verbose(msg); ctrlMsg = (control_message_t*)receive_message_with_timeout(sockfd, timeout, &server); ctrlMsg->seqNum = ntohs(ctrlMsg->seqNum); if (ctrlMsg->seqNum != seqNum) ctrlMsg = NULL; } free(msg); // Network order conversion and verbose check if (verbose_flag) ack_verbose((message_t*)ctrlMsg); free(ctrlMsg); close(sockfd); exit(EXIT_SUCCESS); }