aboutsummaryrefslogtreecommitdiffstats
path: root/P3
diff options
context:
space:
mode:
Diffstat (limited to 'P3')
-rw-r--r--P3/server.c214
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;
}