Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <arpa/inet.h>
- #include <fcntl.h>
- #include <netinet/in.h>
- #include <signal.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/mman.h>
- #include <sys/socket.h>
- #include <sys/stat.h>
- #include <unistd.h>
- volatile sig_atomic_t is_terminated = 0;
- enum {
- MAX_PATH_SIZE = 4096,
- PATH_LEFT_INDENT = (int)strlen("GET "),
- PATH_RIGHT_INDENT = (int)strlen(" HTTP/1.1\r\n")
- };
- void close_connection(int current_fd, FILE** current_stream)
- {
- if (*current_stream != NULL) {
- fflush(*current_stream);
- shutdown(current_fd, SHUT_RDWR);
- fclose(*current_stream);
- *current_stream = NULL;
- }
- }
- void terminate(
- char* line_buffer,
- int socket_fd,
- int current_fd,
- FILE** current_stream)
- {
- close_connection(current_fd, current_stream);
- free(line_buffer);
- close(socket_fd);
- exit(0);
- }
- bool check_termination(
- char* line_buffer,
- int socket_fd,
- int current_fd,
- FILE** current_stream)
- {
- if (is_terminated) {
- terminate(line_buffer, socket_fd, current_fd, current_stream);
- }
- return true;
- }
- void handle_signal(int signo, siginfo_t* siginfo, void* context)
- {
- is_terminated = 1;
- }
- void set_up_sigaction()
- {
- struct sigaction signal_action = {.sa_sigaction = handle_signal,
- .sa_flags = SA_SIGINFO};
- sigaction(SIGTERM, &signal_action, NULL);
- sigaction(SIGINT, &signal_action, NULL);
- }
- int set_up_socket(char* port_num)
- {
- struct sockaddr_in addr = {AF_INET, 0, 0};
- inet_aton("127.0.0.1", &addr.sin_addr);
- addr.sin_port = htons(strtol(port_num, NULL, 10));
- int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
- bind(socket_fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in));
- listen(socket_fd, SOMAXCONN);
- return socket_fd;
- }
- int main(int argc, char** argv)
- {
- const int directory_path_len = strlen(argv[2]);
- int socket_fd = set_up_socket(argv[1]);
- set_up_sigaction();
- char* line_buffer = NULL;
- size_t line_len = 0;
- char path[MAX_PATH_SIZE] = {};
- int current_fd = -1;
- FILE* current_stream = NULL;
- while (check_termination(line_buffer, socket_fd, current_fd, ¤t_stream)) {
- current_fd = accept(socket_fd, NULL, NULL);
- if (current_fd != -1) {
- current_stream = fdopen(current_fd, "r+");
- getline(&line_buffer, &line_len, current_stream);
- check_termination(line_buffer, socket_fd, current_fd, ¤t_stream);
- memset(path, 0, MAX_PATH_SIZE);
- strncpy(path, argv[2], directory_path_len);
- strncpy(
- path + directory_path_len,
- line_buffer + PATH_LEFT_INDENT,
- strlen(line_buffer) - (PATH_RIGHT_INDENT + PATH_LEFT_INDENT));
- do {
- check_termination(
- line_buffer, socket_fd, current_fd, ¤t_stream);
- getline(&line_buffer, &line_len, current_stream);
- } while (!(line_buffer[0] == '\r') || !(line_buffer[1] == '\n'));
- check_termination(
- line_buffer, socket_fd, current_fd, ¤t_stream);
- switch (access(path, F_OK) + access(path, R_OK)) {
- case -2:
- fprintf(current_stream, "%s", "HTTP/1.1 404 Not Found\r\n\r\n");
- fflush(current_stream);
- break;
- case -1:
- fprintf(current_stream, "%s", "HTTP/1.1 403 Forbidden\r\n\r\n");
- fflush(current_stream);
- break;
- case 0:
- fprintf(current_stream, "%s", "HTTP/1.1 200 OK\r\n");
- fflush(current_stream);
- struct stat file_info = {};
- lstat(path, &file_info);
- fprintf(
- current_stream,
- "Content-Length: %d\r\n\r\n",
- file_info.st_size);
- fflush(current_stream);
- int file_fd = open(path, O_RDONLY);
- char* file_content = mmap(
- NULL, file_info.st_size, PROT_READ, MAP_SHARED, file_fd, 0);
- write(current_fd, file_content, file_info.st_size);
- munmap(file_content, file_info.st_size);
- close(file_fd);
- }
- close_connection(current_fd, ¤t_stream);
- }
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement