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