diff options
Diffstat (limited to 'apps/netutils/thttpd/fdwatch.c')
-rw-r--r-- | apps/netutils/thttpd/fdwatch.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/apps/netutils/thttpd/fdwatch.c b/apps/netutils/thttpd/fdwatch.c new file mode 100644 index 000000000..50ea65e78 --- /dev/null +++ b/apps/netutils/thttpd/fdwatch.c @@ -0,0 +1,371 @@ +/**************************************************************************** + * netutils/thttpd/timers.c + * FD watcher routines for poll() + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Derived from the file of the same name in the original THTTPD package: + * + * Copyright © 1999,2000 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdlib.h> +#include <debug.h> +#include <poll.h> +#include <debug.h> + +#include "config.h" +#include "thttpd_alloc.h" +#include "fdwatch.h" + +#ifdef CONFIG_THTTPD + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/* Debug output from this file is normally suppressed. If enabled, be aware + * that output to stdout will interfere with CGI programs (you could use the + * the low-level debug (lldbg) functions which probably do not use stdout + */ + +#ifdef CONFIG_THTTPD_FDWATCH_DEBUG +# ifdef CONFIG_CPP_HAVE_VARARGS +# define fwdbg(format, arg...) ndbg(format, ##arg) +# define fwlldbg(format, arg...) nlldbg(format, ##arg) +# define fwvdbg(format, arg...) nvdbg(format, ##arg) +# define fwllvdbg(format, arg...) nllvdbg(format, ##arg) +# else +# define fwdbg ndbg +# define fwlldbg nlldbg +# define fwvdbg nvdbg +# define fwllvdbg nllvdbg +# endif +#else +# ifdef CONFIG_CPP_HAVE_VARARGS +# define fwdbg(x...) +# define fwlldbg(x...) +# define fwvdbg(x...) +# define fwllvdbg(x...) +# else +# define fwdbg (void) +# define fwlldbg (void) +# define fwvdbg (void) +# define fwllvdbg (void) +# endif +#endif + +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_THTTPD_FDWATCH_DEBUG +static void fdwatch_dump(const char *msg, FAR struct fdwatch_s *fw) +{ + int i; + + fwvdbg("%s\n", msg); + fwvdbg("nwatched: %d nfds: %d\n", fw->nwatched, fw->nfds); + for (i = 0; i < fw->nwatched; i++) + { + fwvdbg("%2d. pollfds: {fd: %d events: %02x revents: %02x} client: %p\n", + i+1, fw->pollfds[i].fd, fw->pollfds[i].events, + fw->pollfds[i].revents, fw->client[i]); + } + fwvdbg("nactive: %d next: %d\n", fw->nactive, fw->next); + for (i = 0; i < fw->nactive; i++) + { + fwvdbg("%2d. %d active\n", i, fw->ready[i]); + } +} +#else +# define fdwatch_dump(m,f) +#endif + +static int fdwatch_pollndx(FAR struct fdwatch_s *fw, int fd) +{ + int pollndx; + + /* Get the index associated with the fd */ + + for (pollndx = 0; pollndx < fw->nwatched; pollndx++) + { + if (fw->pollfds[pollndx].fd == fd) + { + fwvdbg("pollndx: %d\n", pollndx); + return pollndx; + } + } + + fwdbg("No poll index for fd %d: %d\n", fd); + return -1; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* Initialize the fdwatch data structures. Returns -1 on failure. */ + +struct fdwatch_s *fdwatch_initialize(int nfds) +{ + FAR struct fdwatch_s *fw; + + /* Allocate the fdwatch data structure */ + + fw = (struct fdwatch_s*)zalloc(sizeof(struct fdwatch_s)); + if (!fw) + { + fwdbg("Failed to allocate fdwatch\n"); + return NULL; + } + + /* Initialize the fdwatch data structures. */ + + fw->nfds = nfds; + + fw->client = (void**)httpd_malloc(sizeof(void*) * nfds); + if (!fw->client) + { + goto errout_with_allocations; + } + + fw->pollfds = (struct pollfd*)httpd_malloc(sizeof(struct pollfd) * nfds); + if (!fw->pollfds) + { + goto errout_with_allocations; + } + + fw->ready = (uint8_t*)httpd_malloc(sizeof(uint8_t) * nfds); + if (!fw->ready) + { + goto errout_with_allocations; + } + + fdwatch_dump("Initial state:", fw); + return fw; + +errout_with_allocations: + fdwatch_uninitialize(fw); + return NULL; +} + +/* Uninitialize the fwdatch data structure */ + +void fdwatch_uninitialize(struct fdwatch_s *fw) +{ + if (fw) + { + fdwatch_dump("Uninitializing:", fw); + if (fw->client) + { + httpd_free(fw->client); + } + + if (fw->pollfds) + { + httpd_free(fw->pollfds); + } + + if (fw->ready) + { + httpd_free(fw->ready); + } + + httpd_free(fw); + } +} + +/* Add a descriptor to the watch list. rw is either FDW_READ or FDW_WRITE. */ + +void fdwatch_add_fd(struct fdwatch_s *fw, int fd, void *client_data) +{ + fwvdbg("fd: %d client_data: %p\n", fd, client_data); + fdwatch_dump("Before adding:", fw); + + if (fw->nwatched >= fw->nfds) + { + fwdbg("too many fds\n"); + return; + } + + /* Save the new fd at the end of the list */ + + fw->pollfds[fw->nwatched].fd = fd; + fw->pollfds[fw->nwatched].events = POLLIN; + fw->client[fw->nwatched] = client_data; + + /* Increment the count of watched descriptors */ + + fw->nwatched++; + fdwatch_dump("After adding:", fw); +} + +/* Remove a descriptor from the watch list. */ + +void fdwatch_del_fd(struct fdwatch_s *fw, int fd) +{ + int pollndx; + + fwvdbg("fd: %d\n", fd); + fdwatch_dump("Before deleting:", fw); + + /* Get the index associated with the fd */ + + pollndx = fdwatch_pollndx(fw, fd); + if (pollndx >= 0) + { + /* Decrement the number of fds in the poll table */ + + fw->nwatched--; + + /* Replace the deleted one with the one at the the end + * of the list. + */ + + if (pollndx != fw->nwatched) + { + fw->pollfds[pollndx] = fw->pollfds[fw->nwatched]; + fw->client[pollndx] = fw->client[fw->nwatched]; + } + } + fdwatch_dump("After deleting:", fw); +} + +/* Do the watch. Return value is the number of descriptors that are ready, + * or 0 if the timeout expired, or -1 on errors. A timeout of INFTIM means + * wait indefinitely. + */ + +int fdwatch(struct fdwatch_s *fw, long timeout_msecs) +{ + int ret; + int i; + + /* Wait for activity on any of the desciptors. When poll() returns, ret + * will hold the number of descriptors with activity (or zero on a timeout + * or <0 on an error. + */ + + fdwatch_dump("Before waiting:", fw); + fwvdbg("Waiting... (timeout %d)\n", timeout_msecs); + fw->nactive = 0; + fw->next = 0; + ret = poll(fw->pollfds, fw->nwatched, (int)timeout_msecs); + fwvdbg("Awakened: %d\n", ret); + + /* Look through all of the descriptors and make a list of all of them than + * have activity. + */ + + if (ret > 0) + { + for (i = 0; i < fw->nwatched; i++) + { + /* Is there activity on this descriptor? */ + + if (fw->pollfds[i].revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL)) + { + /* Yes... save it in a shorter list */ + + fwvdbg("pollndx: %d fd: %d revents: %04x\n", + i, fw->pollfds[i].fd, fw->pollfds[i].revents); + + fw->ready[fw->nactive++] = fw->pollfds[i].fd; + if (fw->nactive == ret) + { + /* We have all of them, break out early */ + + break; + } + } + } + } + + /* Return the number of descriptors with activity */ + + fwvdbg("nactive: %d\n", fw->nactive); + fdwatch_dump("After wakeup:", fw); + return ret; +} + +/* Check if a descriptor was ready. */ + +int fdwatch_check_fd(struct fdwatch_s *fw, int fd) +{ + int pollndx; + + fwvdbg("fd: %d\n", fd); + fdwatch_dump("Checking:", fw); + + /* Get the index associated with the fd */ + + pollndx = fdwatch_pollndx(fw, fd); + if (pollndx >= 0 && (fw->pollfds[pollndx].revents & POLLERR) == 0) + { + return fw->pollfds[pollndx].revents & (POLLIN | POLLHUP | POLLNVAL); + } + + fwvdbg("POLLERR fd: %d\n", fd); + return 0; +} + +void *fdwatch_get_next_client_data(struct fdwatch_s *fw) +{ + fdwatch_dump("Before getting client data:", fw); + if (fw->next >= fw->nwatched) + { + fwvdbg("All client data returned: %d\n", fw->next); + return (void*)-1; + } + + fwvdbg("client_data[%d]: %p\n", fw->next, fw->client[fw->next]); + return fw->client[fw->next++]; +} + +#endif /* CONFIG_THTTPD */ + |