Line | Count | Source (jump to first uncovered line) |
1 | | /* dnsmasq is Copyright (c) 2000-2025 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 | | |
42 | | static struct pollfd *pollfds = NULL; |
43 | | static 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. */ |
48 | | static nfds_t fd_search(int fd) |
49 | 0 | { |
50 | 0 | nfds_t left, right, mid; |
51 | | |
52 | 0 | if ((right = nfds) == 0) |
53 | 0 | return 0; |
54 | | |
55 | 0 | left = 0; |
56 | | |
57 | 0 | while (1) |
58 | 0 | { |
59 | 0 | if (right == left + 1) |
60 | 0 | return (pollfds[left].fd >= fd) ? left : right; |
61 | | |
62 | 0 | mid = (left + right)/2; |
63 | | |
64 | 0 | if (pollfds[mid].fd > fd) |
65 | 0 | right = mid; |
66 | 0 | else |
67 | 0 | left = mid; |
68 | 0 | } |
69 | 0 | } |
70 | | |
71 | | void poll_reset(void) |
72 | 0 | { |
73 | 0 | nfds = 0; |
74 | 0 | } |
75 | | |
76 | | int do_poll(int timeout) |
77 | 0 | { |
78 | 0 | return poll(pollfds, nfds, timeout); |
79 | 0 | } |
80 | | |
81 | | int poll_check(int fd, short event) |
82 | 0 | { |
83 | 0 | nfds_t i = fd_search(fd); |
84 | | |
85 | 0 | if (i < nfds && pollfds[i].fd == fd) |
86 | 0 | return pollfds[i].revents & event; |
87 | | |
88 | 0 | return 0; |
89 | 0 | } |
90 | | |
91 | | void poll_listen(int fd, short event) |
92 | 0 | { |
93 | 0 | nfds_t i = fd_search(fd); |
94 | | |
95 | 0 | if (i < nfds && pollfds[i].fd == fd) |
96 | 0 | pollfds[i].events |= event; |
97 | 0 | else |
98 | 0 | { |
99 | 0 | if (arrsize == nfds) |
100 | 0 | { |
101 | | /* Array too small. Extend. */ |
102 | 0 | struct pollfd *new; |
103 | |
|
104 | 0 | arrsize = (arrsize == 0) ? 64 : arrsize * 2; |
105 | |
|
106 | 0 | if (!(new = whine_realloc(pollfds, arrsize * sizeof(struct pollfd)))) |
107 | 0 | return; |
108 | | |
109 | 0 | pollfds = new; |
110 | 0 | } |
111 | | |
112 | 0 | memmove(&pollfds[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd)); |
113 | |
|
114 | 0 | pollfds[i].fd = fd; |
115 | 0 | pollfds[i].events = event; |
116 | 0 | nfds++; |
117 | 0 | } |
118 | 0 | } |