2 * rs-serve - (c) 2013 Niklas E. Cathor
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.
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/>.
15 #define ASSERT(cond, desc) { \
17 perror(#desc " failed"); \
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)
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));
33 switch(siginfo.ssi_signo) {
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",
45 log_error("Received SIGCHLD, but waitpid() failed: %s", strerror(errno));
54 log_error("Unhandled signal caught: %s", strsignal(siginfo.ssi_signo));
58 struct event_base *rs_event_base = NULL;
60 void log_event_base_message(int severity, const char *msg) {
61 char *format = "(from libevent) %s";
64 log_debug(format, msg);
67 log_info(format, msg);
70 log_error(format, msg);
73 log_warn(format, msg);
78 struct rs_temp_request {
79 struct evbuffer *buffer;
84 void free_temp_request(struct rs_temp_request *temp_req) {
85 if(temp_req->buffer) {
86 evbuffer_free(temp_req->buffer);
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));
98 void read_first_line(evutil_socket_t fd, short events, void *arg) {
99 struct rs_temp_request *temp_req = arg;
104 count = recv(fd, &byte, 1, 0);
106 // recv() returned an error
107 if(errno == EAGAIN || errno == EWOULDBLOCK) {
108 // we've read all we could, but nothing fatal happened.
110 if(dispatch_request(temp_req->buffer, fd) != 0) {
111 log_error("Failed to dispatch request. Closing socket.");
113 free_temp_request(temp_req);
118 // some fatal error occured
119 log_error("recv() failed: %s", strerror(errno));
120 free_temp_request(temp_req);
123 } else if(count == 0) {
124 log_error("Connection closed");
125 free_temp_request(temp_req);
130 // end of line reached, ready to proceed once no more bytes to read.
133 evbuffer_add(temp_req->buffer, &byte, 1);
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) {
145 log_error("Dropping connection, malloc() failed: %s\n", strerror(errno));
149 temp_req->buffer = evbuffer_new();
150 if(temp_req->buffer == NULL) {
153 log_error("Dropping connection, evbuffer_new() failed: %s\n", strerror(errno));
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);
162 log_error("Dropping connection, event_new() failed: %s\n", strerror(errno));
164 event_add(temp_req->event, NULL);
167 magic_t magic_cookie;
169 int main(int argc, char **argv) {
171 init_config(argc, argv);
173 /** OPEN MAGIC DATABASE **/
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));
181 /** CHECK IF WE ARE ROOT **/
184 log_error("Sorry, you need to run this as user root for (so the child processes are able to chroot(2)).");
188 log_info("starting process: main");
190 if(prctl(PR_SET_NAME, "rs-serve [main]", 0, 0, 0) != 0) {
191 log_error("Failed to set process name: %s", strerror(errno));
194 /** SETUP EVENT BASE **/
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);
201 // TODO: add error cb to base
204 /** SETUP LISTENER **/
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);
212 struct evconnlistener *listener = evconnlistener_new_bind(rs_event_base,
215 LEV_OPT_CLOSE_ON_FREE |
216 LEV_OPT_REUSEABLE, -1,
217 (struct sockaddr*)&sin,
219 ASSERT_NOT_NULL(listener, "evconnlistener_new_bind()");
221 // TODO: add error cb to listener
223 // unfortunately required to initialize htparse internas:
224 evhtp_free(evhtp_new(rs_event_base, NULL));
226 /** SETUP SIGNALS **/
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()");
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);
241 /** WRITE PID FILE **/
243 fprintf(RS_PID_FILE, "%d", getpid());
247 /** RUN EVENT LOOP **/
249 return event_base_dispatch(rs_event_base);