From 9e8a15634f2ada06bae99978079bcdec4603dc88 Mon Sep 17 00:00:00 2001
From: Anqi Chen <a.chen49@student.unimelb.edu.au>
Date: Mon, 29 Apr 2019 16:44:37 +1000
Subject: [PATCH] redo logic

---
 h.c   |  37 ++--
 img.c | 477 +++++++++++++++++++++++++++++++++++++++++++++++++++
 new.c | 535 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1030 insertions(+), 19 deletions(-)
 create mode 100644 img.c
 create mode 100644 new.c

diff --git a/h.c b/h.c
index 73d2f73..e0e2d48 100644
--- a/h.c
+++ b/h.c
@@ -312,17 +312,24 @@ static bool handle_http_request(int sockfd, struct User* user_arr[])
     // assume the only valid request URI is "/" but it can be modified to accept more files
     if (*curr == ' ' || *curr == '?')
 
+         if(strstr(buff, "quit=Quit") != NULL) {
+            simple_load_html("7_gameover.html",sockfd,buff,n,curr_user);
+            curr_user->stage=100;
+            curr_user->isOnline=0;
+
+         }
+
         //Stage1: when user name is not registed
-        if (curr_user->stage==0){
+        else if (curr_user->stage==0){
             if (method==GET)
             {
-                printf("curr_user->username%s == %d\n", curr_user->username,curr_user->username==NULL);
+                //printf("curr_user->username%s == %d\n", curr_user->username,curr_user->username==NULL);
                 simple_load_html("1_intro.html",sockfd,buff,n,curr_user);
             }
         
             else if (method == POST)
             {
-                printf("curr_user->username%s == %d\n", curr_user->username,curr_user->username==NULL);
+                //printf("curr_user->username%s == %d\n", curr_user->username,curr_user->username==NULL);
                 // locate the username, it is safe to do so in this sample code, but usually the result is expected to be
                 // copied to another buffer using strcpy or strncpy to ensure that it will not be overwritten.
                 char * user = strstr(buff, "user=") + 5;
@@ -341,19 +348,12 @@ static bool handle_http_request(int sockfd, struct User* user_arr[])
         else if(curr_user->stage==1)
         {   
             
-            // quit: user not online
-            if(strstr(buff, "quit=Quit") != NULL)
-            {   curr_user->isOnline=0;
-                simple_load_html("7_gameover.html",sockfd,buff,n,curr_user);
-                curr_user->stage=3;
 
-            }
             // start is the only GET mathod for ther stage 1
-            else if (method == GET)
+            if (method == GET)
             {   curr_user->isOnline=1;
-                simple_load_html("3_first_turn.html",sockfd,buff,n,curr_user);
                 curr_user->stage =2;
-                curr_user->isOnline=1;
+                simple_load_html("3_first_turn.html",sockfd,buff,n,curr_user);
             }
         }
 
@@ -363,15 +363,12 @@ static bool handle_http_request(int sockfd, struct User* user_arr[])
 
             char * new_guess = strstr(buff, "keyword=") + 8;
 
-            if(strstr(buff, "quit=Quit") != NULL)
-            {   curr_user->isOnline=0;
-                simple_load_html("7_gameover.html",sockfd,buff,n,curr_user);
-                clear_user_keyword(curr_user);
-            }
 
-            else if (the_other_user(curr_user, user_arr)->stage==3){
+            if (the_other_user(curr_user, user_arr)->stage==100){
+                printf("%dbhjbjhbjhbhjbjasdc\n", curr_user->stage);
                 simple_load_html("7_gameover.html",sockfd,buff,n,curr_user);
                 clear_user_keyword(curr_user);
+                 
             }
 
             else if(the_other_user(curr_user, user_arr)->isOnline==0){
@@ -385,9 +382,11 @@ static bool handle_http_request(int sockfd, struct User* user_arr[])
                 {
                     simple_load_html("6_endgame.html",sockfd,buff,n,curr_user);
                     clear_user_keyword(curr_user);
+                    curr_user->isOnline=0;
+
                 }
                 else{
-                    curr_user->stage =2;
+                    
                     printf("curr_user->n_word%d\n",curr_user->n_word );
                     // remember new guess
                     record_keyword(curr_user, new_guess);
diff --git a/img.c b/img.c
new file mode 100644
index 0000000..82530cd
--- /dev/null
+++ b/img.c
@@ -0,0 +1,477 @@
+/*
+** http-server.c
+*/
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <strings.h>
+#include <sys/select.h>
+#include <sys/sendfile.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+
+#define MAX_BUFF 2049
+
+
+
+// cookie for user, formtted with userID
+static char const * const HTTP_200_FORMAT = "HTTP/1.1 200 OK\r\n\
+Content-Length: %ld\r\n\
+Content-Type: text/html\r\n\
+Set-Cookie: cookie_id= %d\r\n\r\n";
+
+
+
+
+
+static char const * const HTTP_400 = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n";
+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;
+
+
+
+typedef enum
+{
+    GET,
+    POST,
+    UNKNOWN
+} METHOD;
+
+
+
+// struct User
+struct User {
+    int userID;
+    char* username;
+    char** keywords;
+    int isOnline; // Online=1, OffLine=0
+    int stage;
+    int n_word;
+};
+
+
+// malloc a newUser
+struct User* newUser() {
+    struct User* newUser = malloc(sizeof (struct User));
+    newUser->userID = 0;
+    //newUser->username = malloc(MAX_BUFF*sizeof(char));
+    //newUser->keywords = NULL;
+    newUser->keywords =malloc(MAX_BUFF*sizeof(char*));
+    for (int i = 0; i < MAX_BUFF; i++)
+    {
+        newUser->keywords[i] = NULL;
+    }
+    newUser->isOnline = 0;
+    newUser->stage = 0;
+    newUser->n_word = 0;
+    return newUser;
+}
+
+void clear_user_keyword(struct User* user){
+    user->stage=0;
+    user->isOnline=0;
+    user->n_word=0;
+    for (int i = 0; i < MAX_BUFF; i++)
+    {
+        user->keywords[i] = NULL;
+    }
+}
+
+int find_cookie(char* buff)
+{
+    char* cookie_id=strstr(buff, "cookie_id=");
+    char* temp;
+    if(cookie_id == NULL)
+    {
+        return 0;
+    }
+    else
+    {
+        temp = malloc(sizeof(char)*strlen(cookie_id)+1);
+        strcpy(temp, cookie_id);
+        temp+=10;
+    }
+    printf("find_cookie in buff %s\n", cookie_id);
+    //int cookie_length = strlen(username);
+    temp[strlen(temp)-3]='\0';
+    printf("find_cookie in buff %s\n", cookie_id);
+
+
+    return  atoi(temp);
+}
+
+
+struct User* find_curr(struct User* user_arr[], char* buff)
+{
+    int cookie_id = find_cookie(buff);
+
+    printf("the kmimimji%d  %d\n", cookie_id,user_arr[0]->userID);
+    if(cookie_id==0){
+        
+        struct User* curr_user = newUser();
+        
+
+
+        if ((cookie_id!=1||cookie_id!=2)&& user_arr[0]->userID!=1)
+        {    
+            curr_user->userID = 1;
+            user_arr[0]= curr_user;
+        }
+        else if((cookie_id!=1||cookie_id!=2)&& user_arr[1]->userID!=2){
+            curr_user->userID = 2;
+            user_arr[1]= curr_user;
+        }
+        cookie_id=curr_user->userID;
+        printf(" func curr: cookie_id is %d\n%d\n\n\n", cookie_id,curr_user->userID);
+    }
+    
+    for (int i=0; i<2; i++) {
+        if (user_arr[i]->userID == cookie_id)
+        {               
+            printf("existing curr user %d , with cookie_id %d", i,cookie_id);
+            return user_arr[i];
+            
+        }
+    }
+
+}
+
+struct User* the_other_user(struct User* curr_user, struct User* user_arr[]){
+    for(int i=0; i<2; i++){
+        if (user_arr[i]!=curr_user){
+            return user_arr[i];
+        }
+    }
+}
+
+
+bool match(char* w1, char** w2, int n_word){
+    for (int i=0; i<n_word; i++){
+        if (w2[i]==w1){
+            return true;
+        }
+    }
+    return false;
+}
+
+
+void simple_load_html(char* html, int sockfd, char* buff, int n, struct User* curr_user){
+    struct stat st;
+    stat(html, &st);
+    n = sprintf(buff, HTTP_200_FORMAT, st.st_size+6,curr_user->userID);
+    if (write(sockfd, buff, n) < 0)
+            {
+                perror("write");
+                return ;
+            }
+    int filefd = open(html, O_RDONLY);
+            do
+            {
+                n = sendfile(sockfd, filefd, NULL, 2048);
+            }
+            while (n > 0);
+            if (n < 0)
+            {
+                perror("sendfile");
+                close(filefd);
+                return ;
+            }
+            close(filefd);
+}
+
+    /* adds the new word in the html (between the <body> */
+void plug_in_html(char* newword, char* old_buffer, char* new_buffer){
+
+    // slice the html string into 2 parts
+    char start[MAX_BUFF];
+    char* end = strstr(old_buffer, "</body>");
+
+    // front part
+    strncpy(start, old_buffer, strlen(old_buffer)-strlen(end));
+    start[strlen(start)] = '\0';
+
+    // combine 
+    strcpy(new_buffer, start);
+    strcat(new_buffer, newword);
+    strcat(new_buffer, end);
+
+    new_buffer[strlen(new_buffer)] = '\0';
+}
+
+
+
+void edit_load_html(char* html, int sockfd, char* buff, char* newword,struct User* curr_user){
+
+    // get the size of the file
+    struct stat st;
+    stat(html, &st);
+
+    // increase file size to accommodate the new guess
+    int added_length= strlen(newword);
+    long size = st.st_size + added_length;
+    int n = sprintf(buff, HTTP_200_FORMAT, size+6, curr_user->userID);
+    // send the header first
+    if (write(sockfd, buff, n) < 0)
+    {
+        perror("write");
+        return;
+    }
+    // read the content of the HTML file
+    int filefd = open(html, O_RDONLY);
+    n = read(filefd, buff, st.st_size);
+    if (n < 0)
+    {
+        perror("read");
+        close(filefd);
+        return;
+    }
+    close(filefd);
+
+    // makes new buffer, copies the username into it
+    char* new_buffer = (char *) malloc(sizeof(MAX_BUFF));
+    plug_in_html(newword, buff, new_buffer);
+
+    if (write(sockfd, new_buffer, size) < 0)
+    {
+        perror("write");
+        return;
+    }
+    free(new_buffer);
+}
+
+void record_keyword(struct User* curr_user, char *new_guess){
+    for (int i=0; i<=curr_user->n_word; i++){
+        if(curr_user->keywords[curr_user->n_word]==NULL){
+            curr_user->keywords[curr_user->n_word] = malloc((1 + strlen(new_guess)) * sizeof(char*));
+            strcpy(curr_user->keywords[curr_user->n_word],new_guess);
+            curr_user->n_word++;
+            break;
+        }
+    }
+}
+
+static bool handle_http_request(int sockfd, struct User* user_arr[])
+{
+    // try to read the request
+    char buff[2049];
+    int n = read(sockfd, buff, 2049);
+    if (n <= 0)
+    {
+        if (n < 0)
+            perror("read");
+        else
+            printf("socket %d close the connection\n", sockfd);
+        return false;
+    }
+
+    // terminate the string
+    buff[n] = 0;
+
+    char * curr = buff;
+
+    // parse the method
+    METHOD method = UNKNOWN;
+    if (strncmp(curr, "GET ", 4) == 0)
+    {
+        curr += 4;
+        method = GET;
+    }
+    else if (strncmp(curr, "POST ", 5) == 0)
+    {
+        curr += 5;
+        method = POST;
+    }
+    else if (write(sockfd, HTTP_400, HTTP_400_LENGTH) < 0)
+    {
+        perror("write");
+        return false;
+    }
+
+    printf("buff1: \n");
+    printf("%s\n",buff);
+
+    struct User* curr_user=find_curr(user_arr,buff);
+
+    // sanitise the URI
+    while (*curr == '.' || *curr == '/')
+        ++curr;
+
+    printf("stage%d\n",curr_user->stage );
+    // assume the only valid request URI is "/" but it can be modified to accept more files
+    if (*curr == ' ' || *curr == '?')
+    {
+        if (method == GET)
+        {
+            if (curr_user->isOnline==0)
+            {
+                simple_load_html("1_intro.html",sockfd,buff,n,curr_user);
+                
+            }
+            else if (curr_user->isOnline==1){
+                simple_load_html("3_first_turn.html",sockfd,buff,n,curr_user);
+                curr_user->stage = 1;
+            }
+            else if (curr_user->stage==2){
+                simple_load_html("3_first_turn.html",sockfd,buff,n,curr_user);
+                curr_user->stage = 1;
+                if (the_other_user(curr_user, user_arr)->stage==2){
+                    the_other_user(curr_user, user_arr)->stage==4;
+                }
+            }
+        }
+        else if (method == POST){
+
+            if(strstr(buff, "quit=Quit") != NULL)
+            {
+            
+                simple_load_html("7_gameover.html",sockfd,buff,n,curr_user);
+                curr_user->stage=3;
+            }
+            else if(curr_user->isOnline == 0) 
+            {
+                
+            }
+
+        }
+        
+
+
+
+            
+
+
+
+        
+        else
+            // never used, just for completeness
+            fprintf(stderr, "no other methods supported");
+    }
+    // send 404
+    else if (write(sockfd, HTTP_404, HTTP_404_LENGTH) < 0)
+    {
+        perror("write");
+        return false;
+    }
+
+    return true;
+}
+
+int main(int argc, char * argv[])
+{
+    if (argc < 3)
+    {
+        fprintf(stderr, "usage: %s ip port\n", argv[0]);
+        return 0;
+    }
+
+    // create TCP socket which only accept IPv4
+    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
+    if (sockfd < 0)
+    {
+        perror("socket");
+        exit(EXIT_FAILURE);
+    }
+
+    // reuse the socket if possible
+    int const reuse = 1;
+    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) < 0)
+    {
+        perror("setsockopt");
+        exit(EXIT_FAILURE);
+    }
+
+    // create and initialise address we will listen on
+    struct sockaddr_in serv_addr;
+    bzero(&serv_addr, sizeof(serv_addr));
+    serv_addr.sin_family = AF_INET;
+    // if ip parameter is not specified
+    serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
+    serv_addr.sin_port = htons(atoi(argv[2]));
+
+    // bind address to socket
+    if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
+    {
+        perror("bind");
+        exit(EXIT_FAILURE);
+    }
+
+    // listen on the socket
+    listen(sockfd, 5);
+
+    // initialise an active file descriptors set
+    fd_set masterfds;
+    FD_ZERO(&masterfds);
+    FD_SET(sockfd, &masterfds);
+    // record the maximum socket number
+    int maxfd = sockfd;
+
+    //global variable for 2 users
+    struct User* user_arr[2];
+
+
+
+    while (1)
+    {
+        // monitor file descriptors
+        fd_set readfds = masterfds;
+        if (select(FD_SETSIZE, &readfds, NULL, NULL, NULL) < 0)
+        {
+            perror("select");
+            exit(EXIT_FAILURE);
+        }
+
+        // loop all possible descriptor
+        for (int i = 0; i <= maxfd; ++i)
+            // determine if the current file descriptor is active
+            if (FD_ISSET(i, &readfds))
+            {
+                // create new socket if there is new incoming connection request
+                if (i == sockfd)
+                {
+                    struct sockaddr_in cliaddr;
+                    socklen_t clilen = sizeof(cliaddr);
+                    int newsockfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen);
+                    if (newsockfd < 0)
+                        perror("accept");
+                    else
+                    {
+                        // add the socket to the set
+                        FD_SET(newsockfd, &masterfds);
+                        // update the maximum tracker
+                        if (newsockfd > maxfd)
+                            maxfd = newsockfd;
+                        // print out the IP and the socket number
+                        char ip[INET_ADDRSTRLEN];
+                        printf(
+                            "new connection from %s on socket %d\n",
+                            // convert to human readable string
+                            inet_ntop(cliaddr.sin_family, &cliaddr.sin_addr, ip, INET_ADDRSTRLEN),
+                            newsockfd
+                        );
+                    }
+                }
+                // a request is sent from the client
+                else if (!handle_http_request(i, user_arr))
+                {
+                    close(i);
+                    FD_CLR(i, &masterfds);
+                }
+            }
+    }
+
+    return 0;
+}
+
+
diff --git a/new.c b/new.c
new file mode 100644
index 0000000..73d2f73
--- /dev/null
+++ b/new.c
@@ -0,0 +1,535 @@
+/*
+** http-server.c
+*/
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <strings.h>
+#include <sys/select.h>
+#include <sys/sendfile.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+
+#define MAX_BUFF 2049
+
+
+
+// cookie for user, formtted with userID
+static char const * const HTTP_200_FORMAT = "HTTP/1.1 200 OK\r\n\
+Content-Length: %ld\r\n\
+Content-Type: text/html\r\n\
+Set-Cookie: cookie_id= %d\r\n\r\n";
+
+
+
+
+
+static char const * const HTTP_400 = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n";
+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;
+
+
+
+typedef enum
+{
+    GET,
+    POST,
+    UNKNOWN
+} METHOD;
+
+
+
+// struct User
+struct User {
+    int userID;
+    char* username;
+    char** keywords;
+    int isOnline; // Online=1, OffLine=0
+    int stage;
+    int n_word;
+};
+
+
+// malloc a newUser
+struct User* newUser() {
+    struct User* newUser = malloc(sizeof (struct User));
+    newUser->userID = 0;
+    //newUser->username = malloc(MAX_BUFF*sizeof(char));
+    //newUser->keywords = NULL;
+    newUser->keywords =malloc(MAX_BUFF*sizeof(char*));
+    for (int i = 0; i < MAX_BUFF; i++)
+    {
+        newUser->keywords[i] = NULL;
+    }
+    newUser->isOnline = 0;
+    newUser->stage = 0;
+    newUser->n_word = 0;
+    return newUser;
+}
+
+void clear_user_keyword(struct User* user){
+    user->stage=0;
+    user->isOnline=0;
+    user->n_word=0;
+    for (int i = 0; i < MAX_BUFF; i++)
+    {
+        user->keywords[i] = NULL;
+    }
+}
+
+int find_cookie(char* buff)
+{
+    char* cookie_id=strstr(buff, "cookie_id=");
+    char* temp;
+    if(cookie_id == NULL)
+    {
+        return 0;
+    }
+    else
+    {
+        temp = malloc(sizeof(char)*strlen(cookie_id)+1);
+        strcpy(temp, cookie_id);
+        temp+=10;
+    }
+    printf("find_cookie in buff %s\n", cookie_id);
+    //int cookie_length = strlen(username);
+    temp[strlen(temp)-3]='\0';
+    printf("find_cookie in buff %s\n", cookie_id);
+
+
+    return  atoi(temp);
+}
+
+
+struct User* find_curr(struct User* user_arr[], char* buff)
+{
+    int cookie_id = find_cookie(buff);
+
+    printf("the kmimimji%d  %d\n", cookie_id,user_arr[0]->userID);
+    if(cookie_id==0){
+        
+        struct User* curr_user = newUser();
+        
+
+
+        if ((cookie_id!=1||cookie_id!=2)&& user_arr[0]->userID!=1)
+        {    
+            curr_user->userID = 1;
+            user_arr[0]= curr_user;
+        }
+        else if((cookie_id!=1||cookie_id!=2)&& user_arr[1]->userID!=2){
+            curr_user->userID = 2;
+            user_arr[1]= curr_user;
+        }
+        cookie_id=curr_user->userID;
+        printf(" func curr: cookie_id is %d\n%d\n\n\n", cookie_id,curr_user->userID);
+    }
+    
+    for (int i=0; i<2; i++) {
+        if (user_arr[i]->userID == cookie_id)
+        {               
+            printf("existing curr user %d , with cookie_id %d", i,cookie_id);
+            return user_arr[i];
+            
+        }
+    }
+
+}
+
+struct User* the_other_user(struct User* curr_user, struct User* user_arr[]){
+    for(int i=0; i<2; i++){
+        if (user_arr[i]!=curr_user){
+            return user_arr[i];
+        }
+    }
+}
+
+
+bool match(char* w1, char** w2, int n_word){
+    for (int i=0; i<n_word; i++){
+        if (w2[i]==w1){
+            return true;
+        }
+    }
+    return false;
+}
+
+
+void simple_load_html(char* html, int sockfd, char* buff, int n, struct User* curr_user){
+    struct stat st;
+    stat(html, &st);
+    n = sprintf(buff, HTTP_200_FORMAT, st.st_size+6,curr_user->userID);
+    if (write(sockfd, buff, n) < 0)
+            {
+                perror("write");
+                return ;
+            }
+    int filefd = open(html, O_RDONLY);
+            do
+            {
+                n = sendfile(sockfd, filefd, NULL, 2048);
+            }
+            while (n > 0);
+            if (n < 0)
+            {
+                perror("sendfile");
+                close(filefd);
+                return ;
+            }
+            close(filefd);
+}
+
+    /* adds the new word in the html (between the <body> */
+void plug_in_html(char* newword, char* old_buffer, char* new_buffer){
+
+    // slice the html string into 2 parts
+    char start[MAX_BUFF];
+    char* end = strstr(old_buffer, "</body>");
+
+    // front part
+    strncpy(start, old_buffer, strlen(old_buffer)-strlen(end));
+    start[strlen(start)] = '\0';
+
+    // combine 
+    strcpy(new_buffer, start);
+    strcat(new_buffer, newword);
+    strcat(new_buffer, end);
+
+    new_buffer[strlen(new_buffer)] = '\0';
+}
+
+
+
+void edit_load_html(char* html, int sockfd, char* buff, char* newword,struct User* curr_user){
+
+    // get the size of the file
+    struct stat st;
+    stat(html, &st);
+
+    // increase file size to accommodate the new guess
+    int added_length= strlen(newword);
+    long size = st.st_size + added_length;
+    int n = sprintf(buff, HTTP_200_FORMAT, size+6, curr_user->userID);
+    // send the header first
+    if (write(sockfd, buff, n) < 0)
+    {
+        perror("write");
+        return;
+    }
+    // read the content of the HTML file
+    int filefd = open(html, O_RDONLY);
+    n = read(filefd, buff, st.st_size);
+    if (n < 0)
+    {
+        perror("read");
+        close(filefd);
+        return;
+    }
+    close(filefd);
+
+    // makes new buffer, copies the username into it
+    char* new_buffer = (char *) malloc(sizeof(MAX_BUFF));
+    plug_in_html(newword, buff, new_buffer);
+
+    if (write(sockfd, new_buffer, size) < 0)
+    {
+        perror("write");
+        return;
+    }
+    free(new_buffer);
+}
+
+void record_keyword(struct User* curr_user, char *new_guess){
+    for (int i=0; i<=curr_user->n_word; i++){
+        if(curr_user->keywords[curr_user->n_word]==NULL){
+            curr_user->keywords[curr_user->n_word] = malloc((1 + strlen(new_guess)) * sizeof(char*));
+            strcpy(curr_user->keywords[curr_user->n_word],new_guess);
+            curr_user->n_word++;
+            break;
+        }
+    }
+}
+
+static bool handle_http_request(int sockfd, struct User* user_arr[])
+{
+    // try to read the request
+    char buff[2049];
+    int n = read(sockfd, buff, 2049);
+    if (n <= 0)
+    {
+        if (n < 0)
+            perror("read");
+        else
+            printf("socket %d close the connection\n", sockfd);
+        return false;
+    }
+
+    // terminate the string
+    buff[n] = 0;
+
+    char * curr = buff;
+
+    // parse the method
+    METHOD method = UNKNOWN;
+    if (strncmp(curr, "GET ", 4) == 0)
+    {
+        curr += 4;
+        method = GET;
+    }
+    else if (strncmp(curr, "POST ", 5) == 0)
+    {
+        curr += 5;
+        method = POST;
+    }
+    else if (write(sockfd, HTTP_400, HTTP_400_LENGTH) < 0)
+    {
+        perror("write");
+        return false;
+    }
+
+    printf("buff1: \n");
+    printf("%s\n",buff);
+
+    struct User* curr_user=find_curr(user_arr,buff);
+
+    // sanitise the URI
+    while (*curr == '.' || *curr == '/')
+        ++curr;
+
+    printf("stage%d\n",curr_user->stage );
+    // assume the only valid request URI is "/" but it can be modified to accept more files
+    if (*curr == ' ' || *curr == '?')
+
+        //Stage1: when user name is not registed
+        if (curr_user->stage==0){
+            if (method==GET)
+            {
+                printf("curr_user->username%s == %d\n", curr_user->username,curr_user->username==NULL);
+                simple_load_html("1_intro.html",sockfd,buff,n,curr_user);
+            }
+        
+            else if (method == POST)
+            {
+                printf("curr_user->username%s == %d\n", curr_user->username,curr_user->username==NULL);
+                // locate the username, it is safe to do so in this sample code, but usually the result is expected to be
+                // copied to another buffer using strcpy or strncpy to ensure that it will not be overwritten.
+                char * user = strstr(buff, "user=") + 5;
+                char username[MAX_BUFF];
+                strcpy(username, "<br>");
+                strcat(username, user);
+                username[strlen(username)] = '\0';
+                edit_load_html("2_start.html", sockfd,buff,username,curr_user);
+                printf("buffer %s\n",buff );
+                curr_user->stage=1;
+            }
+        }
+
+
+        //Stage 1: start the game
+        else if(curr_user->stage==1)
+        {   
+            
+            // quit: user not online
+            if(strstr(buff, "quit=Quit") != NULL)
+            {   curr_user->isOnline=0;
+                simple_load_html("7_gameover.html",sockfd,buff,n,curr_user);
+                curr_user->stage=3;
+
+            }
+            // start is the only GET mathod for ther stage 1
+            else if (method == GET)
+            {   curr_user->isOnline=1;
+                simple_load_html("3_first_turn.html",sockfd,buff,n,curr_user);
+                curr_user->stage =2;
+                curr_user->isOnline=1;
+            }
+        }
+
+
+        // Stage 2: in the process of guessing
+        else if (curr_user->stage ==2){
+
+            char * new_guess = strstr(buff, "keyword=") + 8;
+
+            if(strstr(buff, "quit=Quit") != NULL)
+            {   curr_user->isOnline=0;
+                simple_load_html("7_gameover.html",sockfd,buff,n,curr_user);
+                clear_user_keyword(curr_user);
+            }
+
+            else if (the_other_user(curr_user, user_arr)->stage==3){
+                simple_load_html("7_gameover.html",sockfd,buff,n,curr_user);
+                clear_user_keyword(curr_user);
+            }
+
+            else if(the_other_user(curr_user, user_arr)->isOnline==0){
+                simple_load_html("5_discarded.html",sockfd,buff,n,curr_user);
+                clear_user_keyword(curr_user);
+            }
+
+
+            else if(new_guess!=NULL){
+                if(match(new_guess, the_other_user(curr_user, user_arr)->keywords, the_other_user(curr_user, user_arr)->n_word))
+                {
+                    simple_load_html("6_endgame.html",sockfd,buff,n,curr_user);
+                    clear_user_keyword(curr_user);
+                }
+                else{
+                    curr_user->stage =2;
+                    printf("curr_user->n_word%d\n",curr_user->n_word );
+                    // remember new guess
+                    record_keyword(curr_user, new_guess);
+                    // display new guess
+                    char guess[MAX_BUFF];
+                    strcpy(guess,"<br>");
+                    if (curr_user->n_word==1){
+                        strcat(guess, new_guess);
+                        guess[strlen(new_guess)]='\0';
+                    }else
+                    {
+                        for (int i = 0; i < curr_user->n_word; i++)
+                        {
+                            strcat(guess, curr_user->keywords[i]);
+                            strcat(guess,"<br>");
+                        }
+                    }
+
+                    edit_load_html("4_accepted.html", sockfd,buff,guess,curr_user);
+                }
+            }
+
+
+
+        } 
+        else
+            // never used, just for completeness
+            fprintf(stderr, "no other methods supported");
+    // send 404
+    else if (write(sockfd, HTTP_404, HTTP_404_LENGTH) < 0)
+    {
+        perror("write");
+        return false;
+    }
+
+    return true;
+}
+
+int main(int argc, char * argv[])
+{
+    if (argc < 3)
+    {
+        fprintf(stderr, "usage: %s ip port\n", argv[0]);
+        return 0;
+    }
+
+    // create TCP socket which only accept IPv4
+    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
+    if (sockfd < 0)
+    {
+        perror("socket");
+        exit(EXIT_FAILURE);
+    }
+
+    // reuse the socket if possible
+    int const reuse = 1;
+    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) < 0)
+    {
+        perror("setsockopt");
+        exit(EXIT_FAILURE);
+    }
+
+    // create and initialise address we will listen on
+    struct sockaddr_in serv_addr;
+    bzero(&serv_addr, sizeof(serv_addr));
+    serv_addr.sin_family = AF_INET;
+    // if ip parameter is not specified
+    serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
+    serv_addr.sin_port = htons(atoi(argv[2]));
+
+    // bind address to socket
+    if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
+    {
+        perror("bind");
+        exit(EXIT_FAILURE);
+    }
+
+    // listen on the socket
+    listen(sockfd, 5);
+
+    // initialise an active file descriptors set
+    fd_set masterfds;
+    FD_ZERO(&masterfds);
+    FD_SET(sockfd, &masterfds);
+    // record the maximum socket number
+    int maxfd = sockfd;
+
+    //global variable for 2 users
+    struct User* user_arr[2];
+
+
+
+    while (1)
+    {
+        // monitor file descriptors
+        fd_set readfds = masterfds;
+        if (select(FD_SETSIZE, &readfds, NULL, NULL, NULL) < 0)
+        {
+            perror("select");
+            exit(EXIT_FAILURE);
+        }
+
+        // loop all possible descriptor
+        for (int i = 0; i <= maxfd; ++i)
+            // determine if the current file descriptor is active
+            if (FD_ISSET(i, &readfds))
+            {
+                // create new socket if there is new incoming connection request
+                if (i == sockfd)
+                {
+                    struct sockaddr_in cliaddr;
+                    socklen_t clilen = sizeof(cliaddr);
+                    int newsockfd = accept(sockfd, (struct sockaddr *)&cliaddr, &clilen);
+                    if (newsockfd < 0)
+                        perror("accept");
+                    else
+                    {
+                        // add the socket to the set
+                        FD_SET(newsockfd, &masterfds);
+                        // update the maximum tracker
+                        if (newsockfd > maxfd)
+                            maxfd = newsockfd;
+                        // print out the IP and the socket number
+                        char ip[INET_ADDRSTRLEN];
+                        printf(
+                            "new connection from %s on socket %d\n",
+                            // convert to human readable string
+                            inet_ntop(cliaddr.sin_family, &cliaddr.sin_addr, ip, INET_ADDRSTRLEN),
+                            newsockfd
+                        );
+                    }
+                }
+                // a request is sent from the client
+                else if (!handle_http_request(i, user_arr))
+                {
+                    close(i);
+                    FD_CLR(i, &masterfds);
+                }
+            }
+    }
+
+    return 0;
+}
+
+
-- 
GitLab