diff options
Diffstat (limited to 'examples/async/main.c')
| -rw-r--r-- | examples/async/main.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/examples/async/main.c b/examples/async/main.c new file mode 100644 index 0000000..dbf69a8 --- /dev/null +++ b/examples/async/main.c @@ -0,0 +1,232 @@ +/* As of FreeBSD 13.2, sigaction(2) still conforms to IEEE Std + * 1003.1-1990 (POSIX.1), which did not define SA_RESTART. + * FreeBSD supports it as an extension, but then _POSIX_C_SOURCE must + * not be defined. */ +#ifndef __FreeBSD__ +#define _POSIX_C_SOURCE 200809L +#endif + +#include <dynstr.h> +#include <libweb/handler.h> +#include <libweb/html.h> +#include <libweb/http.h> +#include <errno.h> +#include <signal.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static int send_response(const unsigned cnt, struct http_response *const r) +{ + int ret = -1; + + struct html_node *html = html_node_alloc("html"), *body, *p; + struct dynstr d, text; + + dynstr_init(&d); + dynstr_init(&text); + + if (!html) + { + fprintf(stderr, "%s: html_node_alloc failed\n", __func__); + goto end; + } + else if (!(body = html_node_add_child(html, "body"))) + { + fprintf(stderr, "%s: html_node_add_child body failed\n", __func__); + goto end; + } + else if (!(p = html_node_add_child(body, "p"))) + { + fprintf(stderr, "%s: html_node_add_child p failed\n", __func__); + goto end; + } + else if (dynstr_append(&text, "It took %u iterations to generate " + "this response!", cnt)) + { + fprintf(stderr, "%s: dynstr_append failed\n", __func__); + goto end; + } + else if (html_node_set_value(p, text.str)) + { + fprintf(stderr, "%s: html_node_set_value p failed\n", __func__); + goto end; + } + else if (html_serialize(html, &d)) + { + fprintf(stderr, "%s: html_serialize failed\n", __func__); + goto end; + } + + *r = (const struct http_response) + { + .status = HTTP_STATUS_OK, + .buf.rw = d.str, + .n = d.len, + .free = free + }; + + if (http_response_add_header(r, "Content-Type", "text/html")) + { + fprintf(stderr, "%s: http_response_add_header failed\n", __func__); + goto end; + } + + ret = 0; + +end: + dynstr_free(&text); + html_node_free(html); + + if (ret) + dynstr_free(&d); + + return ret; +} + +static int step(const struct http_payload *const pl, + struct http_response *const r, void *const user, void *step_args) +{ + unsigned *const cnt = step_args; + const unsigned max = 10; + + fprintf(stderr, "%s: step %u\n", __func__, *cnt); + + if (++(*cnt) >= max) + return send_response(*cnt, r); + + return 0; +} + +static int hello(const struct http_payload *const pl, + struct http_response *const r, void *const user) +{ + unsigned *const cnt = malloc(sizeof *cnt); + + if (!cnt) + { + fprintf(stderr, "%s: malloc(3): %s\n", __func__, strerror(errno)); + return -1; + } + + *r = (const struct http_response) + { + .step.payload = step, + .step_args = cnt + }; + + *cnt = 0; + return 0; +} + +static int on_length(const unsigned long long len, + const struct http_cookie *const c, struct http_response *const r, + void *const user) +{ + *r = (const struct http_response) + { + .status = HTTP_STATUS_FORBIDDEN + }; + + return 1; +} + +struct handler *handler; + +static void handle_signal(const int signum) +{ + switch (signum) + { + case SIGINT: + /* Fall through. */ + case SIGTERM: + handler_notify_close(handler); + break; + + default: + break; + } +} + +static int init_signals(void) +{ + struct sigaction sa = + { + .sa_handler = handle_signal, + .sa_flags = SA_RESTART + }; + + sigemptyset(&sa.sa_mask); + + static const struct signal + { + int signal; + const char *name; + } signals[] = + { + {.signal = SIGINT, .name = "SIGINT"}, + {.signal = SIGTERM, .name = "SIGTERM"}, + {.signal = SIGPIPE, .name = "SIGPIPE"} + }; + + for (size_t i = 0; i < sizeof signals / sizeof *signals; i++) + { + const struct signal *const s = &signals[i]; + + if (sigaction(s->signal, &sa, NULL)) + { + fprintf(stderr, "%s: sigaction(2) %s: %s\n", + __func__, s->name, strerror(errno)); + return -1; + } + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + int ret = EXIT_FAILURE; + const struct handler_cfg cfg = + { + .length = on_length + }; + + static const char *const urls[] = {"/", "/index.html"}; + + if (!(handler = handler_alloc(&cfg))) + { + fprintf(stderr, "%s: handler_alloc failed\n", __func__); + goto end; + } + + for (size_t i = 0; i < sizeof urls / sizeof *urls; i++) + if (handler_add(handler, urls[i], HTTP_OP_GET, hello, NULL)) + { + fprintf(stderr, "%s: handler_add failed\n", __func__); + goto end; + } + + unsigned short outport; + + if (handler_listen(handler, 0, &outport)) + { + fprintf(stderr, "%s: handler_listen failed\n", __func__); + goto end; + } + + printf("Listening on port %hu\n", outport); + + if (handler_loop(handler)) + { + fprintf(stderr, "%s: handler_loop failed\n", __func__); + goto end; + } + + ret = EXIT_SUCCESS; + +end: + handler_free(handler); + return ret; +} |
