port to arm64
[lnanohttp.git] / lnanohttp.c
blob41ea7a150b07f05277b2322b58067b87b921af53
1 /* this code is protected by the GNU affero GPLv3
2 author:Sylvain BERTRAND <sylvain DOT bertrand AT legeek DOT net>
3 /*----------------------------------------------------------------------------*/
4 /* compiler stuff */
5 #include <stdarg.h>
6 /*----------------------------------------------------------------------------*/
8 /*----------------------------------------------------------------------------*/
9 /* ulinux stuff */
10 #include <ulinux/compiler_types.h>
11 #include <ulinux/types.h>
12 #include <ulinux/sysc.h>
14 #include <ulinux/file.h>
15 #include <ulinux/socket/socket.h>
16 #ifdef CONFIG_IPV4
17 #include <ulinux/socket/in.h>
18 #else
19 #include <ulinux/socket/in6.h>
20 #endif
21 #include <ulinux/signal/signal.h>
22 #include <ulinux/error.h>
23 #include <ulinux/epoll.h>
24 #include <ulinux/utils/mem.h>
25 #include <ulinux/utils/endian.h>
26 #include <ulinux/mmap.h>
27 #include <ulinux/time.h>
28 #include <ulinux/select.h>
29 #include <ulinux/stat.h>
31 #include <ulinux/utils/ascii/string/vsprintf.h>
33 #include "ulinux_namespace.h"
34 #include "exit_codes.h"
35 /*----------------------------------------------------------------------------*/
37 /******************************************************************************/
38 #ifdef CONFIG_IPV4
39 /* 32 bits value for the IPv4 address, can be INADDR_ANY */
40 #ifdef CONFIG_LISTENING_IPV4
41 #define LISTENING_IPV4 CONFIG_LISTENING_IPV4
42 #else
43 #define LISTENING_IPV4 INADDR_ANY
44 #endif
45 #else /* IPv6 */
46 static struct ulinux_in6_addr listening_ipv6;
47 /* 128 bits value for the IPv6 address, is "IN6ADDR_ANY" if all 0 */
48 static void listening_ipv6_init(void)
50 /* yep, at that time, I really did not like initializers */
51 #ifdef CONFIG_LISTENING_IPV6_BYTE_0
52 listening_ipv6.s6_addr[0x0] = 0;
53 #else
54 listening_ipv6.s6_addr[0x0] = CONFIG_LISTENING_IPV6_BYTE_0;
55 #endif
56 #ifdef CONFIG_LISTENING_IPV6_BYTE_1
57 listening_ipv6.s6_addr[0x1] = 0;
58 #else
59 listening_ipv6.s6_addr[0x1] = CONFIG_LISTENING_IPV6_BYTE_1;
60 #endif
61 #ifdef CONFIG_LISTENING_IPV6_BYTE_2
62 listening_ipv6.s6_addr[0x2] = 0;
63 #else
64 listening_ipv6.s6_addr[0x2] = CONFIG_LISTENING_IPV6_BYTE_2;
65 #endif
66 #ifdef CONFIG_LISTENING_IPV6_BYTE_3
67 listening_ipv6.s6_addr[0x3] = 0;
68 #else
69 listening_ipv6.s6_addr[0x3] = CONFIG_LISTENING_IPV6_BYTE_3;
70 #endif
71 #ifdef CONFIG_LISTENING_IPV6_BYTE_4
72 listening_ipv6.s6_addr[0x4] = 0;
73 #else
74 listening_ipv6.s6_addr[0x4] = CONFIG_LISTENING_IPV6_BYTE_4;
75 #endif
76 #ifdef CONFIG_LISTENING_IPV6_BYTE_5
77 listening_ipv6.s6_addr[0x5] = 0;
78 #else
79 listening_ipv6.s6_addr[0x5] = CONFIG_LISTENING_IPV6_BYTE_5;
80 #endif
81 #ifdef CONFIG_LISTENING_IPV6_BYTE_6
82 listening_ipv6.s6_addr[0x6] = 0;
83 #else
84 listening_ipv6.s6_addr[0x6] = CONFIG_LISTENING_IPV6_BYTE_6;
85 #endif
86 #ifdef CONFIG_LISTENING_IPV6_BYTE_7
87 listening_ipv6.s6_addr[0x7] = 0;
88 #else
89 listening_ipv6.s6_addr[0x7] = CONFIG_LISTENING_IPV6_BYTE_7;
90 #endif
91 #ifdef CONFIG_LISTENING_IPV6_BYTE_8
92 listening_ipv6.s6_addr[0x8] = 0;
93 #else
94 listening_ipv6.s6_addr[0x8] = CONFIG_LISTENING_IPV6_BYTE_8;
95 #endif
96 #ifdef CONFIG_LISTENING_IPV6_BYTE_9
97 listening_ipv6.s6_addr[0x9] = 0;
98 #else
99 listening_ipv6.s6_addr[0x9] = CONFIG_LISTENING_IPV6_BYTE_9;
100 #endif
101 #ifdef CONFIG_LISTENING_IPV6_BYTE_A
102 listening_ipv6.s6_addr[0xa] = 0;
103 #else
104 listening_ipv6.s6_addr[0xa] = CONFIG_LISTENING_IPV6_BYTE_A;
105 #endif
106 #ifdef CONFIG_LISTENING_IPV6_BYTE_B
107 listening_ipv6.s6_addr[0xb] = 0;
108 #else
109 listening_ipv6.s6_addr[0xb] = CONFIG_LISTENING_IPV6_BYTE_B;
110 #endif
111 #ifdef CONFIG_LISTENING_IPV6_BYTE_C
112 listening_ipv6.s6_addr[0xc] = 0;
113 #else
114 listening_ipv6.s6_addr[0xc] = CONFIG_LISTENING_IPV6_BYTE_C;
115 #endif
116 #ifdef CONFIG_LISTENING_IPV6_BYTE_D
117 listening_ipv6.s6_addr[0xd] = 0;
118 #else
119 listening_ipv6.s6_addr[0xd] = CONFIG_LISTENING_IPV6_BYTE_D;
120 #endif
121 #ifdef CONFIG_LISTENING_IPV6_BYTE_E
122 listening_ipv6.s6_addr[0xe] = 0;
123 #else
124 listening_ipv6.s6_addr[0xe] = CONFIG_LISTENING_IPV6_BYTE_E;
125 #endif
126 #ifdef CONFIG_LISTENING_IPV6_BYTE_F
127 listening_ipv6.s6_addr[0xf] = 0;
128 #else
129 listening_ipv6.s6_addr[0xf] = CONFIG_LISTENING_IPV6_BYTE_F;
130 #endif
132 #endif /* IPv6 */
133 /*----------------------------------------------------------------------------*/
134 #define RESP_HDR_FMT (u8*)"\
135 HTTP/1.1 200 \r\n\
136 content-length:%u\r\n\r\n"
138 #define RESP_HDR_CONTENT_TYPE_FMT (u8*)"\
139 HTTP/1.1 200 \r\n\
140 content-length:%u\r\n\
141 content-type:%s\r\n\r\n"
142 /******************************************************************************/
144 #define SIGBIT(sig) (1<<(sig-1))
146 /*----------------------------------------------------------------------------*/
147 /* sockets stuff */
148 #ifdef CONFIG_IPV4
149 static struct sockaddr_in srv_addr;
150 #else
151 static struct sockaddr_in6 srv_addr;
152 #endif
153 static si srv_sock; /* the main listening socket */
154 static si cnx_sock; /* a cnx socket from accept */
156 static ul cnx_sock_fd_set[FD_SET_ULS_N];
157 static u8 cnx_sock_fd_set_ul_idx;
158 static u8 cnx_sock_fd_ul_shift;
159 /*----------------------------------------------------------------------------*/
161 /*----------------------------------------------------------------------------*/
162 /* fd facilities */
163 static si sigs_fd; /* fd for signals */
164 static si epfd; /* epoll fd */
165 /*----------------------------------------------------------------------------*/
167 /*----------------------------------------------------------------------------*/
168 #define HTTP_METHOD_GET 0
169 #define HTTP_METHOD_HEAD 1
170 static u8 http_method;
171 /*----------------------------------------------------------------------------*/
173 /*----------------------------------------------------------------------------*/
174 /* the buffer page */
175 static u8 *page;
176 static ul page_bytes_rd_n; /* keep an eye on how much was read */
178 static u8 *method_target_space;
179 static u8 *target_start;
180 static u8 *target_end; /* point the space char right after */
181 /*----------------------------------------------------------------------------*/
183 /*----------------------------------------------------------------------------*/
184 static u8 target_file_is_default;
185 static si target_file_fd;
186 static ul target_file_sz;
187 static u8 target_file_mime[255 + 1]; /* actually the content-type */
188 /*----------------------------------------------------------------------------*/
190 /*----------------------------------------------------------------------------*/
191 static sl resp_hdr_sz; /* the generated response header */
192 /*----------------------------------------------------------------------------*/
195 /******************************************************************************/
196 /******************************************************************************/
197 /******************************************************************************/
200 static void epoll_srv_sock_setup(void)
202 struct epoll_event ep_evt;
203 sl r;
205 memset(&ep_evt, 0, sizeof(ep_evt));
206 ep_evt.events = EPOLLIN | EPOLLPRI;
207 ep_evt.data.fd = srv_sock;
209 r = epoll_ctl(epfd, EPOLL_CTL_ADD, srv_sock, &ep_evt);
210 if(ISERR(r))
211 exit(SRV_SOCK_SETUP_EPOLL_CTL_ADD_FAILURE);
214 /*---------------------------------------------------------------------------*/
215 /* http method can request to close the connexion exiting, we are violent: we close the tcp cnx
216 though we should send a response in order to be rfc correct */
217 #define HTTP_CLOSE 1
219 /* PAGE_SZ is way bigger than 4 bytes */
220 static u8 http_method_is_get(void)
222 if ( page[0] == 'G'
223 && page[1] == 'E'
224 && page[2] == 'T'
225 && page[3] == ' ')
226 return 1;
227 return 0;
230 /* PAGE_SZ is way bigger than 4 bytes */
231 static u8 http_method_is_head(void)
233 if ( page[0] == 'H'
234 && page[1] == 'E'
235 && page[2] == 'A'
236 && page[3] == 'D')
237 return 1;
238 return 0;
241 static u8 http_method_match(void)
243 if (http_method_is_get())
244 http_method = HTTP_METHOD_GET;
245 else if (http_method_is_head())
246 http_method = HTTP_METHOD_HEAD;
247 else
248 return HTTP_CLOSE; /* garbage or method not handled */
249 return 0;
252 /* if we have an error or we time out, notify for socket closing */
253 #define CNX_SOCK_RD_WAIT_FAILURE 1
254 #define fd_set cnx_sock_fd_set
255 #define ul_idx cnx_sock_fd_set_ul_idx
256 #define ul_shift cnx_sock_fd_ul_shift
257 static u8 cnx_sock_rd_wait(void)
259 struct timeval tv;
260 sl r;
262 fd_set[ul_idx] = (1UL << ul_shift); /* was zero-ed in global_init */
264 tv.sec = CONFIG_CNX_WAIT_TIMEOUT;
265 tv.usec = 0;
267 loop {
268 /* pselect6 is common on x86_64 and aarch64 */
269 r = pselect6(cnx_sock + 1, &cnx_sock_fd_set[0], 0, 0, &tv,0);
270 /* XXX: to address some concerns: by design for the sake of
271 simplicity we ignore handled signals here. May do state
272 management around epoll_pwait someday. */
273 if (r != -EINTR)
274 break;
277 if (ISERR(r) || r == 0) /* r != 1 */
278 return CNX_SOCK_RD_WAIT_FAILURE;
279 return 0;
281 #undef fd_set
282 #undef byte_offset
283 #undef byte_shift
285 #define CNX_SOCK_RD_FAILURE -1
286 static sl cnx_sock_rd(void)
288 sl bytes_rd_n;
290 loop {
291 bytes_rd_n = read(cnx_sock, page + page_bytes_rd_n,
292 PAGE_SZ - page_bytes_rd_n);
293 if (bytes_rd_n != -EINTR) {
294 if (ISERR(bytes_rd_n))
295 bytes_rd_n = CNX_SOCK_RD_FAILURE;
296 break;
299 return bytes_rd_n;
302 static u8 http_method_rd(void)
304 u8 *c;
306 c = page;
308 loop {
309 u8 r;
310 sl bytes_rd_n;
312 r = cnx_sock_rd_wait();
313 if (r == CNX_SOCK_RD_WAIT_FAILURE)
314 break;
316 bytes_rd_n = cnx_sock_rd();
317 if (bytes_rd_n == CNX_SOCK_RD_FAILURE || bytes_rd_n == 0)
318 break;
320 page_bytes_rd_n += bytes_rd_n;
322 loop {
323 if (bytes_rd_n-- == 0)
324 break;
326 if (*c == ' ') {
327 /* got the space separator:method' 'target */
328 method_target_space = c;
329 return 0;
332 ++c;
335 if (page_bytes_rd_n == PAGE_SZ) /* no more page room */
336 break;
338 return HTTP_CLOSE;
341 /* XXX:must be called with room in the page or it will loop with 0 read bytes
342 till the other end decides to shutdown the connection */
343 #define UNABLE_TO_READ_AT_LEAST_ONE_BYTE 1
344 static u8 http_rd_at_least_one_byte(void)
346 loop {
347 u8 r;
348 sl bytes_rd_n;
350 r = cnx_sock_rd_wait();
351 if (r == CNX_SOCK_RD_WAIT_FAILURE)
352 break;
354 bytes_rd_n = cnx_sock_rd();
355 if (bytes_rd_n == CNX_SOCK_RD_FAILURE || bytes_rd_n == 0)
356 break;
358 if (bytes_rd_n != 0) {
359 page_bytes_rd_n += bytes_rd_n;
360 return 0;
363 return UNABLE_TO_READ_AT_LEAST_ONE_BYTE;
366 static u8 http_target_end_locate(void)
368 u8 *c;
370 c = method_target_space + 1;
372 loop {
373 /* need at least 1 more byte to keep going */
374 if (c == (page + page_bytes_rd_n)) {
375 u8 r;
377 if (page_bytes_rd_n == PAGE_SZ)
378 break;/* but no more room in our page */
380 /* we have still room in our page */
382 r = http_rd_at_least_one_byte();
383 if (r == UNABLE_TO_READ_AT_LEAST_ONE_BYTE)
384 break;
387 if (*c == ' ') {
388 target_end = c;
389 return 0;
391 ++c;
393 return HTTP_CLOSE;
396 static u8 http_target_file_open(void)
398 sl r;
400 loop {
401 /* openat is common to x86_64 and aarch64 */
402 r = openat(target_start, O_RDONLY, 0);
403 if (r != -EINTR)
404 break;
406 if (ISERR(r))
407 return HTTP_CLOSE;
409 target_file_fd = (si)r;
410 return 0;
413 static u8 http_target_file_sz_get(void)
415 struct stat target_stat;
416 sl r;
418 memset(&target_stat, 0, sizeof(target_stat));
419 r = fstat(target_file_fd, &target_stat);
420 if (ISERR(r))
421 return HTTP_CLOSE;
423 target_file_sz = target_stat.size;
424 return 0;
427 /* if we have an error or we time out, notify for socket closing */
428 #define CNX_SOCK_SEND_WAIT_FAILURE 1
429 #define fd_set cnx_sock_fd_set
430 #define ul_idx cnx_sock_fd_set_ul_idx
431 #define ul_shift cnx_sock_fd_ul_shift
432 static u8 cnx_sock_send_wait(void)
434 struct timeval tv;
435 sl r;
437 fd_set[ul_idx] = (1UL << ul_shift); /* was zero-ed in global_init */
439 tv.sec = CONFIG_CNX_WAIT_TIMEOUT;
440 tv.usec = 0;
442 loop {
443 /* pselect6 is common on x86_64 and aarch64 */
444 r = pselect6(cnx_sock + 1, 0, &cnx_sock_fd_set[0], 0, &tv, 0);
445 /* XXX: to address some concerns: by design for the sake of
446 simplicity we ignore handled signals here. May do state
447 management around epoll_pwait someday. */
448 if (r != -EINTR)
449 break;
452 if (ISERR(r) || r == 0) /* r != 1 */
453 return CNX_SOCK_SEND_WAIT_FAILURE;
454 return 0;
456 #undef fd_set
457 #undef byte_offset
458 #undef byte_shift
460 #define CNX_SOCK_SEND_RESP_HDR_FAILURE -1
461 static sl cnx_sock_send_resp_hdr(void)
463 sl bytes_sent_n;
465 loop {
466 bytes_sent_n = write(cnx_sock, page, resp_hdr_sz);
467 if (bytes_sent_n != -EINTR) {
468 if (ISERR(bytes_sent_n))
469 bytes_sent_n = CNX_SOCK_SEND_RESP_HDR_FAILURE;
470 break;
473 return bytes_sent_n;
476 static u8 http_resp_hdr_send(void)
478 if (target_file_mime[0] == 0)
479 resp_hdr_sz = (sl)snprintf(page, PAGE_SZ, RESP_HDR_FMT,
480 target_file_sz);
481 else
482 resp_hdr_sz = (sl)snprintf(page, PAGE_SZ,
483 RESP_HDR_CONTENT_TYPE_FMT,
484 target_file_sz,
485 &target_file_mime[0]);
487 if (resp_hdr_sz == 0)
488 return HTTP_CLOSE;
490 loop {
491 u8 r;
492 sl bytes_sent_n;
494 r = cnx_sock_send_wait();
495 if (r == CNX_SOCK_SEND_WAIT_FAILURE)
496 return HTTP_CLOSE;
498 bytes_sent_n = cnx_sock_send_resp_hdr();
499 if (bytes_sent_n == CNX_SOCK_SEND_RESP_HDR_FAILURE)
500 break;
502 resp_hdr_sz -= bytes_sent_n;
504 if (resp_hdr_sz == 0)
505 return 0; /* resp hrd was sent */
507 return HTTP_CLOSE;
510 #define CNX_SOCK_SENDFILE_FAILURE -1
511 static sl cnx_sock_sendfile(void)
513 sl bytes_sent_n;
515 loop {
516 bytes_sent_n = sendfile(cnx_sock, target_file_fd, 0,
517 target_file_sz);
518 if (bytes_sent_n != -EINTR) {
519 if (ISERR(bytes_sent_n))
520 bytes_sent_n = CNX_SOCK_SENDFILE_FAILURE;
521 break;
524 return bytes_sent_n;
527 static u8 http_sendfile(void)
529 loop {
530 u8 r;
531 sl bytes_sent_n;
533 if (target_file_sz == 0)
534 break;
536 r = cnx_sock_send_wait();
537 if (r == CNX_SOCK_SEND_WAIT_FAILURE)
538 return HTTP_CLOSE;
540 bytes_sent_n = cnx_sock_sendfile();
541 if (bytes_sent_n == CNX_SOCK_SENDFILE_FAILURE)
542 break;
544 target_file_sz -= bytes_sent_n;
546 return HTTP_CLOSE;
549 static u8 *http_target_mime_file_path(void)
551 /* We have room in the page. target_end has not be modified */
552 target_end[0] = '.';
553 target_end[1] = 'm';
554 target_end[2] = 'i';
555 target_end[3] = 'm';
556 target_end[4] = 'e';
557 target_end[5] = 0;
558 return target_start;
561 static void http_target_mime_file(void)
563 u8 *mime_file_path;
564 sl r;
565 si mime_file_fd;
566 struct stat mime_file_stat;
567 ul bytes_to_read_n;
569 if (target_file_is_default)
570 mime_file_path = CONFIG_DEFAULT_FILE_MIME;
571 else
572 mime_file_path = http_target_mime_file_path();
574 /*--------------------------------------------------------------------*/
575 /* open */
576 loop {
577 /* openat is common to x86_64 and aarch64 */
578 r = openat(mime_file_path, O_RDONLY, 0);
579 if (r != -EINTR)
580 break;
582 if (ISERR(r))
583 goto direct_exit;
585 mime_file_fd = (si)r;
586 /*--------------------------------------------------------------------*/
588 /*--------------------------------------------------------------------*/
589 /* get size */
590 memset(&mime_file_stat, 0, sizeof(mime_file_stat));
592 r = fstat(mime_file_fd, &mime_file_stat);
593 if (ISERR(r))
594 goto direct_exit;
596 /* mime_file_stat.size */
597 /*--------------------------------------------------------------------*/
599 /*--------------------------------------------------------------------*/
600 /* check size */
601 if ((mime_file_stat.size + 1) > sizeof(target_file_mime)) {
602 r = -1;
603 goto direct_exit;
605 bytes_to_read_n = mime_file_stat.size;
606 /*--------------------------------------------------------------------*/
608 /*--------------------------------------------------------------------*/
609 /* read it */
610 loop {
611 r = read(mime_file_fd, &target_file_mime[0]
612 + mime_file_stat.size - bytes_to_read_n,
613 bytes_to_read_n);
614 if (r != -EINTR) {
615 if (ISERR(r))
616 goto close_mime_file;
618 bytes_to_read_n -= r;
620 if (bytes_to_read_n == 0)
621 break;
624 /*--------------------------------------------------------------------*/
626 target_file_mime[mime_file_stat.size] = 0;
628 close_mime_file:
629 close(mime_file_fd);
631 direct_exit:
632 if (ISERR(r))
633 target_file_mime[0] = 0; /* no mime */
636 /*---------------------------------------------------------------------------*/
638 static void cnx_handle(void)
640 u8 r;
642 page_bytes_rd_n = 0;
644 /* read till we find the first space */
645 r = http_method_rd();
646 if (r == HTTP_CLOSE)
647 goto direct_exit;
649 /* is this space defining a reasonable method name? */
650 if (method_target_space == (page + PAGE_SZ)) /* huge method name */
651 goto direct_exit;
653 r = http_method_match();
654 if (r == HTTP_CLOSE)
655 goto direct_exit;
657 r = http_target_end_locate();
658 if (r == HTTP_CLOSE)
659 goto direct_exit;
661 /* now we check we have room for the ".mime" extension */
662 if ((target_end - 1 + sizeof(".mime")) >= (page + PAGE_SZ))
663 goto direct_exit;
665 /* target is exactly "/" or prepare the path */
666 if ((target_end - (method_target_space + 1)) == 1
667 && method_target_space[1] == '/') {
668 target_file_is_default = 1;
669 target_start = CONFIG_DEFAULT_FILE;
670 } else {
671 target_file_is_default = 0;
672 target_start = method_target_space + 1;
673 *target_end = 0;
676 r = http_target_file_open();
677 if (r == HTTP_CLOSE)
678 goto direct_exit;
680 r = http_target_file_sz_get();
681 if (r == HTTP_CLOSE)
682 goto close_target_file;
684 http_target_mime_file();
686 r = http_resp_hdr_send();
687 if (r == HTTP_CLOSE)
688 goto close_target_file;
690 if (http_method == HTTP_METHOD_GET)
691 (void)http_sendfile();
693 close_target_file:
694 close(target_file_fd);
695 direct_exit:
696 return;
699 static void cnx_sock_close(void)
701 loop {
702 sl r;
704 r = close(cnx_sock);
705 if (r != -EINTR) /* ignores errors */
706 break;
710 static void cnx_sock_fd_set_params(void)
712 si ul_bits_n;
714 ul_bits_n = 8 * sizeof(ul);
716 cnx_sock_fd_set_ul_idx = cnx_sock / ul_bits_n;
717 cnx_sock_fd_ul_shift = cnx_sock % ul_bits_n;
720 static void cnxs_consume(void)
722 loop {
723 sl r;
724 #ifdef CONFIG_IPV4
725 struct sockaddr_in peer;
726 #else
727 struct sockaddr_in6 peer;
728 #endif
729 sl peer_len;
731 peer_len = sizeof(peer);
732 loop {
733 r = accept(srv_sock, &peer, &peer_len);
734 if (r != -EINTR && r != ECONNABORTED) /* based on man page */
735 break;
736 /* SIGSTOP will generate a EINTR */
739 if (r != -EAGAIN && ISERR(r))
740 exit(CNXS_CONSUME_ACCEPT_GENERIC_FAILURE);
741 if (peer_len != sizeof(peer))
742 exit(CNXS_CONSUME_ACCEPT_WRONG_PEER);
743 if (r == -EAGAIN)
744 break; /* no more connexion pending */
746 cnx_sock=(si)r;
748 cnx_sock_fd_set_params();
750 cnx_handle();
751 cnx_sock_close();
755 static void sigs_consume(void)
757 struct signalfd_siginfo info;
759 loop {
760 sl r;
762 loop {
763 memset(&info, 0, sizeof(info));
764 r = read(sigs_fd, &info, sizeof(info));
765 if (r != -EINTR)
766 break;
768 if (r != -EAGAIN && ((ISERR(r) || (r > 0
769 && r != sizeof(info)))))
770 exit(SIGS_CONSUME_SIGINFO_READ_FAILURE);
771 if (r == 0 || r == -EAGAIN)
772 break;
774 switch (info.ssi_signo) {
775 case SIGTERM:
776 exit(0);
777 break;
778 /* please, do add the ones you like */
783 static void main_loop(void)
785 loop {
786 struct epoll_event evts[2]; /*sigs_fd and srv_sock */
787 sl r;
788 sl j;
790 loop {
791 memset(evts, 0, sizeof(evts));
792 /* epoll_pwait is common to aarch64 and x86_64 */
793 r = epoll_pwait(epfd, evts, 2, -1, 0);
794 if (r != -EINTR)
795 break;
797 if (ISERR(r))
798 exit(MAIN_LOOP_EPOLL_WAIT_GENERIC_FAILURE);
800 j = 0;
801 loop {
802 if (j == r)
803 break;
805 if (evts[j].data.fd == sigs_fd) {
806 if(evts[j].events & EPOLLIN)
807 sigs_consume();
808 else
809 exit(MAIN_LOOP_EPOLL_WAIT_SIGS_FD_EVENT_IS_NOT_EPOLLIN);
810 } else if (evts[j].data.fd == srv_sock) {
811 if (evts[j].events & (EPOLLERR | EPOLLHUP | EPOLLPRI))
812 exit(MAIN_LOOP_EPOLL_WAIT_SRV_SOCK_UNEXPECTED_EVENT);
813 else if (evts[j].events & EPOLLIN)
814 cnxs_consume();
815 else
816 exit(MAIN_LOOP_EPOLL_WAIT_SRV_SOCK_UNKNOWN_FAILURE);
819 ++j;
824 static void srv_sock_create(void)
826 sl bool_true;
827 sl r;
829 #ifdef CONFIG_IPV4
830 r = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
831 #else
832 r = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, 0);
833 #endif
834 if (ISERR(r))
835 exit(SRV_SOCK_CREATE_FAILURE);
836 srv_sock = (si)r;
838 bool_true = 1;
839 r = setsockopt(srv_sock, SOL_SOCKET, SO_REUSEADDR, &bool_true,
840 sizeof(bool_true));
841 if (ISERR(r))
842 exit(SRV_SOCK_SET_SOCK_OPTION_FAILURE);
844 r = bind(srv_sock, &srv_addr, sizeof(srv_addr));
845 if (ISERR(r))
846 exit(SRV_SOCK_BIND_FAILURE);
848 r = listen(srv_sock, 0);
849 if (ISERR(r))
850 exit(SRV_SOCK_LISTEN_FAILURE);
853 static void epoll_sigs_setup(void)
855 struct epoll_event ep_evt;
856 sl r;
858 memset(&ep_evt, 0, sizeof(ep_evt));
859 ep_evt.events = EPOLLET | EPOLLIN;
860 ep_evt.data.fd = sigs_fd;
861 r = epoll_ctl(epfd, EPOLL_CTL_ADD, sigs_fd, &ep_evt);
862 if (ISERR(r))
863 exit(EPOLL_SIGS_SETUP_EPOLL_ADD_FAILURE);
866 static void sigs_setup(void)
867 {/* synchronous treatement of signals with signalfd
868 cannot change SIGKILL, neither SIGSTOP */
869 u64 mask;
870 sl r;
872 mask = (~0);
873 r = rt_sigprocmask(SIG_BLOCK, &mask, 0, sizeof(mask));
874 if (ISERR(r))
875 exit(SIGS_SETUP_BLOCKING_FAILURE);
877 mask = SIGBIT(SIGTERM) | SIGBIT(SIGCHLD);
878 sigs_fd = (si)signalfd4(-1, &mask, sizeof(mask), SFD_NONBLOCK);
879 if (ISERR(sigs_fd))
880 exit(SIGS_SETUP_HANDLERS_FAILURE);
883 static void page_mmap(void)
885 sl addr;
887 addr = mmap(PAGE_SZ, RD | WR, PRIVATE | ANONYMOUS);
888 if(addr == 0 || ISERR(addr))
889 exit(RCV_PAGE_MMAP_FAILURE);
891 page = (u8*)addr;
894 static void setup(void)
896 sigs_setup();
898 epfd =(si)epoll_create1(0);
899 if (ISERR(epfd))
900 exit(SETUP_EPOLL_CREATE_FAILURE);
902 epoll_sigs_setup();
903 srv_sock_create();
904 epoll_srv_sock_setup();
906 page_mmap();
909 static void globals_init(void)
911 #ifdef CONFIG_IPV4
912 srv_addr.family = AF_INET;
914 /* big endian port */
915 srv_addr.port = cpu_to_be16(CONFIG_LISTENING_PORT);
916 srv_addr.addr = cpu_to_be32(LISTENING_IPV4);
917 #else
918 srv_addr.sin6_family = AF_INET6;
920 /* big endian port */
921 srv_addr.sin6_port = cpu_to_be16(CONFIG_LISTENING_PORT);
922 listening_ipv6_init();
923 srv_addr.sin6_addr = listening_ipv6; /* C compiler block copy */
924 #endif
926 srv_sock = -1; /* our listening socket */
927 cnx_sock = -1; /* a cnx socket from accept */
929 sigs_fd = -1; /* fd for signals */
930 epfd = -1; /* epoll fd */
932 memset(&cnx_sock_fd_set[0], 0, sizeof(cnx_sock_fd_set));
935 static void chroot_do(void)
937 sl r;
939 r = chroot(CONFIG_CHROOT_PATH);
940 if (ISERR(r))
941 exit(CHROOT_FAILURE);
943 r = chdir("/");
944 if (ISERR(r))
945 exit(CHDIR_FAILURE);
949 /******************************************************************************/
950 /******************************************************************************/
951 /******************************************************************************/
954 /* XXX:may do the daemonic stuff if _really_ we need it */
955 void _start(void)
957 close(0);
958 close(1);
959 close(2);
960 chroot_do();
961 globals_init();
962 setup();
963 main_loop();