From 8abd74f3dc9a0482111a2fc8f99b59434f80acd9 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 14 Mar 2018 05:31:09 +0100 Subject: add suspend_resume_epoll example (from mailinglist) --- src/examples/Makefile.am | 12 +++ src/examples/suspend_resume_epoll.c | 202 ++++++++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 src/examples/suspend_resume_epoll.c (limited to 'src/examples') diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am index 58f4b4aa..545a236a 100644 --- a/src/examples/Makefile.am +++ b/src/examples/Makefile.am @@ -29,6 +29,11 @@ noinst_PROGRAMS = \ fileserver_example_external_select \ refuse_post_example +if MHD_HAVE_EPOLL +noinst_PROGRAMS += \ + suspend_resume_epoll +endif + EXTRA_DIST = msgs_i18n.c noinst_EXTRA_DIST = msgs_i18n.c @@ -123,6 +128,13 @@ benchmark_CPPFLAGS = \ benchmark_LDADD = \ $(top_builddir)/src/microhttpd/libmicrohttpd.la +suspend_resume_epoll_SOURCES = \ + suspend_resume_epoll.c +suspend_resume_epoll_CPPFLAGS = \ + $(AM_CPPFLAGS) $(CPU_COUNT_DEF) +suspend_resume_epoll_LDADD = \ + $(top_builddir)/src/microhttpd/libmicrohttpd.la + benchmark_https_SOURCES = \ benchmark_https.c benchmark_https_CPPFLAGS = \ diff --git a/src/examples/suspend_resume_epoll.c b/src/examples/suspend_resume_epoll.c new file mode 100644 index 00000000..adff673c --- /dev/null +++ b/src/examples/suspend_resume_epoll.c @@ -0,0 +1,202 @@ +/* + This file is part of libmicrohttpd + Copyright (C) 2018 Christian Grothoff (and other contributing authors) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/** + * @file suspend_resume_epoll.c + * @brief example for how to use libmicrohttpd with epoll() and + * resume a suspended connection + * @author Robert D Kocisko + * @author Christian Grothoff + */ +#include "platform.h" +#include +#include +#include +#include + +#define TIMEOUT_INFINITE -1 + +struct Request { + struct MHD_Connection *connection; + int timerfd; +}; + + +static int epfd; + +static struct epoll_event evt; + + +static int +ahc_echo (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, size_t *upload_data_size, void **ptr) +{ + struct MHD_Response *response; + int ret; + struct Request* req; + struct itimerspec ts; + (void)url; /* Unused. Silence compiler warning. */ + (void)version; /* Unused. Silence compiler warning. */ + (void)upload_data; /* Unused. Silence compiler warning. */ + (void)upload_data_size; /* Unused. Silence compiler warning. */ + + req = *ptr; + if (!req) + { + + req = malloc(sizeof(struct Request)); + req->connection = connection; + req->timerfd = 0; + *ptr = req; + return MHD_YES; + } + + if (req->timerfd) + { + // send response (echo request url) + response = MHD_create_response_from_buffer (strlen (url), + (void *) url, + MHD_RESPMEM_MUST_COPY); + ret = MHD_queue_response (connection, MHD_HTTP_OK, response); + MHD_destroy_response (response); + return ret; + } + else + { + // create timer and suspend connection + req->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); + if (-1 == req->timerfd) + { + printf("timerfd_create: %s", strerror(errno)); + return MHD_NO; + } + evt.events = EPOLLIN; + evt.data.ptr = req; + if (-1 == epoll_ctl(epfd, EPOLL_CTL_ADD, req->timerfd, &evt)) + { + printf("epoll_ctl: %s", strerror(errno)); + return MHD_NO; + } + ts.it_value.tv_sec = 1; + ts.it_value.tv_nsec = 0; + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + if (-1 == timerfd_settime(req->timerfd, 0, &ts, NULL)) + { + printf("timerfd_settime: %s", strerror(errno)); + return MHD_NO; + } + MHD_suspend_connection(connection); + return MHD_YES; + } +} + + +static int +connection_done(struct MHD_Connection *connection, + void **con_cls, + enum MHD_RequestTerminationCode toe) +{ + free(*con_cls); +} + + +int +main (int argc, + char *const *argv) +{ + struct MHD_Daemon *d; + const union MHD_DaemonInfo * info; + int current_event_count; + struct epoll_event events_list[1]; + struct Request *req; + uint64_t timer_expirations; + + if (argc != 2) + { + printf ("%s PORT\n", argv[0]); + return 1; + } + d = MHD_start_daemon (MHD_USE_EPOLL | MHD_ALLOW_SUSPEND_RESUME, + atoi (argv[1]), + NULL, NULL, &ahc_echo, NULL, + MHD_OPTION_NOTIFY_COMPLETED, &connection_done, NULL, + MHD_OPTION_END); + if (d == NULL) + return 1; + + info = MHD_get_daemon_info(d, MHD_DAEMON_INFO_EPOLL_FD); + if (info == NULL) + return 1; + + epfd = epoll_create1(EPOLL_CLOEXEC); + if (-1 == epfd) + return 1; + + evt.events = EPOLLIN; + evt.data.ptr = NULL; + if (-1 == epoll_ctl(epfd, EPOLL_CTL_ADD, info->epoll_fd, &evt)) + return 1; + + while (1) + { + int timeout; + MHD_UNSIGNED_LONG_LONG to; + + if (MHD_YES != + MHD_get_timeout (d, + &to)) + timeout = TIMEOUT_INFINITE; + else + timeout = (to < INT_MAX - 1) ? (int) to : (INT_MAX - 1); + current_event_count = epoll_wait(epfd, events_list, 1, timeout); + + if (1 == current_event_count) + { + if (events_list[0].data.ptr) + { + // A timer has timed out + req = events_list[0].data.ptr; + // read from the fd so the system knows we heard the notice + if (-1 == read(req->timerfd, &timer_expirations, sizeof(timer_expirations))) + { + return 1; + } + // Now resume the connection + MHD_resume_connection(req->connection); + } + } + else if (0 == current_event_count) + { + // no events: continue + } + else + { + // error + return 1; + } + if (! MHD_run(d)) + return 1; + } + + return 0; +} -- cgit v1.2.3