bool AdlMetaEngine::addFileProps(const FileMap &allFiles, Common::String fname, FilePropertiesMap &filePropsMap) const { if (filePropsMap.contains(fname)) return true; if (!allFiles.contains(fname)) return false; FileProperties fileProps; fileProps.size = computeMD5(allFiles[fname], fileProps.md5, 16384); if (fileProps.size != -1) { debug(3, "> '%s': '%s'", fname.c_str(), fileProps.md5.c_str()); filePropsMap[fname] = fileProps; } return true; }
/** * When client.out is executed, the client will operate in one of two modes. * In SEED mode, the client first connects to the tracker server and creates a tracker file. It spins of a thread to accept and serve connections (client_handler()), and then updates the tracker server every \a server_update_frequency seconds with new chunks that it is sharing. * In download mode, the client contacts the server every 5 seconds, looking to see if anyone is currently sharing "picture-wallpaper.jpg". Once the server responds with this information, the client downloads the "picture-wallpaper.jpg.track " tracker file from the server, and spins off threads to download the image. * */ int main(int argc, const char* argv[]) { /** * First checks to see if mode, seed_port, client_i, and server_update_frequency were passed in as parameters. * If no parameters were passed, readConfig() is called, and a default values are assigned. */ if (argc < 5) { readConfig(); } else { server_port = 3457; mode = atoi(argv[1]); seed_port = atoi(argv[2]); client_i = atoi(argv[3]); server_update_frequency = atoi(argv[4]); } /* Specifies address: Where we are connecting our socket. */ struct sockaddr_in server_addr = { AF_INET, htons( server_port ) }; struct hostent *hp; /* A buffer for temporarily storing text used in main. */ char buf[CHUNK_SIZE]; /** Get the IP address of the tracker server.*/ if((hp = gethostbyname("localhost")) == NULL) { printf("Error: Unknown Host"); exit(1); } bcopy( hp->h_addr_list[0], (char*)&server_addr.sin_addr, hp->h_length ); /** Initialize the client array so each element is marked as unused. */ setUpPeerArray(); if (mode == SEED) { /** Initialize a TCP connection to the tracker server. */ struct sockaddr_in server_addr = { AF_INET, htons( server_port ) }; if( ( server_sock = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) { perror( "Error: socket failed" ); exit( 1 ); } /** Connect to the server. * Now when we need to communicate to the server, we do it over "server_sock". */ if (connect( server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr) ) == -1 ) { perror( "Error: Connection Issue" ); exit(1); } memset(buf, '\0', sizeof(buf)); /** Calculate the MD5 of the picture file we will be sharing. */ sprintf(buf, "test_clients/client_%d/picture-wallpaper.jpg", client_i); char *md5 = computeMD5(buf); /** Contact the tracker server, and try to create a tracker file. */ sprintf(buf, "<createtracker picture-wallpaper.jpg 35738 img %s localhost %d>", md5, seed_port); write(server_sock, buf , strlen(buf)); free(md5); /** Spin off a single thread that will accept connections, and share chunks. */ /* We use the 0th element of the peers array since we only need 1 thread to upload (as per Final Demo requirement. */ if (pthread_create(&(peers[0].m_thread), NULL, &client_handler, &(client_i)) != 0) { printf("Error Creating Thread\n"); exit(1); } /* Clocks used to wait a predetermined amount of time between contacting the server for a list of tracker files.*/ clock_t elapsed_time, start = clock(); /* The initial lower bound of the segment percentage we are sharing. (ie 21% for client_i = 1) */ int percentage = ((client_i == 1)? (0) : ((client_i * 20) - 19)); int increment, segment_num = 0; /* The client shares in 5% increments. 20 / 5 = 4. So we will increment our percentage 4 times. */ while (segment_num < 4) { elapsed_time = clock() - start; /* If it has been so many seconds... */ if (((float)elapsed_time/CLOCKS_PER_SEC) >= server_update_frequency) { if((server_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror( "Error: socket failed" ); exit( 1 ); } /* Reconnect the the tracker server. */ if (connect( server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr) ) == -1 ) { perror( "Error: Connection Issue" ); exit(1); } increment = (percentage == 0)? (5) : (4); printf("I am client_%d, and I am advertising the following chunk of the file: %d%% to %d%%.\n", client_i, percentage, percentage + increment); /* Update the server, letting it know that we are now sharing an additional 5% of the file. If we had more time, we would have calculated the actual start and end bytes. */ sprintf(buf, "<updatetracker picture-wallpaper.jpg %d %d localhost %d>", percentage /*start byte*/, percentage + increment /*end byte*/, seed_port); write(server_sock, buf , strlen(buf)); /**Increment the percentage of the file we are sharing. */ (percentage == 0)? (percentage+=6) : (percentage+=5); segment_num++; start = clock(); } } } /* When foundPic = 1, this means that the server has responded to the <REQ LIST> command indicating that someone is sharing "picture-wallpaper.jpg" Every 5 seconds, the client will send the <REQ LIST> command and check the servers response. Once somone is sharing the file we want, foundPic = 1.*/ int foundPic = 0; int sent; /** * When presenting in DOWNLOAD mode, the client will automatically contact the tracker server every 5 seconds until someone is sharing the picture-wallpaper.jpg. * The client will then call the <GET> command, download the tracker file from the server, and spin off a download thread. * The client will then allow the user to input commands from the keyboard until the client is closed. */ if (mode == DOWNLOAD) { while (1) { /* Once we begin downloading the picture, we will allow the user to input commands. */ if (foundPic == 1 /* && donwload_finish == false*/) { fgets(buf, sizeof(buf), stdin); } else { /* Wait 5 seconds. */ clock_t elapsed_time, start = clock(); do { elapsed_time = clock() - start; } while (((float)elapsed_time/CLOCKS_PER_SEC) < 5); } /* For presenting mode, the <REQ LIST> command will automatically be called (the foundPic == 0 will always be evaluated to true). */ if ((strncmp(buf, "<REQ LIST>", strlen("<REQ LIST>")) == 0) || foundPic == 0) { /* create a socket */ /* internet stream socket, TCP */ if( ( server_sock = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) { perror( "Error: socket failed" ); exit( 1 ); } /* connect to the server */ if (connect( server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr) ) == -1 ) { perror( "Error: Connection Issue" ); exit(1); } /* Send the server the <REQ LIST> command. */ write(server_sock, "<REQ LIST>", strlen("<REQ LIST>")); memset(buf, '\0', sizeof(buf)); while((sent = read(server_sock, buf, sizeof(buf))) > 0) { /* Search the server's message for the picture-wallpaper tracker file. */ if (strstr(buf, "picture-wallpaper.jpg") != NULL) { /*Once we find it, set foundPic to 1 to allow keyboard input after the download has begun. */ foundPic = 1; } printf("%s", buf); memset(buf, '\0', sizeof(buf)); } /* Since buf now contains a <GET> statement, the <GET> command should be invoked below. */ if (foundPic == 1) { strcpy(buf, "<GET picture-wallpaper.jpg.track>"); } } if (strncmp(buf, "<createtracker", strlen("<createtracker")) == 0) { if( ( server_sock = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) { perror( "Error: socket failed" ); exit( 1 ); } if (connect( server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr) ) == -1 ) { perror( "Error: Connection Issue" ); exit(1); } /* Send the server the <createtracker> command. */ write(server_sock, buf, strlen(buf)); memset(buf, '\0', sizeof(buf)); while((sent = read(server_sock, buf, sizeof(buf))) > 0) { printf("%s", buf); } } if (strncmp(buf, "<updatetracker", strlen("<updatetracker")) == 0) { if( ( server_sock = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) { perror( "Error: socket failed" ); exit( 1 ); } if (connect( server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr) ) == -1 ) { perror( "Error: Connection Issue" ); exit(1); } write(server_sock, buf, strlen(buf)); memset(buf, '\0', sizeof(buf)); while((sent = read(server_sock, buf, sizeof(buf))) > 0) { printf("%s", buf); } printf("\n"); } /* When presenting, this code will automatically be executed once someone is sharing the picture-wallpaper.jpg file. */ if (strncmp(buf, "<GET", strlen("<GET")) == 0) { FILE *file; char tokenize[CHUNK_SIZE], filename[CHUNK_SIZE]; char *line; if( ( server_sock = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) { perror( "Error: socket failed" ); exit( 1 ); } if (connect( server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr) ) == -1 ) { perror( "Error: Connection Issue" ); exit(1); } /* Send the tracker server the command. */ write(server_sock, buf, strlen(buf)); strcpy(tokenize, buf); /*Get the tracker filename*/ line = strtok(tokenize, " "); line = strtok(NULL, ">"); strcpy(filename, line); /* Create an empty file to save the tracker file in. */ file = fopen(filename, "wb"); memset(buf, '\0', sizeof(buf)); while((sent = read(server_sock, buf, sizeof(buf))) > 0) { /* Save the tracker file (sent from server). */ fwrite(buf, sizeof(char), strlen(buf), file); memset(buf, '\0', sizeof(buf)); } fclose(file); /* Spin off 5 downloads thread. */ int i; for (i = 0; i < 1; i++) /* For debugging purposes, we only spin off 1 thread. */ { if (pthread_create(&(peers[i].m_thread), NULL, &download, &(peers[i].m_index)) != 0) { perror("Error creating download thread"); } } } /* if (download_finish == true) { //call xiao's appendSegment() function too piece together everything } */ close(server_sock); } } int i; /** Close the program once all threads have completed their work (seeding or downloading). */ for (i = 0; i < MAX_CLIENT; i++) { pthread_join(peers[i].m_thread, NULL); } return 0; }
void *client_handler(void * index) { /* Dereference the index passed as a parameter by the pthread_create() function */ int client_index = *((int *) index); /* Clear the buffer of any data used by a previous peer in the same index of the clients array. */ memset(clients[client_index].m_buf, '\0', sizeof(clients[client_index].m_buf)); /** * Read data from the peer's socket, store it in m_buf. * Compare the string stored in m_buf to see if it is any of the four commands. * And then serve the peer. */ if (read(clients[client_index].m_peer_socket , clients[client_index].m_buf, CHUNK_SIZE) > 0) { /** <b>CREATETRACKER Command</b> */ if (strncmp(clients[client_index].m_buf, "<createtracker", strlen("<createtracker")) == 0) { /* First check if the client send the correct number of arguments */ int num_arg = 0; char countArgs[CHUNK_SIZE]; char *numArgCheck; stpcpy(countArgs, clients[client_index].m_buf); /* Each argument/param is seperated with a space. */ numArgCheck = strtok(countArgs, " "); while (numArgCheck != NULL) { /* For each string of text separated by a space, or delimited with a new line, * increment num_arg */ num_arg = num_arg + 1; numArgCheck = strtok(NULL, " \n"); } /** If client did not send the correct number of arguments, send a "createtracker fail" protocol message. */ if (num_arg != 7) { write(clients[client_index].m_peer_socket, "<createtracker fail>\n", strlen("<createtracker fail>\n")); } else { /** The create tracker command is broken up into 7 words: * createtracker, filename, filesize, description, md5, ip, and port. * We are interested in the last 6. */ char *filename, *filesize, *description, *md5, *ip, *port; char tokenize[CHUNK_SIZE]; /* We will copy the buffer into a new array, and parse. */ stpcpy(tokenize, clients[client_index].m_buf); /* Get the filename */ filename = strtok(tokenize, " "); /* Skip over the "createtracker" string. */ filename = strtok(NULL, " "); strcpy(filename, filename); /* Get filesize */ filesize= strtok(NULL, " "); strcpy(filesize, filesize); /* Get description */ description = strtok(NULL, " "); strcpy(description, description); /* Get md5 */ md5 = strtok(NULL, " "); strcpy(md5, md5); /* Get IP */ ip = strtok(NULL, " "); strcpy(ip, ip); /* Get port */ port = strtok(NULL, ">"); strcpy(port, port); /* We now need to check to see if this tracker file already exists. */ memset(clients[client_index].m_buf, '\0', sizeof(clients[client_index].m_buf)); sprintf(clients[client_index].m_buf, "Tracker Files/%s.track", filename); /* Ensure that only 1 thread is checking the directory at a time */ pthread_mutex_lock(&file_mutex); /** If this tracker file already exists, send a "createtracker ferr" protocol message. */ if (access(clients[client_index].m_buf, F_OK) == 0) { write(clients[client_index].m_peer_socket, "<createtracker ferr>\n", strlen("<createtracker ferr>\n")); } /** Otherwise, since this tracker file does not exist, create the tracker file. * Start by creating an empty file. */ else if((clients[client_index].m_file = fopen(clients[client_index].m_buf, "w")) != NULL) { memset(clients[client_index].m_buf, '\0', sizeof(clients[client_index].m_buf)); /* Copy the tracker file contents into the buffer. */ //sprintf(clients[client_index].m_buf, "Filename: %s\nFilesize: %s\nDescription: %s\nMD5: %s\n%s:%s:0:%s:%d", filename, filesize, description, md5, ip, port, filesize, (unsigned)time(NULL)); sprintf(clients[client_index].m_buf, "Filename: %s\nFilesize: %s\nDescription: %s\nMD5: %s", filename, filesize, description, md5); /* Write the buffer contents to the new tracker file. */ fwrite(clients[client_index].m_buf, sizeof(char), strlen(clients[client_index].m_buf), clients[client_index].m_file); /** Let the client know that the creation was successful with a "createtracker succ" protocol message. */ write(clients[client_index].m_peer_socket, "<createtracker succ>\n", strlen("<createtracker succ>\n")); /* Close the tracker file. */ fclose(clients[client_index].m_file); } /** If there was a problem creating the file, send the user a "createtracker fail" protocol message. */ else { perror("can't write file"); write(clients[client_index].m_peer_socket, "<createtracker fail>\n", strlen("<createtracker fail>\n")); } /* Unlock the mutex. */ pthread_mutex_unlock(&file_mutex); } } /** <b>UPDATETRACKER Command</b> */ else if (strncmp(clients[client_index].m_buf, "<updatetracker", strlen("<updatetracker")) == 0) { /** The update tracker command is broken up into 6 words: * updatetracker, filename, start byte, end byte, ip, and port. * We are interested in the last 5. */ char *filename, *start, *end, *ip, *port; char tokenize[CHUNK_SIZE]; strcpy(tokenize, clients[client_index].m_buf); /* Get the filename */ filename = strtok(tokenize, " "); filename = strtok(NULL, " "); strcpy(filename, filename); /* Get the start byte */ start = strtok(NULL, " "); strcpy(start, start); /* Get the end byte */ end = strtok(NULL, " "); strcpy(end, end); /* Get IP */ ip = strtok(NULL, " "); strcpy(ip, ip); /* Get port */ port = strtok(NULL, ">"); strcpy(port, port); /* We now need to check to see if this tracker file already exists. */ memset(clients[client_index].m_buf, '\0', sizeof(clients[client_index].m_buf)); sprintf(clients[client_index].m_buf, "Tracker Files/%s.track", filename); pthread_mutex_lock(&file_mutex); /** If this tracker file does not exist, send a "createtracker ferr" protocol message. */ if (access(clients[client_index].m_buf, F_OK) == -1) { write(clients[client_index].m_peer_socket, "<updatetracker ferr>\n", strlen("<updatetracke ferr>\n")); } /** Otherwise, append the new chunk data to the end of the tracker file. */ else { if((clients[client_index].m_file = fopen(clients[client_index].m_buf, "a")) != NULL) { /* Copy contents into buffer. */ sprintf(clients[client_index].m_buf, "\n%s:%s:%s:%s:%d", ip, port, start, end, (unsigned)time(NULL)); /* Append the buffer contents to the end of the tracker file. */ fwrite(clients[client_index].m_buf, sizeof(char), strlen(clients[client_index].m_buf), clients[client_index].m_file); /** Let the client know that the update was successful with a "updatetracker succ" protocol message. */ write(clients[client_index].m_peer_socket, "<updatetracker succ>", strlen("<updatetracker succ>")); /* Close the tracker file. */ fclose(clients[client_index].m_file); } /** If there was a problem updating the file, send the user a "updatetracker fail" protocol message. */ else { write(clients[client_index].m_peer_socket, "<updatetracker fail>\n", strlen("<updatetracke fail>\n")); } } /* Unlock the mutex. */ pthread_mutex_unlock(&file_mutex); } /** <b>REQ LIST Command</b> */ else if (strncmp(clients[client_index].m_buf, "<REQ LIST>", strlen("<REQ LIST>")) == 0) { DIR *tracker_directory; struct dirent *individual_file; pthread_mutex_lock(&file_mutex); /** First, opens the "Tracker Files" folder, and counts the number of files. */ if ((tracker_directory = opendir("Tracker Files")) != NULL) { int num_files = 0; while ((individual_file = readdir(tracker_directory)) != NULL) { /*readdir returns root directories "." and ".."*/ /*We need to ignore them*/ if ((strncmp(individual_file->d_name, ".", 1) != 0) && (strncmp(individual_file->d_name, "..", 2) != 0)) { num_files = num_files + 1; } } if (closedir(tracker_directory) == -1) { perror("Closing dir error.\n"); } /* Send the first line of the LIST response. */ sprintf(clients[client_index].m_buf, "<REP LIST %d>\n", num_files); write(clients[client_index].m_peer_socket, clients[client_index].m_buf, strlen(clients[client_index].m_buf)); } /** For each file in the "Tracker Files" folder, stores the tracker file's: Filename, filesize, and md5. */ if ((tracker_directory = opendir("Tracker Files")) != NULL) { int num_files = 0; while ((individual_file = readdir(tracker_directory)) != NULL) { /*readdir returns root directories "." and ".."*/ /*We need to ignore them*/ if ((strncmp(individual_file->d_name, ".", 1) != 0) && (strncmp(individual_file->d_name, "..", 2) != 0)) { num_files = num_files + 1; memset(clients[client_index].m_buf, '\0', sizeof(clients[client_index].m_buf)); char *line = NULL; char *filename, *filesize, *md5; size_t len = 0; sprintf(clients[client_index].m_buf, "Tracker Files/%s", individual_file->d_name); if((clients[client_index].m_file = fopen(clients[client_index].m_buf, "r")) != NULL) { memset(clients[client_index].m_buf, '\0', sizeof(clients[client_index].m_buf)); sprintf(clients[client_index].m_buf, "<%d",num_files); /* Get the filename */ getline(&line, &len, clients[client_index].m_file); filename = strtok(line, ": "); filename = strtok(NULL, "\n"); strcat(clients[client_index].m_buf, filename); /* Get the filesize */ getline(&line, &len, clients[client_index].m_file); filesize = strtok(line, ": "); filesize = strtok(NULL, "\n"); strcat(clients[client_index].m_buf, filesize); /* Skip over the file description line */ getline(&line, &len, clients[client_index].m_file); /* Get the md5 */ getline(&line, &len, clients[client_index].m_file); md5 = strtok(line, ": "); md5 = strtok(NULL, "\n"); strcat(clients[client_index].m_buf, md5); strcat(clients[client_index].m_buf, ">\n"); fclose(clients[client_index].m_file); free(line); /** Sends each tracker file info, indexed by a number. */ write(clients[client_index].m_peer_socket, clients[client_index].m_buf, strlen(clients[client_index].m_buf)); } } } memset(clients[client_index].m_buf, '\0', sizeof(clients[client_index].m_buf)); strcpy(clients[client_index].m_buf, "<REP LIST END>\n"); /* Send the footer of the "REQ" protocol message */ write(clients[client_index].m_peer_socket, clients[client_index].m_buf, strlen(clients[client_index].m_buf)); if (closedir(tracker_directory) == -1) { perror("Closing dir error.\n"); } } pthread_mutex_unlock(&file_mutex); } /** <b>GET Command</b> */ else if (strncmp(clients[client_index].m_buf, "<GET", strlen("<GET")) == 0) { char *tracker_filename; char parseFileName[CHUNK_SIZE]; /* Get the filename.track */ stpcpy(parseFileName, clients[client_index].m_buf); tracker_filename = strtok(parseFileName, " "); tracker_filename = strtok(NULL, ">"); sprintf(clients[client_index].m_buf, "Tracker Files/%s", tracker_filename); sprintf(tracker_filename, "%s", clients[client_index].m_buf); pthread_mutex_lock(&file_mutex); /** First, the server checks to make sure that the requested tracker file already exists. */ if (access(clients[client_index].m_buf, F_OK) == 0) /* If that file exists..... */ { /** Next, it opens the file, and copies it's contents. */ if((clients[client_index].m_file = fopen(tracker_filename, "r")) != NULL) { /* ADD ME BACK LATER //write(clients[client_index].m_peer_socket, "<REP GET BEGIN>\n", strlen("<REP GET BEGIN>\n")); * */ memset(clients[client_index].m_buf, '\0', sizeof(clients[client_index].m_buf)); int read; /** It then sends the peer the tracker file, copied into a buffer. */ while((read = fread(clients[client_index].m_buf, sizeof(char), CHUNK_SIZE, clients[client_index].m_file)) > 0) { write(clients[client_index].m_peer_socket, clients[client_index].m_buf, read); memset(clients[client_index].m_buf, '\0', sizeof(clients[client_index].m_buf)); } /**Finally, it includes the md5 sum of the tracker file itself, and appends it to the end of the "GET" protocol footer. */ char * md5_string; md5_string = computeMD5(tracker_filename); memset(clients[client_index].m_buf, '\0', sizeof(clients[client_index].m_buf)); /* ADD ME BACK LATER sprintf(clients[client_index].m_buf, "\n<REP GET END %s>", md5_string); */ free(md5_string); /* ADD ME BACK LATER write(clients[client_index].m_peer_socket, clients[client_index].m_buf, strlen(clients[client_index].m_buf)); */ } /** If the tracker file could not be opened, the server sends the peer a "GET invalid" protocol error message. */ else { write(clients[client_index].m_peer_socket, "<GET invalid>", strlen("<GET invalid>")); } } /** If the file does not exist, the server sends the peer a "GET invalid" protocol error message. */ else { write(clients[client_index].m_peer_socket, "<GET invalid>", strlen("<GET invalid>")); } pthread_mutex_unlock(&file_mutex); } } /** <b> Closing the connection to the peer.</b> */ /** * Once the peer's request has been handled, the server closes that socket, * indicates that there is a new opening in the \a client array, * and ends the thread. */ if (close(clients[client_index].m_peer_socket) != 0) { perror("Closing socket issue"); } /* Indicate that this element of the clients array is free to use. */ clients[client_index].m_peer_socket = -1; /* End the thread. * In this context, thread clean-up behaviour using pthread_cancel() and pthread_exit() are the same. */ if (pthread_cancel(clients[client_index].m_thread) != 0) { perror("Ending thread issue"); exit(1); } //return; }