/**respond the cache to client * which contains BOTH the HTTP Response Header * AND the Response Body * i.e. the whole HTTP Response from the server */ int respondCache(char* URL, int client_sd) { char filename[23]; memset(filename, 0, sizeof(filename)); hashURL(filename, URL); char filepath[50]; memset(filepath, 0, sizeof(filepath)); strcpy(filepath, cachePath); strcat(filepath, filename); char block[512]; pthread_mutex_lock(&mutex); FILE* fp = fopen(filepath, "rb"); if (fp == NULL) return -1; int readSize = 0; int totalSize = 0; do { memset(block, 0, sizeof(block)); readSize = fread(block, 1, 512, fp); if (readSize > 0) if (send(client_sd, block, readSize, MSG_NOSIGNAL) <= 0) return -1; totalSize+=readSize; } while(readSize > 0); printf("%srespondCache(): Totally respond %d bytes back to client. %s\n", BG_GREEN, totalSize, DEFAULT); fclose(fp); pthread_mutex_unlock(&mutex); return 0; }
/**If the file does not exist, return -1 * Otherwise, return the raw long time of the Last Modified Time of this file */ time_t getFileModificationTime(char* URL) { // First, hash the URL to filename char filename[23]; memset(filename, 0, sizeof(filename)); hashURL(filename, URL); // Then check if the file, whose name is filename, exists struct stat statbuf; int statReturnValue = stat(cachePath, &statbuf); if (statReturnValue == -1) { mkdir(cachePath, 0777); return -1; } char filepath[50]; memset(filepath, 0, sizeof(filepath)); strcpy(filepath, cachePath); strcat(filepath, filename); //debug printf("getFileModificationTime(): filepath is |%s%s%s|\n", BG_PURPLE, filepath, DEFAULT); memset(&statbuf, 0, sizeof(statbuf)); statReturnValue = stat(filepath, &statbuf); if (statReturnValue == -1) // The file does not exist return -1; return statbuf.st_mtime; }
inline unsigned int Find_longURLSerial(char * shortURL,int * found) { *found = 0; if (loaded_links==0) { return 0; } unsigned long our_hash = hashURL(shortURL); int i=loaded_links-1; while ( i > 0 ) { if (our_hash==links[i].shortURLHash) { *found = 1; return i; } --i; } if (our_hash==links[0].shortURLHash) { *found = 1; return 0; } return 0; }
unsigned long Add_MyURL(char * longURL,char * shortURL,int saveit) { int shortURL_AlreadyExists=0; Find_longURL(shortURL,&shortURL_AlreadyExists); if (shortURL_AlreadyExists) { return 0; } if (loaded_links>=MAX_LINKS) { return 0; } allocateLinksIfNeeded(); unsigned int long_url_length = strlen(longURL); if (long_url_length>=MAX_LONG_URL_SIZE) { return 0; } unsigned int sort_url_length = strlen(shortURL); if (sort_url_length>=MAX_TO_SIZE) { return 0; } pthread_mutex_lock (&db_addIDLock); // LOCK PROTECTED OPERATION ------------------------------------------- //it might not seem like it but here we are doing two seperate operations //first we give our_index the loaded_links value , and then we increment loaded_links //of course this is a potential race condition where two threads assign themselves the same link //and we have an empty record after that , solved using a lock protection unsigned int our_index=loaded_links++; pthread_mutex_unlock (&db_addIDLock); // LOCK PROTECTED OPERATION ------------------------------------------- links[our_index].longURL = ( char * ) malloc (sizeof(char) * (long_url_length+1) ); //+1 for null termination if ( links[our_index].longURL == 0 ) { AmmServer_Warning("Could not allocate space for a new string \n "); return 0; } links[our_index].shortURL = ( char * ) malloc (sizeof(char) * (sort_url_length+1) ); //+1 for null termination if ( links[our_index].shortURL == 0 ) { AmmServer_Warning("Could not allocate space for a new string \n "); return 0; } links[our_index].shortURLHash=hashURL(shortURL); strncpy(links[our_index].longURL,longURL,long_url_length); links[our_index].longURL[long_url_length]=0; // null terminator :P strncpy(links[our_index].shortURL,shortURL,sort_url_length); links[our_index].shortURL[sort_url_length]=0; // null terminator :P if (saveit) { Append2MyURLDBFile(db_file,longURL,shortURL); } if ( REGROUP_AFTER_X_UNSORTED_LINKS <= loaded_links-sorted_links ) { ResortDB(db_file,links,loaded_links); } return 1; }
//Binary Search inline unsigned int Find_longURL(char * shortURL,int * found) { #if USE_BINARY_SEARCH *found = 0; if (shortURL==0) { return 0; } if (loaded_links==0) { return 0; } if (sorted_links!=0) { unsigned long our_hash = hashURL(shortURL); unsigned int binarySearchLastElement = sorted_links; unsigned int beg=0,mid=0,fin=binarySearchLastElement-1; while ( beg <= fin ) { mid=(unsigned int) beg + ( (fin-beg)/2 ); if (mid >= binarySearchLastElement) { AmmServer_Error("Binary Search overflowed ( beg %u mid %u fin %u ) , binarySearchLastElement %u \n",beg,mid,fin,binarySearchLastElement); break; } else if (our_hash<links[mid].shortURLHash) { fin=mid-1; } else if (our_hash>links[mid].shortURLHash) { beg=mid+1; } else { *found = 1; AmmServer_Success("Found %s using binary search\n",shortURL); return mid; } } } //TODO : Remove this message in the future ------------- AmmServer_Warning("Binary Search couldn't find result , extending search to unsorted list\n"); return Find_longURLSerial(shortURL,found); //---------------------------------------- #else // USE_BINARY_SEARCH return Find_longURLSerial(shortURL,found); #endif return 0; }
/** Simutaneously cache the whole server response * and forward the response back to the client */ int cacheServerResponse(char* responseHeader, char* URL, int server_sd, int client_sd, int has_no_body) { char responseHeaderCopy[MAX_RESPONSE_SIZE]; strcpy(responseHeaderCopy, responseHeader); char filename[23]; memset(filename, 0, sizeof(filename)); hashURL(filename, URL); char filepath[50]; memset(filepath, 0, sizeof(filepath)); strcpy(filepath, cachePath); strcat(filepath, filename); // First write the header part of the response to cache file pthread_mutex_lock(&mutex); FILE* fp = fopen(filepath, "wb"); int byteWritten = fwrite(responseHeaderCopy, 1, strlen(responseHeaderCopy), fp); if (byteWritten == 0) return -1; // fwrite error? // Then forward the header part to client if (send(client_sd, responseHeaderCopy, strlen(responseHeaderCopy), MSG_NOSIGNAL) <= 0) return -1; int totalSize = strlen(responseHeaderCopy); // Then if the response has body, continue to write the body part to cache // And forward it back to client at the same time if (!has_no_body) { char block[1024]; // Read body from server block by block while(1) { memset(block, 0, sizeof(block)); int readSize = read(server_sd, block, sizeof(block)); //debug // printf("cacheServerResponse(): readSize is now: /%s%d%s/\n", BG_YELLOW, readSize, DEFAULT); if (readSize < 0) // read error? return -1; if (readSize == 0) // has read up the response body break; // Write the body block to cache fwrite(block, 1, readSize, fp); // Send the body block back to client if (send(client_sd, block, readSize, MSG_NOSIGNAL) <= 0) return -1; totalSize += readSize; } } printf("%scacheServerResponse(): Cached and forwarded %d bytes in total%s\n", BG_PURPLE, totalSize, DEFAULT); fclose(fp); pthread_mutex_unlock(&mutex); return 0; }