Make the server listen constantly and fix a bug

This commit is contained in:
Ivaylo Ivanov 2018-11-10 14:07:08 +01:00
parent a8698e38f9
commit 36495526b5
3 changed files with 98 additions and 145 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@
*.out *.out
*.o *.o
*.html *.html
*.tgz
!public/*.html !public/*.html
http/client http/client
http/server http/server

View File

@ -25,3 +25,7 @@ clean:
$(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

View File

@ -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,14 +65,31 @@ 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);
while(1) { //< Accept connections until terminated
/// Start accepting connections /// Start accepting connections
int current_session = accept(sockfd, (struct sockaddr*) &incoming, &peer_addr_size); //< Save the current session current_session = accept(sockfd, (struct sockaddr*) &incoming, &peer_addr_size); //< Save the current session
if(current_session < 0) {
(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__);
if(recv(current_session, request, strlen(request) - 1, 0) < 0) {
(void) fprintf(stderr, "ERROR: Could not receive connection from client\n");
close(current_session);
close(sockfd);
exit(EXIT_FAILURE);
}
/// Setup the server response /// Setup the server response
response = setup_server_response(dir, ifile, current_session, sockfd); response = setup_server_response(dir, ifile, request);
/// Send the response to the client /// Send the response to the client
if(send(current_session, response, strlen(response) + 1, 0) < 0) { if(send(current_session, response, strlen(response) + 1, 0) < 0) {
@ -83,6 +98,8 @@ int main(int argc, char *argv[]) {
close(sockfd); close(sockfd);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
}
}
close(current_session); close(current_session);
close(sockfd); close(sockfd);
@ -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) {
(void) fprintf(stderr, "ERROR: Could not receive connection from client\n");
close(current_session);
close(sockfd);
exit(EXIT_FAILURE);
} else {
char method[4]; char method[4];
strncpy(method, request, 4); //< Get the request type strncpy(method, request, 3); //< Get the request type
method[3] = 0; //< Add terminating char method[3] = 0; //< Add terminating string
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(strlen(req_file) == 1) {
body = get_file_contents(dir, ifile);
}
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) { if(body != NULL) {
time_t t = time(NULL); time_t current_time;
struct tm tm = *gmtime(&t); time(&current_time);
struct tm * tm = gmtime(&current_time);
char time_string[50];
char *wday = wday_to_string(tm.tm_wday); strftime(time_string, 50, "%a, %d %b %y %H:%M:%S %Z", tm);
char *month = month_to_string(tm.tm_mon + 1);
snprintf( snprintf(
header, header,
sizeof 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", "HTTP/1.1 200 OK\r\nDate: %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) time_string, strlen(body)
); //< Build the 200 header ); //< Build the 200 header
strcat(response, header); strcat(response, header);
strcat(response, body); strcat(response, body);
} else { } else {
snprintf( strcpy(
header, header,
sizeof header,
"HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n" "HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n"
); //< Build the 404 header ); //< Build the 404 header
strcat(response, header); strcat(response, header);
} }
} else { } else {
fprintf(stderr, "ERROR: Unhandled HTTP request method received\n"); strcpy(
snprintf(
header, header,
sizeof header, "HTTP/1.1 501 Not Implemented\r\nConnection: close\r\n\r\n"
"HTTP/1.1 501 Not ImplementedConnection: close\r\n\r\n"
); //< Build 501 the header ); //< Build 501 the header
strcat(response, header); strcat(response, header);
} }
return response; 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
if(res != 0) {
fread(res, 1, file_length, file); //< Read the contents into res 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;
}
}