Make the server listen constantly and fix a bug
This commit is contained in:
parent
a8698e38f9
commit
36495526b5
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,6 +2,7 @@
|
|||||||
*.out
|
*.out
|
||||||
*.o
|
*.o
|
||||||
*.html
|
*.html
|
||||||
|
*.tgz
|
||||||
!public/*.html
|
!public/*.html
|
||||||
http/client
|
http/client
|
||||||
http/server
|
http/server
|
||||||
|
@ -24,4 +24,8 @@ clean:
|
|||||||
$(RM) $(TARGET_1)
|
$(RM) $(TARGET_1)
|
||||||
$(RM) $(TARGET_2)
|
$(RM) $(TARGET_2)
|
||||||
$(RM) *.o
|
$(RM) *.o
|
||||||
$(RM) *.html
|
$(RM) *.html
|
||||||
|
$(RM) *.tgz
|
||||||
|
|
||||||
|
package:
|
||||||
|
tar -cvzf server.tgz $(TARGET_1).c $(TARGET_2).c shared public Makefile
|
||||||
|
236
http/server.c
236
http/server.c
@ -14,10 +14,8 @@
|
|||||||
#define LISTEN_BACKLOG 5 //< Define maximum size of the input queue
|
#define LISTEN_BACKLOG 5 //< Define maximum size of the input queue
|
||||||
|
|
||||||
static int create_server_socket(uint16_t port, struct sockaddr_in incoming);
|
static int create_server_socket(uint16_t port, struct sockaddr_in incoming);
|
||||||
static char * setup_server_response(char* dir, char* filename, int current_session, int sockfd);
|
static char * setup_server_response(char* dir, char* ifile, char* request);
|
||||||
static char * get_file_contents(char* dir, char* filename);
|
static char * get_file_contents(char* dir, char* filename);
|
||||||
static char * wday_to_string(int day);
|
|
||||||
static char * month_to_string(int month);
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
check_opts_number(argc);
|
check_opts_number(argc);
|
||||||
@ -67,21 +65,40 @@ int main(int argc, char *argv[]) {
|
|||||||
incoming.sin_family = AF_INET; //< Use IPv4
|
incoming.sin_family = AF_INET; //< Use IPv4
|
||||||
|
|
||||||
int sockfd = create_server_socket(port, incoming); //< Define a server socket
|
int sockfd = create_server_socket(port, incoming); //< Define a server socket
|
||||||
|
int current_session = 0;
|
||||||
|
|
||||||
socklen_t peer_addr_size = sizeof(struct sockaddr_in);
|
socklen_t peer_addr_size = sizeof(struct sockaddr_in);
|
||||||
|
|
||||||
/// Start accepting connections
|
while(1) { //< Accept connections until terminated
|
||||||
int current_session = accept(sockfd, (struct sockaddr*) &incoming, &peer_addr_size); //< Save the current session
|
/// Start accepting connections
|
||||||
|
current_session = accept(sockfd, (struct sockaddr*) &incoming, &peer_addr_size); //< Save the current session
|
||||||
|
|
||||||
/// Setup the server response
|
if(current_session < 0) {
|
||||||
response = setup_server_response(dir, ifile, current_session, sockfd);
|
(void) fprintf(stderr, "ERROR: Could not start accepting connections\n");
|
||||||
|
close(current_session);
|
||||||
|
close(sockfd);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
|
char *request = malloc (sizeof (char) * __INT16_MAX__);
|
||||||
|
|
||||||
/// Send the response to the client
|
if(recv(current_session, request, strlen(request) - 1, 0) < 0) {
|
||||||
if(send(current_session, response, strlen(response) + 1, 0) < 0) {
|
(void) fprintf(stderr, "ERROR: Could not receive connection from client\n");
|
||||||
(void) fprintf(stderr, "ERROR: Could not send the response to the client\n");
|
close(current_session);
|
||||||
close(current_session);
|
close(sockfd);
|
||||||
close(sockfd);
|
exit(EXIT_FAILURE);
|
||||||
exit(EXIT_FAILURE);
|
}
|
||||||
|
|
||||||
|
/// Setup the server response
|
||||||
|
response = setup_server_response(dir, ifile, request);
|
||||||
|
|
||||||
|
/// Send the response to the client
|
||||||
|
if(send(current_session, response, strlen(response) + 1, 0) < 0) {
|
||||||
|
(void) fprintf(stderr, "ERROR: Could not send the response to the client\n");
|
||||||
|
close(current_session);
|
||||||
|
close(sockfd);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close(current_session);
|
close(current_session);
|
||||||
@ -153,80 +170,80 @@ static int create_server_socket(uint16_t port, struct sockaddr_in incoming) {
|
|||||||
/**
|
/**
|
||||||
* @brief Function to create the HTTP response
|
* @brief Function to create the HTTP response
|
||||||
* @details Gets the client request
|
* @details Gets the client request
|
||||||
* If there is no current session, it exits with an error
|
* If the server receives an invalid requests, a 400 header is build and the function adds it to response
|
||||||
* If the server could not receive a client connection, it exits with an error
|
|
||||||
* If a GET request is received, the function tries to open the resource:
|
* If a GET request is received, the function tries to open the resource:
|
||||||
* - if it could open it, it builds a 200 header and the file contents as body and adds them to response
|
* - if it could open it, it builds a 200 header and the file contents as body and adds them to response
|
||||||
* - if it could not open it, it builds a 404 header and adds it to response
|
* - if it could not open it, it builds a 404 header and adds it to response
|
||||||
* If anything other than a GET request is received, a 501 header is build, adds it to response and logs it
|
* If anything other than a GET request is received, a 501 header is build and the function adds it to response
|
||||||
* At the end, it returns the server response with header and body (if available)
|
* At the end, it returns the server response with header and body (if available)
|
||||||
* @param dir - the directory of the file
|
* @param dir - the directory of the file
|
||||||
* filename - the name of the file
|
* ifile - the name of the indexfile
|
||||||
* current_session - the current client session
|
* request - the request of the client
|
||||||
* sockfd - the socket configuration
|
|
||||||
* @return response - A header with the status code and a body (if available)
|
* @return response - A header with the status code and a body (if available)
|
||||||
**/
|
**/
|
||||||
static char * setup_server_response(char* dir, char* filename, int current_session, int sockfd) {
|
static char * setup_server_response(char* dir, char* ifile, char* request) {
|
||||||
if(current_session < 0) {
|
char *response = malloc (sizeof (char) * __INT16_MAX__);
|
||||||
(void) fprintf(stderr, "ERROR: Could not start accepting connections\n");
|
|
||||||
close(current_session);
|
|
||||||
close(sockfd);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
} else {
|
|
||||||
char request[__INT16_MAX__];
|
|
||||||
static char response[__INT16_MAX__];
|
|
||||||
|
|
||||||
if(recv(current_session, request, strlen(request) - 1, 0) < 0) {
|
char method[4];
|
||||||
(void) fprintf(stderr, "ERROR: Could not receive connection from client\n");
|
strncpy(method, request, 3); //< Get the request type
|
||||||
close(current_session);
|
method[3] = 0; //< Add terminating string
|
||||||
close(sockfd);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
} else {
|
|
||||||
char method[4];
|
|
||||||
strncpy(method, request, 4); //< Get the request type
|
|
||||||
method[3] = 0; //< Add terminating char
|
|
||||||
|
|
||||||
char header[__INT8_MAX__ + 100];
|
char header[__INT8_MAX__ + 100];
|
||||||
|
|
||||||
if(strcmp(method, "GET") == 0) {
|
if(strcmp(method, "GET") == 0) {
|
||||||
char *body = get_file_contents(dir, filename);
|
char *body = NULL;
|
||||||
|
char *delim = strstr(request, "/");
|
||||||
|
char *req_file = strtok(delim, " "); //< Get the requested file
|
||||||
|
|
||||||
if(body != NULL) {
|
if(strlen(req_file) == 1) {
|
||||||
time_t t = time(NULL);
|
body = get_file_contents(dir, ifile);
|
||||||
struct tm tm = *gmtime(&t);
|
|
||||||
|
|
||||||
char *wday = wday_to_string(tm.tm_wday);
|
|
||||||
char *month = month_to_string(tm.tm_mon + 1);
|
|
||||||
|
|
||||||
snprintf(
|
|
||||||
header,
|
|
||||||
sizeof header,
|
|
||||||
"HTTP/1.1 200 OK\r\nDate: %s, %d %s %d %d:%d:%d %s\r\nContent-Length: %ld\r\nConnection: close\r\n\r\n",
|
|
||||||
wday, tm.tm_mday, month, tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_zone, strlen(body)
|
|
||||||
); //< Build the 200 header
|
|
||||||
strcat(response, header);
|
|
||||||
strcat(response, body);
|
|
||||||
} else {
|
|
||||||
snprintf(
|
|
||||||
header,
|
|
||||||
sizeof header,
|
|
||||||
"HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n"
|
|
||||||
); //< Build the 404 header
|
|
||||||
strcat(response, header);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "ERROR: Unhandled HTTP request method received\n");
|
|
||||||
snprintf(
|
|
||||||
header,
|
|
||||||
sizeof header,
|
|
||||||
"HTTP/1.1 501 Not ImplementedConnection: close\r\n\r\n"
|
|
||||||
); //< Build 501 the header
|
|
||||||
strcat(response, header);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
char *rest = strstr(request, "HTTP/1.1");
|
||||||
|
rest = strtok(rest, "\r\n");
|
||||||
|
if(rest == NULL) {
|
||||||
|
strcpy(
|
||||||
|
header,
|
||||||
|
"HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n"
|
||||||
|
); //< Build the 400 header
|
||||||
|
strcat(response, header);
|
||||||
|
} else {
|
||||||
|
body = get_file_contents(dir, req_file + 1);
|
||||||
|
(void) fprintf(stdout, "GET: %s\n", req_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(body != NULL) {
|
||||||
|
time_t current_time;
|
||||||
|
time(¤t_time);
|
||||||
|
struct tm * tm = gmtime(¤t_time);
|
||||||
|
char time_string[50];
|
||||||
|
|
||||||
|
strftime(time_string, 50, "%a, %d %b %y %H:%M:%S %Z", tm);
|
||||||
|
|
||||||
|
snprintf(
|
||||||
|
header,
|
||||||
|
sizeof header,
|
||||||
|
"HTTP/1.1 200 OK\r\nDate: %s\r\nContent-Length: %ld\r\nConnection: close\r\n\r\n",
|
||||||
|
time_string, strlen(body)
|
||||||
|
); //< Build the 200 header
|
||||||
|
strcat(response, header);
|
||||||
|
strcat(response, body);
|
||||||
|
} else {
|
||||||
|
strcpy(
|
||||||
|
header,
|
||||||
|
"HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n"
|
||||||
|
); //< Build the 404 header
|
||||||
|
strcat(response, header);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strcpy(
|
||||||
|
header,
|
||||||
|
"HTTP/1.1 501 Not Implemented\r\nConnection: close\r\n\r\n"
|
||||||
|
); //< Build 501 the header
|
||||||
|
strcat(response, header);
|
||||||
}
|
}
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -256,77 +273,8 @@ static char * get_file_contents(char *dir, char *filename) {
|
|||||||
int file_length = ftell(file); //< Get file length
|
int file_length = ftell(file); //< Get file length
|
||||||
fseek(file, 0, SEEK_SET); //< Set the position to begining of stream
|
fseek(file, 0, SEEK_SET); //< Set the position to begining of stream
|
||||||
res = malloc(file_length); //< Allocate memory for the file contents
|
res = malloc(file_length); //< Allocate memory for the file contents
|
||||||
|
fread(res, 1, file_length, file); //< Read the contents into res
|
||||||
if(res != 0) {
|
|
||||||
fread(res, 1, file_length, file); //< Read the contents into res
|
|
||||||
} else {
|
|
||||||
return " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Function to convert a int weekday to string weekday
|
|
||||||
* @details Gets the weekday as int, converts it to string and returns the string
|
|
||||||
* @param day - the weekday as int
|
|
||||||
* @return the weekday as a string
|
|
||||||
**/
|
|
||||||
static char * wday_to_string(int day) {
|
|
||||||
switch(day) {
|
|
||||||
case 1:
|
|
||||||
return "Mon";
|
|
||||||
case 2:
|
|
||||||
return "Tue";
|
|
||||||
case 3:
|
|
||||||
return "Wed";
|
|
||||||
case 4:
|
|
||||||
return "Thu";
|
|
||||||
case 5:
|
|
||||||
return "Fri";
|
|
||||||
case 6:
|
|
||||||
return "Sat";
|
|
||||||
case 7:
|
|
||||||
return "Sun";
|
|
||||||
default:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Function to convert a int month to string month
|
|
||||||
* @details Gets the month as int, converts it to string and returns the string
|
|
||||||
* @param day - the month as int
|
|
||||||
* @return the month as a string
|
|
||||||
**/
|
|
||||||
static char * month_to_string(int month) {
|
|
||||||
switch(month) {
|
|
||||||
case 1:
|
|
||||||
return "Jan";
|
|
||||||
case 2:
|
|
||||||
return "Feb";
|
|
||||||
case 3:
|
|
||||||
return "Mar";
|
|
||||||
case 4:
|
|
||||||
return "Apr";
|
|
||||||
case 5:
|
|
||||||
return "May";
|
|
||||||
case 6:
|
|
||||||
return "Jun";
|
|
||||||
case 7:
|
|
||||||
return "Jul";
|
|
||||||
case 8:
|
|
||||||
return "Aug";
|
|
||||||
case 9:
|
|
||||||
return "Sep";
|
|
||||||
case 10:
|
|
||||||
return "Oct";
|
|
||||||
case 11:
|
|
||||||
return "Nov";
|
|
||||||
case 12:
|
|
||||||
return "Dec";
|
|
||||||
default:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user