removed lots of obsolete stuff
[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 static const char * method_strmap[] = {
26     "GET",
27     "HEAD",
28     "POST",
29     "PUT",
30     "DELETE",
31     "MKCOL",
32     "COPY",
33     "MOVE",
34     "OPTIONS",
35     "PROPFIND",
36     "PROPATCH",
37     "LOCK",
38     "UNLOCK",
39     "TRACE",
40     "CONNECT",
41     "PATCH",
42 };
43
44 void handle_signal(evutil_socket_t fd, short events, void *arg) {
45   log_info("handle_signal()");
46   struct signalfd_siginfo siginfo;
47   if(read(fd, &siginfo, sizeof(siginfo)) < 0) {
48     log_error("Failed to read signal: %s", strerror(errno));
49     return;
50   }
51   switch(siginfo.ssi_signo) {
52   case SIGINT:
53   case SIGTERM:
54     exit(EXIT_SUCCESS);
55     break;
56   default:
57     log_error("Unhandled signal caught: %s", strsignal(siginfo.ssi_signo));
58   }
59 }
60
61 struct event_base *rs_event_base = NULL;
62
63 void log_event_base_message(int severity, const char *msg) {
64   char *format = "(from libevent) %s";
65   switch(severity) {
66   case EVENT_LOG_DEBUG:
67     log_debug(format, msg);
68     break;
69   case EVENT_LOG_MSG:
70     log_info(format, msg);
71     break;
72   case EVENT_LOG_ERR:
73     log_error(format, msg);
74     break;
75   case EVENT_LOG_WARN:
76     log_warn(format, msg);
77     break;
78   }
79 }
80
81 static evhtp_res finish_request(evhtp_request_t *req, void *arg) {
82   log_info("%s %s -> %d (fini: %d)", method_strmap[req->method], req->uri->path->full, req->status, req->finished);
83   return 0;
84 }
85
86 static evhtp_res receive_path(evhtp_request_t *req, evhtp_path_t *path, void *arg) {
87   log_info("full path: %s (user: %s, path: %s, file: %s)",
88            path->full, path->match_start, path->match_end, path->file);
89   char *username = path->match_start;
90   uid_t uid = user_get_uid(username);
91   if(uid == -1) {
92     evhtp_send_reply(req, EVHTP_RES_NOTFOUND);
93   } else if(uid == -2) {
94     evhtp_send_reply(req, EVHTP_RES_SERVERR);
95   } else if(uid < RS_MIN_UID) {
96     log_info("User not allowed: %s (uid: %ld)", username, uid);
97     evhtp_send_reply(req, EVHTP_RES_NOTFOUND);
98   } else {
99     log_debug("User found: %s (uid: %ld)", username, uid);
100     return EVHTP_RES_OK;
101   }
102   return EVHTP_RES_PAUSE;
103 }
104
105 void add_cors_headers(evhtp_request_t *req) {
106   ADD_RESP_HEADER(req, "Access-Control-Allow-Origin", RS_ALLOW_ORIGIN);
107   ADD_RESP_HEADER(req, "Access-Control-Allow-Headers", RS_ALLOW_HEADERS);
108   ADD_RESP_HEADER(req, "Access-Control-Allow-Methods", RS_ALLOW_METHODS);
109 }
110
111 static evhtp_res handle_options(evhtp_request_t *req) {
112   evhtp_send_reply(req, EVHTP_RES_NOCONTENT);
113   return EVHTP_RES_PAUSE;
114 }
115
116 static evhtp_res receive_headers(evhtp_request_t *req, evhtp_headers_t *hdr, void *arg) {
117
118   add_cors_headers(req);
119
120   if(req->method == htp_method_OPTIONS) {
121     return handle_options(req);
122   }
123
124   int auth_result = authorize_request(req);
125   if(auth_result == 0) {
126     log_debug("Request authorized.");
127     return EVHTP_RES_OK;
128   } else if(auth_result == -1) {
129     log_info("Request NOT authorized.");
130     return EVHTP_RES_UNAUTH;
131   } else if(auth_result == -2) {
132     log_error("An error occured while authorizing request.");    
133     return EVHTP_RES_SERVERR; 
134  }
135   return EVHTP_RES_PAUSE;
136 }
137
138 static void handle_storage(evhtp_request_t *req, void *arg) {
139   switch(req->method) {
140   case htp_method_GET:
141     req->status = storage_handle_get(req);
142     break;
143   case htp_method_HEAD:
144     req->status = storage_handle_head(req);
145     break;
146   case htp_method_PUT:
147     req->status = storage_handle_put(req);
148    break;
149   //case htp_method_DELETE:
150   //  req->status = storage_handle_delete(req);
151   //  break;
152   default:
153     req->status = EVHTP_RES_METHNALLOWED;
154   }
155   if(req->status != 0) {
156     evhtp_send_reply(req, req->status);
157   }
158 }
159
160 magic_t magic_cookie;
161
162 int main(int argc, char **argv) {
163
164   init_config(argc, argv);
165
166   open_authorizations("r");
167
168   /** OPEN MAGIC DATABASE **/
169
170   magic_cookie = magic_open(MAGIC_MIME);
171   if(magic_load(magic_cookie, RS_MAGIC_DATABASE) != 0) {
172     log_error("Failed to load magic database: %s", magic_error(magic_cookie));
173     exit(EXIT_FAILURE);
174   }
175
176   log_info("starting process: main");
177
178   if(prctl(PR_SET_NAME, "rs-serve [main]", 0, 0, 0) != 0) {
179     log_error("Failed to set process name: %s", strerror(errno));
180   }
181
182   /** SETUP EVENT BASE **/
183
184   rs_event_base = event_base_new();
185   ASSERT_NOT_NULL(rs_event_base, "event_base_new()");
186   log_debug("libevent method: %s", event_base_get_method(rs_event_base));
187   event_set_log_callback(log_event_base_message);
188
189   // TODO: add error cb to base
190
191
192   /** SETUP LISTENER **/
193
194   struct sockaddr_in sin;
195   memset(&sin, 0, sizeof(struct sockaddr_in));
196   sin.sin_family = AF_INET;
197   sin.sin_addr.s_addr = htonl(0);
198   sin.sin_port = htons(RS_PORT);
199
200   evhtp_t *server = evhtp_new(rs_event_base, NULL);
201
202   evhtp_callback_t *storage_cb = evhtp_set_regex_cb(server, "^/storage/([^/]+)/.*$", handle_storage, NULL);
203
204   evhtp_set_hook(&storage_cb->hooks, evhtp_hook_on_headers, receive_headers, NULL);
205   evhtp_set_hook(&storage_cb->hooks, evhtp_hook_on_path, receive_path, NULL);
206   evhtp_set_hook(&storage_cb->hooks, evhtp_hook_on_request_fini, finish_request, NULL);
207
208   if(evhtp_bind_sockaddr(server, (struct sockaddr*)&sin, sizeof(sin), 1024) != 0) {
209     log_error("evhtp_bind_sockaddr() failed: %s", strerror(errno));
210     exit(EXIT_FAILURE);
211   }
212
213   /** SETUP SIGNALS **/
214
215   sigset_t sigmask;
216   sigemptyset(&sigmask);
217   sigaddset(&sigmask, SIGINT);
218   sigaddset(&sigmask, SIGTERM);
219   sigaddset(&sigmask, SIGCHLD);
220   ASSERT_ZERO(sigprocmask(SIG_BLOCK, &sigmask, NULL), "sigprocmask()");
221   int sfd = signalfd(-1, &sigmask, SFD_NONBLOCK);
222   ASSERT_NOT_EQ(sfd, -1, "signalfd()");
223
224   struct event *signal_event = event_new(rs_event_base, sfd, EV_READ | EV_PERSIST,
225                                          handle_signal, NULL);
226   event_add(signal_event, NULL);
227
228   /** WRITE PID FILE **/
229   if(RS_PID_FILE) {
230     fprintf(RS_PID_FILE, "%d", getpid());
231     fflush(RS_PID_FILE);
232   }
233
234   /** RUN EVENT LOOP **/
235
236   return event_base_dispatch(rs_event_base);
237 }