Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
C
chen4_comp30023_2019_project-1
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Anqi Chen
chen4_comp30023_2019_project-1
Commits
f97c1262
Commit
f97c1262
authored
6 years ago
by
Anqi Chen
Browse files
Options
Downloads
Patches
Plain Diff
finish
parent
caab1561
Branches
patch-1
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
image_tagger.c
+651
-0
651 additions, 0 deletions
image_tagger.c
with
651 additions
and
0 deletions
image_tagger.c
0 → 100644
+
651
−
0
View file @
f97c1262
/*
** http-server.c
*/
/********************************************Libraries**********************************************/
#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>
/********************************************constants**********************************************/
#define GUESS_SUFFIX "&guess=Guess"
#define MAX_BUFF 2049
/*******isOnline******/
#define INTRO 0
#define START 1
#define FIRST_TURN 2
#define ACCEPTED 3
#define DISCARDED 4
#define ENDGAME 5
#define GAMEOVER 6
/*******stage******/
#define ENTER 0
#define GUESS 1
#define ENDED 2
#define QUIT 3
#define RSTAR 4
/********************************************statics**********************************************/
// 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
"
;
/*******isOnline******/
#define INTRO 0
#define START 1
#define FIRST_TURN 2
#define ACCEPTED 3
#define DISCARDED 4
#define ENDGAME 5
#define GAMEOVER 6
/*******stage******/
#define ENTER 0
#define GUESS 1
#define ENDED 2
#define QUIT 3
#define RSTAR 4
/********************************************Cookie**********************************************/
static
char
const
*
const
HTTP_400
=
"HTTP/1.1 400 Bad Request
\r\n
Content-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\n
Content-Length: 0
\r\n\r\n
"
;
static
int
const
HTTP_404_LENGTH
=
45
;
/********************************************Structs**********************************************/
// enumerate all the methods
typedef
enum
{
GET
,
POST
,
UNKNOWN
}
METHOD
;
// struct User
struct
User
{
int
userID
;
// userID is the identification of the user, used for cookie
char
**
keywords
;
// an array of guessing words
int
isOnline
;
// Online=1, OffLine=0
int
stage
;
// record the stage of the user
int
n_word
;
// number of guessing words
};
// secound round flag
int
is_second_round
=
0
;
/********************************************Function Signitures**********************************************/
struct
User
*
newUser
();
void
clear_user_keyword
(
struct
User
*
user
);
int
find_cookie
(
char
*
buff
);
struct
User
*
find_curr
(
struct
User
*
user_arr
[],
char
*
buff
);
struct
User
*
the_other_user
(
struct
User
*
curr_user
,
struct
User
*
user_arr
[]);
bool
match
(
char
*
w1
,
char
**
w2
,
int
n_word
);
void
simple_load_html
(
char
*
html
,
int
sockfd
,
char
*
buff
,
int
n
,
struct
User
*
curr_user
);
void
edit_load_html
(
char
*
html
,
int
sockfd
,
char
*
buff
,
char
*
newword
,
struct
User
*
curr_user
);
void
record_keyword
(
struct
User
*
curr_user
,
char
*
new_guess
);
static
bool
handle_http_request
(
int
sockfd
,
struct
User
*
user_arr
[]);
/********************************************Functions**********************************************/
/******_________________________________user___________________________________*******/
// replace '+' with ' '
char
*
remove_plus
(
char
*
word
){
for
(
int
i
=
0
;
i
<
strlen
(
word
);
i
++
)
{
if
(
word
[
i
]
==
'+'
){
word
[
i
]
=
' '
;
}
return
word
;
}
}
// malloc a newUser
struct
User
*
newUser
()
{
struct
User
*
newUser
=
malloc
(
sizeof
(
struct
User
));
newUser
->
userID
=
0
;
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
;
}
// clear user: point the array to NULL, reset the int to 0
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
;
}
}
// read the words into the curr_user->keywords
void
record_keyword
(
struct
User
*
curr_user
,
char
*
new_guess
){
remove_plus
(
new_guess
);
for
(
int
i
=
0
;
i
<=
curr_user
->
n_word
;
i
++
){
// add to the first NULL bit and malloc
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
);
printf
(
"record_keyword :curr_user->userID %d the last word stored is %s"
,
curr_user
->
userID
,
curr_user
->
keywords
[
curr_user
->
n_word
]);
curr_user
->
n_word
++
;
break
;
}
}
}
//find the cookie according to id, in buff
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
;
}
temp
[
strlen
(
temp
)
-
3
]
=
'\0'
;
return
atoi
(
temp
);
}
// find the current user by analyse buffer
struct
User
*
find_curr
(
struct
User
*
user_arr
[],
char
*
buff
)
{
int
cookie_id
=
find_cookie
(
buff
);
// if the cookie has not set up, assign it with a new id and malloc the space
if
(
cookie_id
==
0
){
struct
User
*
curr_user
=
newUser
();
//if never accessed before, create new user
//check according to cookie and id
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
);
}
// get the user from array
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
];
}
}
}
// the user in arrsy if not this one, then should be that one
struct
User
*
the_other_user
(
struct
User
*
curr_user
,
struct
User
*
user_arr
[]){
for
(
int
i
=
0
;
i
<
2
;
i
++
){
if
(
user_arr
[
i
]
->
userID
!=
curr_user
->
userID
){
printf
(
"the other user id is %d
\n
"
,
user_arr
[
i
]
->
userID
);
return
user_arr
[
i
];
}
}
}
// try to match the new guess to the other user keywords
bool
match
(
char
*
w1
,
char
**
w2
,
int
n_word
){
for
(
int
i
=
0
;
i
<
n_word
;
i
++
){
printf
(
"%s - %s
\n
"
,
w1
,
w2
[
i
]);
if
(
strcmp
(
w1
,
w2
[
i
])
==
0
){
printf
(
"all good"
);
return
true
;
}
}
return
false
;
}
/******_________________________________html___________________________________*******/
// only load page
void
simple_load_html
(
char
*
html
,
int
sockfd
,
char
*
buff
,
int
n
,
struct
User
*
curr_user
){
struct
stat
st
;
stat
(
html
,
&
st
);
// print into buff
n
=
sprintf
(
buff
,
HTTP_200_FORMAT
,
st
.
st_size
,
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
);
}
// load page with new words
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
);
remove_plus
(
newword
);
// 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
,
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
);
// create two buffers to read the thing before and after </body>
char
front_buff
[
MAX_BUFF
],
back_buff
[
MAX_BUFF
];
int
endlen
=
strstr
(
buff
,
"</body>"
)
-
buff
;
// close teh string
strcpy
(
back_buff
,
"
\n\r\r
<p> "
);
back_buff
[
strlen
(
back_buff
)]
=
'\0'
;
//add new word at the back_buff
strcat
(
back_buff
,
newword
);
back_buff
[
strlen
(
back_buff
)]
=
'\0'
;
// close back_buff
strcat
(
back_buff
,
"
\r\r
</p>
\r
</body> </html>"
);
back_buff
[
strlen
(
back_buff
)]
=
'\0'
;
strncpy
(
front_buff
,
buff
,
endlen
);
front_buff
[
strlen
(
front_buff
)]
=
'\0'
;
//merge
strcpy
(
buff
,
front_buff
);
buff
[
strlen
(
buff
)]
=
'\0'
;
strcat
(
buff
,
back_buff
);
buff
[
strlen
(
buff
)]
=
'\0'
;
if
(
is_second_round
){
endlen
=
strstr
(
buff
,
"image-"
)
+
6
-
buff
;
buff
[
endlen
]
=
3
;
}
//write
if
(
write
(
sockfd
,
buff
,
size
)
<
0
){
perror
(
"write"
);
return
;
}
}
// handle with every single thread from the client requests
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
==
'?'
)
{
///////////// handle GET requests /////////////
if
(
method
==
GET
)
{
//first visit to intro
if
(
curr_user
->
isOnline
==
INTRO
)
{
simple_load_html
(
"1_intro.html"
,
sockfd
,
buff
,
n
,
curr_user
);
}
else
if
(
curr_user
->
isOnline
==
START
){
simple_load_html
(
"3_first_turn.html"
,
sockfd
,
buff
,
n
,
curr_user
);
curr_user
->
stage
=
GUESS
;
}
else
if
(
curr_user
->
stage
==
ENDED
){
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
==
ENDED
){
the_other_user
(
curr_user
,
user_arr
)
->
stage
==
RSTAR
;
}
}
}
///////////// handle POST requests/////////////
else
if
(
method
==
POST
){
if
(
strstr
(
buff
,
"quit="
)
!=
NULL
)
{
simple_load_html
(
"7_gameover.html"
,
sockfd
,
buff
,
n
,
curr_user
);
curr_user
->
stage
=
QUIT
;
}
// in registeration process: read name into html "2_start.html"
else
if
(
curr_user
->
isOnline
==
INTRO
)
{
// get string
char
*
username
=
strstr
(
buff
,
"user="
)
+
5
;
char
u
[
MAX_BUFF
];
strcpy
(
u
,
"<br>"
);
strcat
(
u
,
username
);
u
[
strlen
(
username
)]
=
'\0'
;
curr_user
->
isOnline
=
1
;
//edit into html
edit_load_html
(
"2_start.html"
,
sockfd
,
buff
,
username
,
curr_user
);
}
// in guessing process:
else
if
(
curr_user
->
isOnline
==
FIRST_TURN
||
curr_user
->
isOnline
==
START
)
{
curr_user
->
isOnline
=
FIRST_TURN
;
// 1. the other user not ready but not quit: discard curr_user keyword
if
(
curr_user
->
stage
==
ENTER
||
curr_user
->
stage
==
RSTAR
)
{
simple_load_html
(
"5_discarded.html"
,
sockfd
,
buff
,
n
,
curr_user
);
}
else
if
(
the_other_user
(
curr_user
,
user_arr
)
->
stage
==
ENTER
&&
curr_user
->
stage
==
GUESS
){
simple_load_html
(
"5_discarded.html"
,
sockfd
,
buff
,
n
,
curr_user
);
}
// 2. the other user quit: curr_user quit
else
if
(
curr_user
->
stage
==
QUIT
){
simple_load_html
(
"7_gameover.html"
,
sockfd
,
buff
,
n
,
curr_user
);
curr_user
->
stage
=
QUIT
;
}
// 3. match word successfully
else
if
(
curr_user
->
stage
==
ENDED
||
curr_user
->
stage
==
RSTAR
){
simple_load_html
(
"6_endgame.html"
,
sockfd
,
buff
,
n
,
curr_user
);
if
(
curr_user
->
stage
==
RSTAR
){
curr_user
->
stage
=
ENTER
;
curr_user
->
isOnline
=
START
;
is_second_round
=
1
;
}
else
{
curr_user
->
stage
=
ENDED
;
}
}
else
{
// read the new guess word
char
*
guess
=
strstr
(
buff
,
"keyword="
)
+
8
;
guess
[
strlen
(
guess
)
-
strlen
(
GUESS_SUFFIX
)]
=
'\0'
;
if
(
match
(
guess
,
the_other_user
(
curr_user
,
user_arr
)
->
keywords
,
the_other_user
(
curr_user
,
user_arr
)
->
n_word
)){
// go to end page
curr_user
->
stage
=
ENDED
;
the_other_user
(
curr_user
,
user_arr
)
->
stage
=
ENDED
;
simple_load_html
(
"6_endgame.html"
,
sockfd
,
buff
,
n
,
curr_user
);
clear_user_keyword
(
curr_user
);
}
else
{
// read new guess word into curr_user array
record_keyword
(
curr_user
,
guess
);
char
guess_buff
[
MAX_BUFF
];
strcpy
(
guess_buff
,
"<br>"
);
// add a null bit at the end of the string
if
(
curr_user
->
n_word
==
1
)
{
strcat
(
guess_buff
,
guess
);
guess_buff
[
strlen
(
guess_buff
)]
=
'\0'
;
}
// loop through and print every single word
else
{
for
(
int
i
=
0
;
i
<
curr_user
->
n_word
;
++
i
)
{
strcat
(
guess_buff
,
curr_user
->
keywords
[
i
]);
strcat
(
guess_buff
,
"<br>"
);
}
}
edit_load_html
(
"4_accepted.html"
,
sockfd
,
buff
,
guess_buff
,
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
;
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment