higgs.c (4092B)
1 #include <errno.h> 2 #include <limits.h> 3 #include <netdb.h> 4 #include <poll.h> 5 #include <signal.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <time.h> 10 #include <arpa/inet.h> 11 #include <netinet/in.h> 12 #include <sys/resource.h> 13 #include <sys/socket.h> 14 #include <sys/time.h> 15 #include <sys/types.h> 16 17 #include "config.h" 18 19 static char * 20 strdupcond(char *s, char *skip, char *delim) 21 { 22 char *p; 23 24 for (; !*s || strchr(skip, *s); s++) 25 ; 26 for (p = s; !strchr(delim, *p); p++) 27 ; 28 29 return strndup(s, p - s); 30 } 31 32 static void 33 handle(int fd) 34 { 35 FILE *fp; 36 size_t buflen = 0; 37 off_t range[2] = { -1, -1 }; 38 char *buf = NULL, *p, *url, *host; 39 40 readline: 41 /* check first line of HTTP request (use strtok?) */ 42 if (!(fp = fdopen(fd, "r")) || getline(&buf, &buflen, fp) < 0) 43 goto servererr; 44 if (strncmp(buf, "GET", strlen("GET"))) 45 goto clienterr; 46 if (!(url = strdupcond(buf + strlen("GET"), " ", " "))) 47 goto servererr; 48 for (p = buf + strlen("GET"); *p == ' '; p++); 49 for (; *p && *p != ' '; p++); 50 for (; *p == ' '; p++); 51 if (strncmp(p, "HTTP/", strlen("HTTP/"))) 52 goto clienterr; 53 54 /* read upcoming fields (use strtok? first \r -> \0) */ 55 while (getline(&buf, &buflen, fp) >= 0 && strcmp(buf, "\r\n")) { 56 /* host */ 57 if (!strncmp(buf, "Host:", strlen("Host:"))) { 58 if (!(host = strdupcond(buf + strlen("Host:"), 59 " ", "\r\n"))) 60 goto servererr; 61 printf("FIELD HOST: %s\n", host); 62 /* range */ 63 } else if (!strncmp(buf, "Range:", strlen("Range:"))) { 64 if (!(p = strdupcond(buf + strlen("Range:"), 65 " ", "\r\n"))) 66 goto servererr; 67 printf("FIELD RANGE: %s\n", p); 68 free(p); 69 /* if-modified-since */ 70 } else if (!strncmp(buf, "If-Modified-Since:", 71 strlen("If-Modified-Since:"))) { 72 if (!(p = strdupcond(buf + strlen("If-Modified-Since:"), 73 " ", "\r\n"))) 74 goto servererr; 75 printf("FIELD MOD-SINCE: %s\n", p); 76 free(p); 77 } 78 } 79 /* Response: Allow, Connection, Content-Range, Content-Type, 80 * Date, Server */ 81 return; 82 servererr: 83 /* 500 internal server error */ 84 printf("500 |%s|\n", url); 85 return; 86 clienterr: 87 /* 400 Bad Request */ 88 printf("400 |%s|\n", url); 89 return; 90 } 91 92 int 93 main() 94 { 95 struct addrinfo hints, *ai = NULL; 96 struct rlimit rlim; 97 struct sockaddr sa; 98 pid_t pid; 99 socklen_t salen; 100 int i, listenfd, reqfd, running = 1; 101 102 if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) { 103 fprintf(stderr, "signal: Failed to set SIG_IGN on SIGCHLD\n"); 104 return 1; 105 } 106 107 setbuf(stdout, NULL); /* unbuffered stdout */ 108 109 hints.ai_family = AF_INET; 110 hints.ai_socktype = SOCK_STREAM; 111 hints.ai_flags = AI_PASSIVE; 112 113 if ((i = getaddrinfo(servername, serverport, &hints, &ai))) { 114 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(i)); 115 return 1; 116 } 117 if ((listenfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) { 118 fprintf(stderr, "tsocket: %s\n", strerror(errno)); 119 return 1; 120 } 121 if (bind(listenfd, ai->ai_addr, ai->ai_addrlen) == -1) { 122 fprintf(stderr, "bind: %s\n", strerror(errno)); 123 return 1; 124 } 125 if (listen(listenfd, SOMAXCONN) == -1) { 126 fprintf(stderr, "listen: %s\n", strerror(errno)); 127 return 1; 128 } 129 130 rlim.rlim_cur = rlim.rlim_max = maxnprocs; 131 if (setrlimit(RLIMIT_NPROC, &rlim) < 0) { 132 fprintf(stderr, "setrlimit RLIMIT_NPROC: %s\n", strerror(errno)); 133 return 1; 134 } 135 136 while (running) { 137 salen = sizeof(sa); 138 if ((reqfd = accept(listenfd, &sa, &salen)) < 0) { 139 fprintf(stderr, "accept: %s\n", strerror(errno)); 140 continue; 141 } 142 143 pid = fork(); 144 145 if (pid < 0) { 146 fprintf(stderr, "fork: %s\n", strerror(errno)); 147 /* error-message? */ 148 continue; 149 } else if (pid == 0) { 150 close(listenfd); 151 152 /* close socket after timeout */ 153 if (setsockopt(reqfd, SOL_SOCKET, SO_RCVTIMEO, 154 &timeout, sizeof(timeout)) < 0) { 155 fprintf(stderr, "error\tsetsockopt SO_RCVTIMEO" 156 "failed: %s\n", strerror(errno)); 157 } 158 159 handle(reqfd); 160 161 shutdown(reqfd, SHUT_RD); 162 shutdown(reqfd, SHUT_WR); 163 close(reqfd); 164 exit(0); 165 } else { 166 close(reqfd); 167 } 168 } 169 170 close(listenfd); 171 freeaddrinfo(ai); 172 173 return 0; 174 }