Skip to content
Snippets Groups Projects
Commit 8c8c4dd8 authored by yongk1's avatar yongk1
Browse files

Project1

parents
No related branches found
No related tags found
No related merge requests found
Pipeline #1806 canceled
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h2>Image Tagger Game</h2>
<img src="https://swift.rc.nectar.org.au/v1/AUTH_eab314456b624071ac5aecd721b977f0/comp30023-project/image-3.jpg" alt="HTML5 Icon" style="width:700px;height:400px;">
<form method="GET">
<input type="submit" class="button" name="start" value="Start"/>
</form>
<form method="POST">
<input type="submit" class="button" name="quit" value="Quit"/>
</form>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h2>Image Tagger Game</h2>
<img src="https://swift.rc.nectar.org.au/v1/AUTH_eab314456b624071ac5aecd721b977f0/comp30023-project/image-3.jpg" alt="HTML5 Icon" style="width:700px;height:400px;">
<p>Welcome to the image tagging game. Please enter your name below.</p>
<form method="POST">
Name: <input type="text" name="user" />
<input type="submit" class="button" />
</form>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h2>Image Tagger Game</h2>
<img src="https://swift.rc.nectar.org.au/v1/AUTH_eab314456b624071ac5aecd721b977f0/comp30023-project/image-3.jpg" alt="HTML5 Icon" style="width:700px;height:400px;">
<form method="GET">
<input type="submit" class="button" name="start" value="Start"/>
</form>
<form method="POST">
<input type="submit" class="button" name="quit" value="Quit"/>
</form>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h2>You are ready now!</h2>
<img src="https://swift.rc.nectar.org.au/v1/AUTH_eab314456b624071ac5aecd721b977f0/comp30023-project/image-2.jpg" alt="HTML5 Icon" style="width:700px;height:400px;">
<p>Rule: Try to guess the above image by typing a keyword which describes it:</p>
<form method="POST">
Keyword: <input type="text" name="keyword" />
<input type="submit" class="button" name="guess" value="Guess" />
</form>
<form method="POST">
<input type="submit" class="button" name="quit" value="Quit"/>
</form>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h2>Keyword Accepted! Keep trying more.</h2>
<img src="https://swift.rc.nectar.org.au/v1/AUTH_eab314456b624071ac5aecd721b977f0/comp30023-project/image-2.jpg" alt="HTML5 Icon" style="width:700px;height:400px;">
<p>Rule: Try to guess the above image by typing a keyword which describes it:</p>
<form method="POST">
Keyword: <input type="text" name="keyword" />
<input type="submit" class="button" name="guess" value="Guess" />
</form>
<form method="POST">
<input type="submit" class="button" name="quit" value="Quit"/>
</form>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h2>Keyword Discarded. The other player is not ready yet.</h2>
<img src="https://swift.rc.nectar.org.au/v1/AUTH_eab314456b624071ac5aecd721b977f0/comp30023-project/image-2.jpg" alt="HTML5 Icon" style="width:700px;height:400px;">
<p>Rule: Try to guess the above image by typing a keyword which describes it:</p>
<form method="POST">
Keyword: <input type="text" name="keyword" />
<input type="submit" class="button" name="guess" value="Guess" />
</form>
<form method="POST">
<input type="submit" class="button" name="quit" value="Quit"/>
</form>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h2>Thanks for playing. The game is completed.</h2>
<p>Would you like to play it again?</p>
<form method="GET">
<input type="submit" class="button" name="start" value="Start"/>
</form>
<form method="POST">
<input type="submit" class="button" name="quit" value="Quit"/>
</form>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h2>Game Over!</h2>
</body>
</html>
server.c 0 → 100644
/*
** 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/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
// constants
static char const * const HTTP_200_FORMAT = "HTTP/1.1 200 OK\r\n\
Content-Type: text/html\r\n\
Content-Length: %ld\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;
static int GAMEOVER_STATE = 7;
static int READY_STATE = 3;
static int ENDGAME_STATE = 6;
static int MAX_LENGTH = 20;
// represents the types of method
typedef enum
{
GET,
POST,
UNKNOWN
} METHOD;
// Structure for player
typedef struct Player {
char player_name[20];
int player_socket;
int count;
char keyword_list[20][20];
int player_status;
}Player;
Player* current_player(int sockfd,Player *player1, Player *player2);
static bool handle_http_request(int sockfd,Player *player1, Player *player2)
{
// try to read the request
char buff[2049];
char keyword[20];
char* starting_keyword;
char* ending_keyword;
bool end = false;
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;
}
// sanitise the URI
while (*curr == '.' || *curr == '/')
++curr;
// if player quit or the other player quited
if((strstr(buff,"quit=Quit"))||player1->player_status == GAMEOVER_STATE ||player2->player_status == GAMEOVER_STATE){
// send quit page
struct stat st;
stat("7_gameover.html", &st);
n = sprintf(buff, HTTP_200_FORMAT, st.st_size);
// send the header first
if (write(sockfd, buff, n) < 0)
{
perror("write");
return false;
}
// send the file
int filefd = open("7_gameover.html", O_RDONLY);
do
{
n = sendfile(sockfd, filefd, NULL, 2048);
}
while (n > 0);
if (n < 0)
{
perror("sendfile");
close(filefd);
return false;
}
close(filefd);
// change player status to 7(quit state)
if(player1->player_socket==sockfd){
player1->player_status=GAMEOVER_STATE;
}else if(player2->player_socket == sockfd){
player2->player_status=GAMEOVER_STATE;
}
// reset player struct (reset game)
if(player1->player_status == GAMEOVER_STATE &&player2->player_status ==GAMEOVER_STATE){
player1->player_status = 0;
strcpy(player1->player_name,"none");
player1->player_socket = 0;
player1->count = 0;
player2->player_status = 0;
strcpy(player2->player_name,"none");
player2->player_socket = 0;
player2->count = 0;
}
}
// if player guessing
else if(strstr(buff,"&guess=Guess")){
// if both player are ready
if(player1->player_status == READY_STATE && player2->player_status == READY_STATE){
// reset keyword
memset(keyword, 0, sizeof(char)*20);
// find length of keyword and copy keyword using strncpy
starting_keyword = strstr(buff,"keyword=");
ending_keyword = strstr(starting_keyword, "&guess=Guess");
int keyword_length = ending_keyword-starting_keyword-8;
strncpy(keyword,strstr(buff,"keyword=")+8,keyword_length);
// find current player
if(player1->player_socket==sockfd){
// place keyword into player keyword_list
strcpy(player1->keyword_list[player1->count],keyword);
player1->count++;
// check if keyword appeared in other player keyword_list
for(int k=0; k<=player2->count;k++){
// if keyword appeared in other player keyword_list change both player state to victory state(6)
if(strcmp(keyword,player2->keyword_list[k])==0){
player1->player_status = ENDGAME_STATE;
player2->player_status = ENDGAME_STATE;
}
}
}
else if(player2->player_socket == sockfd){
// place keyword into player keyword_list
strcpy(player2->keyword_list[player2->count],keyword);
player2->count++;
// check if keyword appeared in other player keyword_list
for(int k=0; k<=player1->count;k++){
// if keyword appeared in other player keyword_list change both player state to endgame state(6)
if(strcmp(keyword,player1->keyword_list[k])==0){
player1->player_status = ENDGAME_STATE;
player2->player_status = ENDGAME_STATE;
}
}
}
// if either player in endgame state
if (player2->player_status == ENDGAME_STATE||player1->player_status == ENDGAME_STATE) {
//reset players keyword_list
player1->count = 0;
player2->count = 0;
memset(player1->keyword_list,0,sizeof(player1->keyword_list [0][0])* 20* 20);
memset(player2->keyword_list,0,sizeof(player2->keyword_list [0][0])* 20 * 20);
// send endgame page
struct stat st;
stat("6_endgame.html", &st);
n = sprintf(buff, HTTP_200_FORMAT, st.st_size);
// send the header first
if (write(sockfd, buff, n) < 0)
{
perror("write");
return false;
}
// send the file
int filefd = open("6_endgame.html", O_RDONLY);
do
{
n = sendfile(sockfd, filefd, NULL, 2048);
}
while (n > 0);
if (n < 0)
{
perror("sendfile");
close(filefd);
return false;
}
close(filefd);
// if player keyword not match(not victory state)
}else{
// send accepted file
struct stat st;
stat("4_accepted.html", &st);
char all_keyword[500];
long current_length=0;
// copy keywords in keyword_list to all_keyword string
// calculate the length of extra characters
for(int j=0;j<current_player(sockfd,player1,player2)->count;j++){
strcpy(all_keyword+current_length,current_player(sockfd,player1,player2)->keyword_list[j]);
current_length += strlen(current_player(sockfd,player1,player2)->keyword_list[j]);
strcpy(all_keyword+current_length,",");
current_length += 1;
strcpy(all_keyword+current_length," ");
current_length += 1;
}
// add size
long size = st.st_size + current_length;
n = sprintf(buff, HTTP_200_FORMAT, size);
// send the header first
if (write(sockfd, buff, n) < 0)
{
perror("write");
return false;
}
// read the content of the HTML file
int filefd = open("4_accepted.html", O_RDONLY);
n = read(filefd, buff, 2048);
if (n < 0)
{
perror("read");
close(filefd);
return false;
}
close(filefd);
// print all_keyword
// replace behind with body and html
strncpy(strstr(buff,"</body>"), all_keyword,current_length);
strncpy(strstr(buff,all_keyword)+current_length,"</body>\n</html>",13);
if (write(sockfd, buff, size) < 0)
{
perror("write");
return false;
}
}
// check if player in victory state (for player after the other player win)
}else if(current_player(sockfd,player1,player2)->player_status == ENDGAME_STATE){
// send endgame page
struct stat st;
stat("6_endgame.html", &st);
n = sprintf(buff, HTTP_200_FORMAT, st.st_size);
// send the header first
if (write(sockfd, buff, n) < 0)
{
perror("write");
return false;
}
// send the file
int filefd = open("6_endgame.html", O_RDONLY);
do
{
n = sendfile(sockfd, filefd, NULL, 2048);
}
while (n > 0);
if (n < 0)
{
perror("sendfile");
close(filefd);
return false;
}
close(filefd);
// if other player not ready not in ready state(3)
}else{
// send discarded page
struct stat st;
stat("5_discarded.html", &st);
n = sprintf(buff, HTTP_200_FORMAT, st.st_size);
// send the header first
if (write(sockfd, buff, n) < 0)
{
perror("write");
return false;
}
// send the file
int filefd = open("5_discarded.html", O_RDONLY);
do
{
n = sendfile(sockfd, filefd, NULL, 2048);
}
while (n > 0);
if (n < 0)
{
perror("sendfile");
close(filefd);
return false;
}
}
}
// request intro page
else if (*curr == ' '){
if (method == GET)
{
//send intro page
struct stat st;
stat("1_intro.html", &st);
n = sprintf(buff, HTTP_200_FORMAT, st.st_size);
// send the header first
if (write(sockfd, buff, n) < 0)
{
perror("write");
return false;
}
// send the file
int filefd = open("1_intro.html", O_RDONLY);
do
{
n = sendfile(sockfd, filefd, NULL, 2048);
}
while (n > 0);
if (n < 0)
{
perror("sendfile");
close(filefd);
return false;
}
close(filefd);
}
else if (method == POST)
{
// locate username
char * username = strstr(buff, "user=") + 5;
char username_copy[20];
// ensure username is empty
memset(username_copy, 0, sizeof(char)*MAX_LENGTH);
// copy username
strcpy(username_copy,username);
int username_length = strlen(username);
long added_length = username_length;
//set player name and socket
if(!strcmp(player1->player_name, "none")){
strcpy(player1->player_name,username);
player1->player_socket= sockfd;
player1->player_status = 0;
}else if(!strcmp(player2->player_name, "none")){
strcpy(player2->player_name,username);
player2->player_socket = sockfd;
player2->player_status = 0;
}
// get the size of the file
struct stat st;
stat("2_start.html", &st);
// increase file size to accommodate the username
long size = st.st_size + added_length;
n = sprintf(buff, HTTP_200_FORMAT, size);
// send the header first
if (write(sockfd, buff, n) < 0)
{
perror("write");
return false;
}
// read the content of the HTML file
int filefd = open("2_start.html", O_RDONLY);
n = read(filefd, buff, 2048);
if (n < 0)
{
perror("read");
close(filefd);
return false;
}
close(filefd);
// move the trailing part backward
// copy the username
strncpy(strstr(buff,"</body>"), username_copy, username_length);
strncpy(strstr(buff,username_copy)+username_length,"</body>\n</html>",13);
if (write(sockfd, buff, size) < 0)
{
perror("write");
return false;
}
}
// request for start (start button pressed)
}else if(strstr(buff,"?start=Start")){
if (method == GET)
{
// change player state to read state (3)
if(player1->player_socket==sockfd){
player1->player_status= READY_STATE;
}else if(player2->player_socket == sockfd){
player2->player_status= READY_STATE;
}
// get the size of the file
struct stat st;
stat("3_first_turn.html", &st);
n = sprintf(buff, HTTP_200_FORMAT, st.st_size);
// send the header first
if (write(sockfd, buff, n) < 0)
{
perror("write");
return false;
}
// send the file
int filefd = open("3_first_turn.html", O_RDONLY);
do
{
n = sendfile(sockfd, filefd, NULL, 2048);
}
while (n > 0);
if (n < 0)
{
perror("sendfile");
close(filefd);
return false;
}
close(filefd);
}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]));
//create 2 players
Player player1;
strcpy(player1.player_name,"none");
player1.count = 0;
Player player2;
strcpy(player2.player_name,"none");
player2.count = 0;
// 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;
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,&player1,&player2))
{
close(i);
FD_CLR(i, &masterfds);
}
}
}
return 0;
}
// find current player
Player* current_player(int sockfd,Player *player1, Player *player2){
Player* playerbot;
if(player1->player_socket==sockfd){
return player1;
}else if(player2->player_socket == sockfd){
return player2;
}
return playerbot;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment