diff options
Diffstat (limited to '')
-rw-r--r-- | P3/server.c | 214 |
1 files changed, 69 insertions, 145 deletions
diff --git a/P3/server.c b/P3/server.c index 37f5cc3..2b0d931 100644 --- a/P3/server.c +++ b/P3/server.c @@ -35,16 +35,14 @@ void *worker(void *arg); */ // structs: -typedef struct request_queue -{ +typedef struct request_queue { int fd; char *request; struct request_queue *next; } request_t; request_t *Q = NULL; // The request queue -typedef struct cache_entry -{ +typedef struct cache_entry { int len; char *request; char *content; @@ -55,18 +53,15 @@ cache_entry_t *dynQ = NULL; //The cache queue /* ******************** Dynamic Pool Code [Extra Credit A] **********************/ // Extra Credit: This function implements the policy to change the worker thread pool dynamically // depending on the number of requests -void *dynamic_pool_size_update(void *arg) -{ - while (1) - { +void *dynamic_pool_size_update(void *arg) { + while (1) { // Run at regular intervals usleep(1000000); // Increase / decrease dynamically based on your policy // Policy: Have clock tracking how long the whole process takes // If above maxProcessTime -> spawn X workers // Else if below mostEfficientTime kill all unnecessary threads leaving 1(or 2) of each - if (total_t > 3000) - { + if (total_t > 3000) { // Threads must be detachable pthread_t * newwID = (pthread_t *) realloc(wID, (++wIndex * sizeof(pthread_t))); pthread_attr_t attr; @@ -80,8 +75,7 @@ void *dynamic_pool_size_update(void *arg) pthread_setname_np(wID[wIndex - 1], threadName); printf("Created a new thread\n"); } - else if (total_t < 500) - { + else if (total_t < 500) { //TODO: Make sure thread isn't doing anything before killing it pthread_cancel(wID[wIndex--]); // Need dynamically allocated array of thread ID's so we can cancel the necessary threads @@ -96,20 +90,17 @@ void *dynamic_pool_size_update(void *arg) // Function to check whether the given request is present in cache // return the index if the request is present in the cache -int isInCache(char *request) -{ +int isInCache(char *request) { cache_entry_t *traverse = dynQ; if (dynQ == NULL) return -2; int index = 0; - while (traverse != NULL) - { + while (traverse != NULL) { if (traverse->request == NULL) break; if (!strcmp(request, traverse->request)) - { return index; - } + //else traverse = traverse->next; index++; } @@ -117,22 +108,18 @@ int isInCache(char *request) } // Function to traverse cache queue to find cache -int readFromCache(int index, char *buffer) -{ +int readFromCache(int index, char *buffer) { cache_entry_t *traverse = dynQ; if (traverse == NULL) return -1; for (int i = 0; i < index; i++) - { traverse = traverse->next; - } memcpy(buffer, traverse->content, traverse->len); return 0; } // Function to add the request and its file content into the cache -void addIntoCache(char *mybuf, char *memory, int memory_size) -{ +void addIntoCache(char *mybuf, char *memory, int memory_size) { // It should add the request at an index according to the cache replacement policy // Make sure to allocate/free memory when adding or replacing cache entries @@ -140,10 +127,8 @@ void addIntoCache(char *mybuf, char *memory, int memory_size) if (dynQ == NULL) return; bool fullCache = false; - while (traverse->next != NULL) - { - if (cacheLength >= maxCSiz) - { + while (traverse->next != NULL) { + if (cacheLength >= maxCSiz) { fullCache = true; break; } @@ -151,9 +136,8 @@ void addIntoCache(char *mybuf, char *memory, int memory_size) } char *silence = (char *)malloc(memory_size + 1); memcpy(silence, memory, memory_size); - if (fullCache) - { - //Make temp node to delete oldest member of cache + if (fullCache) { + //Delete oldest member of cache (the first one on the list) cache_entry_t *temp = dynQ; dynQ = dynQ->next; free(temp->content); @@ -162,20 +146,16 @@ void addIntoCache(char *mybuf, char *memory, int memory_size) free(silence); cacheLength--; addIntoCache(mybuf, memory, memory_size); - } - else - { + } else { //Cache is not full cache_entry_t *temp = (cache_entry_t *)calloc(1, sizeof(cache_entry_t)); temp->request = mybuf; temp->content = silence; temp->len = memory_size; - if (cacheLength == 0) - { + if (cacheLength == 0) { dynQ = temp; pthread_cond_signal(&cacheIsEmpty); } - else - { + else { traverse->next = temp; } cacheLength++; @@ -188,8 +168,7 @@ void deleteCache() { request_t *tempReq = NULL; pthread_mutex_lock(&Qlock); - while (Q != NULL) - { + while (Q != NULL) { tempReq = Q; Q = Q->next; free(tempReq->request); @@ -200,8 +179,7 @@ void deleteCache() // De-allocate/free the cache memory cache_entry_t *tempCache = NULL; pthread_mutex_lock(&cacheLock); - while (dynQ != NULL) - { + while (dynQ != NULL) { tempCache = dynQ; dynQ = dynQ->next; free(tempCache->content); @@ -214,8 +192,7 @@ void deleteCache() // Function to initialize the cache -void initCache() -{ +void initCache(){ // Allocating memory and initializing the cache array dynQ = (cache_entry_t *)malloc(sizeof(cache_entry_t)); wIndex = 0; @@ -226,39 +203,32 @@ void initCache() /* ************************************ Utilities ********************************/ // Function to get the content type from the request -char *getContentType(char *mybuf) -{ +char *getContentType(char *mybuf) { // Should return the content type based on the file type in the request // (See Section 5 in Project description for more details) char *ext = strrchr(mybuf, '.'); - if (ext == NULL) - { + if (ext == NULL) { printf("Filetype not found. Exiting\n"); - exit(-1); + return NULL; } - else if ((strcmp((ext + 1), "htm") == 0) || (strcmp((ext + 1), "html") == 0)) - { + else if ((strcmp((ext + 1), "htm") == 0) || (strcmp((ext + 1), "html") == 0)) { return "text/html"; } - else if (strcmp((ext + 1), "jpg") == 0) - { + else if (strcmp((ext + 1), "jpg") == 0) { return "image/jpeg"; } - else if (strcmp((ext + 1), "gif") == 0) - { + else if (strcmp((ext + 1), "gif") == 0) { return "image/gif"; } - else - { + else { return "text/plain"; } } // Function to get the size of the file in the queue // (Thanks Matt from stackOverflow) -long getFileSize(char *file) -{ +long getFileSize(char *file){ char *temp = (char *)malloc(BUFF_SIZE); sprintf(temp, ".%s", file); FILE *f = fopen(temp, "r"); @@ -266,24 +236,21 @@ long getFileSize(char *file) if (f == NULL) return 0; fseek(f, 0, SEEK_END); - long len = (long)ftell(f); + long len = ftell(f); fclose(f); return len; } // Function to open and read the file from the disk into the memory // Add necessary arguments as needed -int readFromDisk(char *fileName, char *buffer, long fileSize) -{ +int readFromDisk(char *fileName, char *buffer, long fileSize) { char *temp = (char *)malloc(BUFF_SIZE + 1); sprintf(temp, ".%s", fileName); // Open and read the contents of file given the request int requestFile = open(temp, O_RDONLY); free(temp); if (requestFile == -1) - { return -1; // Error handle - } read(requestFile, buffer, fileSize); close(requestFile); return 0; @@ -292,33 +259,23 @@ int readFromDisk(char *fileName, char *buffer, long fileSize) /**********************************************************************************/ // Function to receive the request from the client and add to the queue -void *dispatch(void *arg) -{ - - while (1) - { +void *dispatch(void *arg){ + while (1) { // Accept client connection and get the fd int newReq = accept_connection(); - if (newReq > INVALID) - { + if (newReq > INVALID) { pthread_mutex_lock(&Qlock); while (curQSiz == maxQlen) pthread_cond_wait(&QisFull, &Qlock); request_t *traverse = Q; - - int i; - for (i = 0; i < maxQlen - 1; i++) - { - - if (traverse == NULL || traverse->next == NULL) - { + for (int i = 0; i < maxQlen; i++) { + if (traverse == NULL || traverse->next == NULL) { //Add things to queue. Lock & unlock to prevent a deadlock request_t *tempNode = (request_t *)malloc(sizeof(request_t)); tempNodeCounter++; char *dispatchBuf = (char *)malloc(BUFF_SIZE); // Buffer to store the requested filename - if (get_request(newReq, dispatchBuf) != 0) - { + if (get_request(newReq, dispatchBuf) != 0) { free(tempNode); tempNodeCounter--; free(dispatchBuf); @@ -328,21 +285,16 @@ void *dispatch(void *arg) tempNode->fd = newReq; tempNode->request = dispatchBuf; tempNode->next = NULL; - if (traverse == NULL) - { + if (traverse == NULL) { Q = tempNode; pthread_cond_signal(&QisEmpty); - } - else - { + } else { traverse->next = tempNode; } curQSiz++; pthread_mutex_unlock(&Qlock); break; - } - else - { + } else { traverse = traverse->next; } } @@ -354,17 +306,15 @@ void *dispatch(void *arg) /**********************************************************************************/ // Function to retrieve the request from the queue, process it and then return a result to the client -void *worker(void *arg) -{ +void *worker(void *arg) { int id = *(int *)arg; long numbytes; unsigned long numReqs = 0; - while (1) - { + while (1) { // Get the request from the queue pthread_mutex_lock(&Qlock); while (curQSiz == 0) - pthrad_cond_wait(&QisEmpty, &Qlock); + pthread_cond_wait(&QisEmpty, &Qlock); // if (Q == NULL) // { // pthread_mutex_unlock(&Qlock); @@ -384,41 +334,32 @@ void *worker(void *arg) char *workerBuf = (char *)calloc(numbytes + 1, sizeof(char)); char *bytesError = (char *)malloc(BUFF_SIZE); bool fail = false; - if (numbytes != 0) - { + if (numbytes != 0) { //SUCC sprintf(bytesError, "%ld", numbytes); - } - else - { + } else { //ERR fail = true; sprintf(bytesError, "%s", strerror(errno)); } char *cacheTest; //HIT/MISS only - if (!fail) - { + if (!fail) { //Make sure nothing is fiddling with cache before fiddling with cache pthread_mutex_lock(&cacheLock); int test = isInCache(request->request); - if (test != -1) - { + if (test != -1) { //In cache, file exists cacheTest = "HIT"; readFromCache(test, workerBuf); pthread_mutex_unlock(&cacheLock); - } - else - { + } else { pthread_mutex_unlock(&cacheLock); cacheTest = "MISS"; - if (readFromDisk(request->request, workerBuf, numbytes) == -1) - { + if (readFromDisk(request->request, workerBuf, numbytes) == -1) { //Not in cache, disk read failed fail = true; } - else - { + else { //Not in cache, disk read succeeds pthread_mutex_lock(&cacheLock); addIntoCache(request->request, workerBuf, numbytes); @@ -437,13 +378,11 @@ void *worker(void *arg) free(bytesError); // Return the result - if (fail) - { + if (fail) { //ERR return_error(request->fd, request->request); } - else - { + else { //SUCC return_result(request->fd, getContentType(request->request), workerBuf, numbytes); } @@ -463,16 +402,13 @@ void *worker(void *arg) static volatile sig_atomic_t exitFlag = 0; //Sets e flag so process can die happily and not sad. -static void eggs(int signo) -{ +static void eggs(int signo) { exitFlag |= 1; } -int main(int argc, char **argv) -{ +int main(int argc, char **argv) { // Error check on number of arguments - if (argc != 8) - { + if (argc != 8) { printf("usage: %s port path num_dispatcher num_workers dynamic_flag queue_length cache_size\n", argv[0]); return -1; } @@ -488,28 +424,24 @@ int main(int argc, char **argv) //Dynamic worker flag dynFlag = atoi(argv[5]); //Queue Length - maxQlen = atoi(argv[6]); + maxQlen = atoi(argv[6]) - 1; //Max cache size - maxCSiz = atoi(argv[7]); + maxCSiz = atoi(argv[7]) - 1; /* -- ERROR CHECKING -- */ - if (port < 1025 || port > 65535) - { + if (port < 1025 || port > 65535) { printf("Invalid port. Port must be greater than 1025 or less than 65535 (inclusive).\n"); return -1; } - if (dispatchers > MAX_THREADS || dispatchers < 1) - { + if (dispatchers > MAX_THREADS || dispatchers < 1) { printf("Number of dispatchers is invalid. It must be greater than 1 or less than %d (inclusive).\n", MAX_THREADS); return -1; } - if (workers > MAX_THREADS || workers < 1) - { + if (workers > MAX_THREADS || workers < 1) { printf("Number of dispatchers is invalid. It must be greater than 1 or less than %d (inclusive).\n", MAX_THREADS); return -1; } - if (maxQlen > MAX_queue_len || maxQlen < 1) - { + if (maxQlen > MAX_queue_len || maxQlen < 1) { printf("Queue length is invalid It must be greater than 1 or less than %d (inclusive).\n", MAX_queue_len); return -1; } @@ -519,8 +451,7 @@ int main(int argc, char **argv) struct sigaction act; act.sa_handler = eggs; act.sa_flags = 0; - if (sigemptyset(&act.sa_mask) == -1 || sigaction(SIGINT, &act, NULL) == -1) - { + if (sigemptyset(&act.sa_mask) == -1 || sigaction(SIGINT, &act, NULL) == -1) { perror("SIGINT Handler Error"); return -2; } @@ -529,8 +460,7 @@ int main(int argc, char **argv) fclose(logfile); // Change the current working directory to server root directory - if (chdir(path) == -1) - { + if (chdir(path) == -1) { perror("Directory Change error"); return -2; } @@ -546,8 +476,7 @@ int main(int argc, char **argv) char threadName[16]; // Create dispatcher threads (make detachable????) pthread_t dThreads[dispatchers]; - for (int i = 0; i < dispatchers; i++) - { + for (int i = 0; i < dispatchers; i++) { pthread_create(&dThreads[i], &attr, dispatch, NULL); // DEBUG! figure out last arg sprintf(threadName, "Dispatch %d", i); pthread_setname_np(dThreads[i], threadName); @@ -555,8 +484,7 @@ int main(int argc, char **argv) //Create workers (make detachable?????) int *Wargs = (int *)malloc(sizeof(int) * workers); wID = (pthread_t *)malloc(workers * sizeof(pid_t)); - for (int i = 0; i < workers; i++) - { + for (int i = 0; i < workers; i++) { wIndex++; Wargs[i] = i; pthread_create(&wID[i], &attr, worker, (void *)&Wargs[i]); //TODO: Worker arguments @@ -565,25 +493,21 @@ int main(int argc, char **argv) } free(Wargs); // Create dynamic pool manager thread (extra credit A) - if (dynFlag) - { + if (dynFlag) { pthread_t pThread; pthread_create(&pThread, &attr, dynamic_pool_size_update, NULL); //TODO: possible arguments pthread_setname_np(pThread, "Pool Manager"); } //Server loop (RUNS FOREVER) - while (1) - { + while (1) { //TODO: Add something else? // Terminate server gracefully - if (exitFlag) - { + if (exitFlag) { printf("\nSIGINT caught, exiting now.\n"); // Print the number of pending requests in the request queue int pendReqs; - for (pendReqs = 0; pendReqs < maxQlen; pendReqs++) - { + for (pendReqs = 0; pendReqs < maxQlen; pendReqs++) { if (Q == NULL || Q->next == NULL) break; } |