Advertisement
Guest User

Untitled

a guest
Feb 22nd, 2020
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.49 KB | None | 0 0
  1. #include <arpa/inet.h>
  2. #include <fcntl.h>
  3. #include <netinet/in.h>
  4. #include <signal.h>
  5. #include <stdbool.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/mman.h>
  10. #include <sys/socket.h>
  11. #include <sys/stat.h>
  12. #include <unistd.h>
  13.  
  14. volatile sig_atomic_t is_terminated = 0;
  15.  
  16. enum {
  17.     MAX_PATH_SIZE = 4096,
  18.     PATH_LEFT_INDENT = (int)strlen("GET "),
  19.     PATH_RIGHT_INDENT = (int)strlen(" HTTP/1.1\r\n")
  20. };
  21.  
  22. void close_connection(int current_fd, FILE** current_stream)
  23. {
  24.     if (*current_stream != NULL) {
  25.         fflush(*current_stream);
  26.         shutdown(current_fd, SHUT_RDWR);
  27.         fclose(*current_stream);
  28.         *current_stream = NULL;
  29.     }
  30. }
  31.  
  32. void terminate(
  33.     char* line_buffer,
  34.     int socket_fd,
  35.     int current_fd,
  36.     FILE** current_stream)
  37. {
  38.     close_connection(current_fd, current_stream);
  39.     free(line_buffer);
  40.     close(socket_fd);
  41.     exit(0);
  42. }
  43.  
  44. bool check_termination(
  45.     char* line_buffer,
  46.     int socket_fd,
  47.     int current_fd,
  48.     FILE** current_stream)
  49. {
  50.     if (is_terminated) {
  51.         terminate(line_buffer, socket_fd, current_fd, current_stream);
  52.     }
  53.     return true;
  54. }
  55.  
  56. void handle_signal(int signo, siginfo_t* siginfo, void* context)
  57. {
  58.     is_terminated = 1;
  59. }
  60.  
  61. void set_up_sigaction()
  62. {
  63.     struct sigaction signal_action = {.sa_sigaction = handle_signal,
  64.                                       .sa_flags = SA_SIGINFO};
  65.     sigaction(SIGTERM, &signal_action, NULL);
  66.     sigaction(SIGINT, &signal_action, NULL);
  67. }
  68.  
  69. int set_up_socket(char* port_num)
  70. {
  71.     struct sockaddr_in addr = {AF_INET, 0, 0};
  72.     inet_aton("127.0.0.1", &addr.sin_addr);
  73.     addr.sin_port = htons(strtol(port_num, NULL, 10));
  74.  
  75.     int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  76.     bind(socket_fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in));
  77.  
  78.     listen(socket_fd, SOMAXCONN);
  79.  
  80.     return socket_fd;
  81. }
  82.  
  83. int main(int argc, char** argv)
  84. {
  85.     const int directory_path_len = strlen(argv[2]);
  86.     int socket_fd = set_up_socket(argv[1]);
  87.     set_up_sigaction();
  88.  
  89.     char* line_buffer = NULL;
  90.     size_t line_len = 0;
  91.     char path[MAX_PATH_SIZE] = {};
  92.     int current_fd = -1;
  93.     FILE* current_stream = NULL;
  94.     while (check_termination(line_buffer, socket_fd, current_fd, &current_stream)) {
  95.         current_fd = accept(socket_fd, NULL, NULL);
  96.         if (current_fd != -1) {
  97.             current_stream = fdopen(current_fd, "r+");
  98.  
  99.             getline(&line_buffer, &line_len, current_stream);
  100.             check_termination(line_buffer, socket_fd, current_fd, &current_stream);
  101.             memset(path, 0, MAX_PATH_SIZE);
  102.             strncpy(path, argv[2], directory_path_len);
  103.             strncpy(
  104.                 path + directory_path_len,
  105.                 line_buffer + PATH_LEFT_INDENT,
  106.                 strlen(line_buffer) - (PATH_RIGHT_INDENT + PATH_LEFT_INDENT));
  107.             do {
  108.                 check_termination(
  109.                     line_buffer, socket_fd, current_fd, &current_stream);
  110.                 getline(&line_buffer, &line_len, current_stream);
  111.             } while (!(line_buffer[0] == '\r') || !(line_buffer[1] == '\n'));
  112.  
  113.             check_termination(
  114.                 line_buffer, socket_fd, current_fd, &current_stream);
  115.  
  116.             switch (access(path, F_OK) + access(path, R_OK)) {
  117.             case -2:
  118.                 fprintf(current_stream, "%s", "HTTP/1.1 404 Not Found\r\n\r\n");
  119.                 fflush(current_stream);
  120.                 break;
  121.             case -1:
  122.                 fprintf(current_stream, "%s", "HTTP/1.1 403 Forbidden\r\n\r\n");
  123.                 fflush(current_stream);
  124.                 break;
  125.             case 0:
  126.                 fprintf(current_stream, "%s", "HTTP/1.1 200 OK\r\n");
  127.                 fflush(current_stream);
  128.                 struct stat file_info = {};
  129.                 lstat(path, &file_info);
  130.                 fprintf(
  131.                     current_stream,
  132.                     "Content-Length: %d\r\n\r\n",
  133.                     file_info.st_size);
  134.                 fflush(current_stream);
  135.  
  136.                 int file_fd = open(path, O_RDONLY);
  137.                 char* file_content = mmap(
  138.                     NULL, file_info.st_size, PROT_READ, MAP_SHARED, file_fd, 0);
  139.  
  140.                 write(current_fd, file_content, file_info.st_size);
  141.                    
  142.                 munmap(file_content, file_info.st_size);
  143.                 close(file_fd);
  144.             }
  145.             close_connection(current_fd, &current_stream);
  146.         }
  147.     }
  148.  
  149.     return 0;
  150. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement