1/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley 2 3 This program is free software; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License as published by 5 the Free Software Foundation; version 2 dated June, 1991, or 6 (at your option) version 3 dated 29 June, 2007. 7 8 This program is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License 14 along with this program. If not, see <http://www.gnu.org/licenses/>. 15*/ 16 17#include "dnsmasq.h" 18 19/* Wrapper for poll(). Allocates and extends array of struct pollfds, 20 keeps them in fd order so that we can set and test conditions on 21 fd using a simple but efficient binary chop. */ 22 23/* poll_reset() 24 poll_listen(fd, event) 25 . 26 . 27 poll_listen(fd, event); 28 29 hits = do_poll(timeout); 30 31 if (poll_check(fd, event) 32 . 33 . 34 35 if (poll_check(fd, event) 36 . 37 . 38 39 event is OR of POLLIN, POLLOUT, POLLERR, etc 40*/ 41 42static struct pollfd *pollfds = NULL; 43static nfds_t nfds, arrsize = 0; 44 45/* Binary search. Returns either the pollfd with fd, or 46 if the fd doesn't match, or return equals nfds, the entry 47 to the left of which a new record should be inserted. */ 48static nfds_t fd_search(int fd) 49{ 50 nfds_t left, right, mid; 51 52 if ((right = nfds) == 0) 53 return 0; 54 55 left = 0; 56 57 while (1) 58 { 59 if (right == left + 1) 60 return (pollfds[left].fd >= fd) ? left : right; 61 62 mid = (left + right)/2; 63 64 if (pollfds[mid].fd > fd) 65 right = mid; 66 else 67 left = mid; 68 } 69} 70 71void poll_reset(void) 72{ 73 nfds = 0; 74} 75 76int do_poll(int timeout) 77{ 78 return poll(pollfds, nfds, timeout); 79} 80 81int poll_check(int fd, short event) 82{ 83 nfds_t i = fd_search(fd); 84 85 if (i < nfds && pollfds[i].fd == fd) 86 return pollfds[i].revents & event; 87 88 return 0; 89} 90 91void poll_listen(int fd, short event) 92{ 93 nfds_t i = fd_search(fd); 94 95 if (i < nfds && pollfds[i].fd == fd) 96 pollfds[i].events |= event; 97 else 98 { 99 if (arrsize != nfds) 100 memmove(&pollfds[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd)); 101 else 102 { 103 /* Array too small, extend. */ 104 struct pollfd *new; 105 106 arrsize = (arrsize == 0) ? 64 : arrsize * 2; 107 108 if (!(new = whine_malloc(arrsize * sizeof(struct pollfd)))) 109 return; 110 111 if (pollfds) 112 { 113 memcpy(new, pollfds, i * sizeof(struct pollfd)); 114 memcpy(&new[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd)); 115 free(pollfds); 116 } 117 118 pollfds = new; 119 } 120 121 pollfds[i].fd = fd; 122 pollfds[i].events = event; 123 nfds++; 124 } 125} 126