ETag handling for directories, xattr based MIME types for GET / HEAD
[krsd] / src / process / main.c
1 /*
2  * rs-serve - (c) 2013 Niklas E. Cathor
3  *
4  * This program is distributed in the hope that it will be useful,
5  * but WITHOUT ANY WARRANTY; without even the implied warranty of
6  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7  * GNU Affero General Public License for more details.
8  *
9  * You should have received a copy of the GNU Affero General Public License
10  * along with this program. If not, see <http://www.gnu.org/licenses/>.
11  */
12
13 #include "rs-serve.h"
14
15 #define ASSERT(cond, desc) {                    \
16     if(!(cond)) {                               \
17       perror(#desc " failed");                  \
18       exit(EXIT_FAILURE);                       \
19     }                                           \
20   }
21 #define ASSERT_NOT_NULL(var, desc) ASSERT((var) != NULL, desc)
22 #define ASSERT_ZERO(var, desc)     ASSERT((var) == 0, desc)
23 #define ASSERT_NOT_EQ(a, b, desc)  ASSERT((a) != (b), desc)
24
25 void handle_signal(evutil_socket_t fd, short events, void *arg) {
26   log_info("handle_signal()");
27   struct signalfd_siginfo siginfo;
28   if(read(fd, &siginfo, sizeof(siginfo)) < 0) {
29     log_error("Failed to read signal: %s", strerror(errno));
30     return;
31   }
32   int child_status = 0;
33   switch(siginfo.ssi_signo) {
34   case SIGCHLD:
35     if(waitpid(siginfo.ssi_pid, &child_status, WNOHANG) == siginfo.ssi_pid) {
36       log_info("Child %ld exited with status %d.", siginfo.ssi_pid, child_status);
37       struct rs_process_info *child_info = process_remove(siginfo.ssi_pid);
38       if(child_info == NULL) {
39         log_error("while tidying up child %ld: couldn't find process info",
40                   siginfo.ssi_pid);
41       } else {
42         free(child_info);
43       }
44     } else {
45       log_error("Received SIGCHLD, but waitpid() failed: %s", strerror(errno));
46     }
47     break;
48   case SIGINT:
49   case SIGTERM:
50     process_kill_all();
51     exit(EXIT_SUCCESS);
52     break;
53   default:
54     log_error("Unhandled signal caught: %s", strsignal(siginfo.ssi_signo));
55   }
56 }
57
58 struct event_base *rs_event_base = NULL;
59
60 void log_event_base_message(int severity, const char *msg) {
61   char *format = "(from libevent) %s";
62   switch(severity) {
63   case EVENT_LOG_DEBUG:
64     log_debug(format, msg);
65     break;
66   case EVENT_LOG_MSG:
67     log_info(format, msg);
68     break;
69   case EVENT_LOG_ERR:
70     log_error(format, msg);
71     break;
72   case EVENT_LOG_WARN:
73     log_warn(format, msg);
74     break;
75   }
76 }
77
78 struct rs_temp_request {
79   struct evbuffer *buffer;
80   struct event *event;
81   int fd;
82 };
83
84 void free_temp_request(struct rs_temp_request *temp_req) {
85   if(temp_req->buffer) {
86     evbuffer_free(temp_req->buffer);
87   }
88   if(temp_req->event) {
89     event_del(temp_req->event);
90     event_free(temp_req->event);
91     if(close(temp_req->fd) != 0) {
92       log_error("close() failed: %s", strerror(errno));
93     }
94   }
95   free(temp_req);
96 }
97
98 void read_first_line(evutil_socket_t fd, short events, void *arg) {
99   struct rs_temp_request *temp_req = arg;
100   char byte;
101   int eol_reached = 0;
102   int count;
103   for(;;) {
104     count = recv(fd, &byte, 1, 0);
105     if(count == -1) {
106       // recv() returned an error
107       if(errno == EAGAIN || errno == EWOULDBLOCK) {
108         // we've read all we could, but nothing fatal happened.
109         if(eol_reached) {
110           if(dispatch_request(temp_req->buffer, fd) != 0) {
111             log_error("Failed to dispatch request. Closing socket.");
112           }
113           free_temp_request(temp_req);
114           return;
115         }
116         return;
117       } else {
118         // some fatal error occured
119         log_error("recv() failed: %s", strerror(errno));
120         free_temp_request(temp_req);
121         return;
122       }
123     } else if(count == 0) {
124       log_error("Connection closed");
125       free_temp_request(temp_req);
126       return;
127     } else {
128       // recv() succeeded
129       if(byte == '\n') {
130         // end of line reached, ready to proceed once no more bytes to read.
131         eol_reached = 1;
132       }
133       evbuffer_add(temp_req->buffer, &byte, 1);
134     }
135   }
136 }
137
138 static void accept_connection(struct evconnlistener *listener, evutil_socket_t fd,
139                               struct sockaddr *address, int socklen, void *ctx) {
140   log_debug("Accepted connection");
141   // setup event to receive first line
142   struct rs_temp_request *temp_req = malloc(sizeof(struct rs_temp_request));
143   if(temp_req == NULL) {
144     close(fd);
145     log_error("Dropping connection, malloc() failed: %s\n", strerror(errno));
146     return;
147   }
148   temp_req->fd = fd;
149   temp_req->buffer = evbuffer_new();
150   if(temp_req->buffer == NULL) {
151     free(temp_req);
152     close(fd);
153     log_error("Dropping connection, evbuffer_new() failed: %s\n", strerror(errno));
154     return;
155   }
156   temp_req->event = event_new(RS_EVENT_BASE, fd, EV_READ | EV_PERSIST,
157                               read_first_line, temp_req);
158   if(temp_req->event == NULL) {
159     evbuffer_free(temp_req->buffer);
160     free(temp_req);
161     close(fd);
162     log_error("Dropping connection, event_new() failed: %s\n", strerror(errno));
163   }
164   event_add(temp_req->event, NULL);
165 }
166
167 magic_t magic_cookie;
168
169 int main(int argc, char **argv) {
170
171   init_config(argc, argv);
172
173   /** OPEN MAGIC DATABASE **/
174
175   magic_cookie = magic_open(MAGIC_MIME);
176   if(magic_load(magic_cookie, RS_MAGIC_DATABASE) != 0) {
177     log_error("Failed to load magic database: %s", magic_error(magic_cookie));
178     exit(EXIT_FAILURE);
179   }
180
181   /** CHECK IF WE ARE ROOT **/
182
183   if(getuid() != 0) {
184     log_error("Sorry, you need to run this as user root for (so the child processes are able to chroot(2)).");
185     exit(EXIT_FAILURE);
186   }
187
188   log_info("starting process: main");
189
190   if(prctl(PR_SET_NAME, "rs-serve [main]", 0, 0, 0) != 0) {
191     log_error("Failed to set process name: %s", strerror(errno));
192   }
193
194   /** SETUP EVENT BASE **/
195
196   rs_event_base = event_base_new();
197   ASSERT_NOT_NULL(rs_event_base, "event_base_new()");
198   log_debug("libevent method: %s", event_base_get_method(rs_event_base));
199   event_set_log_callback(log_event_base_message);
200
201   // TODO: add error cb to base
202
203
204   /** SETUP LISTENER **/
205
206   struct sockaddr_in sin;
207   memset(&sin, 0, sizeof(struct sockaddr_in));
208   sin.sin_family = AF_INET;
209   sin.sin_addr.s_addr = htonl(0);
210   sin.sin_port = htons(RS_PORT);
211
212   struct evconnlistener *listener = evconnlistener_new_bind(rs_event_base,
213                                                             accept_connection,
214                                                             NULL,
215                                                             LEV_OPT_CLOSE_ON_FREE |
216                                                             LEV_OPT_REUSEABLE, -1,
217                                                             (struct sockaddr*)&sin,
218                                                             sizeof(sin));
219   ASSERT_NOT_NULL(listener, "evconnlistener_new_bind()");
220
221   // TODO: add error cb to listener
222
223   // unfortunately required to initialize htparse internas:
224   evhtp_free(evhtp_new(rs_event_base, NULL));
225
226   /** SETUP SIGNALS **/
227
228   sigset_t sigmask;
229   sigemptyset(&sigmask);
230   sigaddset(&sigmask, SIGINT);
231   sigaddset(&sigmask, SIGTERM);
232   sigaddset(&sigmask, SIGCHLD);
233   ASSERT_ZERO(sigprocmask(SIG_BLOCK, &sigmask, NULL), "sigprocmask()");
234   int sfd = signalfd(-1, &sigmask, SFD_NONBLOCK);
235   ASSERT_NOT_EQ(sfd, -1, "signalfd()");
236
237   struct event *signal_event = event_new(rs_event_base, sfd, EV_READ | EV_PERSIST,
238                                          handle_signal, NULL);
239   event_add(signal_event, NULL);
240
241   /** WRITE PID FILE **/
242   if(RS_PID_FILE) {
243     fprintf(RS_PID_FILE, "%d", getpid());
244     fflush(RS_PID_FILE);
245   }
246
247   /** RUN EVENT LOOP **/
248
249   return event_base_dispatch(rs_event_base);
250 }