From 23c4e0c2fa0394ad241412b42656319506d5ec43 Mon Sep 17 00:00:00 2001 From: Abhisha Nirmalathas <a.nirmalathas1@student.unimelb.edu.au> Date: Sun, 21 Apr 2019 10:32:01 +1000 Subject: [PATCH] cookie initial implementation --- hashtable.c | 21 ++++- hashtable.h | 4 +- http-parser.c | 51 +++++++++---- http-parser.h | 4 +- http-response.c | 16 +++- http-server.c | 199 +++++++++++++++++++++++++++--------------------- user.c | 7 +- 7 files changed, 189 insertions(+), 113 deletions(-) diff --git a/hashtable.c b/hashtable.c index a02d701..c85a4c0 100644 --- a/hashtable.c +++ b/hashtable.c @@ -54,6 +54,8 @@ Bucket *add_to_bucket(Bucket *bucket, char *key, char *value) { //adds new key and avlue to end of bucket bucket->values[bucket->n_elems-1] = value; bucket->keys[bucket->n_elems-1] = key; + // printf("key is %s\n\n", bucket->keys[bucket->n_elems-1]); + // printf("value is %s\n\n", bucket->values[bucket->n_elems-1]); return bucket; } /************************************************************************/ @@ -108,17 +110,17 @@ void hash_table_put(HashTable *table, char *key, char *value) { int hash_value = xor_hash(key, table->size); // look for existing key Bucket *bucket = &table->buckets[hash_value]; + printf("the number of elements in bucket is %d\n", bucket->n_elems); for (int i=0; i < bucket->n_elems; i++){ if (equal(bucket->keys[i], key)){ bucket->values[i] = value; - move_to_front(bucket, i); return; } } // adds key and value as not in hash table bucket = add_to_bucket(bucket, key, value); table->buckets[hash_value] = *bucket; - move_to_front(bucket, bucket->n_elems - 1); + printf("the number of elements in bucket is %d\n", bucket->n_elems); } /************************************************************************/ void move_to_front(Bucket *bucket, int index){ @@ -176,7 +178,7 @@ bool hash_table_has(HashTable *table, char *key) { return false; } char* print_hash_map(HashTable *table){ - char* headers = calloc(100,sizeof(char)); + char* headers = calloc(800,sizeof(char)); assert(headers); for (int i = 0; i < table->size; i++) { if (table->buckets[i].n_elems > 0){ @@ -204,4 +206,15 @@ void free_cookie(HashTable *headers) { free(bucket->values[i]); } } -} \ No newline at end of file +} + +void free_hash_map(HashTable *table){ + for (int i = 0; i < table->size; i++) { + if (table->buckets[i].n_elems > 0){ + for (int j=0; j< table->buckets[i].n_elems; j++){ + free(table->buckets[i].keys[j]); + free(table->buckets[i].values[j]); + } + } + } +} diff --git a/hashtable.h b/hashtable.h index 4f50386..0a266fd 100644 --- a/hashtable.h +++ b/hashtable.h @@ -25,4 +25,6 @@ bool hash_table_has(HashTable *table, char *key); char* print_hash_map(HashTable *table); -void free_cookie(HashTable *headers); \ No newline at end of file +void free_cookie(HashTable *headers); + +void free_hash_map(HashTable *table); \ No newline at end of file diff --git a/http-parser.c b/http-parser.c index a5a5a27..9d2f9d2 100644 --- a/http-parser.c +++ b/http-parser.c @@ -9,20 +9,20 @@ #include <string.h> #include <assert.h> #include "http-parser.h" +#include "hashtable.h" // user-determined constants for requests #define MAX_URL_SIZE 60 -#define MAX_HEADER_SIZE 600 +#define MAX_HEADER_SIZE 200 #define MAX_VERSION_SIZE 10 -#define MAX_HEADERS 10 +#define MAX_HEADERS 20 Request* parse_request(char* request_message){ /** * Reads a requests and creates a request object containing the parsed information * */ - Request *req = calloc(1, sizeof(Request)); + Request *req = calloc(1, sizeof *req); assert(req); - memset(req, 0, sizeof(Request)); // parses the method of the request if (strncmp(request_message, "GET ", 4) == 0){ @@ -47,20 +47,24 @@ Request* parse_request(char* request_message){ //parses the headers req->header = new_hash_table(MAX_HEADERS); - char header_field_name[MAX_HEADER_SIZE]; - char header_value[MAX_HEADER_SIZE]; + // char *header_field_name = calloc(MAX_HEADER_SIZE, sizeof(char)); + // char *header_value = calloc(MAX_HEADER_SIZE, sizeof(char)); while(*request_message != '\r' && *request_message != '\n'){ + request_message = insert_headers(request_message, req); // printf("req message first char %d\n", *request_message); - strcpy(header_field_name,strtok(request_message, " ")); - // printf("header field name: %s\n", header_field_name); - request_message += strcspn(request_message, " ")+1; - strcpy(header_value,strtok(request_message, "\r\n")); - // printf("header value: %s\n", header_value); - request_message += strcspn(request_message, "\r\n")+2; - hash_table_put(req->header, header_field_name, header_value); + // memset(header_field_name,0,strlen(header_field_name)); + // memset(header_value,0,strlen(header_value)); + // size_t field_len = strcspn(request_message, " "); + // memcpy(header_field_name, request_message,field_len); + // request_message += field_len+1; + // size_t value_len = strcspn(request_message, "\r\n"); + // memcpy(header_value,request_message, value_len); + // printf("header key: %s\n", header_field_name); + // request_message += value_len+2; + // hash_table_put(req->header, header_field_name, header_value); } request_message += strcspn(request_message, "\r\n")+2; - + printf("request header %s\n", print_hash_map(req->header)); // parses the body if(*request_message != '\r'||*request_message != '\n'){ req->body = request_message; @@ -71,10 +75,27 @@ Request* parse_request(char* request_message){ return req; } +char* insert_headers(char* request_message, Request * req){ + char *header_field_name = calloc(MAX_HEADER_SIZE, sizeof(char)); + char *header_value = calloc(MAX_HEADER_SIZE, sizeof(char)); + memset(header_field_name,0,strlen(header_field_name)); + memset(header_value,0,strlen(header_value)); + size_t field_len = strcspn(request_message, " "); + memcpy(header_field_name, request_message,field_len); + request_message += field_len+1; + size_t value_len = strcspn(request_message, "\r\n"); + memcpy(header_value,request_message, value_len); + printf("header key: %s\n", header_field_name); + request_message += value_len+2; + hash_table_put(req->header, header_field_name, header_value); + return request_message; +} + void free_request(Request* req){ /** * Deallocates memory * */ + free_hash_map(req->header); free_hash_table(req->header); - free(req); + // free(req); } diff --git a/http-parser.h b/http-parser.h index 203079e..0343385 100644 --- a/http-parser.h +++ b/http-parser.h @@ -27,4 +27,6 @@ typedef struct Request { Request* parse_request(char* request_message); // Deallocates memory -void free_request(Request* req); \ No newline at end of file +void free_request(Request* req); + +char* insert_headers(char* request_message, Request * req); \ No newline at end of file diff --git a/http-response.c b/http-response.c index 626b5d9..66efeb7 100644 --- a/http-response.c +++ b/http-response.c @@ -16,7 +16,7 @@ #define MAX_URL_SIZE 60 #define MAX_HEADER_SIZE 300 #define MAX_VERSION_SIZE 10 -#define MAX_N_HEADERS 2 +#define MAX_N_HEADERS 4 char* cookie_generator(){ /** @@ -24,7 +24,7 @@ char* cookie_generator(){ * */ char* cookie_value; cookie_value = (char*) malloc(sizeof(char)*60); - snprintf(cookie_value, 60, "sessionToken=%d; Expires=Wed, 01 Apr 2019 10:10:10 GMT", rand()); + snprintf(cookie_value, 60, "id=%d", rand() % (111-0+1)); return cookie_value; } @@ -44,7 +44,9 @@ Response* initialise_session(Request* request){ // sets the cookies char *cookie = cookie_generator(); + hash_table_put(resp->header, "Content-length: ", "%ld"); hash_table_put(resp->header, "Set-cookie: ", cookie); + hash_table_put(resp->header, "Content-type: ", "text/html"); // sends empty body resp->body=""; @@ -69,8 +71,14 @@ char* parse_response(Response* response){ strncat(response_string, headers, strlen(headers)); strcat(response_string, "\r\n"); strcat(response_string, response->body); - // free(headers); - return response_string; + strcat(response_string, "\r\n"); + char * new_response_string = calloc(100,sizeof(char)); + assert(new_response_string); + strncpy(new_response_string, response_string, strlen(response_string)); + free(headers); + free(response_string); + return new_response_string; + // return response_string; } diff --git a/http-server.c b/http-server.c index 8aba403..36212c2 100644 --- a/http-server.c +++ b/http-server.c @@ -25,6 +25,7 @@ #include <sys/types.h> #include <unistd.h> #include "response-formatter.h" +#include "hashtable.h" #include "http-parser.h" #include "http-response.h" #include "hashtable.h" @@ -40,6 +41,8 @@ static int const HTTP_400_LENGTH = 47; static char const * const HTTP_404 = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n"; static int const HTTP_404_LENGTH = 45; +static Request* req; +static User_list* user_list; int keep_alive = 1; @@ -49,28 +52,32 @@ bool player_session(char* buff, int sockfd, char* file_name, char* response){ * */ struct stat st; stat(file_name, &st); + // printf("pre add %s\n", buff); int n = sprintf(buff, response, st.st_size); + printf("post add %s\n", buff); // send the header first if (write(sockfd, buff, n) < 0) { perror("write"); return false; } - // send the file + // read the content of the HTML file int filefd = open(file_name, O_RDONLY); - do - { - n = sendfile(sockfd, filefd, NULL, 2048); - } - while (n > 0); + n = read(filefd, buff, st.st_size); + clean_trailing_buffer(buff); if (n < 0) { - perror("sendfile"); + perror("read"); close(filefd); return false; } close(filefd); - return true; + if (write(sockfd, buff, st.st_size) < 0) + { + perror("write"); + return false; + } + return true; } bool text_render_response(char *buff, int sockfd, char* file_name, char* text){ /** @@ -117,7 +124,9 @@ bool response(char *buff, int sockfd, char* file_name){ * */ struct stat st; stat(file_name, &st); + printf("pre add %s\n", buff); int n = sprintf(buff, HTTP_200_FORMAT, st.st_size); + printf("post add %s\n", buff); // send the header first if (write(sockfd, buff, n) < 0) { @@ -220,7 +229,7 @@ bool text_render_game_play(char *buff, int sockfd, char* file_name, char* text, return true; } -static bool handle_http_request(int sockfd, User_list *users){ +static bool handle_http_request(int sockfd, User_list *user_list){ /** * Parses the http request and sends the approapriate response * */ @@ -241,14 +250,12 @@ static bool handle_http_request(int sockfd, User_list *users){ char * curr = buff; // parse the method - Request* req = parse_request(curr); - User* user = get_current_user(users, sockfd); - // printf("REQUEST BODY IS \n\n%s\n", req->url); + // printf("REQUEST IS \n\n%s\n", buff); + req = parse_request(curr); // user should quit game if(strncmp(req->body, "quit=Quit", 9) == 0){ - printf("run\n\n\n\n\\n"); - change_player_status(sockfd,users, QUIT); + change_player_status(sockfd,user_list, QUIT); response(buff,sockfd, "7_gameover.html"); // free_request(req); // return false; @@ -256,56 +263,60 @@ static bool handle_http_request(int sockfd, User_list *users){ // user starting game else if (strncmp(req->url, "/?start=Start", 24) == 0){ - + // printf("THE COOKIE IS %s\n", hash_table_get(req->header, "Cookie: ")); + int id = atoi(hash_table_get(req->header, "Cookie:")+3); + User* user = get_current_user(user_list, id); // user on first turn - if (req->method == GET){ - change_player_status(sockfd, users, READY); - int round = change_player_round(sockfd, users); - game_change(buff,sockfd, "3_first_turn.html", round); - } - if (req->method == POST){ - if(strncmp(req->body, "keyword=", 8) == 0){ - - // checks if other player has quit - if(should_player_quit(users)){ - printf("is quit"); - change_player_status(sockfd,users, QUIT); - response(buff,sockfd, "7_gameover.html"); - // free_request(req); - // keep_alive = 0; - // return false; - } - - // checks if other player has not completed previous round - else if (different_round_discard(sockfd,users)){ - game_change(buff,sockfd, "5_discarded.html", user->round); - } - - // checks if game won - else if(player_won(users)){ - response(buff,sockfd, "6_endgame.html"); - change_player_status(sockfd, users, WAIT); - } + if (user != NULL){ + printf("user aint null"); + if (req->method == GET){ + change_player_status(id, user_list, READY); + int round = change_player_round(id, user_list); + game_change(buff,sockfd, "3_first_turn.html", round); + } + if (req->method == POST){ + if(strncmp(req->body, "keyword=", 8) == 0){ + + // checks if other player has quit + if(should_player_quit(user_list)){ + change_player_status(id,user_list, QUIT); + response(buff,sockfd, "7_gameover.html"); + // free_request(req); + // keep_alive = 0; + // return false; + } - //checks if the other player is not ready and discards keyword - else if(!players_ready(users) && user!= NULL){ - game_change(buff,sockfd, "5_discarded.html", user->round); - //request(buff,sockfd, "5_discarded.html"); - } - else{ - char* keyword = add_keyword(sockfd, users, req->body); + // checks if other player has not completed previous round + else if (different_round_discard(id,user_list)){ + game_change(buff,sockfd, "5_discarded.html", user->round); + } - // game ends as submitted keyword has been submitted by other player - if(has_match_ended(users, keyword, sockfd)){ + // checks if game won + else if(player_won(user_list)){ response(buff,sockfd, "6_endgame.html"); - change_all_status(users, COMPLETE); + change_player_status(id, user_list, WAIT); + } + + //checks if the other player is not ready and discards keyword + else if(!players_ready(user_list) && user!= NULL){ + game_change(buff,sockfd, "5_discarded.html", user->round); + //request(buff,sockfd, "5_discarded.html"); } else{ - // keyword hasn't been submitted yet so is accepted and rendered on screen - if(user!= NULL){ - char* keywords = return_all_keywords(user); - text_render_game_play(buff,sockfd, "4_accepted.html", keywords, user->round); - free(keywords); + char* keyword = add_keyword(sockfd, user_list, req->body); + + // game ends as submitted keyword has been submitted by other player + if(has_match_ended(user_list, keyword, id)){ + response(buff,sockfd, "6_endgame.html"); + change_all_status(user_list, COMPLETE); + } + else{ + // keyword hasn't been submitted yet so is accepted and rendered on screen + if(user!= NULL){ + char* keywords = return_all_keywords(user); + text_render_game_play(buff,sockfd, "4_accepted.html", keywords, user->round); + free(keywords); + } } } } @@ -322,9 +333,9 @@ static bool handle_http_request(int sockfd, User_list *users){ char *name = strchr(req->body, '=')+1; // printf("**%s**\n", name); if (name != NULL){ - for (int i=0; i < users->n_users; i++){ - if(users->users[i]->id == sockfd){ - users->users[i]->name = name; + for (int i=0; i < user_list->n_users; i++){ + if(user_list->users[i]->id == sockfd){ + user_list->users[i]->name = name; } } // get_request(buff,sockfd, "2_start.html"); @@ -333,30 +344,38 @@ static bool handle_http_request(int sockfd, User_list *users){ } // user is created - else if (req->method == GET) + else if (req->method == GET && !hash_table_has(req->header, "Cookie:")) { // printf("matches a / url but url isize is %zu\n\n", strlen(req->url)); - // Response* resp = initialise_session(req); - // char* resp_string = parse_response(resp); + Response* resp = initialise_session(req); + char* resp_string = parse_response(resp); // printf("COOKIE CREATING RESP %s\n", resp_string); - // player_session(buff, sockfd, "1_welcome.html", resp_string); - // User* new_player = new_user(sockfd); - // add_user(new_player, users); - // char* cookie = hash_table_get(resp->header, "Set-cookie: ")+13; - // cookie = strtok(cookie, ";"); + char* cookie = hash_table_get(resp->header, "Set-cookie: ")+3; // printf("the cookie token is %s*****\n", cookie); - // free(resp_string); - // free_response(resp); + User* new_player = new_user(atoi(cookie)); + add_user(new_player, user_list); + // printf("before player sesh"); + player_session(buff, sockfd, "1_welcome.html", resp_string); + // free(cookie); + free(resp_string); + free_response(resp); // ensures user is not already playing/in system - for(int i =0; i< users->n_users; i++){ - if(sockfd == users->users[i]->id){ + for(int i =0; i< user_list->n_users; i++){ + if(sockfd == user_list->users[i]->id){ return false; } } - User* new_player = new_user(sockfd); - add_user(new_player, users); - response(buff,sockfd, "1_welcome.html"); + // User* new_player = new_user(sockfd); + // add_user(new_player, users); + // response(buff,sockfd, "1_welcome.html"); + } + else if (req->method == GET){ + int id = atoi(hash_table_get(req->header, "Cookie:")+3); + User* user = get_current_user(user_list, id); + if (user != NULL){ + text_render_response(buff,sockfd, "2_start.html", user->name); + } } else // unrecognised methods @@ -369,22 +388,22 @@ static bool handle_http_request(int sockfd, User_list *users){ perror("write"); return false; } - printf("the numer of users is %d\n", users->n_users); - for(int i=0; i < users->n_users; i++){ - printf("USER ID %d", users->users[i]->id); - if(users->users[i]->status == READY){ + printf("the numer of users is %d\n", user_list->n_users); + for(int i=0; i < user_list->n_users; i++){ + printf("USER ID %d", user_list->users[i]->id); + if(user_list->users[i]->status == READY){ printf("is ready\n"); } - if(users->users[i]->status == WAIT){ + if(user_list->users[i]->status == WAIT){ printf("is wait\n"); } - if(users->users[i]->status == QUIT){ + if(user_list->users[i]->status == QUIT){ printf("is quit\n"); } - if(users->users[i]->status == COMPLETE){ + if(user_list->users[i]->status == COMPLETE){ printf("is complete\n"); } - if(users->users[i]->status == RESTART){ + if(user_list->users[i]->status == RESTART){ printf("is restart\n"); } } @@ -397,6 +416,12 @@ static void exit_handler(int sig){ * Closes TCP Connection */ keep_alive = 0; + if (req){ + free_request(req); + } + if (user_list){ + free_users(user_list); + } printf("keep alive changed"); } @@ -451,7 +476,7 @@ int main(int argc, char * argv[]) int maxfd = sockfd; // game players - User_list* users = initialise_player_list(); + user_list = initialise_player_list(); signal(SIGINT, exit_handler); while (keep_alive) { @@ -494,7 +519,7 @@ int main(int argc, char * argv[]) } } // a request is sent from the client - else if (!handle_http_request(i,users)) + else if (!handle_http_request(i,user_list)) { close(i); FD_CLR(i, &masterfds); @@ -503,6 +528,6 @@ int main(int argc, char * argv[]) } } printf("break loop"); - free_users(users); + free_users(user_list); return 0; } diff --git a/user.c b/user.c index 1bf913a..bc884a3 100644 --- a/user.c +++ b/user.c @@ -130,9 +130,14 @@ bool players_ready(User_list* user_list){ * checks if all players are ready * */ for(int i=0; i < user_list->n_users; i++){ + // other player is not ready if (user_list->users[i]->status != READY){ return false; } + // only one player, need to wait + else if (user_list->n_users == 1){ + return false; + } } return true; } @@ -265,7 +270,7 @@ char* return_all_keywords(User* user){ * */ printf("%d\n\n\n", user->n_keywords); - int length = (user->n_keywords)*(INITIAL_KEYWORD_LENGTH+1); + int length = (user->n_keywords)*(INITIAL_KEYWORD_LENGTH+3); char *keywords = calloc(length, user->n_keywords); assert(keywords); -- GitLab