| 1 | #include <signal.h> |
|---|
| 2 | #include <stdlib.h> |
|---|
| 3 | #include <string.h> |
|---|
| 4 | #include <unistd.h> |
|---|
| 5 | #include <sys/epoll.h> |
|---|
| 6 | #include <sys/types.h> |
|---|
| 7 | #include <sys/stat.h> |
|---|
| 8 | #include <fcntl.h> |
|---|
| 9 | |
|---|
| 10 | #include "zhttpd.h" |
|---|
| 11 | #include "tcp.h" |
|---|
| 12 | |
|---|
| 13 | static volatile int running; |
|---|
| 14 | zhttpd_context_t zhttpd = {.handler = NULL}; |
|---|
| 15 | |
|---|
| 16 | static void daemonize() { |
|---|
| 17 | switch (fork()) { |
|---|
| 18 | case -1: |
|---|
| 19 | exit(1); |
|---|
| 20 | case 0: |
|---|
| 21 | break; |
|---|
| 22 | default: |
|---|
| 23 | exit(0); |
|---|
| 24 | } |
|---|
| 25 | setsid(); |
|---|
| 26 | chdir("/"); |
|---|
| 27 | int devnull = open("/dev/null", O_RDWR); |
|---|
| 28 | dup2(devnull, STDIN_FILENO); |
|---|
| 29 | dup2(devnull, STDOUT_FILENO); |
|---|
| 30 | dup2(devnull, STDERR_FILENO); |
|---|
| 31 | close(devnull); |
|---|
| 32 | } |
|---|
| 33 | |
|---|
| 34 | static void sighandler(int signal) { |
|---|
| 35 | if (signal == SIGHUP) { |
|---|
| 36 | running = 2; |
|---|
| 37 | } else { |
|---|
| 38 | running = 0; |
|---|
| 39 | } |
|---|
| 40 | } |
|---|
| 41 | |
|---|
| 42 | static void configure() { |
|---|
| 43 | zhttpd.threads = 32; |
|---|
| 44 | zhttpd.timeout = 5; |
|---|
| 45 | zhttpd.daemonize = 1; |
|---|
| 46 | } |
|---|
| 47 | |
|---|
| 48 | static void cleanup() { |
|---|
| 49 | close(zhttpd.epollfd); |
|---|
| 50 | zthread_destroy(zhttpd.threadpool); |
|---|
| 51 | zhttpd_vfs_t *d = NULL; |
|---|
| 52 | for (zhttpd_vfs_t *c = zhttpd.vfs; c; c = d) { |
|---|
| 53 | c->handler->vfs_context_destroy(c->context); |
|---|
| 54 | d = c->next; |
|---|
| 55 | free(c); |
|---|
| 56 | } |
|---|
| 57 | } |
|---|
| 58 | |
|---|
| 59 | static void run() { |
|---|
| 60 | running = 1; |
|---|
| 61 | zhttpd.threadpool = zthread_create(zhttpd.threads); |
|---|
| 62 | zhttpd.epollfd = epoll_create(0); |
|---|
| 63 | zhttpd_tcp_cloexec(zhttpd.epollfd); |
|---|
| 64 | struct epoll_event *events = malloc |
|---|
| 65 | (sizeof(struct epoll_event) * zhttpd.threads); |
|---|
| 66 | |
|---|
| 67 | do { |
|---|
| 68 | int ready = zthread_step(zhttpd.threadpool, zhttpd.timeout); |
|---|
| 69 | int signals = epoll_wait(zhttpd.epollfd, events, zhttpd.threads, |
|---|
| 70 | (ready) ? 0 : 1000); |
|---|
| 71 | for (int i = 0; i < signals; i++) { |
|---|
| 72 | ((zthread_t*)events[i].data.ptr)->status = ZTHREAD_READY; |
|---|
| 73 | } |
|---|
| 74 | } while(running == 1); |
|---|
| 75 | free(events); |
|---|
| 76 | } |
|---|
| 77 | |
|---|
| 78 | int main() { |
|---|
| 79 | struct sigaction action; |
|---|
| 80 | memset(&action, 0, sizeof(action)); |
|---|
| 81 | action.sa_handler = sighandler; |
|---|
| 82 | sigaction(SIGHUP, &action, NULL); |
|---|
| 83 | sigaction(SIGTERM, &action, NULL); |
|---|
| 84 | action.sa_handler = SIG_IGN; |
|---|
| 85 | sigaction(SIGPIPE, &action, NULL); |
|---|
| 86 | |
|---|
| 87 | int firstrun = 1; |
|---|
| 88 | do { |
|---|
| 89 | configure(); |
|---|
| 90 | if (firstrun && zhttpd.daemonize) { |
|---|
| 91 | daemonize(); |
|---|
| 92 | firstrun = 0; |
|---|
| 93 | } |
|---|
| 94 | run(); |
|---|
| 95 | cleanup(); |
|---|
| 96 | } while(running); |
|---|
| 97 | return 0; |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | int zhttpd_vfs_mount(const char *point, zhttpd_options_t *options) { |
|---|
| 101 | size_t pointlen = strlen(point); |
|---|
| 102 | const char *handlername = zhttpd_options_get(options, "handler"); |
|---|
| 103 | if (!handlername) { |
|---|
| 104 | return ZHTTPD_EINVAL; |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | zhttpd_handler_t *handler = NULL; |
|---|
| 108 | for (zhttpd_handler_t *c = zhttpd.handler; c; c = c->next) { |
|---|
| 109 | if (!strcmp(handlername, c->name)) { |
|---|
| 110 | handler = c; |
|---|
| 111 | break; |
|---|
| 112 | } |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | if (!handler) { |
|---|
| 116 | return ZHTTPD_ENOENT; |
|---|
| 117 | } |
|---|
| 118 | |
|---|
| 119 | zhttpd_vfs_t *mount = calloc(1, sizeof(zhttpd_vfs_t) + pointlen + 2); |
|---|
| 120 | if (!mount) { |
|---|
| 121 | return ZHTTPD_ENOMEM; |
|---|
| 122 | } |
|---|
| 123 | |
|---|
| 124 | memcpy(mount->pattern, point, pointlen); |
|---|
| 125 | if (point[pointlen - 1] != '/') { |
|---|
| 126 | mount->pattern[pointlen++] = '/'; |
|---|
| 127 | } |
|---|
| 128 | mount->patternlen = pointlen; |
|---|
| 129 | mount->handler = handler; |
|---|
| 130 | mount->context = handler->vfs_context_create(options); |
|---|
| 131 | mount->next = zhttpd.vfs; |
|---|
| 132 | zhttpd.vfs = mount; |
|---|
| 133 | |
|---|
| 134 | return ZHTTPD_OK; |
|---|
| 135 | } |
|---|
| 136 | |
|---|
| 137 | const char* zhttpd_options_get(zhttpd_options_t *options, const char *key) { |
|---|
| 138 | size_t keylen = strlen(key); |
|---|
| 139 | for (; options; options = options->next) { |
|---|
| 140 | if (!strcmp(key, options->option) && options->option[keylen] == '=') { |
|---|
| 141 | return &options->option[keylen + 1]; |
|---|
| 142 | } |
|---|
| 143 | } |
|---|
| 144 | return NULL; |
|---|
| 145 | } |
|---|
| 146 | |
|---|
| 147 | void zhttpd_register(zhttpd_handler_t *handler) { |
|---|
| 148 | handler->next = zhttpd.handler; |
|---|
| 149 | zhttpd.handler = handler; |
|---|
| 150 | } |
|---|